From 9be7132a77854c06bc5ab992121d19ea1f9b0f78 Mon Sep 17 00:00:00 2001
From: cubicroot <cccv@cubicroot.xyz>
Date: Sun, 1 Dec 2024 16:56:38 +0000
Subject: [PATCH] add info text to related assemblies form

---
 .../locale/de/LC_MESSAGES/django.po           | 11 +++
 .../locale/en/LC_MESSAGES/django.po           | 11 +++
 .../templates/backoffice/assembly_edit.html   |  5 +-
 .../backoffice/assembly_editlinks.html        |  5 +-
 src/backoffice/views/assemblies/assemblies.py | 80 ++++++++++---------
 5 files changed, 73 insertions(+), 39 deletions(-)

diff --git a/src/backoffice/locale/de/LC_MESSAGES/django.po b/src/backoffice/locale/de/LC_MESSAGES/django.po
index 7ca671949..7bf2d55d6 100644
--- a/src/backoffice/locale/de/LC_MESSAGES/django.po
+++ b/src/backoffice/locale/de/LC_MESSAGES/django.po
@@ -450,6 +450,9 @@ msgstr "Zusätzliche Angaben"
 msgid "assemblyedit_links"
 msgstr "Befreundete Assemblies"
 
+msgid "assemblyedit_addlink_info"
+msgstr "Du kannst andere Assemblies verlinken. Diese Information wird vom Assembly-Team genutzt um deine Assembly möglichst nahe bei den befreundeten Assemblies zu platzieren. Nur bereits akzeptierte Assemblies und Assemblies in denen du Mitglied bist können ausgewählt werden."
+
 msgid "assemblyedit_links__intro"
 msgstr "Ihr fühlt euch einer anderen Assembly verbunden, möchtet eure Buddies in der Nähe haben? Lasst uns wissen wer sie sind!"
 
@@ -1721,9 +1724,17 @@ msgstr "Fehlende Details bei einem Feld:"
 msgid "assemblyedit__success"
 msgstr "Deine Assembly-Anmeldung wurde aktualisiert. Vielen Dank!"
 
+#, python-format
+msgid "AssemblyLink__assembly__not_found %s"
+msgstr "Die Assembly ‚%s‘ konnte nicht gefunden werden, der Link kann nicht hinzugefügt werden!"
+
 msgid "assemblyedit_addedlink"
 msgstr "Bezug zur Assembly '{linked_name}' wurde vermerkt."
 
+#, python-format
+msgid "AssemblyLink__link__not_found %s"
+msgstr "Konnte den Link mit der ID ‚%s‘ nicht finden, kann nicht entfernt werden!"
+
 msgid "assemblyedit_removedlink"
 msgstr "Bezug zur Assembly '{linked_name}' wurde entfernt."
 
diff --git a/src/backoffice/locale/en/LC_MESSAGES/django.po b/src/backoffice/locale/en/LC_MESSAGES/django.po
index 992168f95..4722f3777 100644
--- a/src/backoffice/locale/en/LC_MESSAGES/django.po
+++ b/src/backoffice/locale/en/LC_MESSAGES/django.po
@@ -448,6 +448,9 @@ msgstr "additional data"
 msgid "assemblyedit_links"
 msgstr "Related assemblies"
 
+msgid "assemblyedit_addlink_info"
+msgstr "You can link to other assemblies. This information will be used by the assembly team to place your assembly close to befriended ones. Only accepted assemblies and assemblies where you are a member of can be chosen."
+
 msgid "assemblyedit_links__intro"
 msgstr "You like to be close to your friends? Let us know who they are."
 
@@ -1725,9 +1728,17 @@ msgstr "missing details on a field:"
 msgid "assemblyedit__success"
 msgstr "assembly's registration details have been updated. Thanks!"
 
+#, python-format
+msgid "AssemblyLink__assembly__not_found %s"
+msgstr "The assembly '%s' could not be found, unable to add!"
+
 msgid "assemblyedit_addedlink"
 msgstr "Association with assembly '{linked_name}' has been saved."
 
+#, python-format
+msgid "AssemblyLink__link__not_found %s"
+msgstr "Cannot find the linke with the id '%s', unable to remove!"
+
 msgid "assemblyedit_removedlink"
 msgstr "Association with assembly '{linked_name}' has been deleted."
 
