From 3af5d96bf558ee1b9469c40ab8238b42334d3a32 Mon Sep 17 00:00:00 2001 From: Sli Date: Sun, 13 Oct 2024 23:26:18 +0200 Subject: [PATCH] Introduce htmx in sith files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Convert FileModerationView into ListView and add pagination with htmx * Don't allow sas moderation in file moderation view * Split up base.jinja and introduce base_fragment.jinja * Improve FileModerationView performances and make it root only * Add permissions tests for file modération --- core/static/webpack/htmx-index.js | 1 + core/templates/core/base.jinja | 250 +++--------------- core/templates/core/base/header.jinja | 136 ++++++++++ core/templates/core/base/menu.jinja | 48 ++++ core/templates/core/base/tabs.jinja | 9 + core/templates/core/base_fragment.jinja | 20 ++ core/templates/core/file.jinja | 11 +- core/templates/core/file_delete_confirm.jinja | 44 ++- core/templates/core/file_moderation.jinja | 35 ++- core/templates/core/macros.jinja | 57 +++- core/templates/core/user_edit.jinja | 2 +- core/tests/test_files.py | 24 ++ core/views/__init__.py | 6 + core/views/files.py | 28 +- package-lock.json | 6 + package.json | 1 + 16 files changed, 429 insertions(+), 249 deletions(-) create mode 100644 core/static/webpack/htmx-index.js create mode 100644 core/templates/core/base/header.jinja create mode 100644 core/templates/core/base/menu.jinja create mode 100644 core/templates/core/base/tabs.jinja create mode 100644 core/templates/core/base_fragment.jinja diff --git a/core/static/webpack/htmx-index.js b/core/static/webpack/htmx-index.js new file mode 100644 index 00000000..a97ebfef --- /dev/null +++ b/core/static/webpack/htmx-index.js @@ -0,0 +1 @@ +window.htmx = require("htmx.org"); diff --git a/core/templates/core/base.jinja b/core/templates/core/base.jinja index 3849bb87..9736f438 100644 --- a/core/templates/core/base.jinja +++ b/core/templates/core/base.jinja @@ -5,7 +5,6 @@ {% block title %}{% trans %}Welcome!{% endtrans %}{% endblock %} - Association des Étudiants UTBM - @@ -14,7 +13,7 @@ {% block jquery_css %} - {# Thile file is quite heavy (around 250kb), so declaring it in a block allows easy removal #} + {# Thile file is quite heavy (around 250kb), so declaring it in a block allows easy removal #} {% endblock %} @@ -23,6 +22,7 @@ + @@ -37,222 +37,37 @@ - - + + {% csrf_token %} - + {% block header %} {% if not popup %} -
- - {% if not user.is_authenticated %} - - {% else %} -
-
- -
    - {% cache 100 "counters_activity" %} - {# The sith has no periodic tasks manager - and using cron jobs would be way too overkill here. - Thus the barmen timeout is handled in the only place that - is loaded on every page : the header bar. - However, let's be clear : this has nothing to do here. - It's' merely a contrived workaround that should - replaced by a proper task manager as soon as possible. #} - {% set _ = Counter.objects.filter(type="BAR").handle_timeout() %} - {% endcache %} - {% for bar in Counter.objects.annotate_has_barman(user).annotate_is_open().filter(type="BAR") %} -
  • - {# If the user is a barman, we redirect him directly to the barman page - else we redirect him to the activity page #} - {% if bar.has_annotated_barman %} - - {% else %} - - {% endif %} - {% if bar.is_open %} - - {% else %} - - {% endif %} - {{ bar }} - -
  • - {% endfor %} -
-
- -
- {% endif %} -
- {% for language in LANGUAGES %} -
- {% csrf_token %} - - - -
- {% endfor %} -
-
- - {% block info_boxes %} -
- {% set sith = get_sith() %} - {% if sith.alert_msg %} -
- {{ sith.alert_msg|markdown }} -
- {% endif %} - {% if sith.info_msg %} -
- {{ sith.info_msg|markdown }} -
- {% endif %} -
- {% endblock %} - + {% include "core/base/header.jinja" %} {% else %}
{{ user.get_display_name() }}
{% endif %} + {% block info_boxes %} +
+ {% set sith = get_sith() %} + {% if sith.alert_msg %} +
+ {{ sith.alert_msg|markdown }} +
+ {% endif %} + {% if sith.info_msg %} +
+ {{ sith.info_msg|markdown }} +
+ {% endif %} +
+ {% endblock %} {% endblock %} - {% block nav %} {% if not popup %} - + {% include "core/base/menu.jinja" %} {% endif %} {% endblock %} @@ -265,19 +80,16 @@
- {% if list_of_tabs %} -
-
- {% for t in list_of_tabs -%} - {{ t.name }} - {%- endfor %} -
-
- {% endif %} + {% block tabs %} + {% include "core/base/tabs.jinja" %} + {% endblock %} + + {% block errors%} + {% if error %} + {{ error }} + {% endif %} + {% endblock %} - {% if error %} - {{ error }} - {% endif %} {% block content %} {% endblock %}
diff --git a/core/templates/core/base/header.jinja b/core/templates/core/base/header.jinja new file mode 100644 index 00000000..99cd4c4f --- /dev/null +++ b/core/templates/core/base/header.jinja @@ -0,0 +1,136 @@ +
+ + {% if not user.is_authenticated %} + + {% else %} +
+
+ +
    + {% cache 100 "counters_activity" %} + {# The sith has no periodic tasks manager + and using cron jobs would be way too overkill here. + Thus the barmen timeout is handled in the only place that + is loaded on every page : the header bar. + However, let's be clear : this has nothing to do here. + It's' merely a contrived workaround that should + replaced by a proper task manager as soon as possible. #} + {% set _ = Counter.objects.filter(type="BAR").handle_timeout() %} + {% endcache %} + {% for bar in Counter.objects.annotate_has_barman(user).annotate_is_open().filter(type="BAR") %} +
  • + {# If the user is a barman, we redirect him directly to the barman page + else we redirect him to the activity page #} + {% if bar.has_annotated_barman %} + + {% else %} + + {% endif %} + {% if bar.is_open %} + + {% else %} + + {% endif %} + {{ bar }} + +
  • + {% endfor %} +
+
+ +
+ {% endif %} +
+ {% for language in LANGUAGES %} +
+ {% csrf_token %} + + + +
+ {% endfor %} +
+
diff --git a/core/templates/core/base/menu.jinja b/core/templates/core/base/menu.jinja new file mode 100644 index 00000000..fcdd4b1b --- /dev/null +++ b/core/templates/core/base/menu.jinja @@ -0,0 +1,48 @@ + diff --git a/core/templates/core/base/tabs.jinja b/core/templates/core/base/tabs.jinja new file mode 100644 index 00000000..5a45ef09 --- /dev/null +++ b/core/templates/core/base/tabs.jinja @@ -0,0 +1,9 @@ +{% if list_of_tabs %} +
+
+ {% for t in list_of_tabs -%} + {{ t.name }} + {%- endfor %} +
+
+{% endif %} diff --git a/core/templates/core/base_fragment.jinja b/core/templates/core/base_fragment.jinja new file mode 100644 index 00000000..155ed2f2 --- /dev/null +++ b/core/templates/core/base_fragment.jinja @@ -0,0 +1,20 @@ +{% block additional_css %}{% endblock %} +{% block additional_js %}{% endblock %} + +
+ {% block tabs %} + {% include "core/base/tabs.jinja" %} + {% endblock %} + + {% block errors%} + {% if error %} + {{ error }} + {% endif %} + {% endblock %} + + {% block content %} + {% endblock %} +
+ +{% block script %} +{% endblock %} diff --git a/core/templates/core/file.jinja b/core/templates/core/file.jinja index f8f42990..95c29bdc 100644 --- a/core/templates/core/file.jinja +++ b/core/templates/core/file.jinja @@ -1,4 +1,8 @@ -{% extends "core/base.jinja" %} +{% if is_fragment %} + {% extends "core/base_fragment.jinja" %} +{% else %} + {% extends "core/base.jinja" %} +{% endif %} {% block title %} {% if file %} @@ -21,7 +25,7 @@ {% endif %} {% endmacro %} -{% block content %} +{% block tabs %} {{ print_file_name(file) }}
@@ -44,6 +48,9 @@

+{% endblock %} + +{% block content %} {% if file %} {% block file %} diff --git a/core/templates/core/file_delete_confirm.jinja b/core/templates/core/file_delete_confirm.jinja index 521413e2..155ac62a 100644 --- a/core/templates/core/file_delete_confirm.jinja +++ b/core/templates/core/file_delete_confirm.jinja @@ -4,15 +4,49 @@ {% trans %}Delete confirmation{% endtrans %} {% endblock %} +{% if is_fragment %} + + {# Don't display tabs and errors #} + {% block tabs %} + {% endblock %} + {% block errors %} + {% endblock %} + +{% endif %} + {% block file %}

{% trans %}Delete confirmation{% endtrans %}

-
{% csrf_token %} + + {% if next %} + {% set action = current + "?next=" + next %} + {% else %} + {% set action = current %} + {% endif %} + + + {% csrf_token %} +

{% trans obj=object %}Are you sure you want to delete "{{ obj }}"?{% endtrans %}

- -
-
- + + + +
+ {% endblock %} diff --git a/core/templates/core/file_moderation.jinja b/core/templates/core/file_moderation.jinja index f8fd255e..fc9c0f43 100644 --- a/core/templates/core/file_moderation.jinja +++ b/core/templates/core/file_moderation.jinja @@ -1,4 +1,16 @@ -{% extends "core/base.jinja" %} +{% if is_fragment %} + {% extends "core/base_fragment.jinja" %} + + {# Don't display tabs and errors #} + {% block tabs %} + {% endblock %} + {% block errors %} + {% endblock %} +{% else %} + {% extends "core/base.jinja" %} +{% endif %} + +{% from "core/macros.jinja" import paginate_htmx %} {% block title %} {% trans %}File moderation{% endtrans %} @@ -7,8 +19,11 @@ {% block content %}

{% trans %}File moderation{% endtrans %}

- {% for f in files %} -
+ {% for f in object_list %} +
{% if f.is_folder %} Folder {% else %} @@ -20,9 +35,19 @@ {% trans %}Owner: {% endtrans %}{{ f.owner.get_display_name() }}
{% trans %}Date: {% endtrans %}{{ f.date|date(DATE_FORMAT) }} {{ f.date|time(TIME_FORMAT) }}

-

{% trans %}Moderate{% endtrans %} - - {% trans %}Delete{% endtrans %}

+

- + {% set current_page = url('core:file_moderation') + "?page=" + page_obj.number | string %} +

{% endfor %} + {{ paginate_htmx(page_obj, paginator) }}
{% endblock %} diff --git a/core/templates/core/macros.jinja b/core/templates/core/macros.jinja index c08053dd..43a90d07 100644 --- a/core/templates/core/macros.jinja +++ b/core/templates/core/macros.jinja @@ -166,9 +166,37 @@ current_page (django.core.paginator.Page): the current page object paginator (django.core.paginator.Paginator): the paginator object #} + {{ paginate_server_side(current_page, paginator, False) }} +{% endmacro %} + +{% macro paginate_htmx(current_page, paginator) %} + {# Add pagination buttons for pages without Alpine but supporting framgents. + + This must be coupled with a view that handles pagination + with the Django Paginator object and supports framgents. + + The relpaced fragment will be #content so make sure you are calling this macro inside your content block. + + Parameters: + current_page (django.core.paginator.Page): the current page object + paginator (django.core.paginator.Paginator): the paginator object + #} + {{ paginate_server_side(current_page, paginator, True) }} +{% endmacro %} + +{% macro paginate_server_side(current_page, paginator, use_htmx) %}