diff --git a/tests/unit/admin/views/test_projects.py b/tests/unit/admin/views/test_projects.py index 6c981a62a478..1e3cfe0ff56a 100644 --- a/tests/unit/admin/views/test_projects.py +++ b/tests/unit/admin/views/test_projects.py @@ -342,3 +342,56 @@ def test_non_normalized_name(self, db_request): ) with pytest.raises(HTTPMovedPermanently): views.journals_list(project, db_request) + + +class TestProjectSetLimit: + def test_sets_limitwith_integer(self, db_request): + project = ProjectFactory.create(name="foo") + + db_request.route_path = pretend.call_recorder( + lambda *a, **kw: "/admin/projects/") + db_request.session = pretend.stub( + flash=pretend.call_recorder(lambda *a, **kw: None), + ) + db_request.matchdict["project_name"] = project.normalized_name + db_request.POST["upload_limit"] = "12345" + + views.set_upload_limit(project, db_request) + + assert db_request.session.flash.calls == [ + pretend.call( + "Successfully set the upload limit on 'foo' to 12345", + queue="success"), + ] + + assert project.upload_limit == 12345 + + def test_sets_limit_with_none(self, db_request): + project = ProjectFactory.create(name="foo") + project.upload_limit = 12345 + + db_request.route_path = pretend.call_recorder( + lambda *a, **kw: "/admin/projects/") + db_request.session = pretend.stub( + flash=pretend.call_recorder(lambda *a, **kw: None), + ) + db_request.matchdict["project_name"] = project.normalized_name + + views.set_upload_limit(project, db_request) + + assert db_request.session.flash.calls == [ + pretend.call( + "Successfully set the upload limit on 'foo' to None", + queue="success"), + ] + + assert project.upload_limit is None + + def test_sets_limit_with_bad_value(self, db_request): + project = ProjectFactory.create(name="foo") + + db_request.matchdict["project_name"] = project.normalized_name + db_request.POST["upload_limit"] = "meep" + + with pytest.raises(HTTPBadRequest): + views.set_upload_limit(project, db_request) diff --git a/warehouse/admin/routes.py b/warehouse/admin/routes.py index 2948f0e0b1b5..2b5b74b2f03b 100644 --- a/warehouse/admin/routes.py +++ b/warehouse/admin/routes.py @@ -57,6 +57,13 @@ def includeme(config): traverse="/{project_name}", domain=warehouse, ) + config.add_route( + "admin.project.set_upload_limit", + "/admin/projects/{project_name}/set_upload_limit/", + factory="warehouse.packaging.models:ProjectFactory", + traverse="/{project_name}", + domain=warehouse, + ) # Journal related Admin pages config.add_route( diff --git a/warehouse/admin/templates/admin/projects/detail.html b/warehouse/admin/templates/admin/projects/detail.html index 7d84200ec051..4c7cea25c1c7 100644 --- a/warehouse/admin/templates/admin/projects/detail.html +++ b/warehouse/admin/templates/admin/projects/detail.html @@ -46,6 +46,18 @@

{{ project.name }}

+
+ + + + + + + + + +
AttributeValue
Upload limit{{ project.upload_limit }}
+
@@ -108,6 +120,7 @@

{{ project.name }}

+

Blacklist Project

@@ -132,4 +145,30 @@

Blacklist Project

+ + +
+
+

Set upload limit

+
+ +
+
+ +
+ +
+
+ + +
+
+ + + +
{% endblock %} diff --git a/warehouse/admin/views/projects.py b/warehouse/admin/views/projects.py index e0913e5d5d57..c0a54dbb8be7 100644 --- a/warehouse/admin/views/projects.py +++ b/warehouse/admin/views/projects.py @@ -16,6 +16,7 @@ from pyramid.httpexceptions import ( HTTPBadRequest, HTTPMovedPermanently, + HTTPSeeOther, ) from pyramid.view import view_config from sqlalchemy import or_ @@ -201,3 +202,37 @@ def journals_list(project, request): ) return {"journals": journals, "project": project, "query": q} + + +@view_config( + route_name="admin.project.set_upload_limit", + permission="admin", + request_method="POST", + uses_session=True, + require_methods=False, +) +def set_upload_limit(project, request): + upload_limit = request.POST.get("upload_limit", "") + + # Update the project's upload limit. + # If the upload limit is an empty string or othrwise falsy, just set the + # limit to None, indicating the default limit. + if not upload_limit: + project.upload_limit = None + else: + try: + project.upload_limit = int(upload_limit) + except ValueError: + raise HTTPBadRequest( + f"Invalid value for upload_limit: {upload_limit}, " + f"must be integer or empty string.") + + request.session.flash( + f"Successfully set the upload limit on {project.name!r} to " + f"{project.upload_limit!r}", + queue="success", + ) + + return HTTPSeeOther( + request.route_path( + 'admin.project.detail', project_name=project.normalized_name))