Commit 0f2798d498c69372137d13a8ba3ec8e87b7f0a8a

Authored by Dmitriy Zaporozhets
2 parents 52cd655f 85e03904

Merge branch 'feature/refactoring_scopes_pr' of https://github.com/Undev/gitlabh…

…q into Undev-feature/refactoring_scopes_pr

Conflicts:
	db/schema.rb
app/controllers/admin/users_controller.rb
@@ -14,7 +14,7 @@ class Admin::UsersController < Admin::ApplicationController @@ -14,7 +14,7 @@ class Admin::UsersController < Admin::ApplicationController
14 @not_in_projects = @not_in_projects.without_user(admin_user) if admin_user.authorized_projects.present? 14 @not_in_projects = @not_in_projects.without_user(admin_user) if admin_user.authorized_projects.present?
15 15
16 # Projects he already own or joined 16 # Projects he already own or joined
17 - @projects = admin_user.authorized_projects.where('projects.id in (?)', admin_user.authorized_projects.map(&:id)) 17 + @projects = admin_user.authorized_projects
18 end 18 end
19 19
20 def team_update 20 def team_update
app/models/group.rb
@@ -13,6 +13,7 @@ @@ -13,6 +13,7 @@
13 # 13 #
14 14
15 class Group < Namespace 15 class Group < Namespace
  16 +