diff --git a/src/backoffice/templates/backoffice/assembly_edit.html b/src/backoffice/templates/backoffice/assembly_edit.html
index 3dc523a6f..612f13b4a 100644
--- a/src/backoffice/templates/backoffice/assembly_edit.html
+++ b/src/backoffice/templates/backoffice/assembly_edit.html
@@ -53,7 +53,10 @@
       <div class="col-md-6">
         <div class="card">
           {% if not assembly.is_cluster %}
-            <div class="card-header">{% trans "assemblyedit_links" %}</div>
+            <div class="card-header">
+              {% trans "assemblyedit_links" %} <i title="{% trans "assemblyedit_addlink_info" %}"
+    class="bi bi-info-circle-fill text-primary"></i>
+            </div>
             <div class="card-body">
               <p>{% trans "assemblyedit_links__intro" %}</p>
               {% with la=assembly.linked_assemblies %}
diff --git a/src/backoffice/templates/backoffice/assembly_editlinks.html b/src/backoffice/templates/backoffice/assembly_editlinks.html
index a9baba842..8449949f8 100644
--- a/src/backoffice/templates/backoffice/assembly_editlinks.html
+++ b/src/backoffice/templates/backoffice/assembly_editlinks.html
@@ -18,7 +18,10 @@
     <div class="row">
       <div class="col-md-12">
         <div class="card mb-3">
-          <div class="card-header">{% trans "assemblyedit_addlink" %}</div>
+          <div class="card-header">
+            {% trans "assemblyedit_addlink" %} <i title="{% trans "assemblyedit_addlink_info" %}"
+    class="bi bi-info-circle-fill text-primary"></i>
+          </div>
           <div class="card-body">
             <p>{% trans "assemblyedit_links__intro" %}</p>
             <form action="{% url 'backoffice:assembly-editlinks' pk=assembly.id %}"
diff --git a/src/backoffice/views/assemblies/assemblies.py b/src/backoffice/views/assemblies/assemblies.py
index 06bbe8537..1645784cb 100644
--- a/src/backoffice/views/assemblies/assemblies.py
+++ b/src/backoffice/views/assemblies/assemblies.py
@@ -5,6 +5,7 @@ from typing import Any
 from django.conf import settings
 from django.contrib import messages
 from django.core.exceptions import PermissionDenied
+from django.db.models import QuerySet
 from django.http import Http404, HttpRequest, HttpResponse, HttpResponseRedirect
 from django.shortcuts import redirect, render
 from django.urls import reverse
@@ -368,6 +369,17 @@ class AssemblyLinksUpdateView(AssemblyMixin, View):
     require_conference = True
     assembly_management = True
 
+    def get_candidates(self) -> 'QuerySet[Assembly]':
+        return (
+            Assembly.objects.associated_with_user(conference=self.conference, user=self.request.user, show_public=True)
+            .filter(hierarchy=Assembly.Hierarchy.REGULAR)
+            .exclude(state_assembly__in=[Assembly.State.PLANNED, Assembly.State.HIDDEN, Assembly.State.REJECTED])
+            # Remove self from list (cannot link to self)
+            .exclude(pk=self.assembly.pk)
+            # Remove already linked assemblies
+            .exclude(related_assemblies__a=self.assembly)
+        )
+
     def get_object(self, *args, **kwargs):
         assembly = self.assembly
         if not Assembly.type_is(assembly):  # pragma: no cover
@@ -388,57 +400,51 @@ class AssemblyLinksUpdateView(AssemblyMixin, View):
 
         if add_id is not None:
             try:
-                linkee = Assembly.objects.associated_with_user(user=request.user, conference=self.conference).get(pk=add_id)
+                linked_assembly = self.get_candidates().get(pk=add_id)
             except Assembly.DoesNotExist:
-                messages.warning('404 +Assembly %s', add_id)
-                linkee = None
+                messages.warning(self.request, _('AssemblyLink__assembly__not_found %s') % add_id)
+                linked_assembly = None
 
-            if linkee is not None:
-                if linkee.pk == assembly.pk:
-                    messages.info(request, 'You are a l33t hax0r. I like myself, too.')
+            if linked_assembly is not None:
+                if linked_assembly.pk == assembly.pk:
+                    messages.info(request, 'AssemblyLink__cannot_self_link')
                     return redirect('backoffice:assembly-editlinks', pk=assembly.pk)
 
