Simplification de la description des éléments sélectionnés

This commit is contained in:
Jean-Marie Favreau 2024-11-07 22:56:53 +01:00
parent cb69ece6ca
commit 98517da474
13 changed files with 340 additions and 259 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,19 @@
# Generated by Django 4.2.9 on 2024-11-07 20:53
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('agenda_culturel', '0101_alter_tag_category'),
]
operations = [
migrations.AddField(
model_name='duplicatedevents',
name='representative',
field=models.ForeignKey(default=None, help_text='This event is the representative event of the duplicated events group', null=True, on_delete=django.db.models.deletion.SET_DEFAULT, to='agenda_culturel.event', verbose_name='Representative event'),
),
]

View File

@ -0,0 +1,59 @@
# Generated by Django 4.2.9 on 2024-11-07 20:53
from django.db import migrations
def set_representative_from_fixed_masked(apps, cats):
# get all duplicated events
DuplicatedEvents = apps.get_model("agenda_culturel", "DuplicatedEvents")
duplicated = DuplicatedEvents.objects.all().prefetch_related('event_set')
to_update = []
for d in duplicated:
# there is no representative
d.representative = None
# except if d is fixed
if d.fixed:
# and if there is at least one non masked (should be the case)
e_not_masked = [e for e in d.event_set.all() if not e.masked]
# keep the first one
if len(e_not_masked) >= 1:
d.representative = e_not_masked[0]
to_update.append(d)
DuplicatedEvents.objects.bulk_update(to_update, fields=["representative"])
def set_fixed_masked_from_representative(apps, cats):
Event = apps.get_model("agenda_culturel", "Event")
events = Event.objects.all().prefetch_related("possibly_duplicated")
to_update = []
for e in events:
if not e.possibly_duplicated:
e.masked = False
else:
e.masked = e.possibly_duplicated.representative and e.possibly_duplicated.representative == e
to_update.append(e)
Event.objects.bulk_update(to_update, fields=["masked"])
# get all duplicated events
DuplicatedEvents = apps.get_model("agenda_culturel", "DuplicatedEvents")
duplicated = DuplicatedEvents.objects.all().prefetch_related('event_set')
# for each event
to_update = []
for d in duplicated:
d.fixed = not d.representative is None
to_update.append(d)
DuplicatedEvents.objects.bulk_update(to_update, fields=["fixed"])
class Migration(migrations.Migration):
dependencies = [
('agenda_culturel', '0102_duplicatedevents_representative'),
]
operations = [
migrations.RunPython(set_representative_from_fixed_masked, reverse_code=set_fixed_masked_from_representative),
]

View File

@ -0,0 +1,17 @@
# Generated by Django 4.2.9 on 2024-11-07 21:24
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('agenda_culturel', '0103_update_duplicatedevents_datastructure'),
]
operations = [
migrations.RemoveField(
model_name='duplicatedevents',
name='fixed',
),
]

View File

