BigW Consortium Gitlab

member.rb 4.46 KB
Newer Older
Valery Sizov committed
1 2 3 4 5 6 7 8
# == Schema Information
#
# Table name: members
#
#  id                 :integer          not null, primary key
#  access_level       :integer          not null
#  source_id          :integer          not null
#  source_type        :string(255)      not null
Stan Hu committed
9
#  user_id            :integer
Valery Sizov committed
10 11 12 13
#  notification_level :integer          not null
#  type               :string(255)
#  created_at         :datetime
#  updated_at         :datetime
14
#  created_by_id      :integer
Stan Hu committed
15 16
#  invite_email       :string(255)
#  invite_token       :string(255)
17
#  invite_accepted_at :datetime
Valery Sizov committed
18 19
#

20
class Member < ActiveRecord::Base
21
  include Sortable
22 23 24
  include Notifiable
  include Gitlab::Access

25 26
  attr_accessor :raw_invite_token

27
  belongs_to :created_by, class_name: "User"
28 29 30
  belongs_to :user
  belongs_to :source, polymorphic: true

31
  validates :user, presence: true, unless: :invite?
32
  validates :source, presence: true
33 34 35
  validates :user_id, uniqueness: { scope: [:source_type, :source_id], 
                                    message: "already exists in source",
                                    allow_nil: true }
36
  validates :access_level, inclusion: { in: Gitlab::Access.all_values }, presence: true
37 38 39
  validates :invite_email,  presence: { if: :invite? }, 
                            email: { strict_mode: true, allow_nil: true }, 
                            uniqueness: { scope: [:source_type, :source_id], allow_nil: true }
40

41 42
  scope :invite, -> { where(user_id: nil) }
  scope :non_invite, -> { where("user_id IS NOT NULL") }
43 44 45 46 47 48
  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) }

49 50 51 52 53 54
  before_validation :generate_invite_token, on: :create, if: -> (member) { member.invite_email.present? }
  after_create :send_invite, if: :invite?
  after_create :post_create_hook, unless: :invite?
  after_update :post_update_hook, unless: :invite?
  after_destroy :post_destroy_hook, unless: :invite?

55
  delegate :name, :username, :email, to: :user, prefix: true
56

57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
  class << self
    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)
      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

      member.created_by ||= current_user
      member.access_level = access_level

      member.save
    end
Douwe Maan committed
90 91
  end

92 93 94 95 96
  def invite?
    self.invite_token.present?
  end

  def accept_invite!(new_user)
Douwe Maan committed
97 98
    return false unless invite?
    
99 100 101 102 103 104 105 106 107 108 109 110
    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

Douwe Maan committed
111 112 113 114 115 116 117 118 119 120
  def decline_invite!
    return false unless invite?

    destroyed = self.destroy

    after_decline_invite if destroyed

    destroyed
  end

121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
  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

  private

  def send_invite
    # override in subclass
  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

Douwe Maan committed
161 162 163 164
  def after_decline_invite
    # override in subclass
  end

165 166 167 168 169 170 171
  def system_hook_service
    SystemHooksService.new
  end

  def notification_service
    NotificationService.new
  end
172
end