Skip to content

Commit b572d0b

Browse files
committed
Add disallow deletion AdminFlag
See pypi#3218
1 parent 29d7c82 commit b572d0b

File tree

7 files changed

+272
-7
lines changed

7 files changed

+272
-7
lines changed

tests/unit/manage/test_views.py

Lines changed: 165 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import warehouse.utils.otp as otp
2828

2929
from warehouse.accounts.interfaces import IPasswordBreachedService, IUserService
30+
from warehouse.admin.flags import AdminFlagValue
3031
from warehouse.macaroons.interfaces import IMacaroonService
3132
from warehouse.manage import views
3233
from warehouse.packaging.models import (
@@ -2005,15 +2006,24 @@ def test_manage_projects(self, db_request):
20052006

20062007
class TestManageProjectSettings:
20072008
def test_manage_project_settings(self):
2008-
request = pretend.stub()
2009+
request = pretend.stub(
2010+
flags=pretend.stub(enabled=pretend.call_recorder(lambda *a: False))
2011+
)
20092012
project = pretend.stub()
20102013

2011-
assert views.manage_project_settings(project, request) == {"project": project}
2014+
assert views.manage_project_settings(project, request) == {
2015+
"disallow_deletion": False,
2016+
"project": project,
2017+
}
2018+
assert request.flags.enabled.calls == [
2019+
pretend.call(AdminFlagValue.DISALLOW_DELETION)
2020+
]
20122021

20132022
def test_delete_project_no_confirm(self):
20142023
project = pretend.stub(normalized_name="foo")
20152024
request = pretend.stub(
20162025
POST={},
2026+
flags=pretend.stub(enabled=pretend.call_recorder(lambda *a: False)),
20172027
session=pretend.stub(flash=pretend.call_recorder(lambda *a, **kw: None)),
20182028
route_path=lambda *a, **kw: "/foo/bar/",
20192029
)
@@ -2023,6 +2033,9 @@ def test_delete_project_no_confirm(self):
20232033
assert exc.value.status_code == 303
20242034
assert exc.value.headers["Location"] == "/foo/bar/"
20252035

2036+
assert request.flags.enabled.calls == [
2037+
pretend.call(AdminFlagValue.DISALLOW_DELETION)
2038+
]
20262039
assert request.session.flash.calls == [
20272040
pretend.call("Confirm the request", queue="error")
20282041
]
@@ -2031,6 +2044,7 @@ def test_delete_project_wrong_confirm(self):
20312044
project = pretend.stub(normalized_name="foo")
20322045
request = pretend.stub(
20332046
POST={"confirm_project_name": "bar"},
2047+
flags=pretend.stub(enabled=pretend.call_recorder(lambda *a: False)),
20342048
session=pretend.stub(flash=pretend.call_recorder(lambda *a, **kw: None)),
20352049
route_path=lambda *a, **kw: "/foo/bar/",
20362050
)
@@ -2040,13 +2054,46 @@ def test_delete_project_wrong_confirm(self):
20402054
assert exc.value.status_code == 303
20412055
assert exc.value.headers["Location"] == "/foo/bar/"
20422056

2057+
assert request.flags.enabled.calls == [
2058+
pretend.call(AdminFlagValue.DISALLOW_DELETION)
2059+
]
20432060
assert request.session.flash.calls == [
20442061
pretend.call(
20452062
"Could not delete project - 'bar' is not the same as 'foo'",
20462063
queue="error",
20472064
)
20482065
]
20492066

2067+
def test_delete_project_disallow_deletion(self):
2068+
project = pretend.stub(name="foo", normalized_name="foo")
2069+
request = pretend.stub(
2070+
flags=pretend.stub(enabled=pretend.call_recorder(lambda *a: True)),
2071+
route_path=pretend.call_recorder(lambda *a, **kw: "/the-redirect"),
2072+
session=pretend.stub(flash=pretend.call_recorder(lambda *a, **kw: None)),
2073+
)
2074+
2075+
result = views.delete_project(project, request)
2076+
assert isinstance(result, HTTPSeeOther)
2077+
assert result.headers["Location"] == "/the-redirect"
2078+
2079+
assert request.flags.enabled.calls == [
2080+
pretend.call(AdminFlagValue.DISALLOW_DELETION)
2081+
]
2082+
2083+
assert request.session.flash.calls == [
2084+
pretend.call(
2085+
(
2086+
"Project deletion temporarily disabled. "
2087+
"See https://pypi.org/help#admin-intervention for details."
2088+
),
2089+
queue="error",
2090+
)
2091+
]
2092+
2093+
assert request.route_path.calls == [
2094+
pretend.call("manage.project.settings", project_name="foo")
2095+
]
2096+
20502097
def test_delete_project(self, db_request):
20512098
project = ProjectFactory.create(name="foo")
20522099

@@ -2152,26 +2199,83 @@ def test_destroy_project_docs(self, db_request):
21522199

21532200
class TestManageProjectReleases:
21542201
def test_manage_project_releases(self):
2155-
request = pretend.stub()
2202+
request = pretend.stub(
2203+
flags=pretend.stub(enabled=pretend.call_recorder(lambda *a: False))
2204+
)
21562205
project = pretend.stub()
21572206

2158-
assert views.manage_project_releases(project, request) == {"project": project}
2207+
assert views.manage_project_releases(project, request) == {
2208+
"disallow_deletion": False,
2209+
"project": project,
2210+
}
2211+
assert request.flags.enabled.calls == [
2212+
pretend.call(AdminFlagValue.DISALLOW_DELETION)
2213+
]
21592214

21602215

21612216
class TestManageProjectRelease:
21622217
def test_manage_project_release(self):
21632218
files = pretend.stub()
21642219
project = pretend.stub()
21652220
release = pretend.stub(project=project, files=pretend.stub(all=lambda: files))
2166-
request = pretend.stub()
2221+
request = pretend.stub(
2222+
flags=pretend.stub(enabled=pretend.call_recorder(lambda *a: False))
2223+
)
21672224
view = views.ManageProjectRelease(release, request)
21682225

21692226
assert view.manage_project_release() == {
2227+
"disallow_deletion": False,
21702228
"project": project,
21712229
"release": release,
21722230
"files": files,
21732231
}
21742232

2233+
assert request.flags.enabled.calls == [
2234+
pretend.call(AdminFlagValue.DISALLOW_DELETION)
2235+
]
2236+
2237+
def test_delete_project_release_disallow_deletion(self, monkeypatch):
2238+
release = pretend.stub(
2239+
version="1.2.3",
2240+
canonical_version="1.2.3",
2241+
project=pretend.stub(
2242+
name="foobar", record_event=pretend.call_recorder(lambda *a, **kw: None)
2243+
),
2244+
)
2245+
request = pretend.stub(
2246+
flags=pretend.stub(enabled=pretend.call_recorder(lambda *a: True)),
2247+
method="POST",
2248+
route_path=pretend.call_recorder(lambda *a, **kw: "/the-redirect"),
2249+
session=pretend.stub(flash=pretend.call_recorder(lambda *a, **kw: None)),
2250+
)
2251+
view = views.ManageProjectRelease(release, request)
2252+
2253+
result = view.delete_project_release()
2254+
assert isinstance(result, HTTPSeeOther)
2255+
assert result.headers["Location"] == "/the-redirect"
2256+
2257+
assert request.flags.enabled.calls == [
2258+
pretend.call(AdminFlagValue.DISALLOW_DELETION)
2259+
]
2260+
2261+
assert request.session.flash.calls == [
2262+
pretend.call(
2263+
(
2264+
"Project deletion temporarily disabled. "
2265+
"See https://pypi.org/help#admin-intervention for details."
2266+
),
2267+
queue="error",
2268+
)
2269+
]
2270+
2271+
assert request.route_path.calls == [
2272+
pretend.call(
2273+
"manage.project.release",
2274+
project_name=release.project.name,
2275+
version=release.version,
2276+
)
2277+
]
2278+
21752279
def test_delete_project_release(self, monkeypatch):
21762280
release = pretend.stub(
21772281
version="1.2.3",
@@ -2187,6 +2291,7 @@ def test_delete_project_release(self, monkeypatch):
21872291
delete=pretend.call_recorder(lambda a: None),
21882292
add=pretend.call_recorder(lambda a: None),
21892293
),
2294+
flags=pretend.stub(enabled=pretend.call_recorder(lambda *a: False)),
21902295
route_path=pretend.call_recorder(lambda *a, **kw: "/the-redirect"),
21912296
session=pretend.stub(flash=pretend.call_recorder(lambda *a, **kw: None)),
21922297
user=pretend.stub(username=pretend.stub()),
@@ -2205,6 +2310,9 @@ def test_delete_project_release(self, monkeypatch):
22052310

22062311
assert request.db.delete.calls == [pretend.call(release)]
22072312
assert request.db.add.calls == [pretend.call(journal_obj)]
2313+
assert request.flags.enabled.calls == [
2314+
pretend.call(AdminFlagValue.DISALLOW_DELETION)
2315+
]
22082316
assert journal_cls.calls == [
22092317
pretend.call(
22102318
name=release.project.name,
@@ -2237,6 +2345,7 @@ def test_delete_project_release_no_confirm(self):
22372345
POST={"confirm_version": ""},
22382346
method="POST",
22392347
db=pretend.stub(delete=pretend.call_recorder(lambda a: None)),
2348+
flags=pretend.stub(enabled=pretend.call_recorder(lambda *a: False)),
22402349
route_path=pretend.call_recorder(lambda *a, **kw: "/the-redirect"),
22412350
session=pretend.stub(flash=pretend.call_recorder(lambda *a, **kw: None)),
22422351
)
@@ -2251,6 +2360,9 @@ def test_delete_project_release_no_confirm(self):
22512360
assert request.session.flash.calls == [
22522361
pretend.call("Confirm the request", queue="error")
22532362
]
2363+
assert request.flags.enabled.calls == [
2364+
pretend.call(AdminFlagValue.DISALLOW_DELETION)
2365+
]
22542366
assert request.route_path.calls == [
22552367
pretend.call(
22562368
"manage.project.release",
@@ -2265,6 +2377,7 @@ def test_delete_project_release_bad_confirm(self):
22652377
POST={"confirm_version": "invalid"},
22662378
method="POST",
22672379
db=pretend.stub(delete=pretend.call_recorder(lambda a: None)),
2380+
flags=pretend.stub(enabled=pretend.call_recorder(lambda *a: False)),
22682381
route_path=pretend.call_recorder(lambda *a, **kw: "/the-redirect"),
22692382
session=pretend.stub(flash=pretend.call_recorder(lambda *a, **kw: None)),
22702383
)
@@ -2276,6 +2389,9 @@ def test_delete_project_release_bad_confirm(self):
22762389
assert result.headers["Location"] == "/the-redirect"
22772390

22782391
assert request.db.delete.calls == []
2392+
assert request.flags.enabled.calls == [
2393+
pretend.call(AdminFlagValue.DISALLOW_DELETION)
2394+
]
22792395
assert request.session.flash.calls == [
22802396
pretend.call(
22812397
"Could not delete release - "
@@ -2291,6 +2407,42 @@ def test_delete_project_release_bad_confirm(self):
22912407
)
22922408
]
22932409

2410+
def test_delete_project_release_file_disallow_deletion(self):
2411+
release = pretend.stub(version="1.2.3", project=pretend.stub(name="foobar"))
2412+
request = pretend.stub(
2413+
method="POST",
2414+
flags=pretend.stub(enabled=pretend.call_recorder(lambda *a: True)),
2415+
route_path=pretend.call_recorder(lambda *a, **kw: "/the-redirect"),
2416+
session=pretend.stub(flash=pretend.call_recorder(lambda *a, **kw: None)),
2417+
)
2418+
view = views.ManageProjectRelease(release, request)
2419+
2420+
result = view.delete_project_release_file()
2421+
2422+
assert isinstance(result, HTTPSeeOther)
2423+
assert result.headers["Location"] == "/the-redirect"
2424+
2425+
assert request.flags.enabled.calls == [
2426+
pretend.call(AdminFlagValue.DISALLOW_DELETION)
2427+
]
2428+
2429+
assert request.session.flash.calls == [
2430+
pretend.call(
2431+
(
2432+
"Project deletion temporarily disabled. "
2433+
"See https://pypi.org/help#admin-intervention for details."
2434+
),
2435+
queue="error",
2436+
)
2437+
]
2438+
assert request.route_path.calls == [
2439+
pretend.call(
2440+
"manage.project.release",
2441+
project_name=release.project.name,
2442+
version=release.version,
2443+
)
2444+
]
2445+
22942446
def test_delete_project_release_file(self, db_request):
22952447
user = UserFactory.create()
22962448

@@ -2349,6 +2501,7 @@ def test_delete_project_release_file_no_confirm(self):
23492501
POST={"confirm_project_name": ""},
23502502
method="POST",
23512503
db=pretend.stub(delete=pretend.call_recorder(lambda a: None)),
2504+
flags=pretend.stub(enabled=pretend.call_recorder(lambda *a: False)),
23522505
route_path=pretend.call_recorder(lambda *a, **kw: "/the-redirect"),
23532506
session=pretend.stub(flash=pretend.call_recorder(lambda *a, **kw: None)),
23542507
)
@@ -2360,6 +2513,9 @@ def test_delete_project_release_file_no_confirm(self):
23602513
assert result.headers["Location"] == "/the-redirect"
23612514

23622515
assert request.db.delete.calls == []
2516+
assert request.flags.enabled.calls == [
2517+
pretend.call(AdminFlagValue.DISALLOW_DELETION)
2518+
]
23632519
assert request.session.flash.calls == [
23642520
pretend.call("Confirm the request", queue="error")
23652521
]
@@ -2386,6 +2542,7 @@ def no_result_found():
23862542
filter=lambda *a: pretend.stub(one=no_result_found)
23872543
),
23882544
)
2545+
db_request.flags = pretend.stub(enabled=pretend.call_recorder(lambda *a: False))
23892546
db_request.route_path = pretend.call_recorder(lambda *a, **kw: "/the-redirect")
23902547
db_request.session = pretend.stub(
23912548
flash=pretend.call_recorder(lambda *a, **kw: None)
@@ -2399,6 +2556,9 @@ def no_result_found():
23992556
assert result.headers["Location"] == "/the-redirect"
24002557

24012558
assert db_request.db.delete.calls == []
2559+
assert db_request.flags.enabled.calls == [
2560+
pretend.call(AdminFlagValue.DISALLOW_DELETION)
2561+
]
24022562
assert db_request.session.flash.calls == [
24032563
pretend.call("Could not find file", queue="error")
24042564
]

warehouse/admin/flags.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717

1818
class AdminFlagValue:
19+
DISALLOW_DELETION = "disallow-deletion"
1920
DISALLOW_NEW_PROJECT_REGISTRATION = "disallow-new-project-registration"
2021
DISALLOW_NEW_USER_REGISTRATION = "disallow-new-user-registration"
2122
READ_ONLY = "read-only"

0 commit comments

Comments
 (0)