Commit 65b9768ccfbdc3de682d66430601cf3af1b2a2f8

Authored by Dmitriy Zaporozhets
1 parent edd2143d

Group ownership completely based on users_groups relation now

Before we have only owner_id to determine group owner
With multiple owners per group we should get rid of owner_id in group.
So from now @group.owner will always be nil but
@group.owners return an actual array of users who can admin this group
app/controllers/admin/groups_controller.rb
... ... @@ -20,9 +20,9 @@ class Admin::GroupsController < Admin::ApplicationController
20 20 def create
21 21 @group = Group.new(params[:group])
22 22 @group.path = @group.name.dup.parameterize if @group.name
23   - @group.owner = current_user
24 23  
25 24 if @group.save
  25 + @group.add_owner(current_user)
26 26 redirect_to [:admin, @group], notice: 'Group was successfully created.'
27 27 else
28 28 render "new"
... ... @@ -30,14 +30,7 @@ class Admin::GroupsController < Admin::ApplicationController
30 30 end
31 31  
32 32 def update
33   - group_params = params[:group].dup
34   - owner_id =group_params.delete(:owner_id)
35   -
36   - if owner_id
37   - @group.change_owner(User.find(owner_id))
38   - end
39   -
40   - if @group.update_attributes(group_params)
  33 + if @group.update_attributes(params[:group])
41 34 redirect_to [:admin, @group], notice: 'Group was successfully updated.'
42 35 else
43 36 render "edit"
... ...
app/controllers/groups_controller.rb
... ... @@ -21,9 +21,9 @@ class GroupsController < ApplicationController
21 21 def create
22 22 @group = Group.new(params[:group])
23 23 @group.path = @group.name.dup.parameterize if @group.name
24   - @group.owner = current_user
25 24  
26 25 if @group.save
  26 + @group.add_owner(current_user)
27 27 redirect_to @group, notice: 'Group was successfully created.'
28 28 else
29 29 render action: "new"
... ...
app/controllers/profiles/groups_controller.rb
... ... @@ -8,8 +8,8 @@ class Profiles::GroupsController < ApplicationController
8 8 def leave
9 9 @users_group = group.users_groups.where(user_id: current_user.id).first
10 10  
11   - if group.owner == current_user
12   - redirect_to(profile_groups_path, alert: "You can't leave group. You must transfer it to another owner before leaving.")
  11 + if group.last_owner?(current_user)
  12 + redirect_to(profile_groups_path, alert: "You can't leave group. You must add at least one more owner to it.")
13 13 else
14 14 @users_group.destroy
15 15 redirect_to(profile_groups_path, info: "You left #{group.name} group.")
... ...
app/models/ability.rb
... ... @@ -79,7 +79,7 @@ class Ability
79 79 rules << project_admin_rules
80 80 end
81 81  
82   - if project.group && project.group.owners.include?(user)
  82 + if project.group && project.group.has_owner?(user)
83 83 rules << project_admin_rules
84 84 end
85 85  
... ... @@ -159,7 +159,7 @@ class Ability
159 159 end
160 160  
161 161 # Only group owner and administrators can manage group
162   - if group.owners.include?(user) || user.admin?
  162 + if group.has_owner?(user) || user.admin?