@ -202,12 +202,14 @@ class Tag(models.Model):
class DuplicatedEvents(models.Model): class DuplicatedEvents(models.Model):
fixed = models.BooleanField(
verbose_name=_("Fixed"), representative = models.ForeignKey(
help_text=_("This duplicated events is fixed, ie exactly one of the listed events is not masked."), "Event",
default=False, verbose_name=_("Representative event"),
blank=True, help_text=_("This event is the representative event of the duplicated events group"),
null=True, null=True,
default=None,
on_delete=models.SET_DEFAULT,
) )
class Meta: class Meta:
@ -217,9 +219,6 @@ class DuplicatedEvents(models.Model):
def nb_duplicated(self): def nb_duplicated(self):
return self.event_set.count() return self.event_set.count()
def nb_duplicated_not_fixed(self):
return self.event_set.filter(possibly_duplicated=self, fixed=False).count()
def get_duplicated(self): def get_duplicated(self):
return self.event_set.order_by( return self.event_set.order_by(
"created_date" "created_date"
@ -238,7 +237,7 @@ class DuplicatedEvents(models.Model):
e.possibly_duplicated = other e.possibly_duplicated = other
# save them # save them
e.save() e.save()
other.save(force_fixed=False) other.save()
# then delete the empty group # then delete the empty group
self.delete() self.delete()
@ -283,13 +282,8 @@ class DuplicatedEvents(models.Model):
def fix_similar_entries(): def fix_similar_entries():
to_be_fixed = [] to_be_fixed = []
dup_events = Event.objects.order_by('possibly_duplicated').prefetch_related('possibly_duplicated', 'category') for d in DuplicatedEvents.objects.filter(representative__isnull=True).prefetch_related('event_set'):
duplicates = defaultdict(list) comp = Event.get_comparison(d.event_set.all())
for e in dup_events:
duplicates[e.possibly_duplicated].append(e)
for d in duplicates:
comp = Event.get_comparison(duplicates[d])
similar = len([c for c in comp if not c["similar"]]) == 0 similar = len([c for c in comp if not c["similar"]]) == 0
if similar: if similar:
to_be_fixed.append(d) to_be_fixed.append(d)
@ -297,23 +291,14 @@ class DuplicatedEvents(models.Model):
nb = len(to_be_fixed) nb = len(to_be_fixed)
if nb > 0: if nb > 0:
logger.warning("Removing: " + str(nb) + " similar duplicated") logger.warning("Removing: " + str(nb) + " similar duplicated")
for e in to_be_fixed:
logger.warning(" " + e.event_set.first().title)
for s in to_be_fixed: for s in to_be_fixed:
s.fix() s.fix()
return nb return nb
def save(self, *args, **kwargs):
if "force_fixed" in kwargs:
self.fixed = kwargs["force_fixed"]
del kwargs["force_fixed"]
elif not self.pk:
self.fixed = False
else:
self.fixed = self.event_set.filter(masked=False).count() == 1
super().save(*args, **kwargs)
class ReferenceLocation(models.Model): class ReferenceLocation(models.Model):
name = models.CharField(verbose_name=_("Name"), help_text=_("Name of the location"), unique=True, null=False) name = models.CharField(verbose_name=_("Name"), help_text=_("Name of the location"), unique=True, null=False)
location = LocationField(based_fields=["name"], zoom=12, default=Point(3.08333, 45.783329), srid=4326) location = LocationField(based_fields=["name"], zoom=12, default=Point(3.08333, 45.783329), srid=4326)
@ -1047,7 +1032,7 @@ class Event(models.Model):
else: else:
# otherwise merge existing groups # otherwise merge existing groups
group = DuplicatedEvents.merge_groups(groups) group = DuplicatedEvents.merge_groups(groups)
group.save(force_fixed=False) group.save()
# set the possibly duplicated group for the current object # set the possibly duplicated group for the current object
self.possibly_duplicated = group self.possibly_duplicated = group

View File

@ -5,7 +5,7 @@
<article> <article>
<header><a href="{% url 'view_duplicate' duplicate.pk %}"> <header><a href="{% url 'view_duplicate' duplicate.pk %}">
{% if duplicate.fixed %}Duplication{% else %}Possible duplication{% endif %} {% if duplicate.representative %}Duplication{% else %}Possible duplication{% endif %}
&nbsp;:</a> {{ events|length }} événements le {{ events.0.start_day }} &nbsp;:</a> {{ events|length }} événements le {{ events.0.start_day }}
</header> </header>
<ul> <ul>
@ -18,7 +18,7 @@
<div class="infos"></div> <div class="infos"></div>
<div class="buttons"> <div class="buttons">
<a role="button" href="{% url 'view_duplicate' duplicate.pk %}">Consulter {% picto_from_name "eye" %}</a> <a role="button" href="{% url 'view_duplicate' duplicate.pk %}">Consulter {% picto_from_name "eye" %}</a>
<a role="button" href="{% url 'fix_duplicate' duplicate.pk %}">{% if duplicate.fixed %}Modifier{% else %}Corriger{% endif %} {% picto_from_name "tool" %}</a> <a role="button" href="{% url 'fix_duplicate' duplicate.pk %}">{% if duplicate.representative %}Modifier{% else %}Corriger{% endif %} {% picto_from_name "tool" %}</a>
</div> </div>
</footer> </footer>
{% endif %} {% endif %}

View File

@ -14,8 +14,8 @@
<header> <header>
<a href="{% url 'duplicates' %}" role="button">&lt; Tous les dupliqués</a> <a href="{% url 'duplicates' %}" role="button">&lt; Tous les dupliqués</a>
<h1>{% block title %}{% block og_title %}Événements {% if not object.fixed %}possiblement{% endif %} dupliqués{% endblock %}{% endblock %}</h1> <h1>{% block title %}{% block og_title %}Événements {% if not object.representative %}possiblement{% endif %} dupliqués{% endblock %}{% endblock %}</h1>
{% if object.fixed %} {% if object.representative %}
<p>Les événements ci-dessous sont des duplicats du même événement, probablement issus de différentes <p>Les événements ci-dessous sont des duplicats du même événement, probablement issus de différentes
sources. La version qui sera affichée aux internautes en priorité est la version sources. La version qui sera affichée aux internautes en priorité est la version
{% for e in object.get_duplicated %}{% if not e.masked %}<span class="badge-small">{{ forloop.counter0|int_to_abc }}</span>{% endif %}{% endfor %}. {% for e in object.get_duplicated %}{% if not e.masked %}<span class="badge-small">{{ forloop.counter0|int_to_abc }}</span>{% endif %}{% endfor %}.

View File

@ -25,7 +25,10 @@
<button type="submit">Filtrer</button><br /> <button type="submit">Filtrer</button><br />
</form> </form>
<p>{{ paginator.count }} événement{{ paginator.count|pluralize }} dupliqués {% if filter.form.fixed.value %}sont résolus{% else %}doivent être résolus{% endif %}.</p> <p>{{ paginator.count }} événement{{ paginator.count|pluralize }} dupliqués{% if filter.form.fixed.value == None %}.{% else %}
{% if filter.form.fixed.value %}sont résolus.
{% else %}doivent être résolus.{% endif %}
{% endif %}</p>
</header> </header>
<div> <div>

View File

@ -12,8 +12,8 @@
{% block content %} {% block content %}
<article> <article>
<header> <header>
<h1>{% block title %}{% block og_title %}{% if object.fixed %}Modifier{% else %}Corriger{% endif %} des événements {% if not object.fixed %}possiblement{% endif %} dupliqués{% endblock %}{% endblock %}</h1> <h1>{% block title %}{% block og_title %}{% if object.representative %}Modifier{% else %}Corriger{% endif %} des événements {% if not object.representative %}possiblement{% endif %} dupliqués{% endblock %}{% endblock %}</h1>
{% if object.fixed %} {% if object.representative %}
<p>Les événements ci-dessous sont des duplicats du même événement, probablement issus de différentes <p>Les événements ci-dessous sont des duplicats du même événement, probablement issus de différentes
sources. La version qui sera affichée aux internautes en priorité est la version sources. La version qui sera affichée aux internautes en priorité est la version
{% for e in object.get_duplicated %}{% if not e.masked %}<span class="badge-small">{{ forloop.counter0|int_to_abc }}</span>{% endif %}{% endfor %}. {% for e in object.get_duplicated %}{% if not e.masked %}<span class="badge-small">{{ forloop.counter0|int_to_abc }}</span>{% endif %}{% endfor %}.

View File

@ -89,7 +89,7 @@
{% if poss_dup.count > 0 %} {% if poss_dup.count > 0 %}
<article> <article>
<header> <header>
{% if event.possibly_duplicated.fixed %} {% if event.possibly_duplicated.representative %}
<h2>Sources multiples</h2> <h2>Sources multiples</h2>
<p class="remarque">L'événement affiché a également été trouvé à partir <p class="remarque">L'événement affiché a également été trouvé à partir
{% if poss_dup.count == 1 %} {% if poss_dup.count == 1 %}

View File

@ -22,7 +22,7 @@
{% with poss_dup=event.get_possibly_duplicated|only_allowed:user.is_authenticated %} {% with poss_dup=event.get_possibly_duplicated|only_allowed:user.is_authenticated %}
{% if poss_dup.count > 0 %} {% if poss_dup.count > 0 %}
<p class="remarque"> <p class="remarque">
{% if event.possibly_duplicated.fixed %} {% if event.possibly_duplicated.representative %}
cet événement a été {% if user.is_authenticated %}<a href="{{ event.possibly_duplicated.get_absolute_url }}">importé plusieurs fois</a>{% else %}importé plusieurs fois{% endif %}, cet événement a été {% if user.is_authenticated %}<a href="{{ event.possibly_duplicated.get_absolute_url }}">importé plusieurs fois</a>{% else %}importé plusieurs fois{% endif %},
{% if event.masked %} {% if event.masked %}
vous pouvez <a href="{{ event.possibly_duplicated.get_one_event.get_absolute_url }}">consulter l'import principal</a> vous pouvez <a href="{{ event.possibly_duplicated.get_one_event.get_absolute_url }}">consulter l'import principal</a>

View File

@ -16,14 +16,13 @@ register = template.Library()
@register.simple_tag @register.simple_tag
def show_badge_duplicated(placement="top"): def show_badge_duplicated(placement="top"):
nb_duplicated = DuplicatedEvents.objects.annotate(nb_duplicated=Count('event', nb_duplicated = DuplicatedEvents.objects.filter(representative=None).count()
filter=Q(fixed=False), distinct=True)).filter(nb_duplicated__gte=1).count()
if nb_duplicated != 0: if nb_duplicated != 0:
return mark_safe( return mark_safe(
'<a href="' '<a href="'
+ reverse_lazy("duplicates") + reverse_lazy("duplicates")
+ '?fixed=false" class="badge" data-placement="' + '?fixed=False" class="badge" data-placement="'
+ placement + placement
+ '" data-tooltip="' + '" data-tooltip="'
+ str(nb_duplicated) + str(nb_duplicated)

View File

@ -1395,9 +1395,12 @@ def run_all_rimports(request, status=None):
######################### #########################
class DuplicatedEventsFilter(django_filters.FilterSet): class DuplicatedEventsFilter(django_filters.FilterSet):
fixed = django_filters.BooleanFilter(
field_name='representative', lookup_expr='isnull', exclude=True)
class Meta: class Meta:
model = DuplicatedEvents model = DuplicatedEvents
fields = ["fixed"] fields = []
class DuplicatedEventsDetailView(LoginRequiredMixin, DetailView): class DuplicatedEventsDetailView(LoginRequiredMixin, DetailView):