Skip to content

Commit 6c38747

Browse files
Trying to change the group name to an already existing name now fails (#236)
Trying to change the group name to an already existing name now fails Co-authored-by: Leon Kuchenbecker <[email protected]> Co-authored-by: root <[email protected]> Fixes #206
1 parent ef61977 commit 6c38747

File tree

5 files changed

+61
-49
lines changed

5 files changed

+61
-49
lines changed

.vscode/settings.json

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"python.pythonPath": "/usr/local/bin/python3.8"
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
"""make group name unique
2+
3+
Revision ID: 16a09feb3391
4+
Revises: cfb9cf1b7f6c
5+
Create Date: 2021-03-25 20:59:08.171642
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
11+
12+
# revision identifiers, used by Alembic.
13+
revision = '16a09feb3391'
14+
down_revision = 'cfb9cf1b7f6c'
15+
branch_labels = None
16+
depends_on = None
17+
18+
def upgrade():
19+
# ### commands auto generated by Alembic - please adjust! ###
20+
op.create_unique_constraint(op.f('uq_groups_name'), 'groups', ['name'])
21+
# ### end Alembic commands ###
22+
23+
def downgrade():
24+
# ### commands auto generated by Alembic - please adjust! ###
25+
op.drop_constraint(op.f('uq_groups_name'), 'groups', type_='unique')
26+
# ### end Alembic commands ###

datameta/api/groups.py

+11-5
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from .. import security, errors
2323
from ..resource import resource_by_id, resource_query_by_id, get_identifier
2424
from sqlalchemy.orm import joinedload
25+
from sqlalchemy.exc import IntegrityError
2526

2627
from pyramid.httpexceptions import HTTPNoContent, HTTPNotFound, HTTPForbidden, HTTPBadRequest, HTTPGone
2728

@@ -118,7 +119,7 @@ def put(request: Request):
118119
"""Change the name of the group"""
119120

120121
group_id = request.matchdict["id"]
121-
newGroupName = request.openapi_validated.body["name"]
122+
new_group_name = request.openapi_validated.body["name"]
122123
db = request.dbsession
123124

124125
# Authenticate the user
@@ -129,9 +130,14 @@ def put(request: Request):
129130
if target_group is None:
130131
raise HTTPForbidden() # 403 Group ID not found, hidden from the user intentionally
131132

132-
# Change the group name only if the user is site admin
133-
if auth_user.site_admin:
134-
target_group.name = newGroupName
133+
# Change the group name only if the user is site admin or the admin for the specific group
134+
if auth_user.site_admin or (auth_user.group_admin and auth_user.group.uuid == group_id):
135+
136+
try:
137+
target_group.name = new_group_name
138+
db.flush()
139+
except IntegrityError:
140+
raise errors.get_validation_error("A group with that name already exists.")
141+
135142
return HTTPNoContent()
136-
137143
raise HTTPForbidden() # 403 Not authorized to change this group name

datameta/models/db.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ class Group(Base):
5353
id = Column(Integer, primary_key=True)
5454
uuid = Column(UUID(as_uuid=True), unique=True, default=uuid.uuid4, nullable=False)
5555
site_id = Column(String(50), unique=True, nullable=False, index=True)
56-
name = Column(Text, nullable=False)
56+
name = Column(Text, nullable=False, unique=True)
5757
# Relationships
5858
user = relationship('User', back_populates='group')
5959
submissions = relationship('Submission', back_populates='group')

tests/integration/test_groupnameupdate.py

+20-43
Original file line numberDiff line numberDiff line change
@@ -8,51 +8,28 @@
88
class GroupNameUpdate(BaseIntegrationTest):
99

1010
@parameterized.expand([
11-
# TEST_NAME EXEC_USER TARGET_GRP RESP
12-
("foreign_as_admin" , "admin" , "group_x_id" , 204),
13-
("own_as_group_admin" , "group_x_admin" , "group_x_id" , 403),
14-
("foreign_as_group_admin" , "group_x_admin" , "group_y_id" , 403),
15-
("invalid_group" , "admin" , "duckburgh" , 403),
16-
("own_as_regular_user" , "user_a" , "group_x_id" , 403),
17-
("foreign_as_regular_user" , "user_a" , "group_y_id" , 403)
11+
# TEST_NAME EXEC_USER TARGET_GRP NEW_GROUPNAME RESP
12+
("foreign_as_admin" , "admin" , "group_x_id" , "fancy_group" , 204),
13+
("own_as_group_admin" , "group_x_admin" , "group_x_id" , "fancy_group" , 403),
14+
("foreign_as_group_admin" , "group_x_admin" , "group_y_id" , "fancy_group" , 403),
15+
("invalid_group" , "admin" , "duckburgh" , "fancy_group" , 403),
16+
("own_as_regular_user" , "user_a" , "group_x_id" , "fancy_group" , 403),
17+
("foreign_as_regular_user" , "user_a" , "group_y_id" , "fancy_group" , 403),
18+
("admin_use_existing_groupname", "admin" , "group_x_id" , "group_y" , 400),
19+
("unauthorized" , "" , "group_x_id" , "fancy_group" , 401),
20+
("admin_expired_token" , "admin:expired" , "group_x_id" , "fancy_group" , 401),
1821
])
19-
def test_group_name_update(self, _, executing_user:str, target_group_id:str, expected_response:int):
20-
user = self.users[executing_user]
21-
request_body = {"name": "new_group_name"}
22+
def test_group_name_update(self, _, executing_user:str, target_group_id:str, new_groupname:str, expected_response:int):
23+
req_json = {
24+
"status": expected_response,
25+
"params": {"name": new_groupname}
26+
}
27+
if executing_user:
28+
executing_user, *is_expired = executing_user.split(":")
29+
user = self.users[executing_user]
30+
req_json["headers"] = user.expired_auth.header if is_expired else user.auth.header
2231

2332
response = self.testapp.put_json(
2433
f"{base_url}/groups/{target_group_id}",
25-
headers = user.auth.header,
26-
params = request_body,
27-
status = expected_response
28-
)
29-
30-
def test_failure_group_name_update_not_authorised(self, status:int=401):
31-
"""Testing unsuccessful group name change by unidentified, unauthorized user.
32-
33-
Expected Response:
34-
HTTP 401
35-
"""
36-
request_body = {"name": "fancy_group_name"}
37-
38-
response = self.testapp.put_json(
39-
f"{base_url}/groups/group_y_id",
40-
params = request_body,
41-
status = status
42-
)
43-
44-
def test_failure_admin_group_name_update_expired_token(self, status:int=401):
45-
"""Testing unsuccessful group name change by admin user with expired token.
46-
47-
Expected Response:
48-
HTTP 401
49-
"""
50-
user = self.users["admin"]
51-
request_body = {"name": "fancy_group_name"}
52-
53-
response = self.testapp.put_json(
54-
f"{base_url}/groups/group_x_id",
55-
headers = user.expired_auth.header,
56-
params = request_body,
57-
status = status
34+
**req_json
5835
)

0 commit comments

Comments
 (0)