Skip to content

Commit

Permalink
feat: allow marking projects as archived
Browse files Browse the repository at this point in the history
Signed-off-by: Facundo Tuesca <[email protected]>
  • Loading branch information
facutuesca committed Nov 25, 2024
1 parent 2ec275d commit 2c2853b
Show file tree
Hide file tree
Showing 10 changed files with 477 additions and 146 deletions.
101 changes: 97 additions & 4 deletions tests/unit/manage/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
from warehouse.packaging.models import (
File,
JournalEntry,
LifecycleStatus,
Project,
Release,
Role,
Expand Down Expand Up @@ -96,7 +97,6 @@


class TestManageUnverifiedAccount:

def test_manage_account(self, monkeypatch):
user_service = pretend.stub()
name = pretend.stub()
Expand Down Expand Up @@ -2603,7 +2603,7 @@ class TestManageProjectSettings:
@pytest.mark.parametrize("enabled", [False, True])
def test_manage_project_settings(self, enabled, monkeypatch):
request = pretend.stub(organization_access=enabled)
project = pretend.stub(organization=None)
project = pretend.stub(organization=None, lifecycle_status=None)
view = views.ManageProjectSettingsViews(project, request)
form = pretend.stub()
view.transfer_organization_project_form_class = lambda *a, **kw: form
Expand All @@ -2630,7 +2630,7 @@ def test_manage_project_settings_in_organization_managed(self, monkeypatch):
request = pretend.stub(organization_access=True)
organization_managed = pretend.stub(name="managed-org", is_active=True)
organization_owned = pretend.stub(name="owned-org", is_active=True)
project = pretend.stub(organization=organization_managed)
project = pretend.stub(organization=organization_managed, lifecycle_status=None)
view = views.ManageProjectSettingsViews(project, request)
form = pretend.stub()
view.transfer_organization_project_form_class = pretend.call_recorder(
Expand Down Expand Up @@ -2662,7 +2662,7 @@ def test_manage_project_settings_in_organization_owned(self, monkeypatch):
request = pretend.stub(organization_access=True)
organization_managed = pretend.stub(name="managed-org", is_active=True)
organization_owned = pretend.stub(name="owned-org", is_active=True)
project = pretend.stub(organization=organization_owned)
project = pretend.stub(organization=organization_owned, lifecycle_status=None)
view = views.ManageProjectSettingsViews(project, request)
form = pretend.stub()
view.transfer_organization_project_form_class = pretend.call_recorder(
Expand Down Expand Up @@ -7467,3 +7467,96 @@ def test_delete_oidc_publisher_admin_disabled(self, monkeypatch):
queue="error",
)
]


class TestArchiveProject:
def test_archive(self, db_request):
project = ProjectFactory.create(name="foo")
user = UserFactory.create(username="testuser")

db_request.route_path = pretend.call_recorder(lambda *a, **kw: "/the-redirect")
db_request.method = "POST"
db_request.user = user
db_request.session = pretend.stub(
flash=pretend.call_recorder(lambda *a, **kw: None)
)

result = views.archive_project(project, db_request)

assert isinstance(result, HTTPSeeOther)
assert result.headers["Location"] == "/the-redirect"
assert project.lifecycle_status == LifecycleStatus.Archived
assert db_request.route_path.calls == [
pretend.call("manage.project.settings", project_name=project.name)
]

def test_unarchive_project(self, db_request):
project = ProjectFactory.create(
name="foo", lifecycle_status=LifecycleStatus.Archived
)
user = UserFactory.create(username="testuser")

db_request.route_path = pretend.call_recorder(lambda *a, **kw: "/the-redirect")
db_request.method = "POST"
db_request.user = user
db_request.session = pretend.stub(
flash=pretend.call_recorder(lambda *a, **kw: None)
)

result = views.unarchive_project(project, db_request)

assert isinstance(result, HTTPSeeOther)
assert result.headers["Location"] == "/the-redirect"
assert db_request.route_path.calls == [
pretend.call("manage.project.settings", project_name=project.name)
]
assert project.lifecycle_status is None

def test_disallowed_archive(self, db_request):
project = ProjectFactory.create(name="foo", lifecycle_status="quarantine-enter")
user = UserFactory.create(username="testuser")

db_request.route_path = pretend.call_recorder(lambda *a, **kw: "/the-redirect")
db_request.method = "POST"
db_request.user = user
db_request.session = pretend.stub(
flash=pretend.call_recorder(lambda *a, **kw: None)
)

result = views.archive_project(project, db_request)

assert isinstance(result, HTTPSeeOther)
assert result.headers["Location"] == "/the-redirect"
assert db_request.session.flash.calls == [
pretend.call(
f"Cannot archive project with status {project.lifecycle_status}",
queue="error",
)
]
assert db_request.route_path.calls == [
pretend.call("manage.project.settings", project_name="foo")
]
assert project.lifecycle_status == "quarantine-enter"

def test_disallowed_unarchive(self, db_request):
project = ProjectFactory.create(name="foo", lifecycle_status="quarantine-enter")
user = UserFactory.create(username="testuser")

db_request.route_path = pretend.call_recorder(lambda *a, **kw: "/the-redirect")
db_request.method = "POST"
db_request.user = user
db_request.session = pretend.stub(
flash=pretend.call_recorder(lambda *a, **kw: None)
)

result = views.unarchive_project(project, db_request)

assert isinstance(result, HTTPSeeOther)
assert result.headers["Location"] == "/the-redirect"
assert db_request.session.flash.calls == [
pretend.call("Can only unarchive an archived project", queue="error")
]
assert db_request.route_path.calls == [
pretend.call("manage.project.settings", project_name="foo")
]
assert project.lifecycle_status == "quarantine-enter"
14 changes: 14 additions & 0 deletions tests/unit/test_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,20 @@ def add_redirect_rule(*args, **kwargs):
traverse="/{project_name}",
domain=warehouse,
),
pretend.call(
"manage.project.archive",
"/manage/project/{project_name}/archive/",
factory="warehouse.packaging.models:ProjectFactory",
traverse="/{project_name}",
domain=warehouse,
),
pretend.call(
"manage.project.unarchive",
"/manage/project/{project_name}/unarchive/",
factory="warehouse.packaging.models:ProjectFactory",
traverse="/{project_name}",
domain=warehouse,
),
pretend.call(
"manage.project.history",
"/manage/project/{project_name}/history/",
Expand Down
2 changes: 2 additions & 0 deletions warehouse/events/tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ class Project(EventTagEnum):
OrganizationProjectRemove = "project:organization_project:remove"
OwnersRequire2FADisabled = "project:owners_require_2fa:disabled"
OwnersRequire2FAEnabled = "project:owners_require_2fa:enabled"
ProjectArchiveEnter = "project:archive:enter"
ProjectArchiveExit = "project:archive:exit"
ProjectCreate = "project:create"
ProjectQuarantineEnter = "project:quarantine:enter"
ProjectQuarantineExit = "project:quarantine:exit"
Expand Down
Loading

0 comments on commit 2c2853b

Please sign in to comment.