digitalprog/ruby_provisioning_api

View on GitHub
lib/ruby_provisioning_api/user.rb

Summary

Maintainability
A
1 hr
Test Coverage
module RubyProvisioningApi

  # The User class describes a user account on google apps
  #
  # @attr [String] user_name User's username
  # @attr [String] given_name User's first name
  # @attr [String] family_name User's last name
  # @attr [Boolean] suspended User's state (suspended if true, active if false)
  # @attr [String] quota User's disk space quota
  #
  class User
    extend Entity

    include ActiveModel::Validations
    include ActiveModel::Dirty

    define_attribute_methods [:user_name]
    attr_accessor :user_name, :family_name, :given_name, :suspended, :quota
    alias_method :suspended?, :suspended
    validates :user_name, :family_name, :given_name, :presence => true

    def user_name=(value)
      user_name_will_change! unless value == @user_name
      @user_name = value
    end

    # @param [Hash] params the options to create a User with.
    # @option params [String] :user_name User identification
    # @option params [String] :given_name User's first name
    # @option params [String] :family_name User's last name
    # @option params [String] :quota User's disk space quota (optional, default is 1024)
    # @option params [Boolean] :suspended true if user is suspended, false otherwise (optional, default is false)
    #
    def initialize(params = {})
      params.each do |name, value|
        instance_variable_set(:"@#{name}", value)
      end
      @quota = "1024" if quota.nil?
      @suspended = false if suspended.nil?
    end

    # Retrieve all users in the domain
    # @note This method executes a <b>GET</b> request to <i>apps-apis.google.com/a/feeds/domain/user/2.0</i>
    #
    # @example Retrieve all users in the current domain
    #   RubyProvisioningApi::User.all # => [Array<User>]
    #
    # @see https://developers.google.com/google-apps/provisioning/#retrieving_all_users_in_a_domain
    # @return [Array<User>] all users in the domain
    #
    def self.all
      users = []
      response = perform(RubyProvisioningApi.configuration.user_actions[:retrieve_all])
      check_response(response)
      doc = Nokogiri::XML(response.body)
      doc.css("entry").each do |user_entry|
        users << extract_user(user_entry)
      end
      users
    end

    # Retrieve a user account
    # @note This method executes a <b>GET</b> request to <i>https://apps-apis.google.com/a/feeds/domain/user/2.0/userName</i>
    #
    # @example Retrieve the user account for "test"
    #   user = RubyProvisioningApi::User.find("test") # => [User]
    #
    # @see https://developers.google.com/google-apps/provisioning/#retrieving_user_accounts
    # @param [String] user_name
    # @return [User]
    # @raise [Error] if user does not exist
    #
    def self.find(user_name)
      params = prepare_params_for(:retrieve, "userName" => user_name)
      doc = perform_and_check_response(params)
      extract_user(doc)
    end

    # Save a user account. If the user account exists it will be updated, if not, a new user account will be created
    #
    # @note This method executes a <b>POST</b> request to <i>apps-apis.google.com/a/feeds/domain/user/2.0</i> for the create action
    # @note This method executes a <b>PUT</b> request to <i>apps-apis.google.com/a/feeds/domain/user/2.0/userName</i> for the update action
    #
    # @example Create a user account in multiple steps
    #   user = RubyProvisioningApi::User.new
    #   user.user_name = "test" # => "test"
    #   user.given_name = "foo" # => "foo"
    #   user.family_name = "bar" # => "bar"
    #   user.save # => true
    #
    # @example Create a user account in a unique step
    #   user = RubyProvisioningApi::User.new(:user_name => "test",
    #                                        :given_name => "foo",
    #                                        :family_name => "bar",
    #                                        :quota => "2000") # => [User]
    #   user.save # => true
    #
    # @example Update a user account
    #   user = RubyProvisioningApi::User.find("test") # => [User]
    #   user.given_name = "foo2" # => "foo2"
    #   user.save # => true
    #
    # @see https://developers.google.com/google-apps/provisioning/#creating_a_user_account
    # @see https://developers.google.com/google-apps/provisioning/#updating_a_user_account
    # @param [Hash] save_options
    # @option save_options [Boolean] :validate skip validations before save if false, validate otherwise (defaults to true)
    # @return [Boolean] true if saved, false if not valid or not saved
    # @raise [Error] if the user already exists (user_name must be unique)
    #
    def save(save_options = {:validate => true})
      if save_options[:validate]
        return false unless valid?
      end
      builder = prepare_xml_request(user_name, suspended, quota, family_name, given_name)
      if User.present?(user_name_was)
        # UPDATING an old record
        params = self.class.prepare_params_for(:update, "userName" => user_name_was)
        response = self.class.perform(params, builder.to_xml)
      else
        # SAVING a new record
        response = self.class.perform(RubyProvisioningApi.configuration.user_actions[:create], builder.to_xml)
      end
      User.check_response(response)
    end

    # Initialize and save a user.
    # @param [Hash] params the options to create a User with
    # @option params [String] :user_name User identification
    # @option params [String] :given_name User's first name
    # @option params [String] :family_name User's last name
    # @option params [String] :quota User's disk space quota (optional, default is 1024)
    # @option params [Boolean] :suspended true if user is suspended, false otherwise (optional, default is false)
    # @note This method executes a <b>POST</b> request to <i>apps-apis.google.com/a/feeds/domain/user/2.0</i>
    #
    # @example Create the user "test"
    #   user = RubyProvisioningApi::User.create(:user_name => "test",
    #                                           :given_name => "foo",
    #                                           :family_name => "bar",
    #                                           :quota => "2000") # => true
    #
    # @see https://developers.google.com/google-apps/provisioning/#creating_a_user_account
    # @return [Boolean] true if created or already existing, false if not valid
    # @raise [Error] if user already exists (user_name must be unique)
    #
    def self.create(params = {})
      user = User.new(params)
      user.save
    end

    # Update user attributes (except suspend) and save
    #
    # @param [Hash] params the options to update the User with
    # @option params [String] :user_name User identification
    # @option params [String] :given_name User's first name
    # @option params [String] :family_name User's last name
    # @option params [String] :quota User's disk space quota
    #
    # @note This method executes a <b>PUT</b> request to <i>apps-apis.google.com/a/feeds/domain/user/2.0/userName</i> for the update action
    # @note With {User#update_attributes update_attributes} it's not possible to suspend or restore a user account. For these actions take a look
    #       at the {User#suspend suspend} and {User#restore restore} methods.
    #
    # @example Change the family name and the given_name of a user
    #   user = RubyProvisioningApi::User.find("foo") # => [User]
    #   user.update_attributes(:family_name => "smith", :given_name => "john") # => true
    #
    # @see https://developers.google.com/google-apps/provisioning/#updating_a_user_account
    # @return [Boolean] true if updated, false if not valid or not updated
    # @raise [Error] if user already exists (user_name must be unique)
    #
    def update_attributes(params)
      if params.has_key? :user_name and params[:user_name] != self.user_name
        self.user_name = params[:user_name]
      end
      @family_name = params[:family_name] if params.has_key? :family_name
      @given_name = params[:given_name] if params.has_key? :given_name
      @quota = params[:quota] if params.has_key? :quota
      save
    end

    # Suspend a user account
    # @note This method executes a <b>PUT</b> request to <i>apps-apis.google.com/a/feeds/domain/user/2.0/userName</i> for the update action
    #
    # @example Suspend the user account of the user "foo"
    #   user = RubyProvisioningApi::User.find("foo") # => [User]
    #   user.suspend # => true
    #
    # @see https://developers.google.com/google-apps/provisioning/#suspending_a_user_account
    # @return [Boolean] true if the operation succeeded, false otherwise
    #
    def suspend
      self.suspended = true
      save(:validate => false)
    end

    # Restore a user account
    # @note This method executes a <b>PUT</b> request to <i>apps-apis.google.com/a/feeds/domain/user/2.0/userName</i> for the update action
    #
    # @example Restore the user account of the user "foo"
    #   user = RubyProvisioningApi::User.find("foo") # => [User]
    #   user.restore # => true
    #
    # @see https://developers.google.com/google-apps/provisioning/#restoring_a_user_account
    # @return [Boolean] true if the operation succeeded, false otherwise
    #
    def restore
      self.suspended = false
      save(:validate => false)
    end

    # Delete a user account
    # @note This method executes a <b>DELETE</b> request to <i>apps-apis.google.com/a/feeds/domain/user/2.0/userName</i>
    #
    # @example Delete the user "foo"
    #   user = RubyProvisioningApi::User.find("foo") # => [User]
    #   user.delete # => true
    #
    # @see https://developers.google.com/google-apps/provisioning/#deleting_a_user_account
    # @return [Boolean] true if the operation succeeded, false otherwise
    #
    def delete
      params = self.class.prepare_params_for(:delete, "userName" => user_name)
      response = self.class.perform(params)
      self.class.check_response(response)
    end

    # Returns all the groups which the user is subscribed to
    #
    # @example List all the groups which the user "foo" is subscribed to
    #   user = RubyProvisioningApi::User.find("foo") # => [User]
    #   user.groups # => [Array<Group>]
    #
    # @see For more info see: Group.groups
    # @return [Array<Group>]
    #
    def groups
      Group.groups(user_name)
    end

    # Check if the user is a member of the given group
    # @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 Find a user and check if is member of the group 'test'
    #   user = RubyProvisioningApi::User.find("username")
    #   user.is_member_of? "test" # => true
    #
    # @see https://developers.google.com/google-apps/provisioning/#retrieving_all_members_of_a_group
    # @return [Boolean] true if the user is member of the group, false otherwise
    # @raise [Error] if group_id does not exist
    #
    def is_member_of?(group_id)
      params = self.class.prepare_params_for(:member_of, {"groupId" => group_id, "memberId" => user_name})
      begin
        self.class.check_response(self.class.perform(params))
      rescue
        Group.find(group_id)
        false
      end
    end

    private

    def self.extract_user(doc)
      user = new
      extract_info(doc, user, "login", {:user_name => 'userName', :suspended => 'suspended'})
      extract_info(doc, user, "name", {:family_name => 'familyName', :given_name => 'givenName'})
      extract_info(doc, user, "quota", {:quota => 'limit'})
      user
    end

    def self.extract_info(doc, u, location, options)
      options.each do |k, v|
        value = doc.css("apps|#{location}").first.attributes[v].value
        if ["true", "false"].include? value
          value = eval(value)
        end
        u.instance_variable_set(:"@#{k.to_s}", value)
      end
    end

    def prepare_xml_request(user_name, suspended, quota, family_name, given_name)
      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#user')
          xml.send(:'apps:login', 'userName' => user_name, 'password' => '51eea05d46317fadd5cad6787a8f562be90b4446', 'suspended' => suspended)
          xml.send(:'apps:quota', 'limit' => quota)
          xml.send(:'apps:name', 'familyName' => family_name, 'givenName' => given_name)
        }
      end
    end

  end

end