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

772 lines
23 KiB
Ruby
Raw Normal View History

2012-11-19 13:24:05 -05:00
# == Schema Information
#
# Table name: users
#
2015-09-06 10:48:48 -04:00
# id :integer not null, primary key
# email :string(255) default(""), not null
# encrypted_password :string(255) default(""), not null
# reset_password_token :string(255)
# reset_password_sent_at :datetime
# remember_created_at :datetime
# sign_in_count :integer default(0)
# current_sign_in_at :datetime
# last_sign_in_at :datetime
# current_sign_in_ip :string(255)
# last_sign_in_ip :string(255)
# created_at :datetime
# updated_at :datetime
# name :string(255)
# admin :boolean default(FALSE), not null
# projects_limit :integer default(10)
# skype :string(255) default(""), not null
# linkedin :string(255) default(""), not null
# twitter :string(255) default(""), not null
# authentication_token :string(255)
# theme_id :integer default(1), not null
# bio :string(255)
# failed_attempts :integer default(0)
# locked_at :datetime
# username :string(255)
# can_create_group :boolean default(TRUE), not null
# can_create_team :boolean default(TRUE), not null
# state :string(255)
# color_scheme_id :integer default(1), not null
# notification_level :integer default(1), not null
# password_expires_at :datetime
# created_by_id :integer
# last_credential_check_at :datetime
# avatar :string(255)
# confirmation_token :string(255)
# confirmed_at :datetime
# confirmation_sent_at :datetime
# unconfirmed_email :string(255)
# hide_no_ssh_key :boolean default(FALSE)
# website_url :string(255) default(""), not null
# notification_email :string(255)
# hide_no_password :boolean default(FALSE)
# password_automatically_set :boolean default(FALSE)
# location :string(255)
# encrypted_otp_secret :string(255)
# encrypted_otp_secret_iv :string(255)
# encrypted_otp_secret_salt :string(255)
# otp_required_for_login :boolean default(FALSE), not null
# otp_backup_codes :text
# public_email :string(255) default(""), not null
# dashboard :integer default(0)
# project_view :integer default(0)
# layout :integer default(0)
2012-11-19 13:24:05 -05:00
#
2013-10-06 14:13:56 -04:00
require 'carrierwave/orm/activerecord'
require 'file_size_validator'
2011-10-08 17:36:38 -04:00
class User < ActiveRecord::Base
extend Gitlab::ConfigHelper
include Gitlab::ConfigHelper
include Gitlab::CurrentSettings
include Referable
include Sortable
include TokenAuthenticatable
include CaseSensitivity
default_value_for :admin, false
default_value_for :can_create_group, gitlab_config.default_can_create_group
default_value_for :can_create_team, false
default_value_for :hide_no_ssh_key, false
default_value_for :hide_no_password, false
default_value_for :theme_id, gitlab_config.default_theme
2015-05-05 22:16:09 -04:00
devise :two_factor_authenticatable,
otp_secret_encryption_key: File.read(Rails.root.join('.secret')).chomp
alias_attribute :two_factor_enabled, :otp_required_for_login
2015-05-09 15:45:22 -04:00
devise :two_factor_backupable, otp_number_of_backup_codes: 10
2015-05-09 15:45:22 -04:00
serialize :otp_backup_codes, JSON
2015-05-05 22:16:09 -04:00
devise :lockable, :async, :recoverable, :rememberable, :trackable,
:validatable, :omniauthable, :confirmable, :registerable
2011-10-08 17:36:38 -04:00
attr_accessor :force_random_password
2011-10-08 17:36:38 -04:00
2013-03-25 10:10:14 -04:00
# Virtual attribute for authenticating by either username or email
attr_accessor :login
#
# Relations
#
# Namespace for personal projects
has_one :namespace, -> { where type: nil }, dependent: :destroy, foreign_key: :owner_id, class_name: "Namespace"
# Profile
has_many :keys, dependent: :destroy
has_many :emails, dependent: :destroy
has_many :identities, dependent: :destroy, autosave: true
# Groups
has_many :members, dependent: :destroy
has_many :project_members, source: 'ProjectMember'
has_many :group_members, source: 'GroupMember'
has_many :groups, through: :group_members
has_many :owned_groups, -> { where members: { access_level: Gitlab::Access::OWNER } }, through: :group_members, source: :group
has_many :masters_groups, -> { where members: { access_level: Gitlab::Access::MASTER } }, through: :group_members, source: :group
# Projects
has_many :groups_projects, through: :groups, source: :projects
has_many :personal_projects, through: :namespace, source: :projects
has_many :projects, through: :project_members
has_many :created_projects, foreign_key: :creator_id, class_name: 'Project'
2014-06-26 03:49:14 -04:00
has_many :users_star_projects, dependent: :destroy
has_many :starred_projects, through: :users_star_projects, source: :project
has_many :snippets, dependent: :destroy, foreign_key: :author_id, class_name: "Snippet"
has_many :project_members, dependent: :destroy, class_name: 'ProjectMember'
has_many :issues, dependent: :destroy, foreign_key: :author_id
has_many :notes, dependent: :destroy, foreign_key: :author_id
has_many :merge_requests, dependent: :destroy, foreign_key: :author_id
has_many :events, dependent: :destroy, foreign_key: :author_id, class_name: "Event"
has_many :subscriptions, dependent: :destroy
has_many :recent_events, -> { order "id DESC" }, foreign_key: :author_id, class_name: "Event"
has_many :assigned_issues, dependent: :destroy, foreign_key: :assignee_id, class_name: "Issue"
has_many :assigned_merge_requests, dependent: :destroy, foreign_key: :assignee_id, class_name: "MergeRequest"
2014-12-19 09:15:29 -05:00
has_many :oauth_applications, class_name: 'Doorkeeper::Application', as: :owner, dependent: :destroy
has_one :abuse_report, dependent: :destroy
has_many :ci_builds, dependent: :nullify, class_name: 'Ci::Build'
#
# Validations
#
validates :name, presence: true
# Note that a 'uniqueness' and presence check is provided by devise :validatable for email. We do not need to
# duplicate that here as the validation framework will have duplicate errors in the event of a failure.
validates :email, presence: true, email: { strict_mode: true }
validates :notification_email, presence: true, email: { strict_mode: true }
validates :public_email, presence: true, email: { strict_mode: true }, allow_blank: true, uniqueness: true
validates :bio, length: { maximum: 255 }, allow_blank: true
validates :projects_limit, presence: true, numericality: { greater_than_or_equal_to: 0 }
2015-02-03 00:15:44 -05:00
validates :username,
presence: true,
uniqueness: { case_sensitive: false },
exclusion: { in: Gitlab::Blacklist.path },
2015-03-24 09:55:14 -04:00
format: { with: Gitlab::Regex.namespace_regex,
message: Gitlab::Regex.namespace_regex_message }
2012-11-27 22:14:05 -05:00
2013-04-02 18:28:12 -04:00
validates :notification_level, inclusion: { in: Notification.notification_levels }, presence: true
validate :namespace_uniq, if: ->(user) { user.username_changed? }
validate :avatar_type, if: ->(user) { user.avatar.present? && user.avatar_changed? }
validate :unique_email, if: ->(user) { user.email_changed? }
validate :owns_notification_email, if: ->(user) { user.notification_email_changed? }
validate :owns_public_email, if: ->(user) { user.public_email_changed? }
2014-12-02 04:32:24 -05:00
validates :avatar, file_size: { maximum: 200.kilobytes.to_i }
before_validation :generate_password, on: :create
before_validation :restricted_signup_domains, on: :create
2013-07-10 06:48:03 -04:00
before_validation :sanitize_attrs
before_validation :set_notification_email, if: ->(user) { user.email_changed? }
before_validation :set_public_email, if: ->(user) { user.public_email_changed? }
2013-07-10 06:48:03 -04:00
after_update :update_emails_with_primary_email, if: ->(user) { user.email_changed? }
2012-09-27 02:20:36 -04:00
before_save :ensure_authentication_token
2014-06-17 15:32:35 -04:00
after_save :ensure_namespace_correct
after_initialize :set_projects_limit
2014-06-17 15:32:35 -04:00
after_create :post_create_hook
after_destroy :post_destroy_hook
# User's Layout preference
enum layout: [:fixed, :fluid]
# User's Dashboard preference
# Note: When adding an option, it MUST go on the end of the array.
enum dashboard: [:projects, :stars, :project_activity, :starred_project_activity]
2013-07-10 06:48:03 -04:00
# User's Project preference
# Note: When adding an option, it MUST go on the end of the array.
enum project_view: [:readme, :activity, :files]
2012-09-27 02:20:36 -04:00
alias_attribute :private_token, :authentication_token
delegate :path, to: :namespace, allow_nil: true, prefix: true
state_machine :state, initial: :active do
event :block do
transition active: :blocked
end
event :activate do
transition blocked: :active
end
end
mount_uploader :avatar, AvatarUploader
2013-10-06 14:13:56 -04:00
2012-10-08 20:10:04 -04:00
# Scopes
scope :admins, -> { where(admin: true) }
scope :blocked, -> { with_state(:blocked) }
scope :active, -> { with_state(:active) }
2013-12-14 08:43:48 -05:00
scope :not_in_project, ->(project) { project.users.present? ? where("id not in (:ids)", ids: project.users.map(&:id) ) : all }
scope :without_projects, -> { where('id NOT IN (SELECT DISTINCT(user_id) FROM members)') }
scope :with_two_factor, -> { where(two_factor_enabled: true) }
scope :without_two_factor, -> { where(two_factor_enabled: false) }
2012-10-08 20:10:04 -04:00
#
# Class methods
#
2012-10-08 20:10:04 -04:00
class << self
# Devise method overridden to allow sign in with email or username
2013-03-25 10:10:14 -04:00
def find_for_database_authentication(warden_conditions)
conditions = warden_conditions.dup
if login = conditions.delete(:login)
where(conditions).where(["lower(username) = :value OR lower(email) = :value", { value: login.downcase }]).first
else
where(conditions).first
end
end
2014-10-10 08:15:34 -04:00
def sort(method)
case method.to_s
2015-02-05 22:15:05 -05:00
when 'recent_sign_in' then reorder(last_sign_in_at: :desc)
when 'oldest_sign_in' then reorder(last_sign_in_at: :asc)
else
order_by(method)
2014-10-10 08:15:34 -04:00
end
end
# Find a User by their primary email or any associated secondary email
def find_by_any_email(email)
Improve performance of User.find_by_any_email This query used to rely on a JOIN, effectively producing the following SQL: SELECT users.* FROM users LEFT OUTER JOIN emails ON emails.user_id = users.id WHERE (users.email = X OR emails.email = X) LIMIT 1; The use of a JOIN means having to scan over all Emails and users, join them together and then filter out the rows that don't match the criteria (though this step may be taken into account already when joining). In the new setup this query instead uses a sub-query, producing the following SQL: SELECT * FROM users WHERE id IN (select user_id FROM emails WHERE email = X) OR email = X LIMIT 1; This query has the benefit that it: 1. Doesn't have to JOIN any rows 2. Only has to operate on a relatively small set of rows from the "emails" table. Since most users will only have a handful of Emails associated (certainly not hundreds or even thousands) the size of the set returned by the sub-query is small enough that it should not become problematic. Performance of the old versus new version can be measured using the following benchmark: # Save this in ./bench.rb require 'benchmark/ips' email = 'yorick@gitlab.com' def User.find_by_any_email_old(email) user_table = arel_table email_table = Email.arel_table query = user_table. project(user_table[Arel.star]). join(email_table, Arel::Nodes::OuterJoin). on(user_table[:id].eq(email_table[:user_id])). where(user_table[:email].eq(email).or(email_table[:email].eq(email))) find_by_sql(query.to_sql).first end Benchmark.ips do |bench| bench.report 'original' do User.find_by_any_email_old(email) end bench.report 'optimized' do User.find_by_any_email(email) end bench.compare! end Running this locally using "bundle exec rails r bench.rb" produces the following output: Calculating ------------------------------------- original 1.000 i/100ms optimized 93.000 i/100ms ------------------------------------------------- original 11.103 (± 0.0%) i/s - 56.000 optimized 948.713 (± 5.3%) i/s - 4.743k Comparison: optimized: 948.7 i/s original: 11.1 i/s - 85.45x slower In other words, the new setup is 85x faster compared to the old setup, at least when running this benchmark locally. For GitLab.com these improvements result in User.find_by_any_email taking only ~170 ms to run, instead of around 800 ms. While this is "only" an improvement of about 4.5 times (instead of 85x) it's still significantly better than before. Fixes #3242
2015-10-28 09:43:27 -04:00
User.reorder(nil).
where('id IN (SELECT user_id FROM emails WHERE email = :email) OR email = :email', email: email).
take
end
2013-03-25 10:10:14 -04:00
def filter(filter_name)
2012-10-08 20:10:04 -04:00
case filter_name
when 'admins'
self.admins
when 'blocked'
self.blocked
when 'two_factor_disabled'
self.without_two_factor
when 'two_factor_enabled'
self.with_two_factor
when 'wop'
self.without_projects
2012-10-08 20:10:04 -04:00
else
self.active
end
end
def search(query)
where("lower(name) LIKE :query OR lower(email) LIKE :query OR lower(username) LIKE :query", query: "%#{query.downcase}%")
2012-10-08 20:10:04 -04:00
end
def by_login(login)
return nil unless login
if login.include?('@'.freeze)
unscoped.iwhere(email: login).take
else
unscoped.iwhere(username: login).take
end
end
2015-07-23 17:16:39 -04:00
def find_by_username!(username)
find_by!('lower(username) = ?', username.downcase)
end
def by_username_or_id(name_or_id)
where('users.username = ? OR users.id = ?', name_or_id.to_s, name_or_id.to_i).first
end
def build_user(attrs = {})
User.new(attrs)
end
def reference_prefix
'@'
end
# Pattern used to extract `@user` user references from text
def reference_pattern
%r{
#{Regexp.escape(reference_prefix)}
(?<user>#{Gitlab::Regex::NAMESPACE_REGEX_STR})
}x
end
2012-01-28 08:23:17 -05:00
end
2012-06-21 12:05:09 -04:00
#
# Instance methods
#
2013-01-25 13:35:58 -05:00
def to_param
username
end
def to_reference(_from_project = nil)
"#{self.class.reference_prefix}#{username}"
end
2013-03-27 13:04:29 -04:00
def notification
@notification ||= Notification.new(self)
end
2012-10-08 20:10:04 -04:00
def generate_password
if self.force_random_password
self.password = self.password_confirmation = Devise.friendly_token.first(8)
end
2012-06-21 12:05:09 -04:00
end
def generate_reset_token
2014-07-16 04:01:13 -04:00
@reset_token, enc = Devise.token_generator.generate(self.class, :reset_password_token)
self.reset_password_token = enc
self.reset_password_sent_at = Time.now.utc
2014-07-16 04:01:13 -04:00
@reset_token
end
2015-10-01 21:41:56 -04:00
def recently_sent_password_reset?
reset_password_sent_at.present? && reset_password_sent_at >= 1.minute.ago
end
def disable_two_factor!
update_attributes(
two_factor_enabled: false,
encrypted_otp_secret: nil,
encrypted_otp_secret_iv: nil,
encrypted_otp_secret_salt: nil,
otp_backup_codes: nil
)
end
def namespace_uniq
namespace_name = self.username
existing_namespace = Namespace.by_path(namespace_name)
if existing_namespace && existing_namespace != self.namespace
2014-03-02 13:45:38 -05:00
self.errors.add :username, "already exists"
end
end
def avatar_type
unless self.avatar.image?
self.errors.add :avatar, "only images allowed"
end
end
def unique_email
if !self.emails.exists?(email: self.email) && Email.exists?(email: self.email)
self.errors.add(:email, 'has already been taken')
end
end
def owns_notification_email
self.errors.add(:notification_email, "is not an email you own") unless self.all_emails.include?(self.notification_email)
end
def owns_public_email
return if self.public_email.blank?
self.errors.add(:public_email, "is not an email you own") unless self.all_emails.include?(self.public_email)
end
def update_emails_with_primary_email
primary_email_record = self.emails.find_by(email: self.email)
if primary_email_record
primary_email_record.destroy
self.emails.create(email: self.email_was)
self.update_secondary_emails!
end
end
# Groups user has access to
def authorized_groups
@authorized_groups ||= begin
group_ids = (groups.pluck(:id) + authorized_projects.pluck(:namespace_id))
Group.where(id: group_ids)
end
end
2015-10-23 12:15:13 -04:00
def authorized_projects_id
@authorized_projects_id ||= begin
project_ids = personal_projects.pluck(:id)
project_ids.push(*groups_projects.pluck(:id))
project_ids.push(*projects.pluck(:id).uniq)
end
end
# Projects user has access to
def authorized_projects
2015-10-23 12:15:13 -04:00
@authorized_projects ||= Project.where(id: authorized_projects_id)
end
def owned_projects
@owned_projects ||=
begin
namespace_ids = owned_groups.pluck(:id).push(namespace.id)
Project.in_namespace(namespace_ids).joins(:namespace)
end
end
# Team membership in authorized projects
def tm_in_authorized_projects
ProjectMember.where(source_id: authorized_projects.map(&:id), user_id: self.id)
end
2013-01-02 16:35:11 -05:00
def is_admin?
admin
end
def require_ssh_key?
keys.count == 0
end
def require_password?
password_automatically_set? && !ldap_user?
end
def can_change_username?
gitlab_config.username_changing_enabled
end
2013-01-02 16:35:11 -05:00
def can_create_project?
2013-07-09 13:51:49 -04:00
projects_limit_left > 0
2013-01-02 16:35:11 -05:00
end
def can_create_group?
2013-01-25 04:30:49 -05:00
can?(:create_group, nil)
2013-01-02 16:35:11 -05:00
end
def abilities
Ability.abilities
2013-01-02 16:35:11 -05:00
end
def can_select_namespace?
several_namespaces? || admin
end
def can?(action, subject)
2013-01-02 16:35:11 -05:00
abilities.allowed?(self, action, subject)
end
def first_name
name.split.first unless name.blank?
end
def cared_merge_requests
2013-02-19 02:43:41 -05:00
MergeRequest.cared(self)
2013-01-02 16:35:11 -05:00
end
def projects_limit_left
projects_limit - personal_projects.count
end
2013-01-02 16:35:11 -05:00
def projects_limit_percent
return 100 if projects_limit.zero?
(personal_projects.count.to_f / projects_limit) * 100
2013-01-02 16:35:11 -05:00
end
def recent_push(project_id = nil)
2013-01-02 16:35:11 -05:00
# Get push events not earlier than 2 hours ago
events = recent_events.code_push.where("created_at > ?", Time.now - 2.hours)
events = events.where(project_id: project_id) if project_id
# Use the latest event that has not been pushed or merged recently
events.recent.find do |event|
project = Project.find_by_id(event.project_id)
next unless project
repo = project.repository
if repo.branch_names.include?(event.branch_name)
merge_requests = MergeRequest.where("created_at >= ?", event.created_at).
where(source_project_id: project.id,
source_branch: event.branch_name)
merge_requests.empty?
end
end
2013-01-02 16:35:11 -05:00
end
def projects_sorted_by_activity
authorized_projects.sorted_by_activity
end
def several_namespaces?
owned_groups.any? || masters_groups.any?
2013-01-02 16:35:11 -05:00
end
def namespace_id
namespace.try :id
end
2013-01-25 08:51:45 -05:00
2013-03-13 13:24:30 -04:00
def name_with_username
"#{name} (#{username})"
end
2013-04-04 03:53:39 -04:00
def tm_of(project)
project.project_member_by_id(self.id)
2013-04-04 03:53:39 -04:00
end
def already_forked?(project)
!!fork_of(project)
end
def fork_of(project)
links = ForkedProjectLink.where(forked_from_project_id: project, forked_to_project_id: personal_projects)
if links.any?
links.first.forked_to_project
else
nil
end
end
def ldap_user?
identities.exists?(["provider LIKE ? AND extern_uid IS NOT NULL", "ldap%"])
end
def ldap_identity
@ldap_identity ||= identities.find_by(["provider LIKE ?", "ldap%"])
end
def project_deploy_keys
DeployKey.unscoped.in_projects(self.authorized_projects.pluck(:id)).distinct(:id)
end
def accessible_deploy_keys
@accessible_deploy_keys ||= begin
key_ids = project_deploy_keys.pluck(:id)
key_ids.push(*DeployKey.are_public.pluck(:id))
DeployKey.where(id: key_ids)
end
end
def created_by
2014-01-19 13:55:59 -05:00
User.find_by(id: created_by_id) if created_by_id
end
2013-07-10 06:48:03 -04:00
def sanitize_attrs
%w(name username skype linkedin twitter).each do |attr|
2013-07-10 06:48:03 -04:00
value = self.send(attr)
self.send("#{attr}=", Sanitize.clean(value)) if value.present?
end
end
def set_notification_email
if self.notification_email.blank? || !self.all_emails.include?(self.notification_email)
self.notification_email = self.email
end
end
def set_public_email
if self.public_email.blank? || !self.all_emails.include?(self.public_email)
self.public_email = ''
end
end
def update_secondary_emails!
self.set_notification_email
self.set_public_email
self.save if self.notification_email_changed? || self.public_email_changed?
end
def set_projects_limit
connection_default_value_defined = new_record? && !projects_limit_changed?
return unless self.projects_limit.nil? || connection_default_value_defined
self.projects_limit = current_application_settings.default_projects_limit
end
def requires_ldap_check?
if !Gitlab.config.ldap.enabled
false
elsif ldap_user?
!last_credential_check_at || (last_credential_check_at + 1.hour) < Time.now
else
false
end
end
def solo_owned_groups
@solo_owned_groups ||= owned_groups.select do |group|
group.owners == [self]
end
end
def with_defaults
2013-09-14 13:51:16 -04:00
User.defaults.each do |k, v|
self.send("#{k}=", v)
end
2013-09-14 13:51:16 -04:00
self
end
def can_leave_project?(project)
project.namespace != namespace &&
project.project_member(self)
end
# Reset project events cache related to this user
#
# Since we do cache @event we need to reset cache in special cases:
# * when the user changes their avatar
# Events cache stored like events/23-20130109142513.
# The cache key includes updated_at timestamp.
# Thus it will automatically generate a new fragment
# when the event is updated because the key changes.
def reset_events_cache
Event.where(author_id: self.id).
order('id DESC').limit(1000).
update_all(updated_at: Time.now)
end
2014-01-18 14:07:00 -05:00
def full_website_url
return "http://#{website_url}" if website_url !~ /\Ahttps?:\/\//
2014-01-18 14:07:00 -05:00
website_url
end
def short_website_url
website_url.sub(/\Ahttps?:\/\//, '')
2014-01-18 14:07:00 -05:00
end
2014-02-06 06:26:20 -05:00
def all_ssh_keys
2015-06-19 13:17:34 -04:00
keys.map(&:publishable_key)
end
def temp_oauth_email?
email.start_with?('temp-email-for-oauth')
end
def avatar_url(size = nil)
if avatar.present?
[gitlab_config.url, avatar.url].join
else
GravatarService.new.execute(email, size)
end
end
2014-06-17 15:32:35 -04:00
def all_emails
[self.email, *self.emails.map(&:email)]
end
2014-10-05 09:03:15 -04:00
def hook_attrs
{
name: name,
username: username,
avatar_url: avatar_url
}
end
2014-06-17 15:32:35 -04:00
def ensure_namespace_correct
# Ensure user has namespace
self.create_namespace!(path: self.username, name: self.username) unless self.namespace
if self.username_changed?
self.namespace.update_attributes(path: self.username, name: self.username)
end
end
def post_create_hook
log_info("User \"#{self.name}\" (#{self.email}) was created")
notification_service.new_user(self, @reset_token) if self.created_by_id
2014-06-17 15:32:35 -04:00
system_hook_service.execute_hooks_for(self, :create)
end
def post_destroy_hook
log_info("User \"#{self.name}\" (#{self.email}) was removed")
system_hook_service.execute_hooks_for(self, :destroy)
end
2014-06-17 15:54:21 -04:00
def notification_service
2014-06-17 15:32:35 -04:00
NotificationService.new
end
def log_info(message)
2014-06-17 15:32:35 -04:00
Gitlab::AppLogger.info message
end
def system_hook_service
SystemHooksService.new
end
2014-06-26 03:49:14 -04:00
def starred?(project)
starred_projects.exists?(project)
end
def toggle_star(project)
UsersStarProject.transaction do
user_star_project = users_star_projects.
where(project: project, user: self).lock(true).first
if user_star_project
user_star_project.destroy
else
UsersStarProject.create!(project: project, user: self)
end
2014-06-26 03:49:14 -04:00
end
end
def manageable_namespaces
2015-10-03 01:56:37 -04:00
@manageable_namespaces ||= [namespace] + owned_groups + masters_groups
end
def namespaces
namespace_ids = groups.pluck(:id)
namespace_ids.push(namespace.id)
Namespace.where(id: namespace_ids)
end
def oauth_authorized_tokens
Doorkeeper::AccessToken.where(resource_owner_id: self.id, revoked_at: nil)
end
def contributed_projects_ids
Event.contributions.where(author_id: self).
where("created_at > ?", Time.now - 1.year).
reorder(project_id: :desc).
select(:project_id).
uniq.map(&:project_id)
end
def restricted_signup_domains
email_domains = current_application_settings.restricted_signup_domains
unless email_domains.blank?
match_found = email_domains.any? do |domain|
escaped = Regexp.escape(domain).gsub('\*','.*?')
regexp = Regexp.new "^#{escaped}$", Regexp::IGNORECASE
email_domain = Mail::Address.new(self.email).domain
email_domain =~ regexp
end
unless match_found
self.errors.add :email,
'is not whitelisted. ' +
'Email domains valid for registration are: ' +
email_domains.join(', ')
return false
end
end
true
end
def can_be_removed?
!solo_owned_groups.present?
end
2015-09-15 15:21:40 -04:00
def ci_authorized_projects
2015-10-23 12:15:13 -04:00
@ci_authorized_projects ||= Ci::Project.where(gitlab_id: authorized_projects_id)
2015-09-15 15:21:40 -04:00
end
def ci_authorized_runners
2015-10-23 12:15:13 -04:00
@ci_authorized_runners ||= begin
runner_ids = Ci::RunnerProject.joins(:project).
where(ci_projects: { gitlab_id: authorized_projects_id }).select(:runner_id)
Ci::Runner.specific.where(id: runner_ids)
end
2015-09-15 15:21:40 -04:00
end
2011-10-08 17:36:38 -04:00
end