arthexis 0.1.3__tar.gz → 0.1.5__tar.gz
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.3 → arthexis-0.1.5}/PKG-INFO +2 -2
- {arthexis-0.1.3 → arthexis-0.1.5}/README.md +1 -1
- {arthexis-0.1.3 → arthexis-0.1.5}/arthexis.egg-info/PKG-INFO +2 -2
- {arthexis-0.1.3 → arthexis-0.1.5}/core/admin.py +23 -9
- {arthexis-0.1.3 → arthexis-0.1.5}/core/models.py +4 -3
- {arthexis-0.1.3 → arthexis-0.1.5}/core/views.py +14 -1
- {arthexis-0.1.3 → arthexis-0.1.5}/pages/tests.py +23 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/pages/views.py +2 -1
- {arthexis-0.1.3 → arthexis-0.1.5}/pyproject.toml +1 -1
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_package_release_admin_actions.py +19 -6
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_release_fixture_cleanup.py +5 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_release_progress.py +52 -1
- {arthexis-0.1.3 → arthexis-0.1.5}/LICENSE +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/arthexis.egg-info/SOURCES.txt +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/arthexis.egg-info/dependency_links.txt +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/arthexis.egg-info/requires.txt +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/arthexis.egg-info/top_level.txt +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/config/__init__.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/config/active_app.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/config/asgi.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/config/auth_app.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/config/celery.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/config/context_processors.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/config/loadenv.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/config/logging.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/config/middleware.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/config/offline.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/config/settings.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/config/urls.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/config/wsgi.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/core/__init__.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/core/apps.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/core/backends.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/core/entity.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/core/environment.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/core/fields.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/core/lcd_screen.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/core/middleware.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/core/notifications.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/core/release.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/core/system.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/core/tasks.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/core/tests.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/core/urls.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/core/user_data.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/nodes/__init__.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/nodes/actions.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/nodes/admin.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/nodes/apps.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/nodes/lcd.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/nodes/models.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/nodes/tasks.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/nodes/tests.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/nodes/urls.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/nodes/utils.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/nodes/views.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/ocpp/__init__.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/ocpp/admin.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/ocpp/apps.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/ocpp/consumers.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/ocpp/evcs.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/ocpp/models.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/ocpp/routing.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/ocpp/simulator.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/ocpp/store.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/ocpp/tasks.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/ocpp/test_export_import.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/ocpp/test_rfid.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/ocpp/tests.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/ocpp/transactions_io.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/ocpp/urls.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/ocpp/views.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/pages/__init__.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/pages/admin.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/pages/apps.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/pages/checks.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/pages/context_processors.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/pages/models.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/pages/urls.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/pages/utils.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/setup.cfg +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_acronym_capitalization.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_admin_history.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_admin_index_actions.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_awg_admin.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_csrf_failure.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_csrf_origin_subnet.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_email_collector.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_email_inbox.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_email_inbox_admin.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_email_inbox_search_action.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_env_refresh_clean.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_env_refresh_unlink.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_footer_admin_link.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_footer_no_references.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_footer_presence.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_footer_render.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_github_token.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_install_script.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_language_switch.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_lcd_smbus2.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_localhost_admin_backend.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_model_verbose_name_capitalization.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_notifications_fallback.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_notify_command.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_odoo_profile.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_odoo_profile_admin.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_offline.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_pypi_token.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_readme_language.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_reference_qr_code.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_reference_transaction_uuid.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_register_site_apps_command.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_release_logs.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_release_mapping.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_release_tasks.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_rfid_admin_reference_clear.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_rfid_admin_scan_csrf.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_rfid_background_reader.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_save_as_copy.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_seed_data.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_sigil_resolution.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_urls_autodiscover.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_user_datum_admin.py +0 -0
- {arthexis-0.1.3 → arthexis-0.1.5}/tests/test_vscode_manage.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: arthexis
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.5
|
|
4
4
|
Summary: Django-based MESH system
|
|
5
5
|
Author-email: "Rafael J. Guillén-Osorio" <tecnologia@gelectriic.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -118,7 +118,7 @@ Arthexis Constellation is a narrative-driven Django-based suite that centralizes
|
|
|
118
118
|
- Single codebase with special features per role
|
|
119
119
|
|
|
120
120
|
## Support
|
|
121
|
-
You may contact us at tecnologia at gelectriic dot com or visit our web page
|
|
121
|
+
You may contact us at tecnologia at gelectriic dot com or visit our [web page](https://www.gelectriic.com/) for professional services and commercial support.
|
|
122
122
|
|
|
123
123
|
## About Me
|
|
124
124
|
> "What? You want to know about me too? Well, I enjoy developing software, roleplaying games, long walks on the beach and a fourth secret thing."
|
|
@@ -10,7 +10,7 @@ Arthexis Constellation is a narrative-driven Django-based suite that centralizes
|
|
|
10
10
|
- Single codebase with special features per role
|
|
11
11
|
|
|
12
12
|
## Support
|
|
13
|
-
You may contact us at tecnologia at gelectriic dot com or visit our web page
|
|
13
|
+
You may contact us at tecnologia at gelectriic dot com or visit our [web page](https://www.gelectriic.com/) for professional services and commercial support.
|
|
14
14
|
|
|
15
15
|
## About Me
|
|
16
16
|
> "What? You want to know about me too? Well, I enjoy developing software, roleplaying games, long walks on the beach and a fourth secret thing."
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: arthexis
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.5
|
|
4
4
|
Summary: Django-based MESH system
|
|
5
5
|
Author-email: "Rafael J. Guillén-Osorio" <tecnologia@gelectriic.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -118,7 +118,7 @@ Arthexis Constellation is a narrative-driven Django-based suite that centralizes
|
|
|
118
118
|
- Single codebase with special features per role
|
|
119
119
|
|
|
120
120
|
## Support
|
|
121
|
-
You may contact us at tecnologia at gelectriic dot com or visit our web page
|
|
121
|
+
You may contact us at tecnologia at gelectriic dot com or visit our [web page](https://www.gelectriic.com/) for professional services and commercial support.
|
|
122
122
|
|
|
123
123
|
## About Me
|
|
124
124
|
> "What? You want to know about me too? Well, I enjoy developing software, roleplaying games, long walks on the beach and a fourth secret thing."
|
|
@@ -3,7 +3,7 @@ from django.contrib import admin
|
|
|
3
3
|
from django.contrib.admin.widgets import RelatedFieldWidgetWrapper
|
|
4
4
|
from django.urls import path, reverse
|
|
5
5
|
from django.shortcuts import redirect, render
|
|
6
|
-
from django.http import JsonResponse
|
|
6
|
+
from django.http import JsonResponse, HttpResponseBase
|
|
7
7
|
from django.template.response import TemplateResponse
|
|
8
8
|
from django.views.decorators.csrf import csrf_exempt
|
|
9
9
|
from django.core.exceptions import ValidationError
|
|
@@ -17,6 +17,7 @@ from import_export import resources, fields
|
|
|
17
17
|
from import_export.admin import ImportExportModelAdmin
|
|
18
18
|
from import_export.widgets import ForeignKeyWidget
|
|
19
19
|
from django.contrib.auth.models import Group
|
|
20
|
+
from django.templatetags.static import static
|
|
20
21
|
from django.utils.html import format_html
|
|
21
22
|
import json
|
|
22
23
|
import uuid
|
|
@@ -49,6 +50,19 @@ from .user_data import UserDatumAdminMixin
|
|
|
49
50
|
admin.site.unregister(Group)
|
|
50
51
|
|
|
51
52
|
|
|
53
|
+
class SaveBeforeChangeAction(DjangoObjectActions):
|
|
54
|
+
def response_change(self, request, obj):
|
|
55
|
+
action = request.POST.get("_action")
|
|
56
|
+
if action:
|
|
57
|
+
allowed = self.get_change_actions(request, str(obj.pk), None)
|
|
58
|
+
if action in allowed and hasattr(self, action):
|
|
59
|
+
response = getattr(self, action)(request, obj)
|
|
60
|
+
if isinstance(response, HttpResponseBase):
|
|
61
|
+
return response
|
|
62
|
+
return redirect(request.path)
|
|
63
|
+
return super().response_change(request, obj)
|
|
64
|
+
|
|
65
|
+
|
|
52
66
|
@admin.register(Reference)
|
|
53
67
|
class ReferenceAdmin(admin.ModelAdmin):
|
|
54
68
|
list_display = (
|
|
@@ -131,7 +145,7 @@ class ReleaseManagerAdmin(admin.ModelAdmin):
|
|
|
131
145
|
|
|
132
146
|
|
|
133
147
|
@admin.register(Package)
|
|
134
|
-
class PackageAdmin(
|
|
148
|
+
class PackageAdmin(SaveBeforeChangeAction, admin.ModelAdmin):
|
|
135
149
|
list_display = ("name", "description", "homepage_url", "release_manager")
|
|
136
150
|
actions = ["prepare_next_release"]
|
|
137
151
|
change_actions = ["prepare_next_release_action"]
|
|
@@ -755,7 +769,7 @@ class RFIDAdmin(ImportExportModelAdmin):
|
|
|
755
769
|
|
|
756
770
|
|
|
757
771
|
@admin.register(PackageRelease)
|
|
758
|
-
class PackageReleaseAdmin(
|
|
772
|
+
class PackageReleaseAdmin(SaveBeforeChangeAction, admin.ModelAdmin):
|
|
759
773
|
list_display = (
|
|
760
774
|
"version",
|
|
761
775
|
"package",
|
|
@@ -808,18 +822,18 @@ class PackageReleaseAdmin(DjangoObjectActions, admin.ModelAdmin):
|
|
|
808
822
|
publish_release_action.short_description = "Publish this release"
|
|
809
823
|
|
|
810
824
|
@staticmethod
|
|
811
|
-
def
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
)
|
|
825
|
+
def _boolean_icon(value: bool) -> str:
|
|
826
|
+
icon = static("admin/img/icon-yes.svg" if value else "admin/img/icon-no.svg")
|
|
827
|
+
alt = "True" if value else "False"
|
|
828
|
+
return format_html('<img src="{}" alt="{}">', icon, alt)
|
|
815
829
|
|
|
816
830
|
@admin.display(description="Published")
|
|
817
831
|
def published_status(self, obj):
|
|
818
|
-
return self.
|
|
832
|
+
return self._boolean_icon(obj.is_published)
|
|
819
833
|
|
|
820
834
|
@admin.display(description="Is current")
|
|
821
835
|
def is_current(self, obj):
|
|
822
|
-
return self.
|
|
836
|
+
return self._boolean_icon(obj.is_current)
|
|
823
837
|
|
|
824
838
|
def pr_link(self, obj):
|
|
825
839
|
if obj.pr_url:
|
|
@@ -10,7 +10,7 @@ from django.utils.translation import gettext_lazy as _
|
|
|
10
10
|
from django.core.validators import RegexValidator
|
|
11
11
|
from django.core.exceptions import ValidationError
|
|
12
12
|
from django.apps import apps
|
|
13
|
-
from django.db.models.signals import m2m_changed, post_delete
|
|
13
|
+
from django.db.models.signals import m2m_changed, post_delete, post_save
|
|
14
14
|
from django.dispatch import receiver
|
|
15
15
|
from datetime import timedelta
|
|
16
16
|
from django.contrib.contenttypes.models import ContentType
|
|
@@ -1257,8 +1257,9 @@ class PackageRelease(Entity):
|
|
|
1257
1257
|
return self.revision[-6:] if self.revision else ""
|
|
1258
1258
|
|
|
1259
1259
|
|
|
1260
|
-
@receiver(post_delete, sender=PackageRelease)
|
|
1261
|
-
def
|
|
1260
|
+
@receiver([post_save, post_delete], sender=PackageRelease)
|
|
1261
|
+
def _update_release_fixture(sender, instance, **kwargs) -> None:
|
|
1262
|
+
"""Keep the release fixture in sync with the database."""
|
|
1262
1263
|
PackageRelease.dump_fixture()
|
|
1263
1264
|
|
|
1264
1265
|
# Ensure each RFID can only be linked to one energy account
|
|
@@ -43,6 +43,16 @@ def _changelog_notes(version: str) -> str:
|
|
|
43
43
|
|
|
44
44
|
def _step_check_pypi(release, ctx, log_path: Path) -> None:
|
|
45
45
|
from . import release as release_utils
|
|
46
|
+
from packaging.version import Version
|
|
47
|
+
|
|
48
|
+
version_path = Path("VERSION")
|
|
49
|
+
if version_path.exists():
|
|
50
|
+
current = version_path.read_text(encoding="utf-8").strip()
|
|
51
|
+
if current and Version(release.version) < Version(current):
|
|
52
|
+
raise Exception(
|
|
53
|
+
f"Version {release.version} is older than existing {current}"
|
|
54
|
+
)
|
|
55
|
+
version_path.write_text(release.version + "\n", encoding="utf-8")
|
|
46
56
|
|
|
47
57
|
_append_log(log_path, f"Checking if version {release.version} exists on PyPI")
|
|
48
58
|
if release_utils.network_available():
|
|
@@ -389,7 +399,10 @@ def release_progress(request, pk: int, action: str):
|
|
|
389
399
|
identifier = f"{release.package.name}-{release.version}"
|
|
390
400
|
if release.revision:
|
|
391
401
|
identifier = f"{identifier}-{release.revision[:7]}"
|
|
392
|
-
log_name =
|
|
402
|
+
log_name = f"{identifier}.log"
|
|
403
|
+
if ctx.get("log") != log_name:
|
|
404
|
+
ctx = {"step": 0, "log": log_name}
|
|
405
|
+
step_count = 0
|
|
393
406
|
log_path = Path("logs") / log_name
|
|
394
407
|
ctx.setdefault("log", log_name)
|
|
395
408
|
|
|
@@ -9,6 +9,7 @@ from pages.models import Application, Module, SiteBadge, Favorite
|
|
|
9
9
|
from core.user_data import UserDatum
|
|
10
10
|
from pages.admin import ApplicationAdmin
|
|
11
11
|
from django.apps import apps as django_apps
|
|
12
|
+
from core.models import AdminHistory
|
|
12
13
|
from django.core.files.uploadedfile import SimpleUploadedFile
|
|
13
14
|
import base64
|
|
14
15
|
import tempfile
|
|
@@ -86,6 +87,13 @@ class InvitationTests(TestCase):
|
|
|
86
87
|
resp = self.client.get(reverse("pages:request-invite"))
|
|
87
88
|
self.assertIn("csrftoken", resp.cookies)
|
|
88
89
|
|
|
90
|
+
def test_request_invite_allows_post_without_csrf(self):
|
|
91
|
+
client = Client(enforce_csrf_checks=True)
|
|
92
|
+
resp = client.post(
|
|
93
|
+
reverse("pages:request-invite"), {"email": "invite@example.com"}
|
|
94
|
+
)
|
|
95
|
+
self.assertEqual(resp.status_code, 200)
|
|
96
|
+
|
|
89
97
|
def test_invitation_flow(self):
|
|
90
98
|
resp = self.client.post(
|
|
91
99
|
reverse("pages:request-invite"), {"email": "invite@example.com"}
|
|
@@ -626,3 +634,18 @@ class FavoriteTests(TestCase):
|
|
|
626
634
|
resp = self.client.get(reverse("admin:index"))
|
|
627
635
|
self.assertContains(resp, reverse("admin:pages_application_changelist"))
|
|
628
636
|
self.assertContains(resp, reverse("admin:nodes_noderole_changelist"))
|
|
637
|
+
|
|
638
|
+
def test_dashboard_merges_duplicate_future_actions(self):
|
|
639
|
+
ct = ContentType.objects.get_for_model(NodeRole)
|
|
640
|
+
Favorite.objects.create(user=self.user, content_type=ct)
|
|
641
|
+
role = NodeRole.objects.create(name="DataRole2")
|
|
642
|
+
UserDatum.objects.create(user=self.user, content_type=ct, object_id=role.pk)
|
|
643
|
+
AdminHistory.objects.create(
|
|
644
|
+
user=self.user,
|
|
645
|
+
content_type=ct,
|
|
646
|
+
url=reverse("admin:nodes_noderole_changelist"),
|
|
647
|
+
)
|
|
648
|
+
resp = self.client.get(reverse("admin:index"))
|
|
649
|
+
url = reverse("admin:nodes_noderole_changelist")
|
|
650
|
+
self.assertEqual(resp.content.decode().count(url), 1)
|
|
651
|
+
self.assertContains(resp, NodeRole._meta.verbose_name_plural)
|
|
@@ -16,7 +16,7 @@ from django.utils.encoding import force_bytes, force_str
|
|
|
16
16
|
from django.utils.http import urlsafe_base64_decode, urlsafe_base64_encode
|
|
17
17
|
from django.core.mail import send_mail
|
|
18
18
|
from django.utils.translation import gettext as _
|
|
19
|
-
from django.views.decorators.csrf import ensure_csrf_cookie
|
|
19
|
+
from django.views.decorators.csrf import csrf_exempt, ensure_csrf_cookie
|
|
20
20
|
|
|
21
21
|
import markdown
|
|
22
22
|
from pages.utils import landing
|
|
@@ -116,6 +116,7 @@ login_view = CustomLoginView.as_view()
|
|
|
116
116
|
class InvitationRequestForm(forms.Form):
|
|
117
117
|
email = forms.EmailField()
|
|
118
118
|
|
|
119
|
+
@csrf_exempt
|
|
119
120
|
@ensure_csrf_cookie
|
|
120
121
|
def request_invite(request):
|
|
121
122
|
form = InvitationRequestForm(request.POST if request.method == "POST" else None)
|
|
@@ -28,12 +28,10 @@ class PackageReleaseAdminActionsTests(TestCase):
|
|
|
28
28
|
|
|
29
29
|
def test_change_page_contains_publish_action(self):
|
|
30
30
|
change_url = reverse("admin:core_packagerelease_change", args=[self.release.pk])
|
|
31
|
-
action_url = reverse(
|
|
32
|
-
"admin:core_packagerelease_actions",
|
|
33
|
-
args=[self.release.pk, "publish_release_action"],
|
|
34
|
-
)
|
|
35
31
|
resp = self.client.get(change_url)
|
|
36
|
-
self.assertContains(
|
|
32
|
+
self.assertContains(
|
|
33
|
+
resp, 'name="_action" value="publish_release_action"'
|
|
34
|
+
)
|
|
37
35
|
|
|
38
36
|
def test_publish_action_redirects(self):
|
|
39
37
|
url = reverse(
|
|
@@ -45,6 +43,21 @@ class PackageReleaseAdminActionsTests(TestCase):
|
|
|
45
43
|
resp, reverse("release-progress", args=[self.release.pk, "publish"])
|
|
46
44
|
)
|
|
47
45
|
|
|
46
|
+
def test_publish_action_saves_changes_before_execution(self):
|
|
47
|
+
change_url = reverse("admin:core_packagerelease_change", args=[self.release.pk])
|
|
48
|
+
data = {
|
|
49
|
+
"package": self.package.pk,
|
|
50
|
+
"release_manager": "",
|
|
51
|
+
"version": "1.0.1",
|
|
52
|
+
"_action": "publish_release_action",
|
|
53
|
+
}
|
|
54
|
+
resp = self.client.post(change_url, data)
|
|
55
|
+
self.assertRedirects(
|
|
56
|
+
resp, reverse("release-progress", args=[self.release.pk, "publish"])
|
|
57
|
+
)
|
|
58
|
+
self.release.refresh_from_db()
|
|
59
|
+
self.assertEqual(self.release.version, "1.0.1")
|
|
60
|
+
|
|
48
61
|
def test_change_page_pypi_url_readonly(self):
|
|
49
62
|
change_url = reverse("admin:core_packagerelease_change", args=[self.release.pk])
|
|
50
63
|
resp = self.client.get(change_url)
|
|
@@ -77,7 +90,7 @@ class PackageReleaseAdminActionsTests(TestCase):
|
|
|
77
90
|
resp = self.client.get(list_url)
|
|
78
91
|
content = resp.content.decode()
|
|
79
92
|
self.assertIn("Is current", content)
|
|
80
|
-
self.assertIn('
|
|
93
|
+
self.assertIn('icon-yes.svg', content)
|
|
81
94
|
|
|
82
95
|
def test_release_revision_defaults_to_repo_revision(self):
|
|
83
96
|
expected = revision_utils.get_revision()
|
|
@@ -30,3 +30,8 @@ class ReleaseFixtureCleanupTests(TestCase):
|
|
|
30
30
|
data = self.fixture_path.read_text()
|
|
31
31
|
self.assertNotIn("1.0.0", data)
|
|
32
32
|
|
|
33
|
+
def test_create_updates_fixture(self):
|
|
34
|
+
PackageRelease.objects.create(package=self.package, version="2.0.0")
|
|
35
|
+
data = self.fixture_path.read_text()
|
|
36
|
+
self.assertIn("2.0.0", data)
|
|
37
|
+
|
|
@@ -62,7 +62,12 @@ class ReleaseProgressTests(TestCase):
|
|
|
62
62
|
self.assertContains(resp, "All steps completed")
|
|
63
63
|
self.assertContains(
|
|
64
64
|
resp,
|
|
65
|
-
'<a href="http://example.com/pr/1" target="_blank">http://example.com/pr/1</a>',
|
|
65
|
+
'<a href="http://example.com/pr/1" target="_blank" rel="noopener">http://example.com/pr/1</a>',
|
|
66
|
+
html=True,
|
|
67
|
+
)
|
|
68
|
+
self.assertContains(
|
|
69
|
+
resp,
|
|
70
|
+
'<a href="https://pypi.org/project/pkg/1.0.0/" target="_blank" rel="noopener">https://pypi.org/project/pkg/1.0.0/</a>',
|
|
66
71
|
html=True,
|
|
67
72
|
)
|
|
68
73
|
release.refresh_from_db()
|
|
@@ -94,6 +99,11 @@ class ReleaseProgressTests(TestCase):
|
|
|
94
99
|
self.assertEqual(resp.status_code, 200)
|
|
95
100
|
self.assertContains(resp, "All steps completed")
|
|
96
101
|
self.assertIsNone(resp.context["pr_url"])
|
|
102
|
+
self.assertContains(
|
|
103
|
+
resp,
|
|
104
|
+
'<a href="https://pypi.org/project/pkg/1.1.0/" target="_blank" rel="noopener">https://pypi.org/project/pkg/1.1.0/</a>',
|
|
105
|
+
html=True,
|
|
106
|
+
)
|
|
97
107
|
release.refresh_from_db()
|
|
98
108
|
self.assertTrue(release.is_published)
|
|
99
109
|
pub.assert_called_once()
|
|
@@ -112,3 +122,44 @@ class ReleaseProgressTests(TestCase):
|
|
|
112
122
|
self.assertContains(resp, f'<a href="{app_url}">Business Models</a>')
|
|
113
123
|
list_url = reverse("admin:core_packagerelease_changelist")
|
|
114
124
|
self.assertContains(resp, f'<a href="{list_url}">Package Releases</a>')
|
|
125
|
+
|
|
126
|
+
def test_check_step_writes_version_file(self):
|
|
127
|
+
release = PackageRelease.objects.create(package=self.package, version="2.0.0")
|
|
128
|
+
url = reverse("release-progress", args=[release.pk, "publish"])
|
|
129
|
+
self.client.get(url)
|
|
130
|
+
with patch("core.views.release_utils.network_available", return_value=False):
|
|
131
|
+
resp = self.client.get(f"{url}?step=0")
|
|
132
|
+
self.assertEqual(resp.status_code, 200)
|
|
133
|
+
self.assertEqual(self.version_path.read_text().strip(), "2.0.0")
|
|
134
|
+
|
|
135
|
+
def test_check_step_fails_when_version_goes_backwards(self):
|
|
136
|
+
self.version_path.write_text("3.0.0\n")
|
|
137
|
+
release = PackageRelease.objects.create(package=self.package, version="2.0.0")
|
|
138
|
+
url = reverse("release-progress", args=[release.pk, "publish"])
|
|
139
|
+
self.client.get(url)
|
|
140
|
+
with patch("core.views.release_utils.network_available", return_value=False):
|
|
141
|
+
resp = self.client.get(f"{url}?step=0")
|
|
142
|
+
self.assertEqual(resp.context["error"], "Version 2.0.0 is older than existing 3.0.0")
|
|
143
|
+
self.assertEqual(self.version_path.read_text().strip(), "3.0.0")
|
|
144
|
+
|
|
145
|
+
def test_session_resets_when_version_changes(self):
|
|
146
|
+
release = PackageRelease.objects.create(package=self.package, version="1.2.0")
|
|
147
|
+
url = reverse("release-progress", args=[release.pk, "publish"])
|
|
148
|
+
self.client.get(url)
|
|
149
|
+
with patch("core.views.release_utils.network_available", return_value=False):
|
|
150
|
+
self.client.get(f"{url}?step=0")
|
|
151
|
+
|
|
152
|
+
release.version = "1.3.0"
|
|
153
|
+
release.save()
|
|
154
|
+
|
|
155
|
+
resp = self.client.get(url)
|
|
156
|
+
expected_log = f"logs/pkg-1.3.0-{release.revision[:7]}.log"
|
|
157
|
+
self.assertEqual(resp.context["log_path"], expected_log)
|
|
158
|
+
self.assertEqual(resp.context["current_step"], 0)
|
|
159
|
+
|
|
160
|
+
with patch("core.views.release_utils.network_available", return_value=False):
|
|
161
|
+
self.client.get(f"{url}?step=0")
|
|
162
|
+
|
|
163
|
+
log_content = Path(expected_log).read_text()
|
|
164
|
+
self.assertIn("Checking if version 1.3.0 exists on PyPI", log_content)
|
|
165
|
+
self.assertNotIn("1.2.0", log_content)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|