From 1749112ae82697eba0c49928e527575573f18029 Mon Sep 17 00:00:00 2001 From: NothRen Date: Mon, 23 Mar 2026 11:22:50 +0100 Subject: [PATCH 1/8] Remove unused UserForm and linked routes --- core/forms.py | 51 -------------------------------------------------- core/models.py | 2 ++ core/urls.py | 1 - core/views.py | 25 +------------------------ 4 files changed, 3 insertions(+), 76 deletions(-) diff --git a/core/forms.py b/core/forms.py index b6bbb3b..c2c5000 100644 --- a/core/forms.py +++ b/core/forms.py @@ -35,57 +35,6 @@ class Meta: }), } -class UserForm(forms.ModelForm): - """ - Form for creating and updating users profiles - """ - class Meta: - model = User - fields = ["first_name", "last_name", "email", "password", "avatar", "address"] - widgets = { - 'first_name': forms.TextInput(attrs={ - 'class': 'form-control form-control-lg', - 'placeholder': 'Prénom' - }), - 'last_name': forms.TextInput(attrs={ - 'class': 'form-control form-control-lg', - 'placeholder': 'Nom de famille' - }), - 'email': forms.TextInput(attrs={ - 'class': 'form-control form-control-lg', - 'placeholder': 'Email' - }), - 'password': forms.PasswordInput(attrs={ - 'class': 'form-control form-control-lg', - 'placeholder': 'Mot de passe' - }), - 'address': forms.TextInput(attrs={ - 'class': 'form-control form-control-lg', - 'placeholder': 'Adresse ...' - }), - 'avatar': forms.FileInput(attrs={ - 'class': 'form-control', - 'accept': 'image/*' - }), - } - - password_confirm = forms.CharField(widget=forms.PasswordInput( - attrs={ - 'class': 'form-control form-control-lg', - 'placeholder': 'Confirmation du mot de passe' - }), label='Confirmation du mot de passe') - - def clean(self): - """Check if password and password_confirm are matching""" - cleaned_data = super().clean() - password = cleaned_data.get('password') - password_confirm = cleaned_data.get('password_confirm') - if password != password_confirm: - self.add_error(None, 'Les mots de passes ne correspondent pas') - - return cleaned_data - - class PartialUserForm(forms.ModelForm): """ Forms for editing user profiles diff --git a/core/models.py b/core/models.py index 3bf34f5..e1e6df8 100644 --- a/core/models.py +++ b/core/models.py @@ -644,6 +644,8 @@ def add_to_course(course, badge, parent): if parent: item = CourseItem.objects.get(badge=parent, course=course) c.parents.add(item) + + class BadgeCriteria(models.Model): """ Critères d'attribution d'un badge par une structure. diff --git a/core/urls.py b/core/urls.py index fe4ea4b..c2edf87 100644 --- a/core/urls.py +++ b/core/urls.py @@ -20,7 +20,6 @@ # Creation routes path('badge/create/', views.BadgeViewSet.as_view({'get': 'create_badge', 'post': 'create_badge'}), name='create_badge'), path('structure/create/', views.StructureViewSet.as_view({'get': 'create_association', 'post': 'create_association'}), name='create_association'), - path('user/create/', views.UserViewSet.as_view({'get': 'create_user', 'post': 'create_user'}), name='create_user'), # Edition routes path('users//edit', views.UserViewSet.as_view({'get': 'edit', 'post': 'edit'}), name='edit-profile'), diff --git a/core/views.py b/core/views.py index f47787c..9d2a218 100644 --- a/core/views.py +++ b/core/views.py @@ -16,7 +16,7 @@ from .helpers import TokenHelper from .helpers.utils import get_or_create_user, invite_user_to_structure from .models import Structure, Badge, User, BadgeAssignment, BadgeEndorsement, BadgeHistory, BadgeCriteria, Course, CourseItem -from .forms import BadgeForm, UserForm, PartialUserForm +from .forms import BadgeForm, PartialUserForm from .permissions import IsBadgeEditor, IsStructureAdmin, CanEditUser, CanAssignBadge, CanEndorseBadge, CanEditCourse from .validators import BadgeAssignmentValidator, BadgeEndorsementValidator, DreamBadgeValidator, InviteUserValidator, \ @@ -1713,29 +1713,6 @@ def retrieve(self, request, pk=None): 'structures': structures }) - @action(detail=False, methods=['get', 'post']) - def create_user(self, request): - """ - Create a new user. - """ - return raise403(request) - if request.method == 'POST': - form = UserForm(request.POST, request.FILES) - if form.is_valid(): - user = form.save(commit=False) - user.username = f"{form.cleaned_data['first_name']}.{form.cleaned_data['last_name']}".lower() - user.set_password(form.cleaned_data['password']) - user.save() - - return redirect(reverse('core:user-detail', kwargs={'pk': user.pk})) - else: - form = UserForm() - - return render(request, 'core/users/create.html', { - 'title': 'openbadge.coop - Créer un utilisateur', - 'form': form, - }) - @action(detail=True, methods=['get', 'post'],name="edit-profile") def edit(self,request,pk=None): """ From 02b5447153f2960e8bfa4f075bfd737cd7d9f8b2 Mon Sep 17 00:00:00 2001 From: NothRen Date: Wed, 25 Mar 2026 12:58:05 +0100 Subject: [PATCH 2/8] Replace `picture` tag by `svg_or_picture` tag to handle svg files --- core/templatetags/custom_tags.py | 50 +++++++++++++++---- static/css/custom.css | 5 ++ templates/core/badge/index.html | 7 ++- templates/core/course/detail.html | 5 +- templates/core/course/edit.html | 5 +- .../core/course/partial/badge_list_add.html | 5 +- templates/core/home/partial/badge_focus.html | 12 ++--- templates/core/home/partial/multi_focus.html | 18 +++---- templates/core/home/partial/person_focus.html | 8 +-- .../core/home/partial/search_results.html | 7 ++- .../core/home/partial/structure_focus.html | 8 +-- templates/core/structure/index.html | 9 ++-- templates/core/user/passeport.html | 7 ++- templates/unused/core/assignments/detail.html | 6 +-- .../assignments/list_user_assignment.html | 6 +-- .../assignments/partials/assignment_list.html | 6 +-- .../partials/assignment_list_by_badges.html | 4 +- templates/unused/core/users/cv.html | 4 +- templates/unused/core/users/cv_bootstrap.html | 4 +- .../unused/core/users/cv_liquid_glass.html | 4 +- templates/unused/core/users/cv_material.html | 4 +- 21 files changed, 105 insertions(+), 79 deletions(-) diff --git a/core/templatetags/custom_tags.py b/core/templatetags/custom_tags.py index cc8a112..ffd3e8b 100644 --- a/core/templatetags/custom_tags.py +++ b/core/templatetags/custom_tags.py @@ -1,5 +1,7 @@ from django import template from django.template import loader +from pictures.templatetags.pictures import picture +from django.utils.html import format_html register = template.Library() @@ -7,32 +9,58 @@ POPUP_OPEN_JS_FUNCTION = "openPopup" POPUP_CONTENT_ID = "customPopup-content" + @register.simple_block_tag def popup(content, popup_width="40%", *args, **kwargs): outside_click_close = kwargs.pop("outside_click_close", False) esc_key_close = kwargs.pop("esc_key_close", True) + template = loader.get_template("base/includes/popup.html") - template = loader.get_template('base/includes/popup.html') + return template.render( + { + "content": content, + "open_func_name": POPUP_OPEN_JS_FUNCTION, + "close_func_name": POPUP_CLOSE_JS_FUNCTION, + "popup_content_id": POPUP_CONTENT_ID, + "popup_width": popup_width, + "outside_click_close": outside_click_close, + "esc_key_close": esc_key_close, + } + ) - return template.render({ - "content": content, - "open_func_name": POPUP_OPEN_JS_FUNCTION, - "close_func_name": POPUP_CLOSE_JS_FUNCTION, - "popup_content_id":POPUP_CONTENT_ID, - "popup_width":popup_width, - "outside_click_close":outside_click_close, - "esc_key_close" : esc_key_close - }) @register.simple_tag def popup_close(): return f"{POPUP_CLOSE_JS_FUNCTION}()" + @register.simple_tag def popup_open(): return f"{POPUP_OPEN_JS_FUNCTION}()" + @register.simple_tag def popup_content_id(): - return f"#{POPUP_CONTENT_ID}" \ No newline at end of file + return f"#{POPUP_CONTENT_ID}" + + +def is_svg(file_field): + """Check if the file is an SVG.""" + if not file_field: + return False + name = getattr(file_field, "name", str(file_field)) + return name.lower().endswith(".svg") + +@register.simple_tag() +def svg_or_picture(img_src, img_alt, ratio, **kwargs): + """ + If the file is a svg, return an html img + Else return the image using "picture" template tag from django-pictures + + The usage is the same to the "picture" template tag from django-pictures + """ + if is_svg(img_src.url): + return format_html("{}", img_src.url, img_alt) + + return picture(img_src, img_alt=img_alt, ratio=ratio, **kwargs) \ No newline at end of file diff --git a/static/css/custom.css b/static/css/custom.css index 3de8828..fc21cda 100644 --- a/static/css/custom.css +++ b/static/css/custom.css @@ -2632,4 +2632,9 @@ picture.text-center img.badge-icon { justify-content: center; padding: 0.85rem 1.5rem; } +} + +.badge-svg-icon{ + width: 100%; + height: 100%; } \ No newline at end of file diff --git a/templates/core/badge/index.html b/templates/core/badge/index.html index b027909..b6b0b64 100644 --- a/templates/core/badge/index.html +++ b/templates/core/badge/index.html @@ -3,7 +3,6 @@ {# / Dedicated badge page. Shows header, structures, holders, actions, map. #} {% extends 'base/base.html' %} {% load i18n %} -{% load pictures %} {% load static %} {% load l10n %} {% load custom_tags %} @@ -51,7 +50,7 @@
{% if badge.icon %} - {% picture badge.icon img_alt=badge.name ratio="1/1" %} + {% svg_or_picture badge.icon img_alt=badge.name ratio="1/1" %} {% else %}
@@ -189,7 +188,7 @@

