Skip to content

Commit c6349bb

Browse files
committed
Merge branch 'Rossi-Luciano-implement_sps_package_validation'
2 parents 1b61794 + 423bc91 commit c6349bb

21 files changed

Lines changed: 1230 additions & 112 deletions

config/settings/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@
247247
# This can be omitted to allow all files, but note that this may present a security risk
248248
# if untrusted users are allowed to upload files -
249249
# see https://docs.wagtail.org/en/stable/advanced_topics/deploying.html#user-uploaded-files
250-
WAGTAILDOCS_EXTENSIONS = ['csv', 'docx', 'key', 'odt', 'pdf', 'pptx', 'rtf', 'txt', 'xlsx', 'zip']
250+
WAGTAILDOCS_EXTENSIONS = ['csv', 'docx', 'json', 'key', 'odt', 'pdf', 'pptx', 'rtf', 'txt', 'xlsx', 'zip']
251251

252252
# https://docs.djangoproject.com/en/dev/ref/settings/#auth-user-model
253253
AUTH_USER_MODEL = 'users.CustomUser'

config/settings/test.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import tempfile
2+
3+
from .base import *
4+
5+
DEBUG = False
6+
TEMPLATE_DEBUG = False
7+
SECRET_KEY = "test-secret-key-not-for-production"
8+
ALLOWED_HOSTS = ["localhost", "127.0.0.1", "testserver"]
9+
WAGTAILADMIN_BASE_URL = "http://testserver"
10+
11+
PASSWORD_HASHERS = [
12+
"django.contrib.auth.hashers.MD5PasswordHasher",
13+
]
14+
15+
EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend"
16+
17+
CACHES = {
18+
"default": {
19+
"BACKEND": "django.core.cache.backends.locmem.LocMemCache",
20+
}
21+
}
22+
23+
CELERY_TASK_ALWAYS_EAGER = True
24+
CELERY_TASK_EAGER_PROPAGATES = True
25+
26+
COMPRESS_ENABLED = False
27+
28+
MEDIA_ROOT = tempfile.mkdtemp(prefix="markapi_test_media_")
29+
30+
LLAMA_ENABLED = False

conftest.py

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

requirements/local.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ watchgod==0.8.2 # https://github.com/samuelcolvin/watchgod
88
django-extensions==3.2.3 # https://github.com/django-extensions/django-extensions
99
django-debug-toolbar # https://github.com/jazzband/django-debug-toolbar
1010

11-
pytest==8.3.5
11+
pytest==9.0.3
1212
pytest-django==4.11.1
13-
pytest-cov==6.1.1
14-
coverage==7.8.0
13+
pytest-cov==7.1.0
14+
coverage==7.10.6
1515
django-coverage-plugin==3.1.0

requirements/production.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
-r base.txt
44

55
gevent==24.2.1 # http://www.gevent.org/
6-
gunicorn==21.2.0 # https://github.com/benoitc/gunicorn
6+
gunicorn==26.0.0
77
psycopg2-binary==2.9.9 # https://github.com/psycopg/psycopg2
8-
sentry-sdk[django]==2.5.1 # https://github.com/getsentry/sentry-python
8+
sentry-sdk[django]==2.60.0
99

1010
# Django
1111
# ------------------------------------------------------------------------------

setup.cfg

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ django_settings_module = config.settings.test
3333
# Django migrations should not produce any errors:
3434
ignore_errors = True
3535

