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
pages/context_processors.py
CHANGED
|
@@ -2,7 +2,6 @@ from utils.sites import get_site
|
|
|
2
2
|
from django.urls import Resolver404, resolve
|
|
3
3
|
from django.conf import settings
|
|
4
4
|
from pathlib import Path
|
|
5
|
-
from types import SimpleNamespace
|
|
6
5
|
from nodes.models import Node
|
|
7
6
|
from core.models import Reference
|
|
8
7
|
from core.reference_utils import filter_visible_references
|
|
@@ -49,7 +48,6 @@ def nav_links(request):
|
|
|
49
48
|
modules = []
|
|
50
49
|
|
|
51
50
|
valid_modules = []
|
|
52
|
-
datasette_enabled = False
|
|
53
51
|
current_module = None
|
|
54
52
|
user = getattr(request, "user", None)
|
|
55
53
|
user_is_authenticated = getattr(user, "is_authenticated", False)
|
|
@@ -117,15 +115,6 @@ def nav_links(request):
|
|
|
117
115
|
):
|
|
118
116
|
current_module = module
|
|
119
117
|
|
|
120
|
-
datasette_lock = Path(settings.BASE_DIR) / "locks" / "datasette.lck"
|
|
121
|
-
if datasette_lock.exists():
|
|
122
|
-
datasette_enabled = True
|
|
123
|
-
datasette_module = SimpleNamespace(
|
|
124
|
-
menu_label="Data",
|
|
125
|
-
path="/data/",
|
|
126
|
-
enabled_landings=[SimpleNamespace(path="/data/", label="Datasette")],
|
|
127
|
-
)
|
|
128
|
-
valid_modules.append(datasette_module)
|
|
129
118
|
|
|
130
119
|
valid_modules.sort(key=lambda m: m.menu_label.lower())
|
|
131
120
|
|
|
@@ -159,5 +148,4 @@ def nav_links(request):
|
|
|
159
148
|
"nav_modules": valid_modules,
|
|
160
149
|
"favicon_url": favicon_url,
|
|
161
150
|
"header_references": header_references,
|
|
162
|
-
"datasette_enabled": datasette_enabled,
|
|
163
151
|
}
|
pages/forms.py
CHANGED
|
@@ -171,15 +171,35 @@ class UserStoryForm(forms.ModelForm):
|
|
|
171
171
|
"comments": forms.Textarea(attrs={"rows": 4, "maxlength": 400}),
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
-
def __init__(self, *args, **kwargs):
|
|
174
|
+
def __init__(self, *args, user=None, **kwargs):
|
|
175
|
+
self.user = user
|
|
175
176
|
super().__init__(*args, **kwargs)
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
177
|
+
|
|
178
|
+
if user is not None and user.is_authenticated:
|
|
179
|
+
name_field = self.fields["name"]
|
|
180
|
+
name_field.required = False
|
|
181
|
+
name_field.label = _("Username")
|
|
182
|
+
name_field.initial = (user.get_username() or "")[:40]
|
|
183
|
+
name_field.widget.attrs.update(
|
|
184
|
+
{
|
|
185
|
+
"maxlength": 40,
|
|
186
|
+
"readonly": "readonly",
|
|
187
|
+
}
|
|
188
|
+
)
|
|
189
|
+
else:
|
|
190
|
+
self.fields["name"] = forms.EmailField(
|
|
191
|
+
label=_("Email address"),
|
|
192
|
+
max_length=40,
|
|
193
|
+
required=True,
|
|
194
|
+
widget=forms.EmailInput(
|
|
195
|
+
attrs={
|
|
196
|
+
"maxlength": 40,
|
|
197
|
+
"placeholder": _("name@example.com"),
|
|
198
|
+
"autocomplete": "email",
|
|
199
|
+
"inputmode": "email",
|
|
200
|
+
}
|
|
201
|
+
),
|
|
202
|
+
)
|
|
183
203
|
self.fields["take_screenshot"].initial = True
|
|
184
204
|
self.fields["rating"].widget = forms.RadioSelect(
|
|
185
205
|
choices=[(i, str(i)) for i in range(1, 6)]
|
|
@@ -194,5 +214,8 @@ class UserStoryForm(forms.ModelForm):
|
|
|
194
214
|
return comments
|
|
195
215
|
|
|
196
216
|
def clean_name(self):
|
|
217
|
+
if self.user is not None and self.user.is_authenticated:
|
|
218
|
+
return (self.user.get_username() or "")[:40]
|
|
219
|
+
|
|
197
220
|
name = (self.cleaned_data.get("name") or "").strip()
|
|
198
221
|
return name[:40]
|
pages/models.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import base64
|
|
2
2
|
import logging
|
|
3
|
+
from datetime import timedelta
|
|
3
4
|
from pathlib import Path
|
|
4
5
|
|
|
5
6
|
from django.db import models
|
|
@@ -7,10 +8,11 @@ from django.db.models import Q
|
|
|
7
8
|
from core.entity import Entity
|
|
8
9
|
from core.models import Lead, SecurityGroup
|
|
9
10
|
from django.contrib.sites.models import Site
|
|
10
|
-
from nodes.models import NodeRole
|
|
11
|
+
from nodes.models import ContentSample, NodeRole
|
|
11
12
|
from django.apps import apps as django_apps
|
|
13
|
+
from django.utils import timezone
|
|
12
14
|
from django.utils.text import slugify
|
|
13
|
-
from django.utils.translation import gettext, gettext_lazy as _
|
|
15
|
+
from django.utils.translation import gettext, gettext_lazy as _, get_language_info
|
|
14
16
|
from importlib import import_module
|
|
15
17
|
from django.urls import URLPattern
|
|
16
18
|
from django.conf import settings
|
|
@@ -490,6 +492,14 @@ class ViewHistory(Entity):
|
|
|
490
492
|
def __str__(self) -> str: # pragma: no cover - simple representation
|
|
491
493
|
return f"{self.method} {self.path} ({self.status_code})"
|
|
492
494
|
|
|
495
|
+
@classmethod
|
|
496
|
+
def purge_older_than(cls, *, days: int) -> int:
|
|
497
|
+
"""Delete history entries recorded more than ``days`` days ago."""
|
|
498
|
+
|
|
499
|
+
cutoff = timezone.now() - timedelta(days=days)
|
|
500
|
+
deleted, _ = cls.objects.filter(visited_at__lt=cutoff).delete()
|
|
501
|
+
return deleted
|
|
502
|
+
|
|
493
503
|
|
|
494
504
|
class Favorite(Entity):
|
|
495
505
|
user = models.ForeignKey(
|
|
@@ -500,9 +510,11 @@ class Favorite(Entity):
|
|
|
500
510
|
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
|
|
501
511
|
custom_label = models.CharField(max_length=100, blank=True)
|
|
502
512
|
user_data = models.BooleanField(default=False)
|
|
513
|
+
priority = models.IntegerField(default=0)
|
|
503
514
|
|
|
504
515
|
class Meta:
|
|
505
516
|
unique_together = ("user", "content_type")
|
|
517
|
+
ordering = ["priority", "pk"]
|
|
506
518
|
|
|
507
519
|
|
|
508
520
|
class UserStory(Lead):
|
|
@@ -545,6 +557,19 @@ class UserStory(Lead):
|
|
|
545
557
|
blank=True,
|
|
546
558
|
help_text=_("Link to the GitHub issue created for this feedback."),
|
|
547
559
|
)
|
|
560
|
+
screenshot = models.ForeignKey(
|
|
561
|
+
ContentSample,
|
|
562
|
+
on_delete=models.SET_NULL,
|
|
563
|
+
blank=True,
|
|
564
|
+
null=True,
|
|
565
|
+
related_name="user_stories",
|
|
566
|
+
help_text=_("Screenshot captured for this feedback."),
|
|
567
|
+
)
|
|
568
|
+
language_code = models.CharField(
|
|
569
|
+
max_length=15,
|
|
570
|
+
blank=True,
|
|
571
|
+
help_text=_("Language selected when the feedback was submitted."),
|
|
572
|
+
)
|
|
548
573
|
|
|
549
574
|
class Meta:
|
|
550
575
|
ordering = ["-submitted_at"]
|
|
@@ -590,6 +615,21 @@ class UserStory(Lead):
|
|
|
590
615
|
f"**Screenshot requested:** {screenshot_requested}",
|
|
591
616
|
]
|
|
592
617
|
|
|
618
|
+
language_code = (self.language_code or "").strip()
|
|
619
|
+
if language_code:
|
|
620
|
+
normalized = language_code.replace("_", "-").lower()
|
|
621
|
+
try:
|
|
622
|
+
info = get_language_info(normalized)
|
|
623
|
+
except KeyError:
|
|
624
|
+
language_display = ""
|
|
625
|
+
else:
|
|
626
|
+
language_display = info.get("name_local") or info.get("name") or ""
|
|
627
|
+
|
|
628
|
+
if language_display:
|
|
629
|
+
lines.append(f"**Language:** {language_display} ({normalized})")
|
|
630
|
+
else:
|
|
631
|
+
lines.append(f"**Language:** {normalized}")
|
|
632
|
+
|
|
593
633
|
if self.submitted_at:
|
|
594
634
|
lines.append(f"**Submitted at:** {self.submitted_at.isoformat()}")
|
|
595
635
|
|