From dd5a7a2532f81440c5d4c16b2ecf17cf7fc1254a Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Mon, 29 Jul 2019 14:18:52 -0400 Subject: [PATCH 1/6] warehouse: Allow maintainers to craft project tokens --- warehouse/manage/views.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/warehouse/manage/views.py b/warehouse/manage/views.py index 7e1f5e1dd63e..5bf2d18f5d88 100644 --- a/warehouse/manage/views.py +++ b/warehouse/manage/views.py @@ -559,7 +559,24 @@ def __init__(self, request): @property def project_names(self): - projects = user_projects(self.request)["projects_owned"] + projects_owned_or_maintained = ( + self.request.db.query(Project.id) + .join(Role.project) + .filter( + Role.role_name.in_(("Owner", "Maintainer")), + Role.user == self.request.user, + ) + .subquery() + ) + projects = ( + self.request.db.query(Project) + .join( + projects_owned_or_maintained, + Project.id == projects_owned_or_maintained.c.id, + ) + .order_by(Project.name) + .all() + ) return [project.name for project in projects] @property From 3780eac2576ab41ca49d8973137a7c27a35096cf Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Mon, 29 Jul 2019 14:33:51 -0400 Subject: [PATCH 2/6] tests: Update against new project_names --- tests/unit/manage/test_views.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/tests/unit/manage/test_views.py b/tests/unit/manage/test_views.py index 876b2979ca53..384cc00e6dd8 100644 --- a/tests/unit/manage/test_views.py +++ b/tests/unit/manage/test_views.py @@ -1412,10 +1412,10 @@ def test_create_macaroon_invalid_form(self, monkeypatch): ) monkeypatch.setattr(views, "CreateMacaroonForm", create_macaroon_cls) - user_projects = pretend.call_recorder( - lambda r: {"projects_owned": [pretend.stub(name=pretend.stub())]} + project_names = [pretend.stub()] + monkeypatch.setattr( + views.ProvisionMacaroonViews, "project_names", project_names ) - monkeypatch.setattr(views, "user_projects", user_projects) default_response = {"default": "response"} monkeypatch.setattr( @@ -1458,11 +1458,10 @@ def test_create_macaroon(self, monkeypatch): ) monkeypatch.setattr(views, "CreateMacaroonForm", create_macaroon_cls) - project_name = pretend.stub() - user_projects = pretend.call_recorder( - lambda r: {"projects_owned": [pretend.stub(name=project_name)]} + project_names = [pretend.stub()] + monkeypatch.setattr( + views.ProvisionMacaroonViews, "project_names", project_names ) - monkeypatch.setattr(views, "user_projects", user_projects) default_response = {"default": "response"} monkeypatch.setattr( From f118b5f7c8019e2ec7022d10a834372f01096d17 Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Mon, 29 Jul 2019 14:43:21 -0400 Subject: [PATCH 3/6] tests: Add project_names test --- tests/unit/manage/test_views.py | 35 +++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/unit/manage/test_views.py b/tests/unit/manage/test_views.py index 384cc00e6dd8..ddcdf1c33be3 100644 --- a/tests/unit/manage/test_views.py +++ b/tests/unit/manage/test_views.py @@ -1363,6 +1363,41 @@ def test_default_response(self, monkeypatch): "delete_macaroon_form": delete_macaroon_obj, } + def test_project_names(self, db_request): + user = UserFactory.create() + another_user = UserFactory.create() + + db_request.user = user + db_request.find_service = lambda *a, **kw: pretend.stub() + + # A project with a sole owner that is the user + with_sole_owner = ProjectFactory.create(name="foo") + RoleFactory.create(user=user, project=with_sole_owner, role_name="Owner") + RoleFactory.create( + user=another_user, project=with_sole_owner, role_name="Maintainer" + ) + + # A project with multiple owners, including the user + with_multiple_owners = ProjectFactory.create(name="bar") + RoleFactory.create(user=user, project=with_multiple_owners, role_name="Owner") + RoleFactory.create( + user=another_user, project=with_multiple_owners, role_name="Owner" + ) + + # A project with a sole owner that is not the user + not_an_owner = ProjectFactory.create(name="baz") + RoleFactory.create(user=user, project=not_an_owner, role_name="Maintainer") + RoleFactory.create(user=another_user, project=not_an_owner, role_name="Owner") + + # A project that the user is neither owner nor maintainer of + neither_owner_nor_maintainer = ProjectFactory.create(name="quux") + RoleFactory.create( + user=another_user, project=neither_owner_nor_maintainer, role_name="Owner" + ) + + view = views.ProvisionMacaroonViews(db_request) + assert set(view.project_names) == {"foo", "bar", "baz"} + def test_manage_macaroons(self, monkeypatch): request = pretend.stub(find_service=lambda *a, **kw: pretend.stub()) From 4100823abc6b5f9411465187f5169e528edddd51 Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Mon, 29 Jul 2019 17:21:04 -0400 Subject: [PATCH 4/6] warehouse: Route to project page instead of management page This avoids 403s for tokens created by maintainers. --- warehouse/templates/manage/account.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/warehouse/templates/manage/account.html b/warehouse/templates/manage/account.html index f0f5e7108a3e..14cc5a0835d2 100644 --- a/warehouse/templates/manage/account.html +++ b/warehouse/templates/manage/account.html @@ -152,7 +152,7 @@ All projects {% else %} {% for project in macaroon.caveats.get("permissions")['projects'] %} - {{ project }} + {{ project }} {% endfor %} {% endif %} From 579b438b9f5ed53168020c9eb6a65ebac3778d23 Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Tue, 30 Jul 2019 13:40:57 -0400 Subject: [PATCH 5/6] warehouse: Simplify project_names Use the user.projects relation. --- warehouse/manage/views.py | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/warehouse/manage/views.py b/warehouse/manage/views.py index 5bf2d18f5d88..2b523c493abf 100644 --- a/warehouse/manage/views.py +++ b/warehouse/manage/views.py @@ -559,25 +559,7 @@ def __init__(self, request): @property def project_names(self): - projects_owned_or_maintained = ( - self.request.db.query(Project.id) - .join(Role.project) - .filter( - Role.role_name.in_(("Owner", "Maintainer")), - Role.user == self.request.user, - ) - .subquery() - ) - projects = ( - self.request.db.query(Project) - .join( - projects_owned_or_maintained, - Project.id == projects_owned_or_maintained.c.id, - ) - .order_by(Project.name) - .all() - ) - return [project.name for project in projects] + return sorted(project.name for project in self.request.user.projects) @property def default_response(self): From a43672053173dcd08497146c5ee9950aabf9ca18 Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Tue, 30 Jul 2019 13:46:36 -0400 Subject: [PATCH 6/6] warehouse: Re-add scope:user option Accidentally removed in #6288. --- warehouse/templates/manage/token.html | 1 + 1 file changed, 1 insertion(+) diff --git a/warehouse/templates/manage/token.html b/warehouse/templates/manage/token.html index bc61fa414b23..4500b375c8eb 100644 --- a/warehouse/templates/manage/token.html +++ b/warehouse/templates/manage/token.html @@ -88,6 +88,7 @@

Add another token