parent
11790f0200
commit
489d2e2f0f
@ -80,6 +80,8 @@ class EventForm(ModelForm):
|
|||||||
"imported_date",
|
"imported_date",
|
||||||
"modified_date",
|
"modified_date",
|
||||||
"moderated_date",
|
"moderated_date",
|
||||||
|
"import_sources",
|
||||||
|
"uuids"
|
||||||
]
|
]
|
||||||
widgets = {
|
widgets = {
|
||||||
"start_day": TextInput(
|
"start_day": TextInput(
|
||||||
@ -98,9 +100,7 @@ class EventForm(ModelForm):
|
|||||||
),
|
),
|
||||||
"end_day": TextInput(attrs={"type": "date"}),
|
"end_day": TextInput(attrs={"type": "date"}),
|
||||||
"end_time": TextInput(attrs={"type": "time"}),
|
"end_time": TextInput(attrs={"type": "time"}),
|
||||||
"uuids": MultipleHiddenInput(),
|
|
||||||
"other_versions": HiddenInput(),
|
"other_versions": HiddenInput(),
|
||||||
"import_sources": MultipleHiddenInput(),
|
|
||||||
"reference_urls": DynamicArrayWidgetURLs(),
|
"reference_urls": DynamicArrayWidgetURLs(),
|
||||||
"tags": DynamicArrayWidgetTags(),
|
"tags": DynamicArrayWidgetTags(),
|
||||||
}
|
}
|
||||||
@ -164,12 +164,16 @@ class FixDuplicates(Form):
|
|||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
choices = []
|
choices = []
|
||||||
|
initial = None
|
||||||
for i, e in enumerate(events):
|
for i, e in enumerate(events):
|
||||||
if e.status != Event.STATUS.TRASH:
|
if e.status != Event.STATUS.TRASH:
|
||||||
il = auc[i]
|
il = auc[i]
|
||||||
msg = ""
|
msg = ""
|
||||||
if e.modified():
|
if e.local_version():
|
||||||
msg = _(" (locally modified version)")
|
msg = _(" (locally modified version)")
|
||||||
|
initial = "Select" + il
|
||||||
|
if e.pure_import():
|
||||||
|
msg = _(" (synchronized on import version)")
|
||||||
choices += [
|
choices += [
|
||||||
(
|
(
|
||||||
"Select" + il,
|
"Select" + il,
|
||||||
@ -177,8 +181,10 @@ class FixDuplicates(Form):
|
|||||||
)
|
)
|
||||||
]
|
]
|
||||||
extra = ""
|
extra = ""
|
||||||
if edup.has_modified():
|
if edup.has_local_version():
|
||||||
extra = _(" Warning: a version is already locally modified.")
|
extra = _(" Warning: a version is already locally modified.")
|
||||||
|
if initial is None:
|
||||||
|
initial = "Merge"
|
||||||
choices += [
|
choices += [
|
||||||
("Merge", _("Create a new version by merging.") + extra)
|
("Merge", _("Create a new version by merging.") + extra)
|
||||||
]
|
]
|
||||||
@ -193,6 +199,7 @@ class FixDuplicates(Form):
|
|||||||
choices += [("NotDuplicates", _("Make all versions independent."))]
|
choices += [("NotDuplicates", _("Make all versions independent."))]
|
||||||
|
|
||||||
self.fields["action"].choices = choices
|
self.fields["action"].choices = choices
|
||||||
|
self.fields["action"].initial = initial
|
||||||
|
|
||||||
def is_action_no_duplicates(self):
|
def is_action_no_duplicates(self):
|
||||||
return self.cleaned_data["action"] == "NotDuplicates"
|
return self.cleaned_data["action"] == "NotDuplicates"
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -237,18 +237,24 @@ class DuplicatedEvents(models.Model):
|
|||||||
def fixed(self):
|
def fixed(self):
|
||||||
return not self.representative is None
|
return not self.representative is None
|
||||||
|
|
||||||
|
def is_published(self):
|
||||||
|
return len([e for e in self.get_duplicated() if e.is_published()]) > 0
|
||||||
|
|
||||||
def has_modified(self):
|
def has_modified(self):
|
||||||
return len([e for e in self.get_duplicated() if e.modified()]) > 0
|
return len([e for e in self.get_duplicated() if e.modified()]) > 0
|
||||||
|
|
||||||
|
def has_local_version(self):
|
||||||
|
return len([e for e in self.get_duplicated() if e.local_version()]) > 0
|
||||||
|
|
||||||
def get_local_version(self):
|
def get_local_version(self):
|
||||||
if self.representative and self.representative.modified():
|
if self.representative and self.representative.local_version():
|
||||||
return self.representative
|
return self.representative
|
||||||
|
|
||||||
l = [e for e in self.get_duplicated() if e.modified()]
|
l = [e for e in self.get_duplicated() if e.local_version()]
|
||||||
if len(l) == 0:
|
if len(l) == 0:
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
l.sort(key=lambda x: -x.modified_date)
|
l.sort(key=lambda x: x.modified_date, reverse=True)
|
||||||
return l[0]
|
return l[0]
|
||||||
|
|
||||||
def merge_into(self, other):
|
def merge_into(self, other):
|
||||||
@ -256,7 +262,8 @@ class DuplicatedEvents(models.Model):
|
|||||||
for e in self.get_duplicated():
|
for e in self.get_duplicated():
|
||||||
# change their group membership
|
# change their group membership
|
||||||
e.other_versions = other
|
e.other_versions = other
|
||||||
# save them
|
# save them without updating modified date
|
||||||
|
e.set_no_modification_date_changed()
|
||||||
e.save()
|
e.save()
|
||||||
other.representative = None
|
other.representative = None
|
||||||
other.save()
|
other.save()
|
||||||
@ -304,27 +311,6 @@ class DuplicatedEvents(models.Model):
|
|||||||
nb, d = singletons.delete()
|
nb, d = singletons.delete()
|
||||||
return nb
|
return nb
|
||||||
|
|
||||||
def fix_similar_entries():
|
|
||||||
to_be_fixed = []
|
|
||||||
|
|
||||||
for d in DuplicatedEvents.not_fixed_qs().prefetch_related('event_set'):
|
|
||||||
comp = Event.get_comparison(d.get_duplicated())
|
|
||||||
similar = len([c for c in comp if not c["similar"]]) == 0
|
|
||||||
if similar:
|
|
||||||
to_be_fixed.append(d)
|
|
||||||
|
|
||||||
nb = len(to_be_fixed)
|
|
||||||
if nb > 0:
|
|
||||||
logger.warning("Removing: " + str(nb) + " similar duplicated")
|
|
||||||
for d in to_be_fixed:
|
|
||||||
if len(d.get_duplicated()) == 0:
|
|
||||||
logger.warning(" empty")
|
|
||||||
else:
|
|
||||||
logger.warning(" " + d.get_duplicated()[0].title)
|
|
||||||
for s in to_be_fixed:
|
|
||||||
s.fix()
|
|
||||||
|
|
||||||
return nb
|
|
||||||
|
|
||||||
def not_fixed_qs(qs=None, fixed=False):
|
def not_fixed_qs(qs=None, fixed=False):
|
||||||
if not qs:
|
if not qs:
|
||||||
@ -673,6 +659,21 @@ class Event(models.Model):
|
|||||||
return False
|
return False
|
||||||
return self.modified_date is None or (self.modified_date - self.imported_date).total_seconds() <= 0
|
return self.modified_date is None or (self.modified_date - self.imported_date).total_seconds() <= 0
|
||||||
|
|
||||||
|
def local_version(self):
|
||||||
|
return self.imported_date is None or self.modified()
|
||||||
|
|
||||||
|
def get_reference_urls(self):
|
||||||
|
res = [] if self.reference_urls is None else self.reference_urls
|
||||||
|
|
||||||
|
if self.other_versions:
|
||||||
|
for o in self.other_versions.get_duplicated():
|
||||||
|
if o.status == Event.STATUS.PUBLISHED and not o.reference_urls is None:
|
||||||
|
res += o.reference_urls
|
||||||
|
|
||||||
|
res = list(set(res))
|
||||||
|
res.sort()
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
def get_local_version(self):
|
def get_local_version(self):
|
||||||
# a non-pure import is a local version
|
# a non-pure import is a local version
|
||||||
@ -689,7 +690,12 @@ class Event(models.Model):
|
|||||||
return Event.objects.filter(status=Event.STATUS.DRAFT).count()
|
return Event.objects.filter(status=Event.STATUS.DRAFT).count()
|
||||||
|
|
||||||
def get_qs_events_with_unkwnon_place():
|
def get_qs_events_with_unkwnon_place():
|
||||||
return Event.objects.filter(exact_location__isnull=True).filter(~Q(status=Event.STATUS.TRASH)).filter(Q(other_versions=None)|~Q(other_versions__representative=F('pk')))
|
return Event.objects.filter(exact_location__isnull=True). \
|
||||||
|
filter(~Q(status=Event.STATUS.TRASH)). \
|
||||||
|
filter(Q(other_versions=None)|Q(other_versions__representative=F('pk')))
|
||||||
|
|
||||||
|
def is_representative(self):
|
||||||
|
return self.other_versions is None or self.other_versions.representative == self
|
||||||
|
|
||||||
def download_image(self):
|
def download_image(self):
|
||||||
# first download file
|
# first download file
|
||||||
@ -717,13 +723,19 @@ class Event(models.Model):
|
|||||||
def set_in_importation_process(self):
|
def set_in_importation_process(self):
|
||||||
self.in_importation_process = True
|
self.in_importation_process = True
|
||||||
|
|
||||||
|
def is_no_modification_date_changed(self):
|
||||||
|
return hasattr(self, "no_modification_date_changed")
|
||||||
|
|
||||||
|
def set_no_modification_date_changed(self):
|
||||||
|
self.no_modification_date_changed = True
|
||||||
|
|
||||||
def update_modification_dates(self):
|
def update_modification_dates(self):
|
||||||
now = timezone.now()
|
now = timezone.now()
|
||||||
if not self.id:
|
if not self.id:
|
||||||
self.created_date = now
|
self.created_date = now
|
||||||
if self.is_in_importation_process():
|
if self.is_in_importation_process():
|
||||||
self.imported_date = now
|
self.imported_date = now
|
||||||
if self.modified_date is None or not self.is_in_importation_process():
|
if self.modified_date is None or not self.is_no_modification_date_changed():
|
||||||
self.modified_date = now
|
self.modified_date = now
|
||||||
|
|
||||||
def get_recurrence_at_date(self, year, month, day):
|
def get_recurrence_at_date(self, year, month, day):
|
||||||
@ -873,7 +885,12 @@ class Event(models.Model):
|
|||||||
if len(similar_events) != 0:
|
if len(similar_events) != 0:
|
||||||
self.set_other_versions(similar_events)
|
self.set_other_versions(similar_events)
|
||||||
|
|
||||||
|
# check if it's a clone (that will become representative)
|
||||||
|
clone = self.pk is None and not self.other_versions is None
|
||||||
|
|
||||||
|
# check if we need to clean the other_versions
|
||||||
if (
|
if (
|
||||||
|
not clone and
|
||||||
self.pk and
|
self.pk and
|
||||||
self.other_versions is not None
|
self.other_versions is not None
|
||||||
and self.other_versions.nb_duplicated() == 1
|
and self.other_versions.nb_duplicated() == 1
|
||||||
@ -881,8 +898,14 @@ class Event(models.Model):
|
|||||||
self.other_versions.delete()
|
self.other_versions.delete()
|
||||||
self.other_versions = None
|
self.other_versions = None
|
||||||
|
|
||||||
|
# first save the current object
|
||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
# then if its a clone, update the representative
|
||||||
|
if clone:
|
||||||
|
self.other_versions.representative = self
|
||||||
|
self.other_versions.save()
|
||||||
|
|
||||||
def from_structure(event_structure, import_source=None):
|
def from_structure(event_structure, import_source=None):
|
||||||
if "category" in event_structure and event_structure["category"] is not None:
|
if "category" in event_structure and event_structure["category"] is not None:
|
||||||
try:
|
try:
|
||||||
@ -1057,9 +1080,9 @@ class Event(models.Model):
|
|||||||
def masked(self):
|
def masked(self):
|
||||||
return self.other_versions and self.other_versions.representative != self
|
return self.other_versions and self.other_versions.representative != self
|
||||||
|
|
||||||
def get_comparison(events, all=True):
|
def get_comparison(events):
|
||||||
result = []
|
result = []
|
||||||
for attr in Event.data_fields(all=all, local_img=False, exact_location=False):
|
for attr in Event.data_fields(local_img=False, exact_location=False):
|
||||||
values = [getattr(e, attr) for e in events]
|
values = [getattr(e, attr) for e in events]
|
||||||
values = ["" if v is None else v for v in values]
|
values = ["" if v is None else v for v in values]
|
||||||
values = [[] if attr == "tags" and v == "" else v for v in values]
|
values = [[] if attr == "tags" and v == "" else v for v in values]
|
||||||
@ -1067,20 +1090,22 @@ class Event(models.Model):
|
|||||||
if attr == "image":
|
if attr == "image":
|
||||||
values = [v.split("?")[0] if "fbcdn.net" in v else v for v in values]
|
values = [v.split("?")[0] if "fbcdn.net" in v else v for v in values]
|
||||||
|
|
||||||
if len(set([str(v) for v in values])) == 1:
|
if attr == "description":
|
||||||
|
values = [v.replace("\r\n", "\n") for v in values]
|
||||||
|
if len(set([str(v).strip() for v in values])) == 1:
|
||||||
result.append({"similar": True, "key": attr, "values": values[0]})
|
result.append({"similar": True, "key": attr, "values": values[0]})
|
||||||
else:
|
else:
|
||||||
result.append({"similar": False, "key": attr, "values": values})
|
result.append({"similar": False, "key": attr, "values": values})
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def similar(self, event, all=True):
|
def similar(self, event):
|
||||||
res = Event.get_comparison([self, event], all)
|
res = Event.get_comparison([self, event])
|
||||||
for r in res:
|
for r in res:
|
||||||
if not r["similar"]:
|
if not r["similar"]:
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def set_other_versions(self, events):
|
def set_other_versions(self, events, force_non_fixed=False):
|
||||||
# get existing groups
|
# get existing groups
|
||||||
groups = list(
|
groups = list(
|
||||||
set([e.other_versions for e in events] + [self.other_versions])
|
set([e.other_versions for e in events] + [self.other_versions])
|
||||||
@ -1093,6 +1118,9 @@ class Event(models.Model):
|
|||||||
else:
|
else:
|
||||||
# otherwise merge existing groups
|
# otherwise merge existing groups
|
||||||
group = DuplicatedEvents.merge_groups(groups)
|
group = DuplicatedEvents.merge_groups(groups)
|
||||||
|
|
||||||
|
if force_non_fixed:
|
||||||
|
group.representative = None
|
||||||
group.save()
|
group.save()
|
||||||
|
|
||||||
# set the possibly duplicated group for the current object
|
# set the possibly duplicated group for the current object
|
||||||
@ -1106,13 +1134,10 @@ class Event(models.Model):
|
|||||||
elist = list(events) + ([self] if self.pk is not None else [])
|
elist = list(events) + ([self] if self.pk is not None else [])
|
||||||
Event.objects.bulk_update(elist, fields=["other_versions"])
|
Event.objects.bulk_update(elist, fields=["other_versions"])
|
||||||
|
|
||||||
def data_fields(all=False, local_img=True, exact_location=True):
|
def data_fields(local_img=True, exact_location=True):
|
||||||
if all:
|
result = [
|
||||||
result = ["category"]
|
"category",
|
||||||
else:
|
"tags",
|
||||||
result = []
|
|
||||||
|
|
||||||
result += [
|
|
||||||
"title",
|
"title",
|
||||||
"location",
|
"location",
|
||||||
"start_day",
|
"start_day",
|
||||||
@ -1131,15 +1156,6 @@ class Event(models.Model):
|
|||||||
result += ["tags"]
|
result += ["tags"]
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def same_event_by_data(self, other):
|
|
||||||
for attr in Event.data_fields():
|
|
||||||
if str(getattr(self, attr)) != str(getattr(other, attr)):
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def find_same_event_by_data_in_list(self, events):
|
|
||||||
return [e for e in events if self.same_event_by_data(e)]
|
|
||||||
|
|
||||||
def find_last_imported(events):
|
def find_last_imported(events):
|
||||||
events = [e for e in events if e.imported_date is not None]
|
events = [e for e in events if e.imported_date is not None]
|
||||||
if len(events) == 0:
|
if len(events) == 0:
|
||||||
@ -1148,13 +1164,8 @@ class Event(models.Model):
|
|||||||
events.sort(key=lambda e: e.imported_date, reverse=True)
|
events.sort(key=lambda e: e.imported_date, reverse=True)
|
||||||
return events[0]
|
return events[0]
|
||||||
|
|
||||||
def find_last_imported_not_modified(events):
|
def find_last_pure_import(events):
|
||||||
events = [
|
events = [e for e in events if e.pure_import()]
|
||||||
e
|
|
||||||
for e in events
|
|
||||||
if e.imported_date is not None
|
|
||||||
and (e.modified_date is None or e.modified_date <= e.imported_date)
|
|
||||||
]
|
|
||||||
if len(events) == 0:
|
if len(events) == 0:
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
@ -1163,13 +1174,6 @@ class Event(models.Model):
|
|||||||
|
|
||||||
def update(self, other):
|
def update(self, other):
|
||||||
|
|
||||||
# we do not modify the category (local categories are more important)
|
|
||||||
# however, we add supplementary tags
|
|
||||||
if other.tags:
|
|
||||||
if not self.tags:
|
|
||||||
self.tags = []
|
|
||||||
self.tags += [t for t in other.tags if not t in self.tags]
|
|
||||||
|
|
||||||
# set attributes
|
# set attributes
|
||||||
for attr in Event.data_fields():
|
for attr in Event.data_fields():
|
||||||
setattr(self, attr, getattr(other, attr))
|
setattr(self, attr, getattr(other, attr))
|
||||||
@ -1223,25 +1227,36 @@ class Event(models.Model):
|
|||||||
|
|
||||||
if len(same_events) != 0:
|
if len(same_events) != 0:
|
||||||
# check if one event has been imported and not modified in this list
|
# check if one event has been imported and not modified in this list
|
||||||
same_imported = Event.find_last_imported_not_modified(same_events)
|
same_imported = Event.find_last_pure_import(same_events)
|
||||||
# check if the imported events are similar or not (considering data and not category or tags)
|
|
||||||
same_events_not_similar = [
|
# if not, we check if it does not match exactly with another
|
||||||
e for e in same_events if not e.similar(event, False)
|
if not same_imported:
|
||||||
]
|
for e in same_events:
|
||||||
if same_imported or len(same_events_not_similar) == 0:
|
if event.similar(e):
|
||||||
# TODO: revoir ici:
|
same_imported = e
|
||||||
if not same_imported:
|
break
|
||||||
same_imported = Event.find_last_imported(same_events)
|
|
||||||
|
if same_imported:
|
||||||
|
# reopen DuplicatedEvents if required
|
||||||
|
if not event.similar(same_imported) and same_imported.other_versions:
|
||||||
|
if same_imported.status != Event.STATUS.TRASH:
|
||||||
|
if same_imported.other_versions.is_published():
|
||||||
|
if same_imported.other_versions.representative != same_imported:
|
||||||
|
same_imported.other_versions.representative = None
|
||||||
|
same_imported.other_versions.save()
|
||||||
|
|
||||||
# if this event exists, it will be updated with new data only if the data is fresher
|
|
||||||
if same_imported.modified_date < event.modified_date:
|
|
||||||
same_imported.update(event)
|
same_imported.update(event)
|
||||||
same_imported.set_in_importation_process()
|
same_imported.set_in_importation_process()
|
||||||
same_imported.prepare_save()
|
same_imported.prepare_save()
|
||||||
to_update.append(same_imported)
|
to_update.append(same_imported)
|
||||||
else:
|
else:
|
||||||
# otherwise, the new event possibly a duplication of the remaining others.
|
# otherwise, the new event possibly a duplication of the remaining others.
|
||||||
event.set_other_versions(same_events)
|
|
||||||
|
# check if it should be published
|
||||||
|
trash = len([e for e in same_events if e.status != Event.STATUS.TRASH]) == 0
|
||||||
|
if trash:
|
||||||
|
event.status = Event.STATUS.TRASH
|
||||||
|
event.set_other_versions(same_events, force_non_fixed=not trash)
|
||||||
# it will be imported
|
# it will be imported
|
||||||
to_import.append(event)
|
to_import.append(event)
|
||||||
else:
|
else:
|
||||||
@ -1250,17 +1265,8 @@ class Event(models.Model):
|
|||||||
|
|
||||||
# if it exists similar events, add this relation to the event
|
# if it exists similar events, add this relation to the event
|
||||||
if len(similar_events) != 0:
|
if len(similar_events) != 0:
|
||||||
# check if an event from the list is exactly the same as the new one (using data)
|
|
||||||
same_events = event.find_same_event_by_data_in_list(similar_events)
|
|
||||||
if same_events is not None and len(same_events) > 0:
|
|
||||||
# merge with the first one
|
|
||||||
same_events[0].update(event)
|
|
||||||
same_events[0].set_in_importation_process()
|
|
||||||
same_events[0].prepare_save()
|
|
||||||
to_update.append(same_events[0])
|
|
||||||
else:
|
|
||||||
# the event is possibly a duplication of the others
|
# the event is possibly a duplication of the others
|
||||||
event.set_other_versions(similar_events)
|
event.set_other_versions(similar_events, force_non_fixed=True)
|
||||||
to_import.append(event)
|
to_import.append(event)
|
||||||
else:
|
else:
|
||||||
# import this new event
|
# import this new event
|
||||||
@ -1300,6 +1306,8 @@ class Event(models.Model):
|
|||||||
for e in in_interval:
|
for e in in_interval:
|
||||||
if len(uuids.intersection(e.uuids)) == 0:
|
if len(uuids.intersection(e.uuids)) == 0:
|
||||||
e.status = Event.STATUS.TRASH
|
e.status = Event.STATUS.TRASH
|
||||||
|
# save them without updating modified date
|
||||||
|
e.set_no_modification_date_changed()
|
||||||
e.prepare_save()
|
e.prepare_save()
|
||||||
to_draft.append(e)
|
to_draft.append(e)
|
||||||
|
|
||||||
|
@ -549,6 +549,10 @@ article#filters {
|
|||||||
font-size: 100%;
|
font-size: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
header .remarque {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.django-ckeditor-widget {
|
.django-ckeditor-widget {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
{% if e.imported_date %}<li>Dernière importation : {{ e.imported_date }}</li>{% endif %}
|
{% if e.imported_date %}<li>Dernière importation : {{ e.imported_date }}</li>{% endif %}
|
||||||
<li>État :
|
<li>État :
|
||||||
{% if e.pure_import %}version fidèle à la source importée{% endif %}
|
{% if e.pure_import %}version fidèle à la source importée{% endif %}
|
||||||
{% if e.modified %}<strong>version modifiée localement</strong>{% endif %}
|
{% if e.local_version %}<strong>version modifiée localement</strong>{% endif %}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
{% if user.is_authenticated %}
|
||||||
|
<p class="footer">Création : {{ event.created_date }}
|
||||||
|
{% if event.modified %}
|
||||||
|
— dernière modification : {{ event.modified_date }}
|
||||||
|
{% endif %}
|
||||||
|
{% if event.imported_date %}
|
||||||
|
— dernière importation : {{ event.imported_date }}
|
||||||
|
{% endif %}
|
||||||
|
{% if event.moderated_date %}
|
||||||
|
— dernière modération : {{ event.moderated_date }}
|
||||||
|
{% endif %}
|
||||||
|
{% if event.pure_import %}
|
||||||
|
— <strong>version importée</strong>
|
||||||
|
{% endif %}
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
@ -0,0 +1,14 @@
|
|||||||
|
{% load utils_extra %}
|
||||||
|
|
||||||
|
{% with event.get_reference_urls as refs %}
|
||||||
|
{% if refs|length > 0 %}
|
||||||
|
<p>Source{{ refs|pluralize }} :
|
||||||
|
|
||||||
|
{% for eurl in refs %}
|
||||||
|
<a href="{{ eurl }}">{{ eurl|hostname }}</a>{% if not forloop.last %}, {% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</p>
|
||||||
|
{% else %}
|
||||||
|
<p><em>À notre connaissance, cet événement n'est pas référencé autre part sur internet.</em></p>
|
||||||
|
{% endif %}
|
||||||
|
{% endwith %}
|
@ -84,29 +84,19 @@
|
|||||||
{% endwith %}
|
{% endwith %}
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
</article>
|
</article>
|
||||||
{% if event.other_versions %}
|
{% if event.other_versions and not event.other_versions.fixed %}
|
||||||
{% with poss_dup=event.get_other_versions|only_allowed:user.is_authenticated %}
|
{% with poss_dup=event.get_other_versions|only_allowed:user.is_authenticated %}
|
||||||
{% if poss_dup|length > 0 %}
|
{% if poss_dup|length > 0 %}
|
||||||
<article id="liste-dupliques">
|
<article id="liste-dupliques">
|
||||||
<header>
|
<header>
|
||||||
{% if event.other_versions.representative %}
|
|
||||||
<h2>Sources multiples</h2>
|
|
||||||
<p class="remarque">L'événement affiché est également disponible
|
|
||||||
{% if poss_dup.count == 1 %}
|
|
||||||
dans une autre version
|
|
||||||
{% else %}
|
|
||||||
dans d'autres versions
|
|
||||||
{% endif %} :</p>
|
|
||||||
{% else %}
|
|
||||||
<h2>Possibles doublons</h2>
|
<h2>Possibles doublons</h2>
|
||||||
<p class="remarque">Notre algorithme a détecté que l'événement affiché pourrait être dupliqué sur l'agenda, et consultable dans
|
<p class="remarque">L'événement affiché pourrait être dupliqué sur l'agenda, et consultable dans
|
||||||
{% if poss_dup.count == 1 %}
|
{% if poss_dup.count == 1 %}
|
||||||
une autre version
|
une autre version
|
||||||
{% else %}
|
{% else %}
|
||||||
d'autres versions
|
d'autres versions
|
||||||
{% endif %}
|
{% endif %}
|
||||||
ci-dessous.</p>
|
ci-dessous. Nous faisons notre maximum pour résoudre cette duplication temporaire.</p>
|
||||||
{% endif %}
|
|
||||||
</header>
|
</header>
|
||||||
<nav>
|
<nav>
|
||||||
<ul class="no-breakline">
|
<ul class="no-breakline">
|
||||||
|
@ -48,6 +48,7 @@
|
|||||||
{% if perms.agenda_culturel.change_event %}
|
{% if perms.agenda_culturel.change_event %}
|
||||||
<footer>
|
<footer>
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
|
{% include "agenda_culturel/event-date-info-inc.html" %}
|
||||||
{% include "agenda_culturel/edit-buttons-inc.html" with event=event %}
|
{% include "agenda_culturel/edit-buttons-inc.html" with event=event %}
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
@ -60,16 +60,8 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{% if event.reference_urls %}
|
{% include "agenda_culturel/event-sources-inc.html" %}
|
||||||
<p>Source{{ event.reference_urls|pluralize }} :
|
|
||||||
|
|
||||||
{% for eurl in event.reference_urls %}
|
|
||||||
<a href="{{ eurl }}">{{ eurl|hostname }}</a>{% if not forloop.last %}, {% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
</p>
|
|
||||||
{% else %}
|
|
||||||
<p><em>À notre connaissance, cet événement n'est pas référencé autre part sur internet.</em></p>
|
|
||||||
{% endif %}
|
|
||||||
{% if event.has_recurrences %}
|
{% if event.has_recurrences %}
|
||||||
<p class="footer">
|
<p class="footer">
|
||||||
{% picto_from_name "repeat" %}
|
{% picto_from_name "repeat" %}
|
||||||
|
@ -46,15 +46,7 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{% if event.reference_urls %}
|
{% include "agenda_culturel/event-sources-inc.html" %}
|
||||||
<p>Source{{ event.reference_urls|pluralize }} :
|
|
||||||
{% for eurl in event.reference_urls %}
|
|
||||||
<a href="{{ eurl }}">{{ eurl|hostname }}</a>{% if not forloop.last %}, {% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
</p>
|
|
||||||
{% else %}
|
|
||||||
<p><em>À notre connaissance, cet événement n'est pas référencé autre part sur internet.</em></p>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
{% if perms.agenda_culturel.change_event %}
|
{% if perms.agenda_culturel.change_event %}
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
{{ event.title }}</a></p>
|
{{ event.title }}</a></p>
|
||||||
{% picto_from_name "map-pin" %}
|
{% picto_from_name "map-pin" %}
|
||||||
{% include "agenda_culturel/event-location-inc.html" with event=event %}
|
{% include "agenda_culturel/event-location-inc.html" with event=event %}
|
||||||
</header>
|
|
||||||
<p>{% picto_from_name "calendar" %}
|
<p>{% picto_from_name "calendar" %}
|
||||||
{% if event.end_day and event.end_day != event.start_day %}du{% else %}le{% endif %}
|
{% if event.end_day and event.end_day != event.start_day %}du{% else %}le{% endif %}
|
||||||
{% include "agenda_culturel/date-times-inc.html" with event=event %}
|
{% include "agenda_culturel/date-times-inc.html" with event=event %}
|
||||||
@ -34,6 +33,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if event.tags and event.tags|length > 0 %}
|
||||||
<p>
|
<p>
|
||||||
{% picto_from_name "tag" %}
|
{% picto_from_name "tag" %}
|
||||||
{% for tag in event.tags %}
|
{% for tag in event.tags %}
|
||||||
@ -41,7 +41,12 @@
|
|||||||
{% if not forloop.last %}, {% endif %}
|
{% if not forloop.last %}, {% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</p>
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
</header>
|
||||||
<div class="description">
|
<div class="description">
|
||||||
{% if event.description %}{{ event.description |truncatewords:60 }}{% else %}<em>pas de description</em>{% endif %}
|
{% if event.description %}{{ event.description |truncatewords:60 }}{% else %}<em>pas de description</em>{% endif %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
<footer>
|
||||||
|
{% include "agenda_culturel/event-date-info-inc.html" %}
|
||||||
|
</footer>
|
@ -18,26 +18,38 @@
|
|||||||
{% picto_from_name "map-pin" %}
|
{% picto_from_name "map-pin" %}
|
||||||
{% include "agenda_culturel/event-location-inc.html" with event=event %}
|
{% include "agenda_culturel/event-location-inc.html" with event=event %}
|
||||||
</p>
|
</p>
|
||||||
|
{% if user.is_authenticated %}
|
||||||
|
|
||||||
{% if event.other_versions %}
|
{% if event.other_versions %}
|
||||||
{% with poss_dup=event.get_other_not_trash_versions|only_allowed:user.is_authenticated %}
|
{% with poss_dup=event.get_other_not_trash_versions %}
|
||||||
{% if poss_dup|length > 0 %}
|
{% if poss_dup|length > 0 %}
|
||||||
<p class="remarque">
|
<p class="remarque">
|
||||||
{% if event.other_versions.representative %}
|
{% if event.other_versions.representative %}
|
||||||
cet événement existe <a href="{% if user.is_authenticated %}{{ event.other_versions.get_absolute_url }}{% else %}#liste-dupliques{% endif %}">en plusieurs versions</a>,
|
cet événement existe <a href="{{ event.other_versions.get_absolute_url }}">en plusieurs versions</a>,
|
||||||
{% if event.masked %}
|
{% if event.masked %}
|
||||||
vous pouvez consulter <a href="{{ event.other_versions.get_one_event.get_absolute_url }}">la version mise en avant</a>
|
vous pouvez consulter <a href="{{ event.other_versions.get_one_event.get_absolute_url }}">la version mise en avant</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
et vous consultez la version mise en avant
|
et vous consultez la version mise en avant
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
cet événement existe probablement <a href="{% if user.is_authenticated %}{{ event.other_versions.get_absolute_url }}{% else %}#liste-dupliques{% endif %}">en plusieurs versions</a>
|
cet événement existe probablement <a href="{{ event.other_versions.get_absolute_url }}">en plusieurs versions</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
{% if event.other_versions.representative and event.masked %}
|
||||||
|
<p class="remarque">
|
||||||
|
Vous consultez l'événement dans une version non consolidée. Nous vous invitons
|
||||||
|
à consulter sa <a href="{{ event.other_versions.representative.get_absolute_url }}">version représentative</a>.
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|
||||||
{% if event.has_image_url %}
|
{% if event.has_image_url %}
|
||||||
<article class='illustration'>
|
<article class='illustration'>
|
||||||
<img src="{{ event.get_image_url }}" alt="{{ event.image_alt }}" />
|
<img src="{{ event.get_image_url }}" alt="{{ event.image_alt }}" />
|
||||||
@ -55,15 +67,8 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{% if event.reference_urls %}
|
|
||||||
<p>Cet événement est proposé par
|
{% include "agenda_culturel/event-sources-inc.html" %}
|
||||||
{% for eurl in event.reference_urls %}
|
|
||||||
<a href="{{ eurl }}">{{ eurl|hostname }}</a>{% if not forloop.last %}, {% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
</p>
|
|
||||||
{% else %}
|
|
||||||
<p><em>À notre connaissance, cet événement n'est pas référencé autre part sur internet.</em></p>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if event.has_recurrences %}
|
{% if event.has_recurrences %}
|
||||||
<p class="footer">
|
<p class="footer">
|
||||||
@ -79,21 +84,7 @@
|
|||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<p class="footer">Création : {{ event.created_date }}
|
{% include "agenda_culturel/event-date-info-inc.html" %}
|
||||||
{% if event.modified %}
|
|
||||||
— dernière modification : {{ event.modified_date }}
|
|
||||||
{% endif %}
|
|
||||||
{% if event.imported_date %}
|
|
||||||
— dernière importation : {{ event.imported_date }}
|
|
||||||
{% endif %}
|
|
||||||
{% if event.moderated_date %}
|
|
||||||
— dernière modération : {{ event.moderated_date }}
|
|
||||||
{% endif %}
|
|
||||||
{% if event.pure_import %}
|
|
||||||
— <strong>version importée</strong>
|
|
||||||
{% endif %}
|
|
||||||
{{ event.delai }}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<a href="{% url 'export_event_ical' event.start_day.year event.start_day.month event.start_day.day event.id %}" role="button">Exporter ical {% picto_from_name "calendar" %}</a>
|
<a href="{% url 'export_event_ical' event.start_day.year event.start_day.month event.start_day.day event.id %}" role="button">Exporter ical {% picto_from_name "calendar" %}</a>
|
||||||
|
@ -575,6 +575,8 @@ class EventUpdateView(
|
|||||||
# if no DuplicatedEvents is associated, create one
|
# if no DuplicatedEvents is associated, create one
|
||||||
obj.other_versions = DuplicatedEvents.objects.create()
|
obj.other_versions = DuplicatedEvents.objects.create()
|
||||||
obj.other_versions.save()
|
obj.other_versions.save()
|
||||||
|
# save them without updating modified date
|
||||||
|
obj.set_no_modification_date_changed()
|
||||||
obj.save()
|
obj.save()
|
||||||
result["other_versions"] = obj.other_versions
|
result["other_versions"] = obj.other_versions
|
||||||
|
|
||||||
@ -1542,6 +1544,7 @@ def fix_duplicate(request, pk):
|
|||||||
event.other_versions = None
|
event.other_versions = None
|
||||||
if edup.representative == event:
|
if edup.representative == event:
|
||||||
edup.representative = None
|
edup.representative = None
|
||||||
|
event.set_no_modification_date_changed()
|
||||||
event.save()
|
event.save()
|
||||||
edup.save()
|
edup.save()
|
||||||
messages.success(request, _("The event has been withdrawn from the group and made independent."))
|
messages.success(request, _("The event has been withdrawn from the group and made independent."))
|
||||||
@ -1575,12 +1578,11 @@ class DuplicatedEventsUpdateView(LoginRequiredMixin, UpdateView):
|
|||||||
@permission_required("agenda_culturel.view_duplicatedevents")
|
@permission_required("agenda_culturel.view_duplicatedevents")
|
||||||
def duplicates(request):
|
def duplicates(request):
|
||||||
nb_removed = DuplicatedEvents.remove_singletons()
|
nb_removed = DuplicatedEvents.remove_singletons()
|
||||||
nb_similar = DuplicatedEvents.fix_similar_entries()
|
if nb_removed > 0:
|
||||||
if nb_removed > 0 or nb_similar > 0:
|
|
||||||
messages.success(
|
messages.success(
|
||||||
request,
|
request,
|
||||||
_("Cleaning up duplicates: {} item(s) fixed.").format(
|
_("Cleaning up duplicates: {} item(s) fixed.").format(
|
||||||
nb_removed + nb_similar
|
nb_removed
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1624,6 +1626,8 @@ def set_duplicate(request, year, month, day, pk):
|
|||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
selected = [o for o in others if o.pk == int(form.cleaned_data["event"])]
|
selected = [o for o in others if o.pk == int(form.cleaned_data["event"])]
|
||||||
event.set_other_versions(selected)
|
event.set_other_versions(selected)
|
||||||
|
# save them without updating modified date
|
||||||
|
event.set_no_modification_date_changed()
|
||||||
event.save()
|
event.save()
|
||||||
if request.user.is_authenticated:
|
if request.user.is_authenticated:
|
||||||
messages.success(request, _("The event was successfully duplicated."))
|
messages.success(request, _("The event was successfully duplicated."))
|
||||||
@ -1997,7 +2001,7 @@ def fix_unknown_places(request):
|
|||||||
# get all places
|
# get all places
|
||||||
places = Place.objects.all()
|
places = Place.objects.all()
|
||||||
# get all events without exact location
|
# get all events without exact location
|
||||||
u_events = Event.objects.filter(exact_location__isnull=True)
|
u_events = Event.get_qs_events_with_unkwnon_place()
|
||||||
|
|
||||||
to_be_updated = []
|
to_be_updated = []
|
||||||
# try to find matches
|
# try to find matches
|
||||||
|
Loading…
x
Reference in New Issue
Block a user