|
c588255…
|
ragelink
|
1 |
import pytest |
|
c588255…
|
ragelink
|
2 |
from django.contrib.auth.models import Group, Permission, User |
|
c588255…
|
ragelink
|
3 |
from django.test import Client |
|
c588255…
|
ragelink
|
4 |
from django.urls import reverse |
|
c588255…
|
ragelink
|
5 |
|
|
c588255…
|
ragelink
|
6 |
from organization.models import OrganizationMember, OrgRole |
|
c588255…
|
ragelink
|
7 |
|
|
c588255…
|
ragelink
|
8 |
|
|
c588255…
|
ragelink
|
9 |
@pytest.fixture |
|
c588255…
|
ragelink
|
10 |
def roles(db): |
|
c588255…
|
ragelink
|
11 |
"""Seed default roles via management command.""" |
|
c588255…
|
ragelink
|
12 |
from django.core.management import call_command |
|
c588255…
|
ragelink
|
13 |
|
|
c588255…
|
ragelink
|
14 |
call_command("seed_roles") |
|
c588255…
|
ragelink
|
15 |
return OrgRole.objects.all() |
|
c588255…
|
ragelink
|
16 |
|
|
c588255…
|
ragelink
|
17 |
|
|
c588255…
|
ragelink
|
18 |
@pytest.fixture |
|
c588255…
|
ragelink
|
19 |
def admin_role(roles): |
|
c588255…
|
ragelink
|
20 |
return OrgRole.objects.get(slug="admin") |
|
c588255…
|
ragelink
|
21 |
|
|
c588255…
|
ragelink
|
22 |
|
|
c588255…
|
ragelink
|
23 |
@pytest.fixture |
|
c588255…
|
ragelink
|
24 |
def viewer_role(roles): |
|
c588255…
|
ragelink
|
25 |
return OrgRole.objects.get(slug="viewer") |
|
c588255…
|
ragelink
|
26 |
|
|
c588255…
|
ragelink
|
27 |
|
|
c588255…
|
ragelink
|
28 |
@pytest.fixture |
|
c588255…
|
ragelink
|
29 |
def developer_role(roles): |
|
c588255…
|
ragelink
|
30 |
return OrgRole.objects.get(slug="developer") |
|
c588255…
|
ragelink
|
31 |
|
|
c588255…
|
ragelink
|
32 |
|
|
c588255…
|
ragelink
|
33 |
@pytest.fixture |
|
c588255…
|
ragelink
|
34 |
def manager_role(roles): |
|
c588255…
|
ragelink
|
35 |
return OrgRole.objects.get(slug="manager") |
|
c588255…
|
ragelink
|
36 |
|
|
c588255…
|
ragelink
|
37 |
|
|
c588255…
|
ragelink
|
38 |
@pytest.fixture |
|
c588255…
|
ragelink
|
39 |
def target_user(db, org, admin_user): |
|
c588255…
|
ragelink
|
40 |
user = User.objects.create_user( |
|
c588255…
|
ragelink
|
41 |
username="targetuser", email="[email protected]", password="testpass123", first_name="Target", last_name="User" |
|
c588255…
|
ragelink
|
42 |
) |
|
c588255…
|
ragelink
|
43 |
OrganizationMember.objects.create(member=user, organization=org, created_by=admin_user) |
|
c588255…
|
ragelink
|
44 |
return user |
|
c588255…
|
ragelink
|
45 |
|
|
c588255…
|
ragelink
|
46 |
|
|
c588255…
|
ragelink
|
47 |
@pytest.fixture |
|
c588255…
|
ragelink
|
48 |
def org_admin_user(db, org): |
|
c588255…
|
ragelink
|
49 |
"""Non-superuser with ORGANIZATION_CHANGE permission.""" |
|
c588255…
|
ragelink
|
50 |
user = User.objects.create_user(username="orgadmin", email="[email protected]", password="testpass123") |
|
c588255…
|
ragelink
|
51 |
group, _ = Group.objects.get_or_create(name="OrgAdmins") |
|
c588255…
|
ragelink
|
52 |
change_perm = Permission.objects.get(content_type__app_label="organization", codename="change_organization") |
|
c588255…
|
ragelink
|
53 |
view_perm = Permission.objects.get(content_type__app_label="organization", codename="view_organization") |
|
c588255…
|
ragelink
|
54 |
view_member_perm = Permission.objects.get(content_type__app_label="organization", codename="view_organizationmember") |
|
c588255…
|
ragelink
|
55 |
group.permissions.add(change_perm, view_perm, view_member_perm) |
|
c588255…
|
ragelink
|
56 |
user.groups.add(group) |
|
c588255…
|
ragelink
|
57 |
OrganizationMember.objects.create(member=user, organization=org) |
|
c588255…
|
ragelink
|
58 |
return user |
|
c588255…
|
ragelink
|
59 |
|
|
c588255…
|
ragelink
|
60 |
|
|
c588255…
|
ragelink
|
61 |
@pytest.fixture |
|
c588255…
|
ragelink
|
62 |
def org_admin_client(org_admin_user): |
|
c588255…
|
ragelink
|
63 |
c = Client() |
|
c588255…
|
ragelink
|
64 |
c.login(username="orgadmin", password="testpass123") |
|
c588255…
|
ragelink
|
65 |
return c |
|
c588255…
|
ragelink
|
66 |
|
|
c588255…
|
ragelink
|
67 |
|
|
c588255…
|
ragelink
|
68 |
# --- OrgRole model --- |
|
c588255…
|
ragelink
|
69 |
|
|
c588255…
|
ragelink
|
70 |
|
|
c588255…
|
ragelink
|
71 |
@pytest.mark.django_db |
|
c588255…
|
ragelink
|
72 |
class TestOrgRoleModel: |
|
c588255…
|
ragelink
|
73 |
def test_seed_creates_four_roles(self, roles): |
|
c588255…
|
ragelink
|
74 |
assert OrgRole.objects.count() == 4 |
|
c588255…
|
ragelink
|
75 |
|
|
c588255…
|
ragelink
|
76 |
def test_seed_idempotent(self, roles): |
|
c588255…
|
ragelink
|
77 |
from django.core.management import call_command |
|
c588255…
|
ragelink
|
78 |
|
|
c588255…
|
ragelink
|
79 |
call_command("seed_roles") |
|
c588255…
|
ragelink
|
80 |
assert OrgRole.objects.count() == 4 |
|
c588255…
|
ragelink
|
81 |
|
|
c588255…
|
ragelink
|
82 |
def test_admin_role_has_all_app_permissions(self, admin_role): |
|
c588255…
|
ragelink
|
83 |
app_perms = Permission.objects.filter(content_type__app_label__in=["organization", "projects", "pages", "fossil"]).count() |
|
c588255…
|
ragelink
|
84 |
assert admin_role.permissions.count() == app_perms |
|
c588255…
|
ragelink
|
85 |
|
|
c588255…
|
ragelink
|
86 |
def test_viewer_role_is_default(self, viewer_role): |
|
c588255…
|
ragelink
|
87 |
assert viewer_role.is_default is True |
|
c588255…
|
ragelink
|
88 |
|
|
c588255…
|
ragelink
|
89 |
def test_admin_role_not_default(self, admin_role): |
|
c588255…
|
ragelink
|
90 |
assert admin_role.is_default is False |
|
c588255…
|
ragelink
|
91 |
|
|
c588255…
|
ragelink
|
92 |
def test_viewer_has_only_view_permissions(self, viewer_role): |
|
c588255…
|
ragelink
|
93 |
for perm in viewer_role.permissions.all(): |
|
c588255…
|
ragelink
|
94 |
assert perm.codename.startswith("view_"), f"Viewer role should only have view_ permissions, got {perm.codename}" |
|
c588255…
|
ragelink
|
95 |
|
|
c588255…
|
ragelink
|
96 |
def test_developer_has_add_page(self, developer_role): |
|
c588255…
|
ragelink
|
97 |
assert developer_role.permissions.filter(codename="add_page").exists() |
|
c588255…
|
ragelink
|
98 |
|
|
c588255…
|
ragelink
|
99 |
def test_developer_no_delete_project(self, developer_role): |
|
c588255…
|
ragelink
|
100 |
assert not developer_role.permissions.filter(codename="delete_project").exists() |
|
c588255…
|
ragelink
|
101 |
|
|
c588255…
|
ragelink
|
102 |
def test_manager_has_change_organization(self, manager_role): |
|
c588255…
|
ragelink
|
103 |
assert manager_role.permissions.filter(codename="change_organization").exists() |
|
c588255…
|
ragelink
|
104 |
|
|
c588255…
|
ragelink
|
105 |
|
|
c588255…
|
ragelink
|
106 |
# --- apply_to_user --- |
|
c588255…
|
ragelink
|
107 |
|
|
c588255…
|
ragelink
|
108 |
|
|
c588255…
|
ragelink
|
109 |
@pytest.mark.django_db |
|
c588255…
|
ragelink
|
110 |
class TestApplyToUser: |
|
c588255…
|
ragelink
|
111 |
def test_apply_creates_role_group(self, viewer_role, target_user): |
|
c588255…
|
ragelink
|
112 |
viewer_role.apply_to_user(target_user) |
|
c588255…
|
ragelink
|
113 |
assert target_user.groups.filter(name="role_viewer").exists() |
|
c588255…
|
ragelink
|
114 |
|
|
c588255…
|
ragelink
|
115 |
def test_apply_sets_permissions(self, viewer_role, target_user): |
|
c588255…
|
ragelink
|
116 |
viewer_role.apply_to_user(target_user) |
|
c588255…
|
ragelink
|
117 |
assert target_user.has_perm("organization.view_organization") |
|
c588255…
|
ragelink
|
118 |
|
|
c588255…
|
ragelink
|
119 |
def test_apply_replaces_old_role(self, viewer_role, admin_role, target_user): |
|
c588255…
|
ragelink
|
120 |
viewer_role.apply_to_user(target_user) |
|
c588255…
|
ragelink
|
121 |
admin_role.apply_to_user(target_user) |
|
c588255…
|
ragelink
|
122 |
# Should only be in admin role group now |
|
c588255…
|
ragelink
|
123 |
role_groups = target_user.groups.filter(name__startswith="role_") |
|
c588255…
|
ragelink
|
124 |
assert role_groups.count() == 1 |
|
c588255…
|
ragelink
|
125 |
assert role_groups.first().name == "role_admin" |
|
c588255…
|
ragelink
|
126 |
|
|
c588255…
|
ragelink
|
127 |
def test_remove_role_groups(self, viewer_role, target_user): |
|
c588255…
|
ragelink
|
128 |
viewer_role.apply_to_user(target_user) |
|
c588255…
|
ragelink
|
129 |
assert target_user.groups.filter(name__startswith="role_").count() == 1 |
|
c588255…
|
ragelink
|
130 |
OrgRole.remove_role_groups(target_user) |
|
c588255…
|
ragelink
|
131 |
assert target_user.groups.filter(name__startswith="role_").count() == 0 |
|
c588255…
|
ragelink
|
132 |
|
|
c588255…
|
ragelink
|
133 |
|
|
c588255…
|
ragelink
|
134 |
# --- role_list view --- |
|
c588255…
|
ragelink
|
135 |
|
|
c588255…
|
ragelink
|
136 |
|
|
c588255…
|
ragelink
|
137 |
@pytest.mark.django_db |
|
c588255…
|
ragelink
|
138 |
class TestRoleListView: |
|
c588255…
|
ragelink
|
139 |
def test_list_empty(self, admin_client, org): |
|
c588255…
|
ragelink
|
140 |
response = admin_client.get(reverse("organization:role_list")) |
|
c588255…
|
ragelink
|
141 |
assert response.status_code == 200 |
|
c588255…
|
ragelink
|
142 |
assert "No roles defined" in response.content.decode() |
|
c588255…
|
ragelink
|
143 |
|
|
c588255…
|
ragelink
|
144 |
def test_list_with_roles(self, admin_client, org, roles): |
|
c588255…
|
ragelink
|
145 |
response = admin_client.get(reverse("organization:role_list")) |
|
c588255…
|
ragelink
|
146 |
assert response.status_code == 200 |
|
c588255…
|
ragelink
|
147 |
content = response.content.decode() |
|
c588255…
|
ragelink
|
148 |
assert "Admin" in content |
|
c588255…
|
ragelink
|
149 |
assert "Manager" in content |
|
c588255…
|
ragelink
|
150 |
assert "Developer" in content |
|
c588255…
|
ragelink
|
151 |
assert "Viewer" in content |
|
c588255…
|
ragelink
|
152 |
|
|
c588255…
|
ragelink
|
153 |
def test_list_denied_for_no_perm(self, no_perm_client, org): |
|
c588255…
|
ragelink
|
154 |
response = no_perm_client.get(reverse("organization:role_list")) |
|
c588255…
|
ragelink
|
155 |
assert response.status_code == 403 |
|
c588255…
|
ragelink
|
156 |
|
|
c588255…
|
ragelink
|
157 |
def test_list_allowed_for_viewer(self, viewer_client, org, roles): |
|
c588255…
|
ragelink
|
158 |
response = viewer_client.get(reverse("organization:role_list")) |
|
c588255…
|
ragelink
|
159 |
assert response.status_code == 200 |
|
c588255…
|
ragelink
|
160 |
|
|
c588255…
|
ragelink
|
161 |
def test_list_denied_for_anon(self, client, org): |
|
c588255…
|
ragelink
|
162 |
response = client.get(reverse("organization:role_list")) |
|
c588255…
|
ragelink
|
163 |
assert response.status_code == 302 # redirect to login |
|
c588255…
|
ragelink
|
164 |
|
|
c588255…
|
ragelink
|
165 |
|
|
c588255…
|
ragelink
|
166 |
# --- role_detail view --- |
|
c588255…
|
ragelink
|
167 |
|
|
c588255…
|
ragelink
|
168 |
|
|
c588255…
|
ragelink
|
169 |
@pytest.mark.django_db |
|
c588255…
|
ragelink
|
170 |
class TestRoleDetailView: |
|
c588255…
|
ragelink
|
171 |
def test_detail_shows_role_info(self, admin_client, org, admin_role): |
|
c588255…
|
ragelink
|
172 |
response = admin_client.get(reverse("organization:role_detail", kwargs={"slug": "admin"})) |
|
c588255…
|
ragelink
|
173 |
assert response.status_code == 200 |
|
c588255…
|
ragelink
|
174 |
content = response.content.decode() |
|
c588255…
|
ragelink
|
175 |
assert "Admin" in content |
|
c588255…
|
ragelink
|
176 |
assert "Full access" in content |
|
c588255…
|
ragelink
|
177 |
|
|
c588255…
|
ragelink
|
178 |
def test_detail_shows_permissions(self, admin_client, org, viewer_role): |
|
c588255…
|
ragelink
|
179 |
response = admin_client.get(reverse("organization:role_detail", kwargs={"slug": "viewer"})) |
|
c588255…
|
ragelink
|
180 |
assert response.status_code == 200 |
|
c588255…
|
ragelink
|
181 |
content = response.content.decode() |
|
c588255…
|
ragelink
|
182 |
assert "view_organization" in content |
|
c588255…
|
ragelink
|
183 |
|
|
c588255…
|
ragelink
|
184 |
def test_detail_shows_members(self, admin_client, org, viewer_role, target_user): |
|
c588255…
|
ragelink
|
185 |
membership = OrganizationMember.objects.get(member=target_user, organization=org) |
|
c588255…
|
ragelink
|
186 |
membership.role = viewer_role |
|
c588255…
|
ragelink
|
187 |
membership.save() |
|
c588255…
|
ragelink
|
188 |
response = admin_client.get(reverse("organization:role_detail", kwargs={"slug": "viewer"})) |
|
c588255…
|
ragelink
|
189 |
assert response.status_code == 200 |
|
c588255…
|
ragelink
|
190 |
assert "targetuser" in response.content.decode() |
|
c588255…
|
ragelink
|
191 |
|
|
c588255…
|
ragelink
|
192 |
def test_detail_denied_for_no_perm(self, no_perm_client, org, viewer_role): |
|
c588255…
|
ragelink
|
193 |
response = no_perm_client.get(reverse("organization:role_detail", kwargs={"slug": "viewer"})) |
|
c588255…
|
ragelink
|
194 |
assert response.status_code == 403 |
|
c588255…
|
ragelink
|
195 |
|
|
c588255…
|
ragelink
|
196 |
def test_detail_404_for_missing_role(self, admin_client, org): |
|
c588255…
|
ragelink
|
197 |
response = admin_client.get(reverse("organization:role_detail", kwargs={"slug": "nonexistent"})) |
|
c588255…
|
ragelink
|
198 |
assert response.status_code == 404 |
|
c588255…
|
ragelink
|
199 |
|
|
c588255…
|
ragelink
|
200 |
|
|
c588255…
|
ragelink
|
201 |
# --- role_initialize view --- |
|
c588255…
|
ragelink
|
202 |
|
|
c588255…
|
ragelink
|
203 |
|
|
c588255…
|
ragelink
|
204 |
@pytest.mark.django_db |
|
c588255…
|
ragelink
|
205 |
class TestRoleInitializeView: |
|
c588255…
|
ragelink
|
206 |
def test_initialize_creates_roles(self, admin_client, org): |
|
c588255…
|
ragelink
|
207 |
assert OrgRole.objects.count() == 0 |
|
c588255…
|
ragelink
|
208 |
response = admin_client.post(reverse("organization:role_initialize")) |
|
c588255…
|
ragelink
|
209 |
assert response.status_code == 302 |
|
c588255…
|
ragelink
|
210 |
assert OrgRole.objects.count() == 4 |
|
c588255…
|
ragelink
|
211 |
|
|
c588255…
|
ragelink
|
212 |
def test_initialize_denied_for_viewer(self, viewer_client, org): |
|
c588255…
|
ragelink
|
213 |
response = viewer_client.post(reverse("organization:role_initialize")) |
|
c588255…
|
ragelink
|
214 |
assert response.status_code == 403 |
|
c588255…
|
ragelink
|
215 |
|
|
c588255…
|
ragelink
|
216 |
def test_initialize_denied_for_no_perm(self, no_perm_client, org): |
|
c588255…
|
ragelink
|
217 |
response = no_perm_client.post(reverse("organization:role_initialize")) |
|
c588255…
|
ragelink
|
218 |
assert response.status_code == 403 |
|
c588255…
|
ragelink
|
219 |
|
|
c588255…
|
ragelink
|
220 |
def test_initialize_denied_for_anon(self, client, org): |
|
c588255…
|
ragelink
|
221 |
response = client.post(reverse("organization:role_initialize")) |
|
c588255…
|
ragelink
|
222 |
assert response.status_code == 302 # redirect to login |
|
c588255…
|
ragelink
|
223 |
|
|
c588255…
|
ragelink
|
224 |
def test_initialize_allowed_for_org_admin(self, org_admin_client, org): |
|
c588255…
|
ragelink
|
225 |
response = org_admin_client.post(reverse("organization:role_initialize")) |
|
c588255…
|
ragelink
|
226 |
assert response.status_code == 302 |
|
c588255…
|
ragelink
|
227 |
assert OrgRole.objects.count() == 4 |
|
c588255…
|
ragelink
|
228 |
|
|
c588255…
|
ragelink
|
229 |
|
|
c588255…
|
ragelink
|
230 |
# --- user_create with role --- |
|
c588255…
|
ragelink
|
231 |
|
|
c588255…
|
ragelink
|
232 |
|
|
c588255…
|
ragelink
|
233 |
@pytest.mark.django_db |
|
c588255…
|
ragelink
|
234 |
class TestUserCreateWithRole: |
|
c588255…
|
ragelink
|
235 |
def test_create_user_with_role(self, admin_client, org, viewer_role): |
|
c588255…
|
ragelink
|
236 |
response = admin_client.post( |
|
c588255…
|
ragelink
|
237 |
reverse("organization:user_create"), |
|
c588255…
|
ragelink
|
238 |
{ |
|
c588255…
|
ragelink
|
239 |
"username": "roleuser", |
|
c588255…
|
ragelink
|
240 |
"email": "[email protected]", |
|
c588255…
|
ragelink
|
241 |
"first_name": "Role", |
|
c588255…
|
ragelink
|
242 |
"last_name": "User", |
|
c588255…
|
ragelink
|
243 |
"password1": "Str0ng!Pass99", |
|
c588255…
|
ragelink
|
244 |
"password2": "Str0ng!Pass99", |
|
c588255…
|
ragelink
|
245 |
"role": viewer_role.pk, |
|
c588255…
|
ragelink
|
246 |
}, |
|
c588255…
|
ragelink
|
247 |
) |
|
c588255…
|
ragelink
|
248 |
assert response.status_code == 302 |
|
c588255…
|
ragelink
|
249 |
user = User.objects.get(username="roleuser") |
|
c588255…
|
ragelink
|
250 |
membership = OrganizationMember.objects.get(member=user, organization=org) |
|
c588255…
|
ragelink
|
251 |
assert membership.role == viewer_role |
|
c588255…
|
ragelink
|
252 |
# Verify role group was applied |
|
c588255…
|
ragelink
|
253 |
assert user.groups.filter(name="role_viewer").exists() |
|
c588255…
|
ragelink
|
254 |
|
|
c588255…
|
ragelink
|
255 |
def test_create_user_without_role(self, admin_client, org, roles): |
|
c588255…
|
ragelink
|
256 |
response = admin_client.post( |
|
c588255…
|
ragelink
|
257 |
reverse("organization:user_create"), |
|
c588255…
|
ragelink
|
258 |
{ |
|
c588255…
|
ragelink
|
259 |
"username": "noroleuser", |
|
c588255…
|
ragelink
|
260 |
"email": "[email protected]", |
|
c588255…
|
ragelink
|
261 |
"password1": "Str0ng!Pass99", |
|
c588255…
|
ragelink
|
262 |
"password2": "Str0ng!Pass99", |
|
c588255…
|
ragelink
|
263 |
}, |
|
c588255…
|
ragelink
|
264 |
) |
|
c588255…
|
ragelink
|
265 |
assert response.status_code == 302 |
|
c588255…
|
ragelink
|
266 |
user = User.objects.get(username="noroleuser") |
|
c588255…
|
ragelink
|
267 |
membership = OrganizationMember.objects.get(member=user, organization=org) |
|
c588255…
|
ragelink
|
268 |
assert membership.role is None |
|
c588255…
|
ragelink
|
269 |
|
|
c588255…
|
ragelink
|
270 |
def test_create_form_has_role_field(self, admin_client, org, roles): |
|
c588255…
|
ragelink
|
271 |
response = admin_client.get(reverse("organization:user_create")) |
|
c588255…
|
ragelink
|
272 |
assert response.status_code == 200 |
|
c588255…
|
ragelink
|
273 |
content = response.content.decode() |
|
c588255…
|
ragelink
|
274 |
assert "role" in content.lower() |
|
c588255…
|
ragelink
|
275 |
|
|
c588255…
|
ragelink
|
276 |
|
|
c588255…
|
ragelink
|
277 |
# --- user_edit with role --- |
|
c588255…
|
ragelink
|
278 |
|
|
c588255…
|
ragelink
|
279 |
|
|
c588255…
|
ragelink
|
280 |
@pytest.mark.django_db |
|
c588255…
|
ragelink
|
281 |
class TestUserEditWithRole: |
|
c588255…
|
ragelink
|
282 |
def test_edit_assigns_role(self, admin_client, org, target_user, viewer_role): |
|
c588255…
|
ragelink
|
283 |
response = admin_client.post( |
|
c588255…
|
ragelink
|
284 |
reverse("organization:user_edit", kwargs={"username": "targetuser"}), |
|
c588255…
|
ragelink
|
285 |
{ |
|
c588255…
|
ragelink
|
286 |
"email": "[email protected]", |
|
c588255…
|
ragelink
|
287 |
"first_name": "Target", |
|
c588255…
|
ragelink
|
288 |
"last_name": "User", |
|
c588255…
|
ragelink
|
289 |
"is_active": "on", |
|
c588255…
|
ragelink
|
290 |
"role": viewer_role.pk, |
|
c588255…
|
ragelink
|
291 |
}, |
|
c588255…
|
ragelink
|
292 |
) |
|
c588255…
|
ragelink
|
293 |
assert response.status_code == 302 |
|
c588255…
|
ragelink
|
294 |
membership = OrganizationMember.objects.get(member=target_user, organization=org) |
|
c588255…
|
ragelink
|
295 |
assert membership.role == viewer_role |
|
c588255…
|
ragelink
|
296 |
assert target_user.groups.filter(name="role_viewer").exists() |
|
c588255…
|
ragelink
|
297 |
|
|
c588255…
|
ragelink
|
298 |
def test_edit_changes_role(self, admin_client, org, target_user, viewer_role, admin_role): |
|
c588255…
|
ragelink
|
299 |
# First assign viewer role |
|
c588255…
|
ragelink
|
300 |
membership = OrganizationMember.objects.get(member=target_user, organization=org) |
|
c588255…
|
ragelink
|
301 |
membership.role = viewer_role |
|
c588255…
|
ragelink
|
302 |
membership.save() |
|
c588255…
|
ragelink
|
303 |
viewer_role.apply_to_user(target_user) |
|
c588255…
|
ragelink
|
304 |
|
|
c588255…
|
ragelink
|
305 |
# Now change to admin role via edit |
|
c588255…
|
ragelink
|
306 |
response = admin_client.post( |
|
c588255…
|
ragelink
|
307 |
reverse("organization:user_edit", kwargs={"username": "targetuser"}), |
|
c588255…
|
ragelink
|
308 |
{ |
|
c588255…
|
ragelink
|
309 |
"email": "[email protected]", |
|
c588255…
|
ragelink
|
310 |
"first_name": "Target", |
|
c588255…
|
ragelink
|
311 |
"last_name": "User", |
|
c588255…
|
ragelink
|
312 |
"is_active": "on", |
|
c588255…
|
ragelink
|
313 |
"role": admin_role.pk, |
|
c588255…
|
ragelink
|
314 |
}, |
|
c588255…
|
ragelink
|
315 |
) |
|
c588255…
|
ragelink
|
316 |
assert response.status_code == 302 |
|
c588255…
|
ragelink
|
317 |
membership.refresh_from_db() |
|
c588255…
|
ragelink
|
318 |
assert membership.role == admin_role |
|
c588255…
|
ragelink
|
319 |
# Old role group should be gone, new one should be present |
|
c588255…
|
ragelink
|
320 |
assert not target_user.groups.filter(name="role_viewer").exists() |
|
c588255…
|
ragelink
|
321 |
assert target_user.groups.filter(name="role_admin").exists() |
|
c588255…
|
ragelink
|
322 |
|
|
c588255…
|
ragelink
|
323 |
def test_edit_removes_role(self, admin_client, org, target_user, viewer_role): |
|
c588255…
|
ragelink
|
324 |
membership = OrganizationMember.objects.get(member=target_user, organization=org) |
|
c588255…
|
ragelink
|
325 |
membership.role = viewer_role |
|
c588255…
|
ragelink
|
326 |
membership.save() |
|
c588255…
|
ragelink
|
327 |
viewer_role.apply_to_user(target_user) |
|
c588255…
|
ragelink
|
328 |
|
|
c588255…
|
ragelink
|
329 |
# Submit without role |
|
c588255…
|
ragelink
|
330 |
response = admin_client.post( |
|
c588255…
|
ragelink
|
331 |
reverse("organization:user_edit", kwargs={"username": "targetuser"}), |
|
c588255…
|
ragelink
|
332 |
{ |
|
c588255…
|
ragelink
|
333 |
"email": "[email protected]", |
|
c588255…
|
ragelink
|
334 |
"first_name": "Target", |
|
c588255…
|
ragelink
|
335 |
"last_name": "User", |
|
c588255…
|
ragelink
|
336 |
"is_active": "on", |
|
c588255…
|
ragelink
|
337 |
# role intentionally omitted |
|
c588255…
|
ragelink
|
338 |
}, |
|
c588255…
|
ragelink
|
339 |
) |
|
c588255…
|
ragelink
|
340 |
assert response.status_code == 302 |
|
c588255…
|
ragelink
|
341 |
membership.refresh_from_db() |
|
c588255…
|
ragelink
|
342 |
assert membership.role is None |
|
c588255…
|
ragelink
|
343 |
assert not target_user.groups.filter(name__startswith="role_").exists() |
|
c588255…
|
ragelink
|
344 |
|
|
c588255…
|
ragelink
|
345 |
def test_edit_form_pre_selects_role(self, admin_client, org, target_user, viewer_role): |
|
c588255…
|
ragelink
|
346 |
membership = OrganizationMember.objects.get(member=target_user, organization=org) |
|
c588255…
|
ragelink
|
347 |
membership.role = viewer_role |
|
c588255…
|
ragelink
|
348 |
membership.save() |
|
c588255…
|
ragelink
|
349 |
|
|
c588255…
|
ragelink
|
350 |
response = admin_client.get(reverse("organization:user_edit", kwargs={"username": "targetuser"})) |
|
c588255…
|
ragelink
|
351 |
assert response.status_code == 200 |
|
c588255…
|
ragelink
|
352 |
content = response.content.decode() |
|
c588255…
|
ragelink
|
353 |
# The viewer option should be selected |
|
c588255…
|
ragelink
|
354 |
assert "selected" in content |
|
c588255…
|
ragelink
|
355 |
|
|
c588255…
|
ragelink
|
356 |
|
|
c588255…
|
ragelink
|
357 |
# --- member_list role column --- |
|
c588255…
|
ragelink
|
358 |
|
|
c588255…
|
ragelink
|
359 |
|
|
c588255…
|
ragelink
|
360 |
@pytest.mark.django_db |
|
c588255…
|
ragelink
|
361 |
class TestMemberListRoleColumn: |
|
c588255…
|
ragelink
|
362 |
def test_role_shown_in_member_list(self, admin_client, org, admin_user, viewer_role): |
|
c588255…
|
ragelink
|
363 |
membership = OrganizationMember.objects.get(member=admin_user, organization=org) |
|
c588255…
|
ragelink
|
364 |
membership.role = viewer_role |
|
c588255…
|
ragelink
|
365 |
membership.save() |
|
c588255…
|
ragelink
|
366 |
|
|
c588255…
|
ragelink
|
367 |
response = admin_client.get(reverse("organization:members")) |
|
c588255…
|
ragelink
|
368 |
assert response.status_code == 200 |
|
c588255…
|
ragelink
|
369 |
content = response.content.decode() |
|
c588255…
|
ragelink
|
370 |
assert "Role" in content # Column header |
|
c588255…
|
ragelink
|
371 |
assert "Viewer" in content # Role name |
|
c588255…
|
ragelink
|
372 |
|
|
c588255…
|
ragelink
|
373 |
def test_no_role_shown_as_dash(self, admin_client, org, admin_user): |
|
c588255…
|
ragelink
|
374 |
response = admin_client.get(reverse("organization:members")) |
|
c588255…
|
ragelink
|
375 |
assert response.status_code == 200 |
|
c588255…
|
ragelink
|
376 |
content = response.content.decode() |
|
c588255…
|
ragelink
|
377 |
assert "Role" in content # Column header |
|
c588255…
|
ragelink
|
378 |
|
|
c588255…
|
ragelink
|
379 |
|
|
c588255…
|
ragelink
|
380 |
# --- user_detail role display --- |
|
c588255…
|
ragelink
|
381 |
|
|
c588255…
|
ragelink
|
382 |
|
|
c588255…
|
ragelink
|
383 |
@pytest.mark.django_db |
|
c588255…
|
ragelink
|
384 |
class TestUserDetailRole: |
|
c588255…
|
ragelink
|
385 |
def test_detail_shows_role(self, admin_client, org, target_user, viewer_role): |
|
c588255…
|
ragelink
|
386 |
membership = OrganizationMember.objects.get(member=target_user, organization=org) |
|
c588255…
|
ragelink
|
387 |
membership.role = viewer_role |
|
c588255…
|
ragelink
|
388 |
membership.save() |
|
c588255…
|
ragelink
|
389 |
|
|
c588255…
|
ragelink
|
390 |
response = admin_client.get(reverse("organization:user_detail", kwargs={"username": "targetuser"})) |
|
c588255…
|
ragelink
|
391 |
assert response.status_code == 200 |
|
c588255…
|
ragelink
|
392 |
content = response.content.decode() |
|
c588255…
|
ragelink
|
393 |
assert "Viewer" in content |
|
c588255…
|
ragelink
|
394 |
assert "Read-only access" in content |
|
c588255…
|
ragelink
|
395 |
|
|
c588255…
|
ragelink
|
396 |
def test_detail_shows_no_role_assigned(self, admin_client, org, target_user): |
|
c588255…
|
ragelink
|
397 |
response = admin_client.get(reverse("organization:user_detail", kwargs={"username": "targetuser"})) |
|
c588255…
|
ragelink
|
398 |
assert response.status_code == 200 |
|
c588255…
|
ragelink
|
399 |
content = response.content.decode() |
|
c588255…
|
ragelink
|
400 |
assert "No role assigned" in content |
|
c588255…
|
ragelink
|
401 |
|
|
c588255…
|
ragelink
|
402 |
|
|
c588255…
|
ragelink
|
403 |
# --- role_create view --- |
|
c588255…
|
ragelink
|
404 |
|
|
c588255…
|
ragelink
|
405 |
|
|
c588255…
|
ragelink
|
406 |
@pytest.mark.django_db |
|
c588255…
|
ragelink
|
407 |
class TestRoleCreateView: |
|
c588255…
|
ragelink
|
408 |
def test_create_get_shows_form(self, admin_client, org): |
|
c588255…
|
ragelink
|
409 |
response = admin_client.get(reverse("organization:role_create")) |
|
c588255…
|
ragelink
|
410 |
assert response.status_code == 200 |
|
c588255…
|
ragelink
|
411 |
content = response.content.decode() |
|
c588255…
|
ragelink
|
412 |
assert "New Role" in content |
|
c588255…
|
ragelink
|
413 |
assert "Permissions" in content |
|
c588255…
|
ragelink
|
414 |
|
|
c588255…
|
ragelink
|
415 |
def test_create_saves_role(self, admin_client, org): |
|
c588255…
|
ragelink
|
416 |
perm = Permission.objects.filter(content_type__app_label="organization", codename="view_organization").first() |
|
c588255…
|
ragelink
|
417 |
response = admin_client.post( |
|
c588255…
|
ragelink
|
418 |
reverse("organization:role_create"), |
|
c588255…
|
ragelink
|
419 |
{"name": "Custom Role", "description": "A custom role", "permissions": [perm.pk]}, |
|
c588255…
|
ragelink
|
420 |
) |
|
c588255…
|
ragelink
|
421 |
assert response.status_code == 302 |
|
c588255…
|
ragelink
|
422 |
role = OrgRole.objects.get(slug="custom-role") |
|
c588255…
|
ragelink
|
423 |
assert role.name == "Custom Role" |
|
c588255…
|
ragelink
|
424 |
assert role.description == "A custom role" |
|
c588255…
|
ragelink
|
425 |
assert perm in role.permissions.all() |
|
c588255…
|
ragelink
|
426 |
|
|
c588255…
|
ragelink
|
427 |
def test_create_without_permissions(self, admin_client, org): |
|
c588255…
|
ragelink
|
428 |
response = admin_client.post( |
|
c588255…
|
ragelink
|
429 |
reverse("organization:role_create"), |
|
c588255…
|
ragelink
|
430 |
{"name": "Empty Role", "description": "No permissions"}, |
|
c588255…
|
ragelink
|
431 |
) |
|
c588255…
|
ragelink
|
432 |
assert response.status_code == 302 |
|
c588255…
|
ragelink
|
433 |
role = OrgRole.objects.get(slug="empty-role") |
|
c588255…
|
ragelink
|
434 |
assert role.permissions.count() == 0 |
|
c588255…
|
ragelink
|
435 |
|
|
c588255…
|
ragelink
|
436 |
def test_create_with_is_default(self, admin_client, org): |
|
c588255…
|
ragelink
|
437 |
response = admin_client.post( |
|
c588255…
|
ragelink
|
438 |
reverse("organization:role_create"), |
|
c588255…
|
ragelink
|
439 |
{"name": "Default Custom", "description": "Default", "is_default": "on"}, |
|
c588255…
|
ragelink
|
440 |
) |
|
c588255…
|
ragelink
|
441 |
assert response.status_code == 302 |
|
c588255…
|
ragelink
|
442 |
role = OrgRole.objects.get(slug="default-custom") |
|
c588255…
|
ragelink
|
443 |
assert role.is_default is True |
|
c588255…
|
ragelink
|
444 |
|
|
c588255…
|
ragelink
|
445 |
def test_create_denied_for_viewer(self, viewer_client, org): |
|
c588255…
|
ragelink
|
446 |
response = viewer_client.get(reverse("organization:role_create")) |
|
c588255…
|
ragelink
|
447 |
assert response.status_code == 403 |
|
c588255…
|
ragelink
|
448 |
|
|
c588255…
|
ragelink
|
449 |
def test_create_denied_for_no_perm(self, no_perm_client, org): |
|
c588255…
|
ragelink
|
450 |
response = no_perm_client.get(reverse("organization:role_create")) |
|
c588255…
|
ragelink
|
451 |
assert response.status_code == 403 |
|
c588255…
|
ragelink
|
452 |
|
|
c588255…
|
ragelink
|
453 |
def test_create_denied_for_anon(self, client, org): |
|
c588255…
|
ragelink
|
454 |
response = client.get(reverse("organization:role_create")) |
|
c588255…
|
ragelink
|
455 |
assert response.status_code == 302 # redirect to login |
|
c588255…
|
ragelink
|
456 |
|
|
c588255…
|
ragelink
|
457 |
def test_create_allowed_for_org_admin(self, org_admin_client, org): |
|
c588255…
|
ragelink
|
458 |
response = org_admin_client.post( |
|
c588255…
|
ragelink
|
459 |
reverse("organization:role_create"), |
|
c588255…
|
ragelink
|
460 |
{"name": "OrgAdmin Role", "description": "Created by org admin"}, |
|
c588255…
|
ragelink
|
461 |
) |
|
c588255…
|
ragelink
|
462 |
assert response.status_code == 302 |
|
c588255…
|
ragelink
|
463 |
assert OrgRole.objects.filter(slug="orgadmin-role").exists() |
|
c588255…
|
ragelink
|
464 |
|
|
c588255…
|
ragelink
|
465 |
def test_create_sets_created_by(self, admin_client, org, admin_user): |
|
c588255…
|
ragelink
|
466 |
response = admin_client.post( |
|
c588255…
|
ragelink
|
467 |
reverse("organization:role_create"), |
|
c588255…
|
ragelink
|
468 |
{"name": "Tracked Role", "description": "test"}, |
|
c588255…
|
ragelink
|
469 |
) |
|
c588255…
|
ragelink
|
470 |
assert response.status_code == 302 |
|
c588255…
|
ragelink
|
471 |
role = OrgRole.objects.get(slug="tracked-role") |
|
c588255…
|
ragelink
|
472 |
assert role.created_by == admin_user |
|
c588255…
|
ragelink
|
473 |
|
|
c588255…
|
ragelink
|
474 |
def test_create_invalid_missing_name(self, admin_client, org): |
|
c588255…
|
ragelink
|
475 |
response = admin_client.post( |
|
c588255…
|
ragelink
|
476 |
reverse("organization:role_create"), |
|
c588255…
|
ragelink
|
477 |
{"description": "Missing name"}, |
|
c588255…
|
ragelink
|
478 |
) |
|
c588255…
|
ragelink
|
479 |
assert response.status_code == 200 # re-renders form |
|
c588255…
|
ragelink
|
480 |
assert OrgRole.objects.count() == 0 |
|
c588255…
|
ragelink
|
481 |
|
|
c588255…
|
ragelink
|
482 |
|
|
c588255…
|
ragelink
|
483 |
# --- role_edit view --- |
|
c588255…
|
ragelink
|
484 |
|
|
c588255…
|
ragelink
|
485 |
|
|
c588255…
|
ragelink
|
486 |
@pytest.mark.django_db |
|
c588255…
|
ragelink
|
487 |
class TestRoleEditView: |
|
c588255…
|
ragelink
|
488 |
def test_edit_get_shows_form(self, admin_client, org, viewer_role): |
|
c588255…
|
ragelink
|
489 |
response = admin_client.get(reverse("organization:role_edit", kwargs={"slug": "viewer"})) |
|
c588255…
|
ragelink
|
490 |
assert response.status_code == 200 |
|
c588255…
|
ragelink
|
491 |
content = response.content.decode() |
|
c588255…
|
ragelink
|
492 |
assert "Edit Viewer" in content |
|
c588255…
|
ragelink
|
493 |
assert "Permissions" in content |
|
c588255…
|
ragelink
|
494 |
|
|
c588255…
|
ragelink
|
495 |
def test_edit_updates_role(self, admin_client, org, viewer_role): |
|
c588255…
|
ragelink
|
496 |
response = admin_client.post( |
|
c588255…
|
ragelink
|
497 |
reverse("organization:role_edit", kwargs={"slug": "viewer"}), |
|
c588255…
|
ragelink
|
498 |
{"name": "Viewer Updated", "description": "Updated description"}, |
|
c588255…
|
ragelink
|
499 |
) |
|
c588255…
|
ragelink
|
500 |
assert response.status_code == 302 |
|
c588255…
|
ragelink
|
501 |
viewer_role.refresh_from_db() |
|
c588255…
|
ragelink
|
502 |
assert viewer_role.name == "Viewer Updated" |
|
c588255…
|
ragelink
|
503 |
assert viewer_role.description == "Updated description" |
|
c588255…
|
ragelink
|
504 |
|
|
c588255…
|
ragelink
|
505 |
def test_edit_updates_permissions(self, admin_client, org, viewer_role): |
|
c588255…
|
ragelink
|
506 |
add_perm = Permission.objects.get(content_type__app_label="organization", codename="add_organization") |
|
c588255…
|
ragelink
|
507 |
response = admin_client.post( |
|
c588255…
|
ragelink
|
508 |
reverse("organization:role_edit", kwargs={"slug": "viewer"}), |
|
c588255…
|
ragelink
|
509 |
{"name": "Viewer", "description": "Updated", "permissions": [add_perm.pk]}, |
|
c588255…
|
ragelink
|
510 |
) |
|
c588255…
|
ragelink
|
511 |
assert response.status_code == 302 |
|
c588255…
|
ragelink
|
512 |
viewer_role.refresh_from_db() |
|
c588255…
|
ragelink
|
513 |
assert list(viewer_role.permissions.values_list("pk", flat=True)) == [add_perm.pk] |
|
c588255…
|
ragelink
|
514 |
|
|
c588255…
|
ragelink
|
515 |
def test_edit_clears_permissions(self, admin_client, org, viewer_role): |
|
c588255…
|
ragelink
|
516 |
assert viewer_role.permissions.count() > 0 |
|
c588255…
|
ragelink
|
517 |
response = admin_client.post( |
|
c588255…
|
ragelink
|
518 |
reverse("organization:role_edit", kwargs={"slug": "viewer"}), |
|
c588255…
|
ragelink
|
519 |
{"name": "Viewer", "description": "No perms now"}, |
|
c588255…
|
ragelink
|
520 |
) |
|
c588255…
|
ragelink
|
521 |
assert response.status_code == 302 |
|
c588255…
|
ragelink
|
522 |
viewer_role.refresh_from_db() |
|
c588255…
|
ragelink
|
523 |
assert viewer_role.permissions.count() == 0 |
|
c588255…
|
ragelink
|
524 |
|
|
c588255…
|
ragelink
|
525 |
def test_edit_pre_populates_permissions(self, admin_client, org, viewer_role): |
|
c588255…
|
ragelink
|
526 |
response = admin_client.get(reverse("organization:role_edit", kwargs={"slug": "viewer"})) |
|
c588255…
|
ragelink
|
527 |
assert response.status_code == 200 |
|
c588255…
|
ragelink
|
528 |
content = response.content.decode() |
|
c588255…
|
ragelink
|
529 |
assert "checked" in content |
|
c588255…
|
ragelink
|
530 |
|
|
c588255…
|
ragelink
|
531 |
def test_edit_sets_updated_by(self, admin_client, org, viewer_role, admin_user): |
|
c588255…
|
ragelink
|
532 |
response = admin_client.post( |
|
c588255…
|
ragelink
|
533 |
reverse("organization:role_edit", kwargs={"slug": "viewer"}), |
|
c588255…
|
ragelink
|
534 |
{"name": "Viewer", "description": "Audit check"}, |
|
c588255…
|
ragelink
|
535 |
) |
|
c588255…
|
ragelink
|
536 |
assert response.status_code == 302 |
|
c588255…
|
ragelink
|
537 |
viewer_role.refresh_from_db() |
|
c588255…
|
ragelink
|
538 |
assert viewer_role.updated_by == admin_user |
|
c588255…
|
ragelink
|
539 |
|
|
c588255…
|
ragelink
|
540 |
def test_edit_denied_for_viewer(self, viewer_client, org, viewer_role): |
|
c588255…
|
ragelink
|
541 |
response = viewer_client.get(reverse("organization:role_edit", kwargs={"slug": "viewer"})) |
|
c588255…
|
ragelink
|
542 |
assert response.status_code == 403 |
|
c588255…
|
ragelink
|
543 |
|
|
c588255…
|
ragelink
|
544 |
def test_edit_denied_for_no_perm(self, no_perm_client, org, viewer_role): |
|
c588255…
|
ragelink
|
545 |
response = no_perm_client.get(reverse("organization:role_edit", kwargs={"slug": "viewer"})) |
|
c588255…
|
ragelink
|
546 |
assert response.status_code == 403 |
|
c588255…
|
ragelink
|
547 |
|
|
c588255…
|
ragelink
|
548 |
def test_edit_denied_for_anon(self, client, org, viewer_role): |
|
c588255…
|
ragelink
|
549 |
response = client.get(reverse("organization:role_edit", kwargs={"slug": "viewer"})) |
|
c588255…
|
ragelink
|
550 |
assert response.status_code == 302 # redirect to login |
|
c588255…
|
ragelink
|
551 |
|
|
c588255…
|
ragelink
|
552 |
def test_edit_404_for_deleted_role(self, admin_client, org, viewer_role, admin_user): |
|
c588255…
|
ragelink
|
553 |
viewer_role.soft_delete(user=admin_user) |
|
c588255…
|
ragelink
|
554 |
response = admin_client.get(reverse("organization:role_edit", kwargs={"slug": "viewer"})) |
|
c588255…
|
ragelink
|
555 |
assert response.status_code == 404 |
|
c588255…
|
ragelink
|
556 |
|
|
c588255…
|
ragelink
|
557 |
def test_edit_404_for_missing_role(self, admin_client, org): |
|
c588255…
|
ragelink
|
558 |
response = admin_client.get(reverse("organization:role_edit", kwargs={"slug": "nonexistent"})) |
|
c588255…
|
ragelink
|
559 |
assert response.status_code == 404 |
|
c588255…
|
ragelink
|
560 |
|
|
c588255…
|
ragelink
|
561 |
|
|
c588255…
|
ragelink
|
562 |
# --- role_delete view --- |
|
c588255…
|
ragelink
|
563 |
|
|
c588255…
|
ragelink
|
564 |
|
|
c588255…
|
ragelink
|
565 |
@pytest.mark.django_db |
|
c588255…
|
ragelink
|
566 |
class TestRoleDeleteView: |
|
c588255…
|
ragelink
|
567 |
def test_delete_get_shows_confirmation(self, admin_client, org, viewer_role): |
|
c588255…
|
ragelink
|
568 |
response = admin_client.get(reverse("organization:role_delete", kwargs={"slug": "viewer"})) |
|
c588255…
|
ragelink
|
569 |
assert response.status_code == 200 |
|
c588255…
|
ragelink
|
570 |
content = response.content.decode() |
|
c588255…
|
ragelink
|
571 |
assert "Delete Role" in content |
|
c588255…
|
ragelink
|
572 |
assert "Viewer" in content |
|
c588255…
|
ragelink
|
573 |
|
|
c588255…
|
ragelink
|
574 |
def test_delete_soft_deletes_role(self, admin_client, org, viewer_role): |
|
c588255…
|
ragelink
|
575 |
response = admin_client.post(reverse("organization:role_delete", kwargs={"slug": "viewer"})) |
|
c588255…
|
ragelink
|
576 |
assert response.status_code == 302 |
|
c588255…
|
ragelink
|
577 |
viewer_role.refresh_from_db() |
|
c588255…
|
ragelink
|
578 |
assert viewer_role.deleted_at is not None |
|
c588255…
|
ragelink
|
579 |
|
|
c588255…
|
ragelink
|
580 |
def test_delete_blocked_when_members_assigned(self, admin_client, org, viewer_role, target_user): |
|
c588255…
|
ragelink
|
581 |
membership = OrganizationMember.objects.get(member=target_user, organization=org) |
|
c588255…
|
ragelink
|
582 |
membership.role = viewer_role |
|
c588255…
|
ragelink
|
583 |
membership.save() |
|
c588255…
|
ragelink
|
584 |
|
|
c588255…
|
ragelink
|
585 |
response = admin_client.post(reverse("organization:role_delete", kwargs={"slug": "viewer"})) |
|
c588255…
|
ragelink
|
586 |
assert response.status_code == 302 # redirects back to detail |
|
c588255…
|
ragelink
|
587 |
viewer_role.refresh_from_db() |
|
c588255…
|
ragelink
|
588 |
assert viewer_role.deleted_at is None # not deleted |
|
c588255…
|
ragelink
|
589 |
|
|
c588255…
|
ragelink
|
590 |
def test_delete_shows_warning_for_members(self, admin_client, org, viewer_role, target_user): |
|
c588255…
|
ragelink
|
591 |
membership = OrganizationMember.objects.get(member=target_user, organization=org) |
|
c588255…
|
ragelink
|
592 |
membership.role = viewer_role |
|
c588255…
|
ragelink
|
593 |
membership.save() |
|
c588255…
|
ragelink
|
594 |
|
|
c588255…
|
ragelink
|
595 |
response = admin_client.get(reverse("organization:role_delete", kwargs={"slug": "viewer"})) |
|
c588255…
|
ragelink
|
596 |
assert response.status_code == 200 |
|
c588255…
|
ragelink
|
597 |
content = response.content.decode() |
|
c588255…
|
ragelink
|
598 |
assert "active member" in content |
|
c588255…
|
ragelink
|
599 |
assert "targetuser" in content |
|
c588255…
|
ragelink
|
600 |
|
|
c588255…
|
ragelink
|
601 |
def test_delete_denied_for_viewer(self, viewer_client, org, viewer_role): |
|
c588255…
|
ragelink
|
602 |
response = viewer_client.get(reverse("organization:role_delete", kwargs={"slug": "viewer"})) |
|
c588255…
|
ragelink
|
603 |
assert response.status_code == 403 |
|
c588255…
|
ragelink
|
604 |
|
|
c588255…
|
ragelink
|
605 |
def test_delete_denied_for_no_perm(self, no_perm_client, org, viewer_role): |
|
c588255…
|
ragelink
|
606 |
response = no_perm_client.get(reverse("organization:role_delete", kwargs={"slug": "viewer"})) |
|
c588255…
|
ragelink
|
607 |
assert response.status_code == 403 |
|
c588255…
|
ragelink
|
608 |
|
|
c588255…
|
ragelink
|
609 |
def test_delete_denied_for_anon(self, client, org, viewer_role): |
|
c588255…
|
ragelink
|
610 |
response = client.get(reverse("organization:role_delete", kwargs={"slug": "viewer"})) |
|
c588255…
|
ragelink
|
611 |
assert response.status_code == 302 # redirect to login |
|
c588255…
|
ragelink
|
612 |
|
|
c588255…
|
ragelink
|
613 |
def test_delete_404_for_deleted_role(self, admin_client, org, viewer_role, admin_user): |
|
c588255…
|
ragelink
|
614 |
viewer_role.soft_delete(user=admin_user) |
|
c588255…
|
ragelink
|
615 |
response = admin_client.get(reverse("organization:role_delete", kwargs={"slug": "viewer"})) |
|
c588255…
|
ragelink
|
616 |
assert response.status_code == 404 |
|
c588255…
|
ragelink
|
617 |
|
|
c588255…
|
ragelink
|
618 |
def test_delete_htmx_returns_redirect_header(self, admin_client, org, developer_role): |
|
c588255…
|
ragelink
|
619 |
response = admin_client.post( |
|
c588255…
|
ragelink
|
620 |
reverse("organization:role_delete", kwargs={"slug": "developer"}), |
|
c588255…
|
ragelink
|
621 |
HTTP_HX_REQUEST="true", |
|
c588255…
|
ragelink
|
622 |
) |
|
c588255…
|
ragelink
|
623 |
assert response.status_code == 200 |
|
c588255…
|
ragelink
|
624 |
assert response.headers.get("HX-Redirect") == "/settings/roles/" |
|
c588255…
|
ragelink
|
625 |
|
|
c588255…
|
ragelink
|
626 |
|
|
c588255…
|
ragelink
|
627 |
# --- role_list Create Role button --- |
|
c588255…
|
ragelink
|
628 |
|
|
c588255…
|
ragelink
|
629 |
|
|
c588255…
|
ragelink
|
630 |
@pytest.mark.django_db |
|
c588255…
|
ragelink
|
631 |
class TestRoleListCreateButton: |
|
c588255…
|
ragelink
|
632 |
def test_create_button_shown_for_admin(self, admin_client, org, roles): |
|
c588255…
|
ragelink
|
633 |
response = admin_client.get(reverse("organization:role_list")) |
|
c588255…
|
ragelink
|
634 |
assert response.status_code == 200 |
|
c588255…
|
ragelink
|
635 |
assert "Create Role" in response.content.decode() |
|
c588255…
|
ragelink
|
636 |
|
|
c588255…
|
ragelink
|
637 |
def test_create_button_hidden_for_viewer(self, viewer_client, org, roles): |
|
c588255…
|
ragelink
|
638 |
response = viewer_client.get(reverse("organization:role_list")) |
|
c588255…
|
ragelink
|
639 |
assert response.status_code == 200 |
|
c588255…
|
ragelink
|
640 |
assert "Create Role" not in response.content.decode() |
|
c588255…
|
ragelink
|
641 |
|
|
c588255…
|
ragelink
|
642 |
|
|
c588255…
|
ragelink
|
643 |
# --- role_detail Edit/Delete buttons --- |
|
c588255…
|
ragelink
|
644 |
|
|
c588255…
|
ragelink
|
645 |
|
|
c588255…
|
ragelink
|
646 |
@pytest.mark.django_db |
|
c588255…
|
ragelink
|
647 |
class TestRoleDetailButtons: |
|
c588255…
|
ragelink
|
648 |
def test_edit_button_shown_for_admin(self, admin_client, org, viewer_role): |
|
c588255…
|
ragelink
|
649 |
response = admin_client.get(reverse("organization:role_detail", kwargs={"slug": "viewer"})) |
|
c588255…
|
ragelink
|
650 |
assert response.status_code == 200 |
|
c588255…
|
ragelink
|
651 |
content = response.content.decode() |
|
c588255…
|
ragelink
|
652 |
assert "Edit" in content |
|
c588255…
|
ragelink
|
653 |
assert "Delete" in content |
|
c588255…
|
ragelink
|
654 |
|
|
c588255…
|
ragelink
|
655 |
def test_edit_button_hidden_for_viewer(self, viewer_client, org, viewer_role): |
|
c588255…
|
ragelink
|
656 |
response = viewer_client.get(reverse("organization:role_detail", kwargs={"slug": "viewer"})) |
|
c588255…
|
ragelink
|
657 |
assert response.status_code == 200 |
|
c588255…
|
ragelink
|
658 |
content = response.content.decode() |
|
c588255…
|
ragelink
|
659 |
assert "Edit" not in content or "role_edit" not in content |