36+
[tool:pytest]
37+
DJANGO_SETTINGS_MODULE = config.settings.test
38+
3639
[coverage:run]
3740
include =
3841
users/*

xml_manager/apps.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,8 @@
22

33

44
class XmlManagerConfig(AppConfig):
5-
default_auto_field = 'django.db.models.BigAutoField'
6-
name = 'xml_manager'
5+
default_auto_field = "django.db.models.BigAutoField"
6+
name = "xml_manager"
7+
8+
def ready(self):
9+
import xml_manager.signals # noqa: F401

xml_manager/exceptions.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,6 @@ class XML_File_PDF_Generation_Error(Exception):
1212

1313
class XML_File_HTML_Generation_Error(Exception):
1414
pass
15+
16+
class SPS_Package_Validation_Error(Exception):
17+
pass

xml_manager/forms.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import os
2+
3+
from django import forms
4+
from django.core.exceptions import ValidationError
5+
from django.utils.translation import gettext_lazy as _
6+
from wagtail.admin.forms import WagtailAdminModelForm
7+
8+
from xml_manager.models import SPSPackageValidation
9+
10+
11+
class SPSPackageValidationForm(WagtailAdminModelForm):
12+
zip_upload = forms.FileField(
13+
label=_("SPS package (.zip)"),
14+
required=False,
15+
help_text=_(
16+
"On edit, leave empty to revalidate the current package without "
17+
"replacing the file."
18+
),
19+
)
20+
21+
class Meta:
22+
model = SPSPackageValidation
23+
fields = []
24+
25+
def clean_zip_upload(self):
26+
zip_upload = self.cleaned_data.get("zip_upload")
27+
if not zip_upload:
28+
return zip_upload
29+
if not zip_upload.name.lower().endswith(".zip"):
30+
raise ValidationError(_("Only .zip files are allowed."))
31+
if zip_upload.size == 0:
32+
raise ValidationError(_("The file is empty."))
33+
return zip_upload
34+
35+
def clean(self):
36+
cleaned = super().clean()
37+
if not self.instance.pk and not cleaned.get("zip_upload"):
38+
raise ValidationError(_("A .zip file is required."))
39+
return cleaned
40+
41+
@staticmethod
42+
def save_wagtail_document(zip_upload):
43+
from wagtail.documents.models import Document
44+
45+
document = Document(title=os.path.basename(zip_upload.name))
46+
document.file.save(zip_upload.name, zip_upload, save=True)
47+
return document
48+
49+
@staticmethod
50+
def save_wagtail_document_from_path(file_path, title=None):
51+
from django.core.files import File
52+
from wagtail.documents.models import Document
53+
54+
basename = os.path.basename(file_path)
55+
document_title = title or basename
56+
with open(file_path, "rb") as fp:
57+
document = Document(title=document_title)
58+
document.file.save(basename, File(fp), save=True)
59+
return document
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import django.db.models.deletion
2+
from django.conf import settings
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
("wagtaildocs", "0014_alter_document_file_size"),
10+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
11+
("xml_manager", "0003_xmldocumentpdf_docx_file"),
12+
]
13+
14+
operations = [
15+
migrations.CreateModel(
16+
name="SPSPackageValidation",
17+
fields=[
18+
(
19+
"id",
20+
models.BigAutoField(
21+
auto_created=True,
22+
primary_key=True,
23+
serialize=False,
24+
verbose_name="ID",
25+
),
26+
),
27+
(
28+
"zip_size_bytes",
29+
models.PositiveBigIntegerField(
30+
default=0, verbose_name="ZIP size (bytes)"
31+
),
32+
),
33+
(
34+
"validated_at",
35+
models.DateTimeField(
36+
blank=True, null=True, verbose_name="Validated at"
37+
),
38+
),
39+
(
40+
"status",
41+
models.CharField(
42+
choices=[
43+
("pending", "Pending"),
44+
("running", "Running"),
45+
("done", "Done"),
46+
("error", "Error"),
47+
],
48+
default="pending",
49+
max_length=16,
50+
verbose_name="Status",
51+
),
52+
),
53+
(
54+
"error_message",
55+
models.TextField(blank=True, verbose_name="Error message"),
56+
),
57+
(
58+
"exceptions_document",
59+
models.ForeignKey(
60+
blank=True,
61+
null=True,
62+
on_delete=django.db.models.deletion.SET_NULL,
63+
related_name="+",
64+
to="wagtaildocs.document",
65+
verbose_name="Exceptions file",
66+
),
67+
),
68+
(
69+
"package_document",
70+
models.OneToOneField(
71+
on_delete=django.db.models.deletion.CASCADE,
72+
related_name="sps_validation",
73+
to="wagtaildocs.document",
74+
verbose_name="SPS package document",
75+
),
76+
),
77+
(
78+
"validated_by",
79+
models.ForeignKey(
80+
blank=True,
81+
null=True,
82+
on_delete=django.db.models.deletion.SET_NULL,
83+
related_name="sps_package_validations",
84+
to=settings.AUTH_USER_MODEL,
85+
verbose_name="Validated by",
86+
),
87+
),
88+
(
89+
"validation_document",
90+
models.ForeignKey(
91+
blank=True,
92+
null=True,
93+
on_delete=django.db.models.deletion.SET_NULL,
94+
related_name="+",
95+
to="wagtaildocs.document",
96+
verbose_name="Validation file",
97+
),
98+
),
99+
],
100+
options={
101+
"verbose_name": "SPS package validation",
102+
"verbose_name_plural": "SPS package validations",
103+
},
104+
),
105+
]

0 commit comments

Comments
 (0)