From cabd03e7e65b9640bcf5f0c1f3d64e05794e234a Mon Sep 17 00:00:00 2001 From: Herculino Trotta Date: Thu, 23 Jan 2025 11:43:35 -0300 Subject: [PATCH] feat: presets --- app/apps/common/templatetags/json.py | 11 +++++ .../0002_alter_importprofile_name_and_more.py | 23 ++++++++++ app/apps/import_app/models.py | 4 +- app/apps/import_app/services/__init__.py | 2 + app/apps/import_app/services/presets.py | 45 +++++++++++++++++++ app/apps/import_app/urls.py | 5 +++ app/apps/import_app/views.py | 26 ++++++++++- ...alter_usersettings_date_format_and_more.py | 28 ++++++++++++ .../import_app/fragments/profiles/add.html | 10 ++++- .../import_app/fragments/profiles/list.html | 25 ++++++++--- .../fragments/profiles/list_presets.html | 43 ++++++++++++++++++ .../import_app/fragments/runs/log.html | 13 ++++++ 12 files changed, 223 insertions(+), 12 deletions(-) create mode 100644 app/apps/common/templatetags/json.py create mode 100644 app/apps/import_app/migrations/0002_alter_importprofile_name_and_more.py create mode 100644 app/apps/import_app/services/presets.py create mode 100644 app/apps/users/migrations/0014_alter_usersettings_date_format_and_more.py create mode 100644 app/templates/import_app/fragments/profiles/list_presets.html create mode 100644 app/templates/import_app/fragments/runs/log.html diff --git a/app/apps/common/templatetags/json.py b/app/apps/common/templatetags/json.py new file mode 100644 index 0000000..8fb45e2 --- /dev/null +++ b/app/apps/common/templatetags/json.py @@ -0,0 +1,11 @@ +import json + +from django import template + + +register = template.Library() + + +@register.filter("json") +def convert_to_json(value): + return json.dumps(value) diff --git a/app/apps/import_app/migrations/0002_alter_importprofile_name_and_more.py b/app/apps/import_app/migrations/0002_alter_importprofile_name_and_more.py new file mode 100644 index 0000000..efa1ee3 --- /dev/null +++ b/app/apps/import_app/migrations/0002_alter_importprofile_name_and_more.py @@ -0,0 +1,23 @@ +# Generated by Django 5.1.5 on 2025-01-23 03:03 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('import_app', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='importprofile', + name='name', + field=models.CharField(max_length=100, unique=True, verbose_name='Name'), + ), + migrations.AlterField( + model_name='importprofile', + name='yaml_config', + field=models.TextField(verbose_name='YAML Configuration'), + ), + ] diff --git a/app/apps/import_app/models.py b/app/apps/import_app/models.py index b489c43..c0224d8 100644 --- a/app/apps/import_app/models.py +++ b/app/apps/import_app/models.py @@ -9,9 +9,9 @@ from apps.import_app.schemas import version_1 class ImportProfile(models.Model): class Versions(models.IntegerChoices): - VERSION_1 = 1, _("Version 1") + VERSION_1 = 1, _("Version") + " 1" - name = models.CharField(max_length=100, verbose_name=_("Name")) + name = models.CharField(max_length=100, verbose_name=_("Name"), unique=True) yaml_config = models.TextField(verbose_name=_("YAML Configuration")) version = models.IntegerField( choices=Versions, diff --git a/app/apps/import_app/services/__init__.py b/app/apps/import_app/services/__init__.py index 6001902..88aa4e8 100644 --- a/app/apps/import_app/services/__init__.py +++ b/app/apps/import_app/services/__init__.py @@ -1 +1,3 @@ from apps.import_app.services.v1 import ImportService as ImportServiceV1 + +from apps.import_app.services.presets import PresetService diff --git a/app/apps/import_app/services/presets.py b/app/apps/import_app/services/presets.py new file mode 100644 index 0000000..15e7ac1 --- /dev/null +++ b/app/apps/import_app/services/presets.py @@ -0,0 +1,45 @@ +import json +from pathlib import Path + +from apps.import_app.models import ImportProfile + + +class PresetService: + PRESET_PATH = "/usr/src/app/import_presets" + + @classmethod + def get_all_presets(cls): + presets = [] + + for folder in Path(cls.PRESET_PATH).iterdir(): + if folder.is_dir(): + manifest_path = folder / "manifest.json" + config_path = folder / "config.yml" + + if manifest_path.exists() and config_path.exists(): + with open(manifest_path) as f: + manifest = json.load(f) + + with open(config_path) as f: + config = json.dumps(f.read()) + + try: + preset = { + "name": manifest.get("name", folder.name), + "description": manifest.get("description", ""), + "message": json.dumps(manifest.get("message", "")), + "authors": manifest.get("author", "").split(","), + "schema_version": (int(manifest.get("schema_version", 1))), + "folder_name": folder.name, + "config": config, + } + + ImportProfile.Versions( + preset["schema_version"] + ) # Check if schema version is valid + except Exception as e: + print(e) + else: + presets.append(preset) + + return presets diff --git a/app/apps/import_app/urls.py b/app/apps/import_app/urls.py index beb65ba..eae9851 100644 --- a/app/apps/import_app/urls.py +++ b/app/apps/import_app/urls.py @@ -3,6 +3,11 @@ import apps.import_app.views as views urlpatterns = [ path("import/", views.import_view, name="import"), + path( + "import/presets/", + views.import_presets_list, + name="import_presets_list", + ), path( "import/profiles/", views.import_profile_index, diff --git a/app/apps/import_app/views.py b/app/apps/import_app/views.py index 6b869fd..720a5e1 100644 --- a/app/apps/import_app/views.py +++ b/app/apps/import_app/views.py @@ -13,6 +13,7 @@ from apps.common.decorators.htmx import only_htmx from apps.import_app.forms import ImportRunFileUploadForm, ImportProfileForm from apps.import_app.models import ImportRun, ImportProfile from apps.import_app.tasks import process_import +from apps.import_app.services import PresetService def import_view(request): @@ -28,6 +29,18 @@ def import_view(request): return HttpResponse("Hello, world. You're at the polls page.") +@login_required +@require_http_methods(["GET"]) +def import_presets_list(request): + presets = PresetService.get_all_presets() + print(presets) + return render( + request, + "import_app/fragments/profiles/list_presets.html", + {"presets": presets}, + ) + + @login_required @require_http_methods(["GET", "POST"]) def import_profile_index(request): @@ -54,6 +67,8 @@ def import_profile_list(request): @login_required @require_http_methods(["GET", "POST"]) def import_profile_add(request): + message = request.GET.get("message", None) or request.POST.get("message", None) + if request.method == "POST": form = ImportProfileForm(request.POST) @@ -68,12 +83,19 @@ def import_profile_add(request): }, ) else: - form = ImportProfileForm() + print(int(request.GET.get("version", 1))) + form = ImportProfileForm( + initial={ + "name": request.GET.get("name"), + "version": int(request.GET.get("version", 1)), + "yaml_config": request.GET.get("yaml_config"), + } + ) return render( request, "import_app/fragments/profiles/add.html", - {"form": form}, + {"form": form, "message": message}, ) diff --git a/app/apps/users/migrations/0014_alter_usersettings_date_format_and_more.py b/app/apps/users/migrations/0014_alter_usersettings_date_format_and_more.py new file mode 100644 index 0000000..e38b096 --- /dev/null +++ b/app/apps/users/migrations/0014_alter_usersettings_date_format_and_more.py @@ -0,0 +1,28 @@ +# Generated by Django 5.1.5 on 2025-01-23 03:05 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0013_usersettings_date_format_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='usersettings', + name='date_format', + field=models.CharField(default='SHORT_DATE_FORMAT', max_length=100, verbose_name='Date Format'), + ), + migrations.AlterField( + model_name='usersettings', + name='datetime_format', + field=models.CharField(default='SHORT_DATETIME_FORMAT', max_length=100, verbose_name='Datetime Format'), + ), + migrations.AlterField( + model_name='usersettings', + name='language', + field=models.CharField(choices=[('auto', 'Auto'), ('en', 'English'), ('nl', 'Nederlands'), ('pt-br', 'Português (Brasil)')], default='auto', max_length=10, verbose_name='Language'), + ), + ] diff --git a/app/templates/import_app/fragments/profiles/add.html b/app/templates/import_app/fragments/profiles/add.html index beda873..03eb9a5 100644 --- a/app/templates/import_app/fragments/profiles/add.html +++ b/app/templates/import_app/fragments/profiles/add.html @@ -1,11 +1,19 @@ {% extends 'extends/offcanvas.html' %} +{% load json %} {% load i18n %} {% load crispy_forms_tags %} {% block title %}{% translate 'Add new import profile' %}{% endblock %} {% block body %} -
+{% if message %} + +{% endif %} + {% crispy form %}
{% endblock %} diff --git a/app/templates/import_app/fragments/profiles/list.html b/app/templates/import_app/fragments/profiles/list.html index 2872897..cdc9a83 100644 --- a/app/templates/import_app/fragments/profiles/list.html +++ b/app/templates/import_app/fragments/profiles/list.html @@ -3,13 +3,24 @@
{% spaceless %}
{% translate 'Import Profiles' %} - - + + + +
{% endspaceless %}
diff --git a/app/templates/import_app/fragments/profiles/list_presets.html b/app/templates/import_app/fragments/profiles/list_presets.html new file mode 100644 index 0000000..0b64342 --- /dev/null +++ b/app/templates/import_app/fragments/profiles/list_presets.html @@ -0,0 +1,43 @@ +{% extends 'extends/offcanvas.html' %} +{% load i18n %} +{% load crispy_forms_tags %} + +{% block title %}{% translate 'Import Presets' %}{% endblock %} + +{% block body %} + {% if presets %} + +
+ {% for preset in presets %} + + +
+
+
+
{{ preset.name }}
+
+

{{ preset.description }}

+

{% trans 'By' %} {{ preset.authors|join:", " }}

+
+
+
+
+ {% endfor %} + {% else %} + + {% endif %} +
+{% endblock %} diff --git a/app/templates/import_app/fragments/runs/log.html b/app/templates/import_app/fragments/runs/log.html new file mode 100644 index 0000000..a7445a4 --- /dev/null +++ b/app/templates/import_app/fragments/runs/log.html @@ -0,0 +1,13 @@ +{% extends 'extends/offcanvas.html' %} +{% load i18n %} +{% load crispy_forms_tags %} + +{% block title %}{% translate 'Logs for' %} #{{ run.id }}{% endblock %} + +{% block body %} +
+
+ {{ run.logs|linebreaks }} +
+
+{% endblock %}