gitlab-org--gitlab-foss/app/models/member.rb

234 lines
5.8 KiB
Ruby
Raw Normal View History

class Member < ActiveRecord::Base
include Sortable
include Importable
include Gitlab::Access
attr_accessor :raw_invite_token
belongs_to :created_by, class_name: "User"
belongs_to :user
belongs_to :source, polymorphic: true
2015-04-10 13:09:37 +00:00
validates :user, presence: true, unless: :invite?
validates :source, presence: true
validates :user_id, uniqueness: { scope: [:source_type, :source_id],
2015-04-10 13:09:37 +00:00
message: "already exists in source",
allow_nil: true }
validates :access_level, inclusion: { in: Gitlab::Access.all_values }, presence: true
2015-11-17 14:49:37 +00:00
validates :invite_email,
presence: {
if: :invite?
},
email: {
2015-11-17 14:49:37 +00:00
allow_nil: true
},
uniqueness: {
scope: [:source_type, :source_id],
allow_nil: true
}
scope :invite, -> { where.not(invite_token: nil) }
scope :non_invite, -> { where(invite_token: nil) }
scope :request, -> { where.not(requested_at: nil) }
scope :has_access, -> { where('access_level > 0') }
2016-08-09 16:39:13 +00:00
scope :expired, -> { where('expires_at <= ?', Time.current) }
scope :guests, -> { where(access_level: GUEST) }
scope :reporters, -> { where(access_level: REPORTER) }
scope :developers, -> { where(access_level: DEVELOPER) }
scope :masters, -> { where(access_level: MASTER) }
scope :owners, -> { where(access_level: OWNER) }
scope :owners_and_masters, -> { where(access_level: [OWNER, MASTER]) }
2015-04-10 13:09:37 +00:00
before_validation :generate_invite_token, on: :create, if: -> (member) { member.invite_email.present? }
after_create :send_invite, if: :invite?, unless: :importing?
2016-06-16 12:07:49 +00:00
after_create :send_request, if: :request?, unless: :importing?
after_create :create_notification_setting, unless: [:pending?, :importing?]
after_create :post_create_hook, unless: [:pending?, :importing?]
after_update :post_update_hook, unless: [:pending?, :importing?]
after_destroy :post_destroy_hook, unless: :pending?
2015-04-10 13:09:37 +00:00
delegate :name, :username, :email, to: :user, prefix: true
2015-04-10 13:09:37 +00:00
default_value_for :notification_level, NotificationSetting.levels[:global]
class << self
2016-07-25 13:21:55 +00:00
def access_for_user_ids(user_ids)
2016-08-04 05:59:14 +00:00
where(user_id: user_ids).has_access.pluck(:user_id, :access_level).to_h
2016-07-25 13:21:55 +00:00
end
def find_by_invite_token(invite_token)
invite_token = Devise.token_generator.digest(self, :invite_token, invite_token)
find_by(invite_token: invite_token)
end
# This method is used to find users that have been entered into the "Add members" field.
# These can be the User objects directly, their IDs, their emails, or new emails to be invited.
def user_for_id(user_id)
return user_id if user_id.is_a?(User)
user = User.find_by(id: user_id)
user ||= User.find_by(email: user_id)
user ||= user_id
user
end
def add_user(members, user_id, access_level, current_user: nil, expires_at: nil)
user = user_for_id(user_id)
# `user` can be either a User object or an email to be invited
if user.is_a?(User)
member = members.find_or_initialize_by(user_id: user.id)
else
member = members.build
member.invite_email = user
end
if can_update_member?(current_user, member) || project_creator?(member, access_level)
member.created_by ||= current_user
member.access_level = access_level
2016-08-01 18:12:30 +00:00
member.expires_at = expires_at
member.save
end
end
private
def can_update_member?(current_user, member)
2015-11-17 14:49:37 +00:00
# There is no current user for bulk actions, in which case anything is allowed
!current_user ||
current_user.can?(:update_group_member, member) ||
current_user.can?(:update_project_member, member)
end
def project_creator?(member, access_level)
member.new_record? && member.owner? &&
access_level.to_i == ProjectMember::MASTER
end
2015-04-10 13:22:31 +00:00
end
def real_source_type
source_type
end
2015-04-10 13:09:37 +00:00
def invite?
self.invite_token.present?
end
def request?
requested_at.present?
end
def pending?
invite? || request?
2015-04-10 13:09:37 +00:00
end
2016-08-04 05:56:06 +00:00
def expires?
expires_at.present?
end
def accept_request
return false unless request?
updated = self.update(requested_at: nil)
after_accept_request if updated
updated
end
2015-04-10 13:09:37 +00:00
def accept_invite!(new_user)
2015-04-10 13:22:31 +00:00
return false unless invite?
2015-04-10 13:09:37 +00:00
self.invite_token = nil
self.invite_accepted_at = Time.now.utc
self.user = new_user
saved = self.save
after_accept_invite if saved
saved
end
2015-04-10 14:37:02 +00:00
def decline_invite!
return false unless invite?
destroyed = self.destroy
after_decline_invite if destroyed
destroyed
end
2015-04-10 13:09:37 +00:00
def generate_invite_token
raw, enc = Devise.token_generator.generate(self.class, :invite_token)
@raw_invite_token = raw
self.invite_token = enc
end
def generate_invite_token!
generate_invite_token && save(validate: false)
end
def resend_invite
return unless invite?
generate_invite_token! unless @raw_invite_token
send_invite
end
def create_notification_setting
user.notification_settings.find_or_create_for(source)
end
def notification_setting
@notification_setting ||= user.notification_settings_for(source)
end
2015-04-10 13:09:37 +00:00
private
def send_invite
# override in subclass
end
def send_request
notification_service.new_access_request(self)
2015-04-10 13:09:37 +00:00
end
def post_create_hook
system_hook_service.execute_hooks_for(self, :create)
end
def post_update_hook
# override in subclass
end
def post_destroy_hook
system_hook_service.execute_hooks_for(self, :destroy)
end
def after_accept_invite
post_create_hook
end
2015-04-10 14:37:02 +00:00
def after_decline_invite
# override in subclass
end
def after_accept_request
2015-04-10 13:09:37 +00:00
post_create_hook
end
def system_hook_service
SystemHooksService.new
end
def notification_service
NotificationService.new
end
end