16 def add_users_to_project_teams(user_ids, project_access) 17 def add_users_to_project_teams(user_ids, project_access)
17 UsersProject.add_users_into_projects( 18 UsersProject.add_users_into_projects(
18 projects.map(&:id), 19 projects.map(&:id),
app/models/issue.rb
@@ -25,19 +25,9 @@ class Issue &lt; ActiveRecord::Base @@ -25,19 +25,9 @@ class Issue &lt; ActiveRecord::Base
25 25
26 acts_as_taggable_on :labels 26 acts_as_taggable_on :labels
27 27
28 - class << self  
29 - def cared(user)  
30 - where('assignee_id = :user', user: user.id)  
31 - end  
32 -  
33 - def authored(user)  
34 - where('author_id = :user', user: user.id)  
35 - end  
36 -  
37 - def open_for(user)  
38 - opened.assigned(user)  
39 - end  
40 - end 28 + scope :cared, ->(user) { where(assignee_id: user) }
  29 + scope :authored, ->(user) { where(author_id: user) }
  30 + scope :open_for, ->(user) { opened.assigned(user) }
41 31
42 state_machine :state, initial: :opened do 32 state_machine :state, initial: :opened do
43 event :close do 33 event :close do
app/models/key.rb
@@ -23,7 +23,7 @@ class Key &lt; ActiveRecord::Base @@ -23,7 +23,7 @@ class Key &lt; ActiveRecord::Base
23 before_validation :strip_white_space 23 before_validation :strip_white_space
24 24
25 validates :title, presence: true, length: { within: 0..255 } 25 validates :title, presence: true, length: { within: 0..255 }
26 - validates :key, presence: true, length: { within: 0..5000 }, format: { :with => /ssh-.{3} / }, uniqueness: true 26 + validates :key, presence: true, length: { within: 0..5000 }, format: { with: /ssh-.{3} / }, uniqueness: true
27 validate :fingerprintable_key 27 validate :fingerprintable_key
28 28
29 delegate :name, :email, to: :user, prefix: true 29 delegate :name, :email, to: :user, prefix: true
@@ -48,7 +48,7 @@ class Key &lt; ActiveRecord::Base @@ -48,7 +48,7 @@ class Key &lt; ActiveRecord::Base
48 end 48 end
49 49
50 def is_deploy_key 50 def is_deploy_key
51 - !!project_id 51 + project.present?
52 end 52 end
53 53
54 # projects that has this key 54 # projects that has this key
app/models/milestone.rb
@@ -19,6 +19,7 @@ class Milestone &lt; ActiveRecord::Base @@ -19,6 +19,7 @@ class Milestone &lt; ActiveRecord::Base
19 belongs_to :project 19 belongs_to :project
20 has_many :issues 20 has_many :issues
21 has_many :merge_requests 21 has_many :merge_requests
  22 + has_many :participants, through: :issues, source: :assignee
22 23
23 scope :active, -> { with_state(:active) } 24 scope :active, -> { with_state(:active) }
24 scope :closed, -> { with_state(:closed) } 25 scope :closed, -> { with_state(:closed) }
@@ -48,10 +49,6 @@ class Milestone &lt; ActiveRecord::Base @@ -48,10 +49,6 @@ class Milestone &lt; ActiveRecord::Base
48 end 49 end
49 end 50 end
50 51
51 - def participants  
52 - User.where(id: issues.pluck(:assignee_id))  
53 - end  
54 -  
55 def open_items_count 52 def open_items_count
56 self.issues.opened.count + self.merge_requests.opened.count 53 self.issues.opened.count + self.merge_requests.opened.count
57 end 54 end
app/models/project.rb
@@ -30,7 +30,7 @@ class Project &lt; ActiveRecord::Base @@ -30,7 +30,7 @@ class Project &lt; ActiveRecord::Base
30 30
31 attr_accessible :name, :path, :description, :default_branch, :issues_tracker, 31 attr_accessible :name, :path, :description, :default_branch, :issues_tracker,
32 :issues_enabled, :wall_enabled, :merge_requests_enabled, :snippets_enabled, :issues_tracker_id, 32 :issues_enabled, :wall_enabled, :merge_requests_enabled, :snippets_enabled, :issues_tracker_id,
33 - :wiki_enabled, :public, :import_url, as: [:default, :admin] 33 + :wiki_enabled, :public, :import_url, :last_activity_at, as: [:default, :admin]
34 34
35 attr_accessible :namespace_id, :creator_id, as: :admin 35 attr_accessible :namespace_id, :creator_id, as: :admin
36 36
@@ -87,17 +87,18 @@ class Project &lt; ActiveRecord::Base @@ -87,17 +87,18 @@ class Project &lt; ActiveRecord::Base
87 validate :check_limit, :repo_name 87 validate :check_limit, :repo_name
88 88
89 # Scopes 89 # Scopes
90 - scope :without_user, ->(user) { where("id NOT IN (:ids)", ids: user.authorized_projects.map(&:id) ) }  
91 - scope :not_in_group, ->(group) { where("id NOT IN (:ids)", ids: group.project_ids ) }  
92 - scope :without_team, ->(team) { team.projects.present? ? where("id NOT IN (:ids)", ids: team.projects.map(&:id)) : scoped }  
93 - scope :in_team, ->(team) { where("id IN (:ids)", ids: team.projects.map(&:id)) } 90 + scope :without_user, ->(user) { where("projects.id NOT IN (:ids)", ids: user.authorized_projects.map(&:id) ) }
  91 + scope :without_team, ->(team) { team.projects.present? ? where("projects.id NOT IN (:ids)", ids: team.projects.map(&:id)) : scoped }
  92 + scope :not_in_group, ->(group) { where("projects.id NOT IN (:ids)", ids: group.project_ids ) }
  93 + scope :in_team, ->(team) { where("projects.id IN (:ids)", ids: team.projects.map(&:id)) }
94 scope :in_namespace, ->(namespace) { where(namespace_id: namespace.id) } 94 scope :in_namespace, ->(namespace) { where(namespace_id: namespace.id) }
95 - scope :sorted_by_activity, ->() { order("(SELECT max(events.created_at) FROM events WHERE events.project_id = projects.id) DESC") } 95 + scope :in_group_namespace, -> { joins(:group) }
  96 + scope :sorted_by_activity, -> { order("projects.last_activity_at DESC") }
96 scope :personal, ->(user) { where(namespace_id: user.namespace_id) } 97 scope :personal, ->(user) { where(namespace_id: user.namespace_id) }
97 scope :joined, ->(user) { where("namespace_id != ?", user.namespace_id) } 98 scope :joined, ->(user) { where("namespace_id != ?", user.namespace_id) }
98 scope :public_only, -> { where(public: true) } 99 scope :public_only, -> { where(public: true) }
99 100
100 - enumerize :issues_tracker, :in => (Gitlab.config.issues_tracker.keys).append(:gitlab), :default => :gitlab 101 + enumerize :issues_tracker, in: (Gitlab.config.issues_tracker.keys).append(:gitlab), default: :gitlab
101 102
102 class << self 103 class << self
103 def abandoned 104 def abandoned
@@ -190,7 +191,7 @@ class Project &lt; ActiveRecord::Base @@ -190,7 +191,7 @@ class Project &lt; ActiveRecord::Base
190 end 191 end
191 192
192 def last_activity_date 193 def last_activity_date
193 - last_event.try(:created_at) || updated_at 194 + last_activity_at || updated_at
194 end 195 end
195 196
196 def project_id 197 def project_id
app/models/user.rb
@@ -59,11 +59,10 @@ class User &lt; ActiveRecord::Base @@ -59,11 +59,10 @@ class User &lt; ActiveRecord::Base
59 # 59 #
60 60
61 # Namespace for personal projects 61 # Namespace for personal projects
62 - has_one :namespace,  
63 - dependent: :destroy,  
64 - foreign_key: :owner_id,  
65 - class_name: "Namespace",  
66 - conditions: 'type IS NULL' 62 + has_one :namespace, dependent: :destroy, foreign_key: :owner_id, class_name: "Namespace", conditions: 'type IS NULL'
  63 +
  64 + # Namespaces (owned groups and own namespace)
  65 + has_many :namespaces, foreign_key: :owner_id
67 66
68 # Profile 67 # Profile
69 has_many :keys, dependent: :destroy 68 has_many :keys, dependent: :destroy
@@ -72,15 +71,11 @@ class User &lt; ActiveRecord::Base @@ -72,15 +71,11 @@ class User &lt; ActiveRecord::Base
72 has_many :groups, class_name: "Group", foreign_key: :owner_id 71 has_many :groups, class_name: "Group", foreign_key: :owner_id
73 72
74 # Teams 73 # Teams
75 - has_many :own_teams,  
76 - class_name: "UserTeam",  
77 - foreign_key: :owner_id,  
78 - dependent: :destroy  
79 -  
80 - has_many :user_team_user_relationships, dependent: :destroy  
81 - has_many :user_teams, through: :user_team_user_relationships 74 + has_many :own_teams, dependent: :destroy, class_name: "UserTeam", foreign_key: :owner_id
  75 + has_many :user_team_user_relationships, dependent: :destroy
  76 + has_many :user_teams, through: :user_team_user_relationships
82 has_many :user_team_project_relationships, through: :user_teams 77 has_many :user_team_project_relationships, through: :user_teams
83 - has_many :team_projects, through: :user_team_project_relationships 78 + has_many :team_projects, through: :user_team_project_relationships
84 79
85 # Projects 80 # Projects
86 has_many :users_projects, dependent: :destroy 81 has_many :users_projects, dependent: :destroy
@@ -88,14 +83,14 @@ class User &lt; ActiveRecord::Base @@ -88,14 +83,14 @@ class User &lt; ActiveRecord::Base
88 has_many :notes, dependent: :destroy, foreign_key: :author_id 83 has_many :notes, dependent: :destroy, foreign_key: :author_id
89 has_many :merge_requests, dependent: :destroy, foreign_key: :author_id 84 has_many :merge_requests, dependent: :destroy, foreign_key: :author_id
90 has_many :events, dependent: :destroy, foreign_key: :author_id, class_name: "Event" 85 has_many :events, dependent: :destroy, foreign_key: :author_id, class_name: "Event"
  86 + has_many :recent_events, foreign_key: :author_id, class_name: "Event", order: "id DESC"
91 has_many :assigned_issues, dependent: :destroy, foreign_key: :assignee_id, class_name: "Issue" 87 has_many :assigned_issues, dependent: :destroy, foreign_key: :assignee_id, class_name: "Issue"
92 has_many :assigned_merge_requests, dependent: :destroy, foreign_key: :assignee_id, class_name: "MergeRequest" 88 has_many :assigned_merge_requests, dependent: :destroy, foreign_key: :assignee_id, class_name: "MergeRequest"
93 - has_many :projects, through: :users_projects  
94 89
95 - has_many :recent_events,  
96 - class_name: "Event",  
97 - foreign_key: :author_id,  
98 - order: "id DESC" 90 + has_many :personal_projects, through: :namespace, source: :projects
  91 + has_many :projects, through: :users_projects
  92 + has_many :own_projects, foreign_key: :creator_id
  93 + has_many :owned_projects, through: :namespaces, source: :projects
99 94
100 # 95 #
101 # Validations 96 # Validations
@@ -109,9 +104,7 @@ class User &lt; ActiveRecord::Base @@ -109,9 +104,7 @@ class User &lt; ActiveRecord::Base
109 format: { with: Gitlab::Regex.username_regex, 104 format: { with: Gitlab::Regex.username_regex,
110 message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } 105 message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" }
111 106
112 - validates :notification_level,  
113 - inclusion: { in: Notification.notification_levels },  
114 - presence: true 107 + validates :notification_level, inclusion: { in: Notification.notification_levels }, presence: true
115 108
116 validate :namespace_uniq, if: ->(user) { user.username_changed? } 109 validate :namespace_uniq, if: ->(user) { user.username_changed? }
117 110
@@ -145,6 +138,9 @@ class User &lt; ActiveRecord::Base @@ -145,6 +138,9 @@ class User &lt; ActiveRecord::Base
145 scope :alphabetically, -> { order('name ASC') } 138 scope :alphabetically, -> { order('name ASC') }
146 scope :in_team, ->(team){ where(id: team.member_ids) } 139 scope :in_team, ->(team){ where(id: team.member_ids) }
147 scope :not_in_team, ->(team){ where('users.id NOT IN (:ids)', ids: team.member_ids) } 140 scope :not_in_team, ->(team){ where('users.id NOT IN (:ids)', ids: team.member_ids) }
  141 + scope :not_in_project, ->(project) { project.users.present? ? where("id not in (:ids)", ids: project.users.map(&:id) ) : scoped }
  142 + scope :without_projects, -> { where('id NOT IN (SELECT DISTINCT(user_id) FROM users_projects)') }
  143 +
148 scope :potential_team_members, ->(team) { team.members.any? ? active.not_in_team(team) : active } 144 scope :potential_team_members, ->(team) { team.members.any? ? active.not_in_team(team) : active }
149 145
150 # 146 #
@@ -171,18 +167,6 @@ class User &lt; ActiveRecord::Base @@ -171,18 +167,6 @@ class User &lt; ActiveRecord::Base
171 end 167 end
172 end 168 end
173 169
174 - def not_in_project(project)  
175 - if project.users.present?  
176 - where("id not in (:ids)", ids: project.users.map(&:id) )  
177 - else  
178 - scoped  
179 - end  
180 - end  
181 -  
182 - def without_projects  
183 - where('id NOT IN (SELECT DISTINCT(user_id) FROM users_projects)')  
184 - end  
185 -  
186 def create_from_omniauth(auth, ldap = false) 170 def create_from_omniauth(auth, ldap = false)
187 gitlab_auth.create_from_omniauth(auth, ldap) 171 gitlab_auth.create_from_omniauth(auth, ldap)
188 end 172 end
@@ -229,56 +213,36 @@ class User &lt; ActiveRecord::Base @@ -229,56 +213,36 @@ class User &lt; ActiveRecord::Base
229 end 213 end
230 end 214 end
231 215
232 - # Namespaces user has access to  
233 - def namespaces  
234 - namespaces = []  
235 -  
236 - # Add user account namespace  
237 - namespaces << self.namespace if self.namespace  
238 -  
239 - # Add groups you can manage  
240 - namespaces += groups.all  
241 -  
242 - namespaces  
243 - end  
244 -  
245 # Groups where user is an owner 216 # Groups where user is an owner
246 def owned_groups 217 def owned_groups
247 groups 218 groups
248 end 219 end
249 220
  221 + def owned_teams
  222 + own_teams
  223 + end
  224 +
250 # Groups user has access to 225 # Groups user has access to
251 def authorized_groups 226 def authorized_groups
252 - @authorized_groups ||= begin  
253 - groups = Group.where(id: self.authorized_projects.pluck(:namespace_id)).all  
254 - groups = groups + self.groups  
255 - groups.uniq  
256 - end 227 + @group_ids ||= (groups.pluck(:id) + authorized_projects.pluck(:namespace_id))
  228 + Group.where(id: @group_ids)
257 end 229 end
258 230
259 231
260 # Projects user has access to 232 # Projects user has access to
261 def authorized_projects 233 def authorized_projects
262 - project_ids = users_projects.pluck(:project_id)  
263 - project_ids = project_ids | owned_projects.pluck(:id)  
264 - Project.where(id: project_ids) 234 + @project_ids ||= (owned_projects.pluck(:id) + projects.pluck(:id)).uniq
  235 + Project.where(id: @project_ids)
265 end 236 end
266 237
267 - # Projects in user namespace  
268 - def personal_projects  
269 - Project.personal(self)  
270 - end  
271 -  
272 - # Projects where user is an owner  
273 - def owned_projects  
274 - Project.where("(projects.namespace_id IN (:namespaces)) OR  
275 - (projects.namespace_id IS NULL AND projects.creator_id = :user_id)",  
276 - namespaces: namespaces.map(&:id), user_id: self.id) 238 + def authorized_teams
  239 + @team_ids ||= (user_teams.pluck(:id) + own_teams.pluck(:id)).uniq
  240 + UserTeam.where(id: @team_ids)
277 end 241 end
278 242
279 # Team membership in authorized projects 243 # Team membership in authorized projects
280 def tm_in_authorized_projects 244 def tm_in_authorized_projects
281 - UsersProject.where(project_id: authorized_projects.map(&:id), user_id: self.id) 245 + UsersProject.where(project_id: authorized_projects.map(&:id), user_id: self.id)
282 end 246 end
283 247
284 def is_admin? 248 def is_admin?
@@ -348,28 +312,13 @@ class User &lt; ActiveRecord::Base @@ -348,28 +312,13 @@ class User &lt; ActiveRecord::Base
348 end 312 end
349 313
350 def several_namespaces? 314 def several_namespaces?
351 - namespaces.size > 1 315 + namespaces.many?
352 end 316 end
353 317
354 def namespace_id 318 def namespace_id
355 namespace.try :id 319 namespace.try :id
356 end 320 end
357 321
358 - def authorized_teams  
359 - @authorized_teams ||= begin  
360 - ids = []  
361 - ids << UserTeam.with_member(self).pluck('user_teams.id')  
362 - ids << UserTeam.created_by(self).pluck('user_teams.id')  
363 - ids.flatten  
364 -  
365 - UserTeam.where(id: ids)  
366 - end  
367 - end  
368 -  
369 - def owned_teams  
370 - UserTeam.where(owner_id: self.id)  
371 - end  
372 -  
373 def name_with_username 322 def name_with_username
374 "#{name} (#{username})" 323 "#{name} (#{username})"
375 end 324 end
app/observers/project_activity_cache_observer.rb 0 → 100644
@@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
  1 +class ProjectActivityCacheObserver < BaseObserver
  2 + observe :event
  3 +
  4 + def after_create(event)
  5 + event.project.update_attribute(:last_activity_at, event.created_at) if event.project
  6 + end
  7 +end
  8 +
config/application.rb
@@ -24,6 +24,7 @@ module Gitlab @@ -24,6 +24,7 @@ module Gitlab
24 24
25 # Activate observers that should always be running. 25 # Activate observers that should always be running.
26 config.active_record.observers = :activity_observer, 26 config.active_record.observers = :activity_observer,
  27 + :project_activity_cache_observer,
27 :issue_observer, 28 :issue_observer,
28 :key_observer, 29 :key_observer,
29 :merge_request_observer, 30 :merge_request_observer,
db/migrate/20130403003950_add_last_activity_column_into_project.rb 0 → 100644
@@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
  1 +class AddLastActivityColumnIntoProject < ActiveRecord::Migration
  2 + def up
  3 + add_column :projects, :last_activity_at, :datetime
  4 + add_index :projects, :last_activity_at
  5 +
  6 + Project.find_each do |project|
  7 + project.update_attribute(:last_activity_at, project.last_activity_date)
  8 + end
  9 + end
  10 +
  11 + def down
  12 + remove_index :projects, :last_activity_at
  13 + remove_column :projects, :last_activity_at
  14 + end
  15 +end
@@ -12,7 +12,6 @@ @@ -12,7 +12,6 @@
12 # It's strongly recommended to check this file into your version control system. 12 # It's strongly recommended to check this file into your version control system.
13 13
14 ActiveRecord::Schema.define(:version => 20130404164628) do 14 ActiveRecord::Schema.define(:version => 20130404164628) do
15 -  
16 create_table "events", :force => true do |t| 15 create_table "events", :force => true do |t|
17 t.string "target_type" 16 t.string "target_type"
18 t.integer "target_id" 17 t.integer "target_id"
spec/models/project_spec.rb
@@ -109,8 +109,8 @@ describe Project do @@ -109,8 +109,8 @@ describe Project do
109 109
110 describe 'last_activity_date' do 110 describe 'last_activity_date' do
111 it 'returns the creation date of the project\'s last event if present' do 111 it 'returns the creation date of the project\'s last event if present' do
112 - project.stub(last_event: last_event)  
113 - project.last_activity_date.should == last_event.created_at 112 + last_activity_event = create(:event, project: project)
  113 + project.last_activity_date.to_s(:db).should == last_event.created_at.to_s(:db)
114 end 114 end
115 115
116 it 'returns the project\'s last update date if it has no events' do 116 it 'returns the project\'s last update date if it has no events' do