Module: Authify::API::Controllers

Defined in:
lib/authify/api/controllers/user.rb,
lib/authify/api/controllers/group.rb,
lib/authify/api/controllers/apikey.rb,
lib/authify/api/controllers/identity.rb,
lib/authify/api/controllers/organization.rb,
lib/authify/api/controllers/trusted_delegate.rb

Constant Summary collapse

User =
proc do
  helpers do
    def before_index
      params[:fields] = only_indexable_fields
    end

    def before_show_many
      params[:fields] = only_indexable_fields
    end

    def before_show
      params[:fields] = only_indexable_fields
    end

    def find(id)
      Models::User.find(id.to_i)
    end

    def role
      Array(super.dup).tap do |a|
        a << :myself if current_user && resource && (resource.id == current_user.id)
      end.uniq
    end

    def modifiable_fields
      %i[full_name email handle].tap do |a|
        a << :admin if role.include?(:admin)
      end
    end

    def indexable_fields
      %i[full-name admin handle groups organizations identities].tap do |a|
        if role?(:admin) || role?(:myself)
          a << :verified
          a << :email
          a << :'created-at'
          a << :apikeys
        end
      end
    end

    def only_indexable_fields
      {
        users: if params[:fields] && params[:fields].key?(:users)
                 params[:fields][:users].select { |k, _| indexable_fields.include?(k) }
               else
                 indexable_fields
               end
      }
    end

    def filtered_attributes(attributes)
      attributes.select do |k, _v|
        modifiable_fields.include?(k)
      end
    end

    def filter(collection, fields = {})
      collection.where(fields)
    end

    def sort(collection, fields = {})
      collection.order(fields)
    end
  end

  index(roles: %i[user trusted]) do
    Models::User.all
  end

  show(roles: %i[user trusted]) do
    last_modified resource.updated_at
    next resource
  end

  create(roles: [:admin]) do |attributes|
    user = Models::User.new filtered_attributes(attributes)
    user.save
    next user
  end

  update(roles: %i[admin myself]) do |attrs|
    # Necessary because #password= is overridden for Models::User
    new_pass = attrs[:password] if attrs && attrs.key?(:password)
    resource.update filtered_attributes(attrs)
    resource.password = new_pass if new_pass
    resource.save
    next resource
  end

  show_many do |ids|
    Models::User.find(ids)
  end

  has_many :apikeys do
    fetch(roles: %i[myself admin]) do
      resource.apikeys
    end

    clear(roles: %i[myself admin]) do
      resource.apikeys.destroy_all
      resource.save
    end

    subtract(roles: %i[myself admin]) do |rios|
      refs = rios.map { |attrs| Models::APIKey.find(attrs) }
      # This actually calls #destroy on the keys (we don't need orphaned keys)
      resource.apikeys.destroy(refs)
      resource.save
    end
  end

  has_many :identities do
    fetch(roles: %i[myself admin trusted]) do
      resource.identities
    end

    clear(roles: %i[myself admin]) do
      resource.identities.destroy_all
      resource.save
    end

    merge(roles: [:myself]) do |rios|
      refs = rios.map { |attrs| Models::Identity.new(attrs) }
      resource.identities << refs
      resource.save
    end

    subtract(roles: %i[myself admin]) do |rios|
      refs = rios.map { |attrs| Models::Identity.find(attrs) }
      resource.identities.destroy(refs)
      resource.save
    end
  end

  has_many :organizations do
    fetch(roles: %i[user myself admin]) do
      resource.organizations
    end
  end

  has_many :groups do
    fetch(roles: %i[myself admin]) do
      resource.groups
    end
  end
end
Group =
proc do
  helpers do
    def find(id)
      Models::Group.find(id.to_i)
    end

    def role
      Array(super).tap do |a|
        a << :owner if current_user && current_user.admin_for?(resource.organization)
        a << :member if resource && resource.users.include?(current_user)
      end.uniq
    end
  end

  index(roles: [:admin]) do
    Models::Group.all
  end

  show(roles: %i[admin owner]) do
    last_modified resource.updated_at
    next resource
  end

  create(roles: [:admin]) do |attrs|
    g = Models::Group.new(attrs)
    g.save
    next g
  end

  destroy(roles: %i[admin owner]) do
    resource.destroy
  end

  show_many do |ids|
    Models::Group.find(ids)
  end

  has_many :users do
    fetch(roles: %i[admin owner]) do
      resource.users
    end

    replace(roles: %i[admin owner]) do |rios|
      refs = rios.map { |attrs| Models::User.find(attrs) }
      resource.users = refs
      resource.save
    end

    merge(roles: %i[admin owner]) do |rios|
      refs = rios.map { |attrs| Models::User.find(attrs) }
      resource.users << refs
      resource.save
    end

    subtract(roles: %i[admin owner]) do |rios|
      refs = rios.map { |attrs| Models::User.find(attrs) }
      # This only removes the linkage, not the actual users
      resource.users.delete(refs)
      resource.save
    end
  end