-                _, link_created = assembly.assembly_links.get_or_create(b=linkee, is_public=True, type=AssemblyLink.Type.RELATED)
+                linked_assemblies_old = len(self.assembly.linked_assemblies)
+                _link, link_created = assembly.assembly_links.get_or_create(b=linked_assembly, is_public=True, type=AssemblyLink.Type.RELATED)
                 if link_created:
-                    messages.success(request, gettext('assemblyedit_addedlink').format(linked_name=linkee.name))
-                    logger.info(
-                        'Assembly "%(assembly_name)s" (%(assembly_pk)s): added link to "%(linkee)s" (%(linkee_pk)s), requested by {%(user)s}.'
-                        'Not from this assembly',
-                        {'assembly_name': assembly.name, 'assembly_pk': assembly.pk, 'linkee': linkee, 'linkee_pk': linkee.pk, 'user': request.user.username},
+                    messages.success(request, gettext('assemblyedit_addedlink').format(linked_name=linked_assembly.name))
+                    linked_assemblies = len(self.assembly.linked_assemblies)
+                    self.assembly.log_activity(
+                        user=self.request.user,
+                        kind=ActivityLogEntry.Kind.STAFF if self.staff_access else ActivityLogEntry.Kind.ENTITY,
+                        context='backoffice.assembly',
+                        linked_assembly=ActivityLogChange(new=str(linked_assembly.name)),
+                        linked_assemblies=ActivityLogChange(old=str(linked_assemblies_old), new=str(linked_assemblies)),
                     )
 
         if remove_id is not None:
-            try:
-                linkee = Assembly.objects.associated_with_user(user=request.user, conference=self.conference).get(pk=remove_id)
-            except Assembly.DoesNotExist:
-                messages.warning('404 -Assembly %s', remove_id)
-                linkee = None
-
-            if linkee is not None:
-                count = AssemblyLink.objects.filter(a=assembly, b=linkee, is_public=True, type=AssemblyLink.Type.RELATED).delete()[0]
+            link = AssemblyLink.objects.filter(a=self.assembly, b_id=remove_id).first()
+            if link is None:
+                messages.warning(self.request, _('AssemblyLink__link__not_found %s') % remove_id)
+            else:
+                linked_assemblies_old = len(self.assembly.linked_assemblies)
+                count, _model = link.delete()
+                linked_assemblies = len(self.assembly.linked_assemblies)
                 if count > 0:
-                    messages.success(request, gettext('assemblyedit_removedlink').format(linked_name=linkee.name))
-                    logger.info(
-                        'Assembly "%s" (%s): removed link to "%s" (%s) upon request by <%s>',
-                        assembly.slug,
-                        assembly.pk,
-                        linkee.slug,
-                        linkee.pk,
-                        request.user.username,
+                    messages.success(request, gettext('assemblyedit_removedlink').format(linked_name=link.b.name))
+                    self.assembly.log_activity(
+                        user=self.request.user,
+                        kind=ActivityLogEntry.Kind.STAFF if self.staff_access else ActivityLogEntry.Kind.ENTITY,
+                        context='backoffice.assembly',
+                        linked_assembly=ActivityLogChange(old=str(link.b.name)),
+                        linked_assemblies=ActivityLogChange(old=str(linked_assemblies_old), new=str(linked_assemblies)),
                     )
 
         return redirect('backoffice:assembly-editlinks', pk=assembly.pk)
 
     def get(self, *args, **kwargs):
-        candidates_qs = (
-            Assembly.objects.associated_with_user(conference=self.conference, user=self.request.user)
-            .filter(hierarchy=Assembly.Hierarchy.REGULAR)
-            .exclude(state_assembly__in=[Assembly.State.NONE, Assembly.State.PLANNED, Assembly.State.HIDDEN, Assembly.State.REJECTED])
-            # Remove self from list (cannot link to self)
-            .exclude(pk=self.assembly.pk)
-            # Remove already linked assemblies
-            .exclude(related_assemblies__a=self.assembly)
-        )
+        candidates_qs = self.get_candidates()
         candidates = list(candidates_qs.order_by('name'))
         context = self.get_context_data()
         context['candidates'] = candidates
-- 
GitLab