class="home-result-item">
{% if structure.logo %} - {% picture structure.logo img_alt=structure.name ratio="1/1" %} + {% svg_or_picture structure.logo img_alt=structure.name ratio="1/1" %} {% else %}
@@ -242,7 +241,7 @@

data-testid="badge-page-holder-{{ assignment.user.pk }}">
{% if assignment.user.avatar %} - {% picture assignment.user.avatar img_alt=assignment.user.get_full_name|default:assignment.user.username ratio="1/1" %} + {% svg_or_picture assignment.user.avatar img_alt=assignment.user.get_full_name|default:assignment.user.username ratio="1/1" %} {% else %}
diff --git a/templates/core/course/detail.html b/templates/core/course/detail.html index 71df40d..49d81d4 100644 --- a/templates/core/course/detail.html +++ b/templates/core/course/detail.html @@ -3,7 +3,6 @@ {# / Course/journey display page with Cytoscape graph. #} {% extends 'base/base.html' %} {% load i18n %} -{% load pictures %} {% load static %} {% load l10n %} {% load custom_tags %} @@ -216,7 +215,7 @@
{% if course.badge and course.badge.icon %} - {% picture course.badge.icon img_alt=course.badge.name img_class="parcours-badge-icon" ratio="1/1" %} + {% svg_or_picture course.badge.icon img_alt=course.badge.name img_class="parcours-badge-icon" ratio="1/1" %} {% else %}
@@ -275,7 +274,7 @@

data-testid="parcours-badge-{{ item.badge.pk }}">
{% if item.badge.icon %} - {% picture item.badge.icon img_alt=item.badge.name img_class="parcours-badge-icon" ratio="1/1" %} + {% svg_or_picture item.badge.icon img_alt=item.badge.name img_class="parcours-badge-icon" ratio="1/1" %} {% else %}
diff --git a/templates/core/course/edit.html b/templates/core/course/edit.html index b9dd12d..fc55a6d 100644 --- a/templates/core/course/edit.html +++ b/templates/core/course/edit.html @@ -3,7 +3,6 @@ {# / Course/journey display page with Cytoscape graph. #} {% extends 'base/base.html' %} {% load i18n %} -{% load pictures %} {% load static %} {% load l10n %} {% load custom_tags %} @@ -216,7 +215,7 @@
{% if course.badge and course.badge.icon %} - {% picture course.badge.icon img_alt=course.badge.name img_class="parcours-badge-icon" ratio="1/1" %} + {% svg_or_picture course.badge.icon img_alt=course.badge.name img_class="parcours-badge-icon" ratio="1/1" %} {% else %}
@@ -275,7 +274,7 @@

data-testid="parcours-badge-{{ item.badge.pk }}">
{% if item.badge.icon %} - {% picture item.badge.icon img_alt=item.badge.name img_class="parcours-badge-icon" ratio="1/1" %} + {% svg_or_picture item.badge.icon img_alt=item.badge.name img_class="parcours-badge-icon" ratio="1/1" %} {% else %}
diff --git a/templates/core/course/partial/badge_list_add.html b/templates/core/course/partial/badge_list_add.html index 2f37aa5..65d712f 100644 --- a/templates/core/course/partial/badge_list_add.html +++ b/templates/core/course/partial/badge_list_add.html @@ -1,4 +1,4 @@ -{% load pictures %} +{% load custom_tags %}