Séparation des vues Tag

This commit is contained in:
Jean-Marie Favreau 2025-03-24 23:53:20 +01:00
parent e127a25a0e
commit 76610993ba
6 changed files with 305 additions and 279 deletions

View File

@ -1,5 +1,5 @@
default_language_version: default_language_version:
python: python3.12 python: python3
repos: repos:
# Using this mirror lets us use mypyc-compiled black, which is about 2x faster # Using this mirror lets us use mypyc-compiled black, which is about 2x faster
- repo: https://github.com/psf/black-pre-commit-mirror - repo: https://github.com/psf/black-pre-commit-mirror

View File

@ -17,25 +17,31 @@ from .sitemaps import (
) )
from .models import Event, Place, Organisation, Category from .models import Event, Place, Organisation, Category
from .views import ( from .views import (
# Errors # Errors
internal_server_error, internal_server_error,
page_not_found, page_not_found,
# General pages # General pages
about, about,
import_requirements, import_requirements,
mentions_legales, mentions_legales,
moderation_rules, moderation_rules,
thank_you, thank_you,
# TODO pas encore trié # tags
view_tag,
view_tag_past,
TagUpdateView,
tag_list,
TagDeleteView,
rename_tag,
delete_tag,
TagCreateView,
# TODO pas encore trié
home, home,
week_view, week_view,
month_view, month_view,
day_view, day_view,
upcoming_events, upcoming_events,
export_ical, export_ical,
view_tag,
view_tag_past,
TagUpdateView,
recent, recent,
administration, administration,
activite, activite,
@ -64,11 +70,6 @@ from .views import (
cancel_import, cancel_import,
run_all_fb_rimports, run_all_fb_rimports,
run_all_rimports, run_all_rimports,
tag_list,
TagDeleteView,
rename_tag,
delete_tag,
TagCreateView,
EventDetailView, EventDetailView,
EventUpdateView, EventUpdateView,
EventModerateView, EventModerateView,

View File

@ -1,3 +1,4 @@
from .oldviews import * from .oldviews import *
from .errors import * from .errors import *
from .general_pages_views import * from .general_pages_views import *
from .tag_views import *

View File

@ -79,8 +79,6 @@ from ..forms import (
RecurrentImportForm, RecurrentImportForm,
SelectEventInList, SelectEventInList,
SimpleContactForm, SimpleContactForm,
TagForm,
TagRenameForm,
URLSubmissionFormSet, URLSubmissionFormSet,
URLSubmissionFormWithContact, URLSubmissionFormWithContact,
UserProfileForm, UserProfileForm,
@ -97,11 +95,11 @@ from ..models import (
Place, Place,
RecurrentImport, RecurrentImport,
StaticContent, StaticContent,
Tag,
remove_accents, remove_accents,
UserProfile, UserProfile,
) )
from ..utils import PlaceGuesser from ..utils import PlaceGuesser
from .utils import get_event_qs
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -161,26 +159,6 @@ class PaginatorFilter(Paginator):
return page return page
#
#
# Useful for translation
to_be_translated = [
_("Recurrent import name"),
_("Add another"),
_("Browse..."),
_("No file selected."),
]
def get_event_qs(request):
if request.user.is_authenticated:
return Event.objects.filter()
else:
return Event.objects.filter(status=Event.STATUS.PUBLISHED)
def home(request, cat=None): def home(request, cat=None):
return week_view(request, home=True, cat=cat) return week_view(request, home=True, cat=cat)
@ -2622,84 +2600,6 @@ class OrganisationDeleteView(PermissionRequiredMixin, DeleteView):
success_url = reverse_lazy("view_organisations") success_url = reverse_lazy("view_organisations")
#########################
## Tags
#########################
class TagUpdateView(PermissionRequiredMixin, SuccessMessageMixin, UpdateView):
model = Tag
permission_required = "agenda_culturel.change_tag"
form_class = TagForm
success_message = _("The tag has been successfully updated.")
class TagCreateView(PermissionRequiredMixin, SuccessMessageMixin, CreateView):
model = Tag
permission_required = "agenda_culturel.add_tag"
form_class = TagForm
success_message = _("The tag has been successfully created.")
def get_initial(self, *args, **kwargs):
initial = super().get_initial(**kwargs)
if "name" in self.request.GET:
initial["name"] = self.request.GET.get("name")
return initial
def form_valid(self, form):
Tag.clear_cache()
return super().form_valid(form)
class TagDeleteView(PermissionRequiredMixin, DeleteView):
model = Tag
permission_required = "agenda_culturel.delete_tag"
success_url = reverse_lazy("view_all_tags")
def view_tag_past(request, t):
return view_tag(request, t, True)
def view_tag(request, t, past=False):
now = date.today()
qs = get_event_qs(request).filter(tags__contains=[t])
if past:
qs = qs.filter(start_day__lt=now).order_by("-start_day", "-start_time")
else:
qs = qs.filter(start_day__gte=now).order_by("start_day", "start_time")
qs = qs.filter(
Q(other_versions__isnull=True)
| Q(other_versions__representative=F("pk"))
| Q(other_versions__representative__isnull=True)
)
paginator = Paginator(qs, 10)
page = request.GET.get("page")
try:
response = paginator.page(page)
except PageNotAnInteger:
response = paginator.page(1)
except EmptyPage:
response = paginator.page(paginator.num_pages)
rimports = RecurrentImport.objects.filter(defaultTags__contains=[t])
tag = Tag.objects.filter(name=t).first()
context = {
"tag": t,
"paginator_filter": response,
"object": tag,
"rimports": rimports,
"past": past,
}
return render(request, "agenda_culturel/tag.html", context)
def statistics(request, pk=None): def statistics(request, pk=None):
if pk is not None: if pk is not None:
rimport = RecurrentImport.objects.filter(pk=pk) rimport = RecurrentImport.objects.filter(pk=pk)
@ -2811,171 +2711,6 @@ def statistics(request, pk=None):
return render(request, "agenda_culturel/rimport-statistics.html", context) return render(request, "agenda_culturel/rimport-statistics.html", context)
def tag_list(request):
tags = Event.get_all_tags()
r_tags = [t["tag"] for t in tags]
objects = Tag.objects.order_by("name").all()
d_objects = dict()
for o in objects:
d_objects[o.name] = o
tags = [
t | {"obj": d_objects[t["tag"]]} if t["tag"] in d_objects else t for t in tags
]
tags += [
{"obj": o, "tag": o.name, "count": 0} for o in objects if o.name not in r_tags
]
context = {
"tags": sorted(
tags,
key=lambda x: emoji.demojize(
remove_accents(x["tag"]).lower(), delimiters=("000", "")
),
)
}
return render(request, "agenda_culturel/tags.html", context)
@login_required(login_url="/accounts/login/")
@permission_required("agenda_culturel.change_tag")
def rename_tag(request, t):
form = TagRenameForm(name=t)
if request.method == "POST":
form = TagRenameForm(request.POST, name=t)
if form.is_valid():
save = True
if form.cleaned_data["name"] == t:
messages.warning(
request,
_("You have not modified the tag name."),
)
save = False
elif not form.is_force():
if (
Event.objects.filter(
tags__contains=[form.cleaned_data["name"]]
).count()
> 0
):
if Tag.objects.filter(name=form.cleaned_data["name"]):
messages.warning(
request,
(
_(
"This tag {} is already in use, and is described by different information from the current tag. You can force renaming by checking the corresponding option. The information associated with tag {} will be deleted, and all events associated with tag {} will be associated with tag {}."
)
).format(
form.cleaned_data["name"],
t,
t,
form.cleaned_data["name"],
),
)
else:
messages.warning(
request,
(
_(
"This tag {} is already in use. You can force renaming by checking the corresponding option."
)
).format(form.cleaned_data["name"]),
)
save = False
form = TagRenameForm(request.POST, name=t, force=True)
if save:
# find all matching events and update them
events = Event.objects.filter(tags__contains=[t])
new_name = form.cleaned_data["name"]
for e in events:
e.tags = [te for te in e.tags if te != t]
if new_name not in e.tags:
e.tags += [new_name]
Event.objects.bulk_update(events, fields=["tags"])
# find all recurrent imports and fix them
rimports = RecurrentImport.objects.filter(defaultTags__contains=[t])
for ri in rimports:
ri.tags = [te for te in ri.defaultTags if te != t]
if new_name not in ri.tags:
ri.tags += [new_name]
RecurrentImport.objects.bulk_update(rimports, fields=["defaultTags"])
# find tag object
tag_object = Tag.objects.filter(name=t).first()
if tag_object:
tag_object.name = new_name
tag_object.save()
messages.success(
request,
(_("The tag {} has been successfully renamed to {}.")).format(
t, form.cleaned_data["name"]
),
)
return HttpResponseRedirect(
reverse_lazy("view_tag", kwargs={"t": form.cleaned_data["name"]})
)
nb = Event.objects.filter(tags__contains=[t]).count()
return render(
request,
"agenda_culturel/tag_rename_form.html",
context={"form": form, "tag": t, "nb": nb},
)
@login_required(login_url="/accounts/login/")
@permission_required("agenda_culturel.delete_tag")
def delete_tag(request, t):
respage = reverse_lazy("view_all_tags")
if request.method == "POST":
# remove tag from events
events = Event.objects.filter(tags__contains=[t])
for e in events:
e.tags = [te for te in e.tags if te != t]
Event.objects.bulk_update(events, fields=["tags"])
# remove tag from recurrent imports
rimports = RecurrentImport.objects.filter(defaultTags__contains=[t])
for ri in rimports:
ri.tags = [te for te in ri.defaultTags if te != t]
RecurrentImport.objects.bulk_update(rimports, fields=["defaultTags"])
# find tag object
tag_object = Tag.objects.filter(name=t).first()
if tag_object:
tag_object.delete()
messages.success(
request,
(_("The tag {} has been successfully deleted.")).format(t),
)
return HttpResponseRedirect(respage)
else:
nb = Event.objects.filter(tags__contains=[t]).count()
obj = Tag.objects.filter(name=t).first()
nbi = RecurrentImport.objects.filter(defaultTags__contains=[t]).count()
cancel_url = request.META.get("HTTP_REFERER", "")
if cancel_url == "":
cancel_url = respage
return render(
request,
"agenda_culturel/tag_confirm_delete_by_name.html",
{
"tag": t,
"nb": nb,
"nbi": nbi,
"cancel_url": cancel_url,
"obj": obj,
},
)
def clear_cache(request): def clear_cache(request):
if request.method == "POST": if request.method == "POST":
cache.clear() cache.clear()

View File

@ -0,0 +1,270 @@
from django.contrib.auth.decorators import login_required, permission_required
from django.contrib.auth.mixins import (
PermissionRequiredMixin,
)
from django.contrib.messages.views import SuccessMessageMixin
from django.views.generic.edit import (
CreateView,
DeleteView,
UpdateView,
)
from ..forms import (
TagForm,
TagRenameForm,
)
from ..models import (
Tag,
RecurrentImport,
Event,
remove_accents,
)
from django.utils.translation import gettext_lazy as _
from django.urls import reverse_lazy
from datetime import date
from .utils import get_event_qs
from django.db.models import F, Q
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
from django.shortcuts import render
from django.contrib import messages
from django.http import (
HttpResponseRedirect,
)
import emoji
class TagUpdateView(PermissionRequiredMixin, SuccessMessageMixin, UpdateView):
model = Tag
permission_required = "agenda_culturel.change_tag"
form_class = TagForm
success_message = _("The tag has been successfully updated.")
class TagCreateView(PermissionRequiredMixin, SuccessMessageMixin, CreateView):
model = Tag
permission_required = "agenda_culturel.add_tag"
form_class = TagForm
success_message = _("The tag has been successfully created.")
def get_initial(self, *args, **kwargs):
initial = super().get_initial(**kwargs)
if "name" in self.request.GET:
initial["name"] = self.request.GET.get("name")
return initial
def form_valid(self, form):
Tag.clear_cache()
return super().form_valid(form)
class TagDeleteView(PermissionRequiredMixin, DeleteView):
model = Tag
permission_required = "agenda_culturel.delete_tag"
success_url = reverse_lazy("view_all_tags")
def view_tag_past(request, t):
return view_tag(request, t, True)
def view_tag(request, t, past=False):
now = date.today()
qs = get_event_qs(request).filter(tags__contains=[t])
if past:
qs = qs.filter(start_day__lt=now).order_by("-start_day", "-start_time")
else:
qs = qs.filter(start_day__gte=now).order_by("start_day", "start_time")
qs = qs.filter(
Q(other_versions__isnull=True)
| Q(other_versions__representative=F("pk"))
| Q(other_versions__representative__isnull=True)
)
paginator = Paginator(qs, 10)
page = request.GET.get("page")
try:
response = paginator.page(page)
except PageNotAnInteger:
response = paginator.page(1)
except EmptyPage:
response = paginator.page(paginator.num_pages)
rimports = RecurrentImport.objects.filter(defaultTags__contains=[t])
tag = Tag.objects.filter(name=t).first()
context = {
"tag": t,
"paginator_filter": response,
"object": tag,
"rimports": rimports,
"past": past,
}
return render(request, "agenda_culturel/tag.html", context)
def tag_list(request):
tags = Event.get_all_tags()
r_tags = [t["tag"] for t in tags]
objects = Tag.objects.order_by("name").all()
d_objects = dict()
for o in objects:
d_objects[o.name] = o
tags = [
t | {"obj": d_objects[t["tag"]]} if t["tag"] in d_objects else t for t in tags
]
tags += [
{"obj": o, "tag": o.name, "count": 0} for o in objects if o.name not in r_tags
]
context = {
"tags": sorted(
tags,
key=lambda x: emoji.demojize(
remove_accents(x["tag"]).lower(), delimiters=("000", "")
),
)
}
return render(request, "agenda_culturel/tags.html", context)
@login_required(login_url="/accounts/login/")
@permission_required("agenda_culturel.change_tag")
def rename_tag(request, t):
form = TagRenameForm(name=t)
if request.method == "POST":
form = TagRenameForm(request.POST, name=t)
if form.is_valid():
save = True
if form.cleaned_data["name"] == t:
messages.warning(
request,
_("You have not modified the tag name."),
)
save = False
elif not form.is_force():
if (
Event.objects.filter(
tags__contains=[form.cleaned_data["name"]]
).count()
> 0
):
if Tag.objects.filter(name=form.cleaned_data["name"]):
messages.warning(
request,
(
_(
"This tag {} is already in use, and is described by different information from the current tag. You can force renaming by checking the corresponding option. The information associated with tag {} will be deleted, and all events associated with tag {} will be associated with tag {}."
)
).format(
form.cleaned_data["name"],
t,
t,
form.cleaned_data["name"],
),
)
else:
messages.warning(
request,
(
_(
"This tag {} is already in use. You can force renaming by checking the corresponding option."
)
).format(form.cleaned_data["name"]),
)
save = False
form = TagRenameForm(request.POST, name=t, force=True)
if save:
# find all matching events and update them
events = Event.objects.filter(tags__contains=[t])
new_name = form.cleaned_data["name"]
for e in events:
e.tags = [te for te in e.tags if te != t]
if new_name not in e.tags:
e.tags += [new_name]
Event.objects.bulk_update(events, fields=["tags"])
# find all recurrent imports and fix them
rimports = RecurrentImport.objects.filter(defaultTags__contains=[t])
for ri in rimports:
ri.tags = [te for te in ri.defaultTags if te != t]
if new_name not in ri.tags:
ri.tags += [new_name]
RecurrentImport.objects.bulk_update(rimports, fields=["defaultTags"])
# find tag object
tag_object = Tag.objects.filter(name=t).first()
if tag_object:
tag_object.name = new_name
tag_object.save()
messages.success(
request,
(_("The tag {} has been successfully renamed to {}.")).format(
t, form.cleaned_data["name"]
),
)
return HttpResponseRedirect(
reverse_lazy("view_tag", kwargs={"t": form.cleaned_data["name"]})
)
nb = Event.objects.filter(tags__contains=[t]).count()
return render(
request,
"agenda_culturel/tag_rename_form.html",
context={"form": form, "tag": t, "nb": nb},
)
@login_required(login_url="/accounts/login/")
@permission_required("agenda_culturel.delete_tag")
def delete_tag(request, t):
respage = reverse_lazy("view_all_tags")
if request.method == "POST":
# remove tag from events
events = Event.objects.filter(tags__contains=[t])
for e in events:
e.tags = [te for te in e.tags if te != t]
Event.objects.bulk_update(events, fields=["tags"])
# remove tag from recurrent imports
rimports = RecurrentImport.objects.filter(defaultTags__contains=[t])
for ri in rimports:
ri.tags = [te for te in ri.defaultTags if te != t]
RecurrentImport.objects.bulk_update(rimports, fields=["defaultTags"])
# find tag object
tag_object = Tag.objects.filter(name=t).first()
if tag_object:
tag_object.delete()
messages.success(
request,
(_("The tag {} has been successfully deleted.")).format(t),
)
return HttpResponseRedirect(respage)
else:
nb = Event.objects.filter(tags__contains=[t]).count()
obj = Tag.objects.filter(name=t).first()
nbi = RecurrentImport.objects.filter(defaultTags__contains=[t]).count()
cancel_url = request.META.get("HTTP_REFERER", "")
if cancel_url == "":
cancel_url = respage
return render(
request,
"agenda_culturel/tag_confirm_delete_by_name.html",
{
"tag": t,
"nb": nb,
"nbi": nbi,
"cancel_url": cancel_url,
"obj": obj,
},
)

View File

@ -0,0 +1,19 @@
from ..models import Event
from django.utils.translation import gettext_lazy as _
#
#
# Useful for translation
to_be_translated = [
_("Recurrent import name"),
_("Add another"),
_("Browse..."),
_("No file selected."),
]
def get_event_qs(request):
if request.user.is_authenticated:
return Event.objects.filter()
else:
return Event.objects.filter(status=Event.STATUS.PUBLISHED)