163 163 rules << [
164 164 :manage_group,
165 165 :manage_namespace
... ...
app/models/group.rb
... ... @@ -16,14 +16,12 @@ class Group &lt; Namespace
16 16 has_many :users_groups, dependent: :destroy
17 17 has_many :users, through: :users_groups
18 18  
19   - after_create :add_owner
20   -
21 19 def human_name
22 20 name
23 21 end
24 22  
25 23 def owners
26   - @owners ||= (users_groups.owners.map(&:user) << owner).uniq
  24 + @owners ||= users_groups.owners.map(&:user)
27 25 end
28 26  
29 27 def add_users(user_ids, group_access)
... ... @@ -36,20 +34,19 @@ class Group &lt; Namespace
36 34 self.users_groups.create(user_id: user.id, group_access: group_access)
37 35 end
38 36  
39   - def change_owner(user)
40   - self.owner = user
41   - membership = users_groups.where(user_id: user.id).first
  37 + def add_owner(user)
  38 + self.add_user(user, UsersGroup::OWNER)
  39 + end
42 40  
43   - if membership
44   - membership.update_attributes(group_access: UsersGroup::OWNER)
45   - else
46   - add_owner
47   - end
  41 + def has_owner?(user)
  42 + owners.include?(user)
48 43 end
49 44  
50   - private
  45 + def last_owner?(user)
  46 + has_owner?(user) && owners.size == 1
  47 + end
51 48  
52   - def add_owner
53   - self.add_users([owner.id], UsersGroup::OWNER)
  49 + def members
  50 + users_groups
54 51 end
55 52 end
... ...
app/models/namespace.rb
... ... @@ -20,7 +20,7 @@ class Namespace &lt; ActiveRecord::Base
20 20 has_many :projects, dependent: :destroy
21 21 belongs_to :owner, class_name: "User"
22 22  
23   - validates :owner, presence: true
  23 + validates :owner, presence: true, unless: ->(n) { n.type == "Group" }
24 24 validates :name, presence: true, uniqueness: true,
25 25 length: { within: 0..255 },
26 26 format: { with: Gitlab::Regex.name_regex,
... ...
app/models/project.rb
... ... @@ -249,10 +249,10 @@ class Project &lt; ActiveRecord::Base
249 249 end
250 250  
251 251 def owner
252   - if namespace
253   - namespace_owner
  252 + if group
  253 + group
254 254 else
255   - creator
  255 + namespace.try(:owner)
256 256 end
257 257 end
258 258  
... ... @@ -276,10 +276,6 @@ class Project &lt; ActiveRecord::Base
276 276 end
277 277 end
278 278  
279   - def namespace_owner
280   - namespace.try(:owner)
281   - end
282   -
283 279 def path_with_namespace
284 280 if namespace
285 281 namespace.path + '/' + path
... ...
app/models/user.rb
... ... @@ -135,7 +135,7 @@ class User &lt; ActiveRecord::Base
135 135 # Remove user from all groups
136 136 user.users_groups.find_each do |membership|
137 137 # skip owned resources
138   - next if membership.group.owners.include?(user)
  138 + next if membership.group.last_owner?(user)
139 139  
140 140 return false unless membership.destroy
141 141 end
... ...
app/services/system_hooks_service.rb
... ... @@ -23,13 +23,15 @@ class SystemHooksService
23 23  
24 24 case model
25 25 when Project
  26 + owner = model.owner
  27 +
26 28 data.merge!({
27 29 name: model.name,
28 30 path: model.path,
29 31 path_with_namespace: model.path_with_namespace,
30 32 project_id: model.id,
31   - owner_name: model.owner.name,
32   - owner_email: model.owner.email
  33 + owner_name: owner.name,
  34 + owner_email: owner.respond_to?(:email) ? owner.email : nil
33 35 })
34 36 when User
35 37 data.merge!({
... ...
app/views/admin/groups/index.html.haml
... ... @@ -31,11 +31,8 @@
31 31  
32 32 .clearfix.light.append-bottom-10
33 33 %span
34   - %b Owner:
35   - - if group.owner
36   - = link_to group.owner_name, admin_user_path(group.owner)
37   - - else
38   - (deleted)
  34 + %b Members:
  35 + %span.badge= group.members.size
39 36 \|
40 37 %span
41 38 %b Projects:
... ...
app/views/admin/groups/show.html.haml
... ... @@ -25,26 +25,6 @@
25 25 = @group.description
26 26  
27 27 %li
28   - %span.light Owned by:
29   - %strong
30   - - if @group.owner
31   - = link_to @group.owner_name, admin_user_path(@group.owner)
32   - - else
33   - (deleted)
34   - .pull-right
35   - = link_to "#", class: "btn btn-small change-owner-link" do
36   - %i.icon-edit
37   - Change owner
38   - %li.change-owner-holder.hide.bgred
39   - .form-holder
40   - %strong.cred New Owner:
41   - = form_for [:admin, @group] do |f|
42   - = users_select_tag(:"group[owner_id]")
43   - .prepend-top-10
44   - = f.submit 'Change Owner', class: "btn btn-remove"
45   - = link_to "Cancel", "#", class: "btn change-owner-cancel-link"
46   -
47   - %li
48 28 %span.light Created at:
49 29 %strong
50 30 = @group.created_at.stamp("March 1, 1999")
... ... @@ -92,4 +72,5 @@
92 72 = link_to user.name, admin_user_path(user)
93 73 %span.pull-right.light
94 74 = member.human_access
95   -
  75 + = link_to group_users_group_path(@group, member), confirm: remove_user_from_group_message(@group, user), method: :delete, remote: true, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do
  76 + %i.icon-minus.icon-white
... ...
app/views/admin/projects/show.html.haml
... ... @@ -25,7 +25,7 @@
25 25 %span.light Owned by:
26 26 %strong
27 27 - if @project.owner
28   - = link_to @project.owner_name, admin_user_path(@project.owner)
  28 + = link_to @project.owner_name, [:admin, @project.owner]
29 29 - else
30 30 (deleted)
31 31  
... ...