arthexis 0.1.20__py3-none-any.whl → 0.1.22__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of arthexis might be problematic. Click here for more details.
- {arthexis-0.1.20.dist-info → arthexis-0.1.22.dist-info}/METADATA +10 -11
- {arthexis-0.1.20.dist-info → arthexis-0.1.22.dist-info}/RECORD +34 -36
- config/asgi.py +1 -15
- config/settings.py +4 -26
- config/urls.py +5 -1
- core/admin.py +140 -252
- core/apps.py +0 -6
- core/environment.py +2 -220
- core/models.py +425 -77
- core/system.py +76 -0
- core/tests.py +153 -15
- core/views.py +35 -97
- nodes/admin.py +165 -32
- nodes/apps.py +11 -0
- nodes/models.py +26 -6
- nodes/tests.py +263 -1
- nodes/views.py +61 -1
- ocpp/admin.py +68 -7
- ocpp/consumers.py +1 -0
- ocpp/models.py +71 -1
- ocpp/tasks.py +99 -1
- ocpp/tests.py +310 -2
- ocpp/views.py +365 -5
- pages/admin.py +112 -15
- pages/apps.py +32 -0
- pages/context_processors.py +0 -12
- pages/forms.py +31 -8
- pages/models.py +42 -2
- pages/tests.py +361 -63
- pages/urls.py +5 -1
- pages/views.py +264 -16
- core/workgroup_urls.py +0 -17
- core/workgroup_views.py +0 -94
- {arthexis-0.1.20.dist-info → arthexis-0.1.22.dist-info}/WHEEL +0 -0
- {arthexis-0.1.20.dist-info → arthexis-0.1.22.dist-info}/licenses/LICENSE +0 -0
- {arthexis-0.1.20.dist-info → arthexis-0.1.22.dist-info}/top_level.txt +0 -0
core/tests.py
CHANGED
|
@@ -1290,11 +1290,10 @@ class ReleaseProcessTests(TestCase):
|
|
|
1290
1290
|
run.assert_any_call(["git", "clean", "-fd"], check=False)
|
|
1291
1291
|
|
|
1292
1292
|
@mock.patch("core.views.PackageRelease.dump_fixture")
|
|
1293
|
-
@mock.patch("core.views._ensure_release_todo")
|
|
1294
1293
|
@mock.patch("core.views._sync_with_origin_main")
|
|
1295
1294
|
@mock.patch("core.views.subprocess.run")
|
|
1296
1295
|
def test_pre_release_syncs_with_main(
|
|
1297
|
-
self, run, sync_main,
|
|
1296
|
+
self, run, sync_main, dump_fixture
|
|
1298
1297
|
):
|
|
1299
1298
|
import subprocess as sp
|
|
1300
1299
|
|
|
@@ -1306,11 +1305,6 @@ class ReleaseProcessTests(TestCase):
|
|
|
1306
1305
|
return sp.CompletedProcess(cmd, 0)
|
|
1307
1306
|
|
|
1308
1307
|
run.side_effect = fake_run
|
|
1309
|
-
ensure_todo.return_value = (
|
|
1310
|
-
mock.Mock(request="Create release pkg 1.0.1", url="", request_details=""),
|
|
1311
|
-
Path("core/fixtures/todos__next_release.json"),
|
|
1312
|
-
)
|
|
1313
|
-
|
|
1314
1308
|
version_path = Path("VERSION")
|
|
1315
1309
|
original_version = version_path.read_text(encoding="utf-8")
|
|
1316
1310
|
|
|
@@ -1975,7 +1969,7 @@ class PackageReleaseAdminActionTests(TestCase):
|
|
|
1975
1969
|
|
|
1976
1970
|
@mock.patch("core.admin.PackageRelease.dump_fixture")
|
|
1977
1971
|
@mock.patch("core.admin.requests.get")
|
|
1978
|
-
def
|
|
1972
|
+
def test_refresh_from_pypi_reports_missing_releases(self, mock_get, dump):
|
|
1979
1973
|
mock_get.return_value.raise_for_status.return_value = None
|
|
1980
1974
|
mock_get.return_value.json.return_value = {
|
|
1981
1975
|
"releases": {
|
|
@@ -1988,13 +1982,17 @@ class PackageReleaseAdminActionTests(TestCase):
|
|
|
1988
1982
|
}
|
|
1989
1983
|
}
|
|
1990
1984
|
self.admin.refresh_from_pypi(self.request, PackageRelease.objects.none())
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1985
|
+
self.assertFalse(
|
|
1986
|
+
PackageRelease.objects.filter(version="1.1.0").exists()
|
|
1987
|
+
)
|
|
1988
|
+
dump.assert_not_called()
|
|
1989
|
+
self.assertIn(
|
|
1990
|
+
(
|
|
1991
|
+
"Manual creation required for 1 release: 1.1.0",
|
|
1992
|
+
messages.WARNING,
|
|
1993
|
+
),
|
|
1994
|
+
self.messages,
|
|
1996
1995
|
)
|
|
1997
|
-
dump.assert_called_once()
|
|
1998
1996
|
|
|
1999
1997
|
@mock.patch("core.admin.PackageRelease.dump_fixture")
|
|
2000
1998
|
@mock.patch("core.admin.requests.get")
|
|
@@ -2218,13 +2216,97 @@ class TodoDoneTests(TestCase):
|
|
|
2218
2216
|
User.objects.create_superuser("admin", "admin@example.com", "pw")
|
|
2219
2217
|
self.client.force_login(User.objects.get(username="admin"))
|
|
2220
2218
|
|
|
2221
|
-
|
|
2219
|
+
@mock.patch("core.models.revision_utils.get_revision", return_value="rev123")
|
|
2220
|
+
def test_mark_done_sets_timestamp(self, _get_revision):
|
|
2222
2221
|
todo = Todo.objects.create(request="Task", is_seed_data=True)
|
|
2223
2222
|
resp = self.client.post(reverse("todo-done", args=[todo.pk]))
|
|
2224
2223
|
self.assertRedirects(resp, reverse("admin:index"))
|
|
2225
2224
|
todo.refresh_from_db()
|
|
2226
2225
|
self.assertIsNotNone(todo.done_on)
|
|
2227
2226
|
self.assertFalse(todo.is_deleted)
|
|
2227
|
+
self.assertIsNone(todo.done_node)
|
|
2228
|
+
version_path = Path(settings.BASE_DIR) / "VERSION"
|
|
2229
|
+
expected_version = ""
|
|
2230
|
+
if version_path.exists():
|
|
2231
|
+
expected_version = version_path.read_text(encoding="utf-8").strip()
|
|
2232
|
+
self.assertEqual(todo.done_version, expected_version)
|
|
2233
|
+
self.assertEqual(todo.done_revision, "rev123")
|
|
2234
|
+
self.assertEqual(todo.done_username, "admin")
|
|
2235
|
+
|
|
2236
|
+
def test_mark_done_updates_seed_fixture(self):
|
|
2237
|
+
todo = Todo.objects.create(request="Task", is_seed_data=True)
|
|
2238
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
2239
|
+
base = Path(tmp)
|
|
2240
|
+
fixture_dir = base / "core" / "fixtures"
|
|
2241
|
+
fixture_dir.mkdir(parents=True)
|
|
2242
|
+
fixture_path = fixture_dir / "todo__task.json"
|
|
2243
|
+
fixture_path.write_text(
|
|
2244
|
+
json.dumps(
|
|
2245
|
+
[
|
|
2246
|
+
{
|
|
2247
|
+
"model": "core.todo",
|
|
2248
|
+
"fields": {
|
|
2249
|
+
"request": "Task",
|
|
2250
|
+
"url": "",
|
|
2251
|
+
"request_details": "",
|
|
2252
|
+
},
|
|
2253
|
+
}
|
|
2254
|
+
],
|
|
2255
|
+
indent=2,
|
|
2256
|
+
)
|
|
2257
|
+
+ "\n",
|
|
2258
|
+
encoding="utf-8",
|
|
2259
|
+
)
|
|
2260
|
+
|
|
2261
|
+
with override_settings(BASE_DIR=base):
|
|
2262
|
+
with mock.patch(
|
|
2263
|
+
"core.models.revision_utils.get_revision", return_value="rev456"
|
|
2264
|
+
):
|
|
2265
|
+
resp = self.client.post(reverse("todo-done", args=[todo.pk]))
|
|
2266
|
+
|
|
2267
|
+
self.assertRedirects(resp, reverse("admin:index"))
|
|
2268
|
+
data = json.loads(fixture_path.read_text(encoding="utf-8"))
|
|
2269
|
+
self.assertEqual(len(data), 1)
|
|
2270
|
+
fields = data[0]["fields"]
|
|
2271
|
+
self.assertIn("done_on", fields)
|
|
2272
|
+
self.assertTrue(fields["done_on"])
|
|
2273
|
+
self.assertFalse(fields.get("is_deleted", False))
|
|
2274
|
+
self.assertIn("done_version", fields)
|
|
2275
|
+
self.assertEqual(fields.get("done_revision"), "rev456")
|
|
2276
|
+
self.assertEqual(fields.get("done_username"), "admin")
|
|
2277
|
+
|
|
2278
|
+
def test_soft_delete_updates_seed_fixture(self):
|
|
2279
|
+
todo = Todo.objects.create(request="Task", is_seed_data=True)
|
|
2280
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
2281
|
+
base = Path(tmp)
|
|
2282
|
+
fixture_dir = base / "core" / "fixtures"
|
|
2283
|
+
fixture_dir.mkdir(parents=True)
|
|
2284
|
+
fixture_path = fixture_dir / "todo__task.json"
|
|
2285
|
+
fixture_path.write_text(
|
|
2286
|
+
json.dumps(
|
|
2287
|
+
[
|
|
2288
|
+
{
|
|
2289
|
+
"model": "core.todo",
|
|
2290
|
+
"fields": {
|
|
2291
|
+
"request": "Task",
|
|
2292
|
+
"url": "",
|
|
2293
|
+
"request_details": "",
|
|
2294
|
+
},
|
|
2295
|
+
}
|
|
2296
|
+
],
|
|
2297
|
+
indent=2,
|
|
2298
|
+
)
|
|
2299
|
+
+ "\n",
|
|
2300
|
+
encoding="utf-8",
|
|
2301
|
+
)
|
|
2302
|
+
|
|
2303
|
+
with override_settings(BASE_DIR=base):
|
|
2304
|
+
todo.delete()
|
|
2305
|
+
|
|
2306
|
+
data = json.loads(fixture_path.read_text(encoding="utf-8"))
|
|
2307
|
+
self.assertEqual(len(data), 1)
|
|
2308
|
+
fields = data[0]["fields"]
|
|
2309
|
+
self.assertTrue(fields.get("is_deleted"))
|
|
2228
2310
|
|
|
2229
2311
|
def test_mark_done_missing_task_refreshes(self):
|
|
2230
2312
|
todo = Todo.objects.create(request="Task", is_seed_data=True)
|
|
@@ -2330,6 +2412,61 @@ class TodoDoneTests(TestCase):
|
|
|
2330
2412
|
self.assertTrue(todo.is_seed_data)
|
|
2331
2413
|
|
|
2332
2414
|
|
|
2415
|
+
class TodoDeleteTests(TestCase):
|
|
2416
|
+
def setUp(self):
|
|
2417
|
+
self.client = Client()
|
|
2418
|
+
User.objects.create_superuser("admin", "admin@example.com", "pw")
|
|
2419
|
+
self.client.force_login(User.objects.get(username="admin"))
|
|
2420
|
+
|
|
2421
|
+
def test_delete_marks_task_deleted(self):
|
|
2422
|
+
todo = Todo.objects.create(request="Task", is_seed_data=True)
|
|
2423
|
+
resp = self.client.post(reverse("todo-delete", args=[todo.pk]))
|
|
2424
|
+
self.assertRedirects(resp, reverse("admin:index"))
|
|
2425
|
+
todo.refresh_from_db()
|
|
2426
|
+
self.assertTrue(todo.is_deleted)
|
|
2427
|
+
self.assertIsNone(todo.done_on)
|
|
2428
|
+
|
|
2429
|
+
def test_delete_updates_seed_fixture(self):
|
|
2430
|
+
todo = Todo.objects.create(request="Task", is_seed_data=True)
|
|
2431
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
2432
|
+
base = Path(tmp)
|
|
2433
|
+
fixture_dir = base / "core" / "fixtures"
|
|
2434
|
+
fixture_dir.mkdir(parents=True)
|
|
2435
|
+
fixture_path = fixture_dir / "todo__task.json"
|
|
2436
|
+
fixture_path.write_text(
|
|
2437
|
+
json.dumps(
|
|
2438
|
+
[
|
|
2439
|
+
{
|
|
2440
|
+
"model": "core.todo",
|
|
2441
|
+
"fields": {
|
|
2442
|
+
"request": "Task",
|
|
2443
|
+
"url": "",
|
|
2444
|
+
"request_details": "",
|
|
2445
|
+
},
|
|
2446
|
+
}
|
|
2447
|
+
],
|
|
2448
|
+
indent=2,
|
|
2449
|
+
)
|
|
2450
|
+
+ "\n",
|
|
2451
|
+
encoding="utf-8",
|
|
2452
|
+
)
|
|
2453
|
+
|
|
2454
|
+
with override_settings(BASE_DIR=base):
|
|
2455
|
+
resp = self.client.post(reverse("todo-delete", args=[todo.pk]))
|
|
2456
|
+
self.assertRedirects(resp, reverse("admin:index"))
|
|
2457
|
+
data = json.loads(fixture_path.read_text(encoding="utf-8"))
|
|
2458
|
+
self.assertEqual(len(data), 1)
|
|
2459
|
+
fields = data[0]["fields"]
|
|
2460
|
+
self.assertTrue(fields.get("is_deleted"))
|
|
2461
|
+
|
|
2462
|
+
def test_delete_missing_task_redirects(self):
|
|
2463
|
+
todo = Todo.objects.create(request="Task")
|
|
2464
|
+
todo.is_deleted = True
|
|
2465
|
+
todo.save(update_fields=["is_deleted"])
|
|
2466
|
+
resp = self.client.post(reverse("todo-delete", args=[todo.pk]))
|
|
2467
|
+
self.assertRedirects(resp, reverse("admin:index"))
|
|
2468
|
+
|
|
2469
|
+
|
|
2333
2470
|
class TodoFocusViewTests(TestCase):
|
|
2334
2471
|
def setUp(self):
|
|
2335
2472
|
self.client = Client()
|
|
@@ -2347,6 +2484,7 @@ class TodoFocusViewTests(TestCase):
|
|
|
2347
2484
|
self.assertEqual(resp["X-Frame-Options"], "SAMEORIGIN")
|
|
2348
2485
|
self.assertContains(resp, f'src="{todo.url}"')
|
|
2349
2486
|
self.assertContains(resp, "Done")
|
|
2487
|
+
self.assertContains(resp, "Delete")
|
|
2350
2488
|
self.assertContains(resp, "Back")
|
|
2351
2489
|
self.assertContains(resp, "Take Snapshot")
|
|
2352
2490
|
snapshot_url = reverse("todo-snapshot", args=[todo.pk])
|
core/views.py
CHANGED
|
@@ -19,7 +19,6 @@ from django.shortcuts import get_object_or_404, redirect, render, resolve_url
|
|
|
19
19
|
from django.template.response import TemplateResponse
|
|
20
20
|
from django.utils import timezone
|
|
21
21
|
from django.utils.html import strip_tags
|
|
22
|
-
from django.utils.text import slugify
|
|
23
22
|
from django.utils.translation import gettext as _
|
|
24
23
|
from django.urls import NoReverseMatch, reverse
|
|
25
24
|
from django.views.decorators.csrf import csrf_exempt
|
|
@@ -366,6 +365,7 @@ def request_temp_password(request):
|
|
|
366
365
|
)
|
|
367
366
|
|
|
368
367
|
|
|
368
|
+
@staff_member_required
|
|
369
369
|
@require_GET
|
|
370
370
|
def version_info(request):
|
|
371
371
|
"""Return the running application version and Git revision."""
|
|
@@ -496,6 +496,16 @@ def _sync_with_origin_main(log_path: Path) -> None:
|
|
|
496
496
|
if stderr:
|
|
497
497
|
_append_log(log_path, "git errors:\n" + stderr)
|
|
498
498
|
|
|
499
|
+
status = subprocess.run(
|
|
500
|
+
["git", "status"], capture_output=True, text=True, check=False
|
|
501
|
+
)
|
|
502
|
+
status_output = (status.stdout or "").strip()
|
|
503
|
+
status_errors = (status.stderr or "").strip()
|
|
504
|
+
if status_output:
|
|
505
|
+
_append_log(log_path, "git status:\n" + status_output)
|
|
506
|
+
if status_errors:
|
|
507
|
+
_append_log(log_path, "git status errors:\n" + status_errors)
|
|
508
|
+
|
|
499
509
|
branch = _current_branch() or "(detached HEAD)"
|
|
500
510
|
instructions = [
|
|
501
511
|
"Manual intervention required to finish syncing with origin/main.",
|
|
@@ -693,29 +703,6 @@ def _next_patch_version(version: str) -> str:
|
|
|
693
703
|
return f"{parsed.major}.{parsed.minor}.{parsed.micro + 1}"
|
|
694
704
|
|
|
695
705
|
|
|
696
|
-
def _write_todo_fixture(todo: Todo) -> Path:
|
|
697
|
-
safe_request = todo.request.replace(".", " ")
|
|
698
|
-
slug = slugify(safe_request).replace("-", "_")
|
|
699
|
-
if not slug:
|
|
700
|
-
slug = "todo"
|
|
701
|
-
path = TODO_FIXTURE_DIR / f"todos__{slug}.json"
|
|
702
|
-
path.parent.mkdir(parents=True, exist_ok=True)
|
|
703
|
-
data = [
|
|
704
|
-
{
|
|
705
|
-
"model": "core.todo",
|
|
706
|
-
"fields": {
|
|
707
|
-
"request": todo.request,
|
|
708
|
-
"url": todo.url,
|
|
709
|
-
"request_details": todo.request_details,
|
|
710
|
-
"generated_for_version": todo.generated_for_version,
|
|
711
|
-
"generated_for_revision": todo.generated_for_revision,
|
|
712
|
-
},
|
|
713
|
-
}
|
|
714
|
-
]
|
|
715
|
-
path.write_text(json.dumps(data, indent=2) + "\n", encoding="utf-8")
|
|
716
|
-
return path
|
|
717
|
-
|
|
718
|
-
|
|
719
706
|
def _should_use_python_changelog(exc: OSError) -> bool:
|
|
720
707
|
winerror = getattr(exc, "winerror", None)
|
|
721
708
|
if winerror in {193}:
|
|
@@ -736,46 +723,6 @@ def _generate_changelog_with_python(log_path: Path) -> None:
|
|
|
736
723
|
_append_log(log_path, "Regenerated CHANGELOG.rst using Python fallback")
|
|
737
724
|
|
|
738
725
|
|
|
739
|
-
def _ensure_release_todo(
|
|
740
|
-
release, *, previous_version: str | None = None
|
|
741
|
-
) -> tuple[Todo, Path]:
|
|
742
|
-
previous_version = (previous_version or "").strip()
|
|
743
|
-
target_version = _next_patch_version(release.version)
|
|
744
|
-
if previous_version:
|
|
745
|
-
try:
|
|
746
|
-
from packaging.version import InvalidVersion, Version
|
|
747
|
-
|
|
748
|
-
parsed_previous = Version(previous_version)
|
|
749
|
-
parsed_target = Version(target_version)
|
|
750
|
-
except InvalidVersion:
|
|
751
|
-
pass
|
|
752
|
-
else:
|
|
753
|
-
if parsed_target <= parsed_previous:
|
|
754
|
-
target_version = _next_patch_version(previous_version)
|
|
755
|
-
request = f"Create release {release.package.name} {target_version}"
|
|
756
|
-
try:
|
|
757
|
-
url = reverse("admin:core_packagerelease_changelist")
|
|
758
|
-
except NoReverseMatch:
|
|
759
|
-
url = ""
|
|
760
|
-
todo, _ = Todo.all_objects.update_or_create(
|
|
761
|
-
request__iexact=request,
|
|
762
|
-
defaults={
|
|
763
|
-
"request": request,
|
|
764
|
-
"url": url,
|
|
765
|
-
"request_details": "",
|
|
766
|
-
"generated_for_version": release.version or "",
|
|
767
|
-
"generated_for_revision": release.revision or "",
|
|
768
|
-
"is_seed_data": True,
|
|
769
|
-
"is_deleted": False,
|
|
770
|
-
"is_user_data": False,
|
|
771
|
-
"done_on": None,
|
|
772
|
-
"on_done_condition": "",
|
|
773
|
-
},
|
|
774
|
-
)
|
|
775
|
-
fixture_path = _write_todo_fixture(todo)
|
|
776
|
-
return todo, fixture_path
|
|
777
|
-
|
|
778
|
-
|
|
779
726
|
def _todo_blocks_publish(todo: Todo, release: PackageRelease) -> bool:
|
|
780
727
|
"""Return ``True`` when ``todo`` should block the release workflow."""
|
|
781
728
|
|
|
@@ -1226,36 +1173,6 @@ def _step_changelog_docs(release, ctx, log_path: Path) -> None:
|
|
|
1226
1173
|
_append_log(log_path, "CHANGELOG and documentation review recorded")
|
|
1227
1174
|
|
|
1228
1175
|
|
|
1229
|
-
def _record_release_todo(
|
|
1230
|
-
release, ctx, log_path: Path, *, previous_version: str | None = None
|
|
1231
|
-
) -> None:
|
|
1232
|
-
previous_version = previous_version or ctx.pop(
|
|
1233
|
-
"release_todo_previous_version",
|
|
1234
|
-
getattr(release, "_repo_version_before_sync", ""),
|
|
1235
|
-
)
|
|
1236
|
-
todo, fixture_path = _ensure_release_todo(
|
|
1237
|
-
release, previous_version=previous_version
|
|
1238
|
-
)
|
|
1239
|
-
fixture_display = _format_path(fixture_path)
|
|
1240
|
-
_append_log(log_path, f"Added TODO: {todo.request}")
|
|
1241
|
-
_append_log(log_path, f"Wrote TODO fixture {fixture_display}")
|
|
1242
|
-
subprocess.run(["git", "add", str(fixture_path)], check=True)
|
|
1243
|
-
_append_log(log_path, f"Staged TODO fixture {fixture_display}")
|
|
1244
|
-
fixture_diff = subprocess.run(
|
|
1245
|
-
["git", "diff", "--cached", "--quiet", "--", str(fixture_path)],
|
|
1246
|
-
check=False,
|
|
1247
|
-
)
|
|
1248
|
-
if fixture_diff.returncode != 0:
|
|
1249
|
-
commit_message = f"chore: add release TODO for {release.package.name}"
|
|
1250
|
-
subprocess.run(["git", "commit", "-m", commit_message], check=True)
|
|
1251
|
-
_append_log(log_path, f"Committed TODO fixture {fixture_display}")
|
|
1252
|
-
else:
|
|
1253
|
-
_append_log(
|
|
1254
|
-
log_path,
|
|
1255
|
-
f"No changes detected for TODO fixture {fixture_display}; skipping commit",
|
|
1256
|
-
)
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
1176
|
def _step_pre_release_actions(release, ctx, log_path: Path) -> None:
|
|
1260
1177
|
_append_log(log_path, "Execute pre-release actions")
|
|
1261
1178
|
if ctx.get("dry_run"):
|
|
@@ -1329,7 +1246,6 @@ def _step_pre_release_actions(release, ctx, log_path: Path) -> None:
|
|
|
1329
1246
|
for path in staged_release_fixtures:
|
|
1330
1247
|
subprocess.run(["git", "reset", "HEAD", str(path)], check=False)
|
|
1331
1248
|
_append_log(log_path, f"Unstaged release fixture {_format_path(path)}")
|
|
1332
|
-
ctx["release_todo_previous_version"] = repo_version_before_sync
|
|
1333
1249
|
_append_log(log_path, "Pre-release actions complete")
|
|
1334
1250
|
|
|
1335
1251
|
|
|
@@ -1383,7 +1299,6 @@ def _step_promote_build(release, ctx, log_path: Path) -> None:
|
|
|
1383
1299
|
_push_release_changes(log_path)
|
|
1384
1300
|
PackageRelease.dump_fixture()
|
|
1385
1301
|
_append_log(log_path, "Updated release fixtures")
|
|
1386
|
-
_record_release_todo(release, ctx, log_path)
|
|
1387
1302
|
except Exception:
|
|
1388
1303
|
_clean_repo()
|
|
1389
1304
|
raise
|
|
@@ -2456,6 +2371,7 @@ def todo_focus(request, pk: int):
|
|
|
2456
2371
|
"focus_auth": focus_auth,
|
|
2457
2372
|
"next_url": _get_return_url(request),
|
|
2458
2373
|
"done_url": reverse("todo-done", args=[todo.pk]),
|
|
2374
|
+
"delete_url": reverse("todo-delete", args=[todo.pk]),
|
|
2459
2375
|
"snapshot_url": reverse("todo-snapshot", args=[todo.pk]),
|
|
2460
2376
|
}
|
|
2461
2377
|
return render(request, "core/todo_focus.html", context)
|
|
@@ -2474,7 +2390,29 @@ def todo_done(request, pk: int):
|
|
|
2474
2390
|
messages.error(request, _format_condition_failure(todo, result))
|
|
2475
2391
|
return redirect(redirect_to)
|
|
2476
2392
|
todo.done_on = timezone.now()
|
|
2477
|
-
todo.
|
|
2393
|
+
todo.populate_done_metadata(request.user)
|
|
2394
|
+
todo.save(
|
|
2395
|
+
update_fields=[
|
|
2396
|
+
"done_on",
|
|
2397
|
+
"done_node",
|
|
2398
|
+
"done_version",
|
|
2399
|
+
"done_revision",
|
|
2400
|
+
"done_username",
|
|
2401
|
+
]
|
|
2402
|
+
)
|
|
2403
|
+
return redirect(redirect_to)
|
|
2404
|
+
|
|
2405
|
+
|
|
2406
|
+
@staff_member_required
|
|
2407
|
+
@require_POST
|
|
2408
|
+
def todo_delete(request, pk: int):
|
|
2409
|
+
redirect_to = reverse("admin:index")
|
|
2410
|
+
try:
|
|
2411
|
+
todo = Todo.objects.get(pk=pk, is_deleted=False)
|
|
2412
|
+
except Todo.DoesNotExist:
|
|
2413
|
+
return redirect(redirect_to)
|
|
2414
|
+
todo.is_deleted = True
|
|
2415
|
+
todo.save(update_fields=["is_deleted"])
|
|
2478
2416
|
return redirect(redirect_to)
|
|
2479
2417
|
|
|
2480
2418
|
|