digitalprog/ruby_provisioning_api

View on GitHub
lib/ruby_provisioning_api/group.rb

Summary

Maintainability
A
2 hrs
Test Coverage
module RubyProvisioningApi

  # The group class describes a google apps group. Every group can have multiple members. Members can be either
  # users or other groups.
  #
  # @attr [String] group_id Group identification
  # @attr [String] group_name Group name
  # @attr [String] description Group description
  # @attr [String] email_permission Group permission: Owner or Member 
  #
  class Group
    extend Entity
    include Member
    include Owner

    include ActiveModel::Validations
    include ActiveModel::Dirty

    attr_accessor :group_id, :group_name, :description, :email_permission
    validates :group_id, :group_name, :description, :email_permission, :presence => true

    # Group attributes list.
    # This constant is used to dynamically extract group's attributes from the google API response.
    #
    GROUP_ATTRIBUTES = ['groupId','groupName','description','emailPermission']

    # @param [Hash] params the options to create a Group with.
    # @option params [String] :group_id Group identification
    # @option params [String] :group_name Group name
    # @option params [String] :description Group description
    # @option params [String] :email_permission Group permission: Owner or Member
    #
    def initialize(params = {})
      params.each do |name, value|
        send("#{name}=", value)
      end
    end

    # Retrieve all groups in the domain 
    # @note This method executes a <b>GET</b> request to <i>apps-apis.google.com/a/feeds/group/2.0/domain[?[start=]]</i>
    #
    # @example Retrieve all group in the current domain
    #   RubyProvisioningApi::Group.all # => [Array<Group>]
    #
    # @see https://developers.google.com/google-apps/provisioning/#retrieving_all_groups_in_a_domain
    # @return [Array<Group>] all groups in the domain
    #
    def self.all
      response = perform(RubyProvisioningApi.configuration.group_actions[:retrieve_all])
      # Perform the request & Check if the response contains an error
      check_response(response)
      # Parse the response
      xml = Nokogiri::XML(response.body)
      # Return the array of Groups
      groups = parse_group_response(xml)
      while (np = next_page(xml))
        params = prepare_params_for(:group_page, "startFrom" => np.to_s.split("start=").last)
        response = perform(params)
        xml = Nokogiri::XML(response.body)
        groups += parse_group_response(xml)
      end
      groups
    end

    # Retrieve a group
    # @param [String] group_id Group identification
    # @note This method executes a <b>GET</b> request to <i>apps-apis.google.com/a/feeds/group/2.0/domain/groupId </i>
    #
    # @example Find the group "foo"
    #   group = RubyProvisioningApi::Group.find("foo") # => [Group]
    #
    # @see https://developers.google.com/google-apps/provisioning/#retrieving_a_group
    # @return [Group] the group found
    # @raise [Error] if group does not exist
    #      
    def self.find(group_id)
      params = prepare_params_for(:retrieve, "groupId" => group_id)
      response = perform(params)
      # Check if the response contains an error
      check_response(response)
      # Parse the response
      xml = Nokogiri::XML(response.body)
      group = Group.new
      GROUP_ATTRIBUTES.each do |attribute_name|
        name = "#{attribute_name.underscore}="
        value = xml.children.css("entry apps|property[name='#{attribute_name}']").attribute("value").value
        if name.eql?("group_id=")
          value = value.split("@").first
        end
        group.send(name, value)
      end
      group
    end

    # Initialize and save a group 
    # @param [Hash] params the options to create a Group with.
    # @option params [String] :group_id Group identification
    # @option params [String] :group_name Group name
    # @option params [String] :description Group description 
    # @option params [String] :email_permission Group permission: Owner or Member 
    # @note This method executes a <b>POST</b> request to <i>apps-apis.google.com/a/feeds/group/2.0/domain</i>
    #
    # @example Create the group "foo"
    #   group = RubyProvisioningApi::Group.create(:group_id => "foo",
    #                                             :group_name => "foo name" ,
    #                                             :description => "bar",
    #                                             :email_permission => "Owner") # => true
    #
    # @see https://developers.google.com/google-apps/provisioning/#creating_a_group
    # @return [Boolean] true if created, false if not valid or not created
    # @raise [Error] if group already exists (group_id must be unique)
    #    
    def self.create(params = {})
      group = Group.new(params).save
    end

    # Save a group
    # @note This method executes a <b>POST</b> request to <i>apps-apis.google.com/a/feeds/group/2.0/domain</i>
    #
    # @example Save the group "foo"
    #   group = RubyProvisioningApi::Group.new( :group_id => "foo", :group_name => "foo name" , :description => "bar", :email_permission => "Owner" ).save # => true
    #
    # @see https://developers.google.com/google-apps/provisioning/#creating_a_group
    # @return [Boolean] true if saved, false if not valid or not saved
    # @raise [Error] if group already exists (group_id must be unique)
    #
    def save
      return false unless valid?
      # If group is present, this is an update
      update = Group.present?(group_id)
      # Creating the XML request
      builder = prepare_xml_request(:group_id => group_id , :group_name => group_name, :description => description, :email_permission => email_permission, :update => update)
      if !update
        puts "i'm here"
        puts RubyProvisioningApi.configuration.group_actions[:create]
        puts builder.to_xml
        #Acting on a new object
        # Check if the response contains an error
        self.class.check_response(self.class.perform(RubyProvisioningApi.configuration.group_actions[:create],builder.to_xml))
      else
        #Acting on an existing object
        params = self.class.prepare_params_for(:update, "groupId" => group_id)
        # Perform the request & Check if the response contains an error
        self.class.check_response(self.class.perform(params,builder.to_xml))
      end
    end

    # Update a group
    # @note This method executes a <b>PUT</b> request to <i>apps-apis.google.com/a/feeds/group/2.0/domain/groupId</i>
    #
    # @example Update the group "test" description from "foo" to "bar"
    #   group = RubyProvisioningApi::Group.find("test") # => true
    #   group.description # => "foo"
    #   group.description = "bar" # => "bar"
    #   group.update # => true
    #
    # @see https://developers.google.com/google-apps/provisioning/#updating_a_group
    # @return [Boolean] true if updated, false otherwise
    # @raise [Error] if group does not exist
    #
    def update
      save
    end

    # Update attributes of a group 
    # @param [Hash] params the options to update a Group
    # @option params [String] :group_name Group name
    # @option params [String] :description Group description 
    # @option params [String] :email_permission Group permission: Owner or Member 
    # @note This method executes a <b>PUT</b> request to <i>apps-apis.google.com/a/feeds/group/2.0/domain/groupId</i>
    #
    # @example Update the group "test"
    #   group = RubyProvisioningApi::Group.find("test")
    #   group.update_attributes(:group_id => "foo", :group_name => "foo name" , :description => "bar", :email_permission => "Owner") # => true
    #
    # @see https://developers.google.com/google-apps/provisioning/#updating_a_group
    # @return [Boolean] true if updated, false if not valid or not updated
    # @raise [Error] if group does not exist
    #    
    def update_attributes(params = {})
      self.group_name = params[:group_name] if params[:group_name]
      self.description = params[:description] if params[:description]
      self.email_permission = params[:email_permission] if params[:email_permission]
      update
    end

    # Delete group  
    # @note This method executes a <b>DELETE</b> request to <i>apps-apis.google.com/a/feeds/group/2.0/domain/groupId </i>
    #
    # @example Delete the group "test"
    #   group = RubyProvisioningApi::Group.find("test")
    #   group.delete
    #
    # @see https://developers.google.com/google-apps/provisioning/#deleting_a_group
    # @return [Boolean] true if deleted, false otherwise
    # @raise [Error] if group does not exist
    # 
    def delete
      params = self.class.prepare_params_for(:delete, "groupId" => group_id)
      # Perform the request & Check if the response contains an error
      self.class.check_response(self.class.perform(params))
    end

    # Retrieve all groups for a given member 
    # @param [String] member_id Member identification
    # @note This method executes a <b>GET</b> request to <i>apps-apis.google.com/a/feeds/group/2.0/domain/?member=memberId[&directOnly=true|false]</i>
    #
    # @example Retrieve all groups for a member "foo"
    #   groups = RubyProvisioningApi::Group.groups("foo") # => [Array<Group>]
    #
    # @see https://developers.google.com/google-apps/provisioning/#retrieving_all_groups_for_a_member
    # @return [Array<Group>] all groups for a given member
    # @raise [Error] if member(user) does not exist
    #
    def self.groups(member_id)
      params = prepare_params_for(:retrieve_groups, "memberId" => member_id)
      xml = perform_and_check_response(params)
      groups = parse_group_response(xml)
      puts xml
      while (np = next_page(xml))
        params = prepare_params_for(:retrieve_groups_page, "memberId" => member_id, "startFrom" => np.to_s.split("start=").last)
        response = perform(params)
        xml = Nokogiri::XML(response.body)
        groups += parse_group_response(xml)
      end
      groups
    end

    # Add member to group 
    # @param [String] member_id Member identification
    # @note This method executes a <b>POST</b> request to <i>apps-apis.google.com/a/feeds/group/2.0/domain/groupId/member </i>
    #
    # @example Add member "foo" to group "bar"
    #   group = RubyProvisioningApi::Group.find("bar") # => [Group]
    #   group.add_member("foo") # => [true]
    #
    # @see https://developers.google.com/google-apps/provisioning/#adding_a_member_to_a_group
    # @return [Boolean] true if added as a member, false otherwise
    # @raise [Error] if member(user) does not exist
    #
    def add_member(member_id)
      add_entity("member",member_id)
    end

    # Group membership of a given member
    # @param [String] member_id Member identification
    # @note This method executes a <b>GET</b> request to <i>apps-apis.google.com/a/feeds/group/2.0/domain/groupId/member/memberId</i>
    #
    # @example Check if user "foo" is member to the group "bar"
    #   group = RubyProvisioningApi::Group.find("bar") # => [Group]
    #   group.has_member?("foo") # => [true]
    #
    # @see https://developers.google.com/google-apps/provisioning/#retrieving_all_members_of_a_group
    # @return [Boolean] true if user is a member of the group
    # @raise [Error] if member(user) does not exist
    #
    def has_member?(member_id)
      params = self.class.prepare_params_for(:has_member, { "groupId" => group_id, "memberId" => member_id })
      begin
        # Perform the request & Check if the response contains an error
        self.class.check_response(self.class.perform(params))
      rescue
        false
      end
    end


    # Delete group membership of a given member
    # @param [String] member_id Member identification
    # @note This method executes a <b>DELETE</b> request to <i>apps-apis.google.com/a/feeds/group/2.0/domain/groupId/member/memberId</i>
    #
    # @example Delete user "foo" membership from group "bar"
    #   group = RubyProvisioningApi::Group.find("bar") # => [Group]
    #   group.delete_member("foo") # => [true]
    #
    # @see https://developers.google.com/google-apps/provisioning/#deleting_member_from_an_group
    # @return [Boolean] true if deleted, false otherwise
    # @raise [Error] if member(user) does not exist
    #
    def delete_member(member_id)
      delete_entity("member",member_id)
    end

    # Add owner to group 
    # @param [String] owner_id Owner identification
    # @note This method executes a <b>POST</b> request to <i>apps-apis.google.com/a/feeds/group/2.0/domain/groupId/owner</i>
    #
    # @example Add owner "foo" to group "bar"
    #   group = RubyProvisioningApi::Group.find("bar") # => [Group]
    #   group.add_owner("foo") # => [true]
    #
    # @see https://developers.google.com/google-apps/provisioning/#assigning_an_owner_to_a_group
    # @return [Boolean] true if added as a owner, false otherwise
    # @raise [Error] if owner(user) does not exist
    #       
    def add_owner(owner_id)
      add_entity("owner",owner_id)
    end

    # Group ownership of a given owner
    # @param [String] owner_id Owner identification
    # @note This method executes a <b>GET</b> request to <i>apps-apis.google.com/a/feeds/group/2.0/domain/groupId/owner/ownerEmail
    # @example Check if user "foo" is owner to the group "bar"
    #   group = RubyProvisioningApi::Group.find("bar") # => [Group]
    #   group.has_owner?("foo") # => [true]
    #
    # @see https://developers.google.com/google-apps/provisioning/#querying_if_a_user_or_group_is_owner
    # @return [Boolean] true if user is a owner of the group, false otherwise
    # @raise [Error] if owner(user) does not exist
    #
    def has_owner?(owner_id)
      params = self.class.prepare_params_for(:has_owner, {"groupId" => group_id, "ownerId" => owner_id} )
      begin
        # Perform the request & Check if the response contains an error
        self.class.check_response(self.class.perform(params))
      rescue
        false
      end
    end


    # Delete group ownership of a given owner
    # @param [String] owner_id Owner identification
    # @note This method executes a <b>DELETE</b> request to <i>apps-apis.google.com/a/feeds/group/2.0/domain/groupId/owner/ownerEmail</i>
    #
    # @example Delete user "foo" ownership from group "bar"
    #   group = RubyProvisioningApi::Group.find("bar") # => [Group]
    #   group.delete_owner("foo") # => [true]
    #
    # @see https://developers.google.com/google-apps/provisioning/#deleting_an_owner_from_a_group
    # @return [Boolean] true if deleted, false otherwise
    # @raise [Error] if owner(user) does not exist
    #
    def delete_owner(owner_id)
      delete_entity("owner",owner_id)
    end

    private

    def self.parse_group_response(xml)
      # Prepare a Groups array
      groups = []
      xml.children.css("entry").each do |entry|
        group = Group.new
        GROUP_ATTRIBUTES.each do |attribute_name|
          group.send("#{attribute_name.underscore}=", entry.css("apps|property[name='#{attribute_name}']").attribute("value").value)
        end
        # Fill groups array        
        groups << group
      end
      groups
    end

    def add_entity(entity,entity_id)
      # Creating the XML request
      builder = prepare_xml_request("#{entity}_id".to_sym => entity_id)
      params = self.class.prepare_params_for("add_#{entity}".to_sym, "groupId" => group_id )
      # Perform the request & Check if the response contains an error
      self.class.check_response(self.class.perform(params,builder.to_xml))
    end

    def delete_entity(entity,entity_id)
      params = self.class.prepare_params_for("delete_#{entity}".to_sym, { "groupId" => group_id, "#{entity}Id" => entity_id })
      # Perform the request & Check if the response contains an error
      self.class.check_response(self.class.perform(params))
    end

    def prepare_xml_request(params = {})
      Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
        xml.send(:'atom:entry', 'xmlns:atom' => 'http://www.w3.org/2005/Atom', 'xmlns:apps' => 'http://schemas.google.com/apps/2006') {
          xml.send(:'atom:category', 'scheme' => 'http://schemas.google.com/g/2005#kind', 'term' => 'http://schemas.google.com/apps/2006#emailList')
          xml.send(:'apps:property', 'name' => 'email', 'value' => params[:owner_id]) if params.has_key? :owner_id
          xml.send(:'apps:property', 'name' => 'memberId', 'value' => params[:member_id]) if params.has_key? :member_id
          xml.send(:'apps:property', 'name' => 'groupId', 'value' => params[:group_id]) if ( params.has_key? :group_id ) # TODO: is not working with normal save && params[:update] )
          xml.send(:'apps:property', 'name' => 'groupName', 'value' => params[:group_name]) if params.has_key? :group_name
          xml.send(:'apps:property', 'name' => 'description', 'value' => params[:description]) if params.has_key? :description
          xml.send(:'apps:property', 'name' => 'emailPermission', 'value' => params[:email_permission]) if params.has_key? :email_permission
        }
      end
    end

  end
end