end
APIKey =
proc do
  helpers do
    def find(id)
      Models::APIKey.find(id.to_i)
    end

    def role
      Array(super).tap do |a|
        a << :myself if current_user && current_user.apikeys.include?(resource)
      end.uniq
    end
  end

  index(roles: [:admin]) do
    Models::APIKey.all
  end

  show(roles: %i[myself admin]) do
    last_modified resource.updated_at
    next resource, exclude: [:secret_key]
  end

  create(roles: [:user]) do |_attributes|
    key = Models::APIKey.new
    key.populate!
    current_user.apikeys << key
    current_user.save
    next key.id, key
  end

  destroy(roles: %i[myself admin]) do
    resource.destroy
  end

  show_many do |ids|
    Models::APIKey.find(ids)
  end

  has_one :user do
    pluck(roles: %i[myself admin]) do
      resource.user
    end
  end
end
Identity =
proc do
  helpers do
    def find(id)
      Models::Identity.find(id.to_i)
    end

    def role
      Array(super).tap do |a|
        a << :myself if current_user && current_user.identities.include?(resource)
      end.uniq
    end
  end

  index(roles: %i[admin trusted]) do
    Models::Identity.all
  end

  show(roles: %i[myself admin trusted]) do
    last_modified resource.updated_at
    next resource
  end

  create(roles: [:user]) do |attributes|
    ident = Models::Identity.new attributes
    current_user.identities << ident
    current_user.save
    next ident.id, ident
  end

  destroy(roles: %i[myself admin]) do
    resource.destroy
  end

  show_many do |ids|
    Models::Identity.find(ids)
  end

  has_one :user do
    pluck(roles: %i[myself admin trusted]) do
      resource.user
    end
  end
end
Organization =
proc do
  helpers do
    def find(id)
      Models::Organization.includes(:users, :groups, :admins).find(id.to_i)
    end

    def role
      Array(super).tap do |a|
        a << :owner if resource && current_user && current_user.admin_for?(resource)
        a << :member if resource && resource.users.include?(current_user)
      end.uniq
    end

    def modifiable_fields
      %i[
        name
        public_email
        gravatar_email
        billing_email
        description
        url
        location
      ]
    end

    def filtered_attributes(attributes)
      attributes.select do |k, _v|
        modifiable_fields.include?(k)
      end
    end

    def filter(collection, fields = {})
      collection.where(fields)
    end

    def sort(collection, fields = {})
      collection.order(fields)
    end
  end

  index(roles: %i[admin user]) do
    Models::Organization.includes(:users, :groups, :admins)
  end

  get '/mine' do
    halt(403) unless can?(:create)
    serialize_models current_user.organizations.includes(:users, :groups, :admins)
  end

  show(roles: [:user]) do
    last_modified resource.updated_at
    exclude = []
    unless role?(:admin, :owner)
      exclude << 'billing_email'
      exclude << 'gravatar_email'
    end
    next resource, exclude: exclude
  end

  show_many do |ids|
    Models::Organization.includes(:users, :groups, :admins).find(ids)
  end

  create(roles: [:user]) do |attrs|
    o = Models::Organization.new filtered_attributes(attrs)
    new_member = Models::OrganizationMembership.new(user: current_user, admin: true)
    o.organization_memberships << new_member
    o.save
    next o.id, o
  end

  update(roles: %i[owner admin]) do |attrs|
    resource.update filtered_attributes(attrs)
    next resource
  end

  destroy(roles: %i[owner admin]) do
    resource.destroy
  end

  has_many :users do
    fetch(roles: %i[owner admin member]) do
      resource.users
    end
  end

  has_many :admins do
    fetch(roles: %i[owner admin member]) do
      resource.admins
    end
  end

  has_many :groups do
    fetch(roles: %i[owner admin member]) do
      resource.groups
    end
  end
end
TrustedDelegate =
proc do
  helpers do
    def find(id)
      Models::TrustedDelegate.find(id.to_i)
    end

    def modifiable_fields
      %i[name]
    end

    def filtered_attributes(attributes)
      attributes.select do |k, _v|
        modifiable_fields.include?(k)
      end
    end
  end

  index(roles: %i[admin]) do
    Models::TrustedDelegate.all
  end

  show(roles: %i[admin]) do
    last_modified resource.updated_at
    next resource, exclude: [:secret_key]
  end

  create(roles: %i[admin]) do |attrs|
    key = Models::TrustedDelegate.new filtered_attributes(attrs)
    key.access_key = Models::TrustedDelegate.generate_access_key
    key.set_secret!
    key.save
    next key.id, key
  end

  destroy(roles: %i[admin]) do
    resource.destroy
  end

  show_many do |ids|
    Models::TrustedDelegate.find(ids)
  end
end