Skip to content

Commit f6a9939

Browse files
Merge pull request #1134 from code0-tech/#1114-add-namespace-admin-permission
added namespace admin permission
2 parents 0b7de5a + e6ed682 commit f6a9939

8 files changed

Lines changed: 103 additions & 1 deletion

app/models/concerns/namespace_parent.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ def ensure_namespace
1111
return namespace if namespace.present?
1212

1313
ns = build_namespace
14-
ns.save if persisted?
14+
if persisted?
15+
ns.save
16+
ns.ensure_personal_namespace_administrator! if ns.user_type?
17+
end
1518
ns
1619
end
1720
end

app/models/namespace.rb

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# frozen_string_literal: true
22

33
class Namespace < ApplicationRecord
4+
PERSONAL_NAMESPACE_ADMINISTRATOR_ROLE_NAME = 'Administrator'
5+
46
belongs_to :parent, polymorphic: true
57

68
has_many :roles, class_name: 'NamespaceRole', inverse_of: :namespace
@@ -33,6 +35,33 @@ def member?(user)
3335
namespace_members.exists?(user: user)
3436
end
3537
end
38+
39+
def personal_namespace_owner_member?(member)
40+
user_type? && member&.namespace_id == id && member.user_id == parent_id
41+
end
42+
43+
def personal_namespace_owner_administrator_role?(role)
44+
return false unless user_type? && role&.namespace_id == id
45+
46+
role.members.exists?(id: personal_namespace_owner_member&.id) &&
47+
role.abilities.exists?(ability: :namespace_administrator)
48+
end
49+
50+
def ensure_personal_namespace_administrator!
51+
return unless user_type?
52+
53+
role = roles.find_or_create_by!(name: PERSONAL_NAMESPACE_ADMINISTRATOR_ROLE_NAME)
54+
role.abilities.find_or_create_by!(ability: :namespace_administrator)
55+
56+
member = namespace_members.find_or_create_by!(user_id: parent_id)
57+
member.member_roles.find_or_create_by!(role: role)
58+
end
59+
60+
private
61+
62+
def personal_namespace_owner_member
63+
namespace_members.find_by(user_id: parent_id)
64+
end
3665
end
3766

3867
Namespace.prepend_extensions

app/policies/namespace_member_policy.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ class NamespaceMemberPolicy < BasePolicy
44
delegate { subject.namespace }
55

66
condition(:member_is_self) { subject.user.id == user&.id }
7+
condition(:personal_namespace_owner_member) { subject.namespace.personal_namespace_owner_member?(subject) }
78

89
rule { member_is_self }.enable :delete_member
10+
11+
rule { personal_namespace_owner_member }.policy do
12+
prevent :delete_member
13+
prevent :assign_member_roles
14+
end
915
end

app/policies/namespace_role_policy.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,14 @@
22

33
class NamespaceRolePolicy < BasePolicy
44
delegate { subject.namespace }
5+
6+
condition(:personal_namespace_owner_administrator_role) do
7+
subject.namespace.personal_namespace_owner_administrator_role?(subject)
8+
end
9+
10+
rule { personal_namespace_owner_administrator_role }.policy do
11+
prevent :delete_namespace_role
12+
prevent :assign_role_abilities
13+
prevent :assign_role_projects
14+
end
515
end

spec/models/namespace_spec.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,20 @@
4242
expect { namespace.member?(user) }.to match_query_count(0)
4343
end
4444
end
45+
46+
describe 'personal namespace administrator via ensure_namespace' do
47+
let(:user) { create(:user) }
48+
49+
it 'adds the owner as an administrator member' do
50+
namespace = user.ensure_namespace
51+
52+
owner_member = namespace.namespace_members.find_by(user: user)
53+
administrator_role = namespace.roles
54+
.joins(:abilities)
55+
.find_by(namespace_role_abilities: { ability: :namespace_administrator })
56+
57+
expect(owner_member).to be_present
58+
expect(owner_member.roles).to include(administrator_role)
59+
end
60+
end
4561
end

spec/policies/namespace_member_policy_spec.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,13 @@
1616

1717
it { is_expected.to be_allowed(:delete_member) }
1818
end
19+
20+
context 'when member is the personal namespace owner' do
21+
let(:namespace) { current_user.ensure_namespace }
22+
let(:namespace_member) { namespace.namespace_members.find_by(user: current_user) }
23+
24+
it { is_expected.not_to be_allowed(:delete_member) }
25+
it { is_expected.not_to be_allowed(:assign_member_roles) }
26+
end
1927
end
2028
end

spec/policies/namespace_project_policy_spec.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,11 @@
2020

2121
it { is_expected.to be_allowed(:read_namespace_project) }
2222
end
23+
24+
context 'when project belongs to the personal namespace' do
25+
let(:namespace) { current_user.ensure_namespace }
26+
let(:namespace_project) { create(:namespace_project, namespace: namespace) }
27+
28+
it { is_expected.to be_allowed(:update_namespace_project) }
29+
end
2330
end
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# frozen_string_literal: true
2+
3+
require 'rails_helper'
4+
5+
RSpec.describe NamespaceRolePolicy do
6+
subject { described_class.new(create_authentication(current_user), namespace_role) }
7+
8+
let(:current_user) { create(:user) }
9+
let(:namespace_role) { create(:namespace_role) }
10+
11+
context 'when role is the personal namespace owner administrator role' do
12+
let(:namespace) { current_user.ensure_namespace }
13+
let(:namespace_role) do
14+
namespace.namespace_members.find_by(user: current_user).roles
15+
.joins(:abilities)
16+
.find_by(namespace_role_abilities: { ability: :namespace_administrator })
17+
end
18+
19+
it { is_expected.not_to be_allowed(:delete_namespace_role) }
20+
it { is_expected.not_to be_allowed(:assign_role_abilities) }
21+
it { is_expected.not_to be_allowed(:assign_role_projects) }
22+
end
23+
end

0 commit comments

Comments
 (0)