parent
96401b6519
commit
37817cc8f5
@ -10,7 +10,8 @@ from .models import (
|
|||||||
RecurrentImport,
|
RecurrentImport,
|
||||||
Place,
|
Place,
|
||||||
ContactMessage,
|
ContactMessage,
|
||||||
ReferenceLocation
|
ReferenceLocation,
|
||||||
|
Organisation
|
||||||
)
|
)
|
||||||
from django_better_admin_arrayfield.admin.mixins import DynamicArrayMixin
|
from django_better_admin_arrayfield.admin.mixins import DynamicArrayMixin
|
||||||
from django_better_admin_arrayfield.forms.widgets import DynamicArrayWidget
|
from django_better_admin_arrayfield.forms.widgets import DynamicArrayWidget
|
||||||
@ -26,6 +27,7 @@ admin.site.register(RecurrentImport)
|
|||||||
admin.site.register(Place)
|
admin.site.register(Place)
|
||||||
admin.site.register(ContactMessage)
|
admin.site.register(ContactMessage)
|
||||||
admin.site.register(ReferenceLocation)
|
admin.site.register(ReferenceLocation)
|
||||||
|
admin.site.register(Organisation)
|
||||||
|
|
||||||
|
|
||||||
class URLWidget(DynamicArrayWidget):
|
class URLWidget(DynamicArrayWidget):
|
||||||
|
@ -162,13 +162,14 @@ def run_recurrent_import_internal(rimport, downloader, req_id):
|
|||||||
location = rimport.defaultLocation
|
location = rimport.defaultLocation
|
||||||
tags = rimport.defaultTags
|
tags = rimport.defaultTags
|
||||||
published = rimport.defaultPublished
|
published = rimport.defaultPublished
|
||||||
|
organisers = [] if rimport.defaultOrganiser is None else [rimport.defaultOrganiser.pk]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# get events from website
|
# get events from website
|
||||||
events = u2e.process(
|
events = u2e.process(
|
||||||
url,
|
url,
|
||||||
browsable_url,
|
browsable_url,
|
||||||
default_values={"category": category, "location": location, "tags": tags},
|
default_values={"category": category, "location": location, "tags": tags, "organisers": organisers},
|
||||||
published=published,
|
published=published,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -186,6 +186,7 @@ class EventForm(ModelForm):
|
|||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
if not is_authenticated:
|
if not is_authenticated:
|
||||||
del self.fields["status"]
|
del self.fields["status"]
|
||||||
|
del self.fields["organisers"]
|
||||||
self.fields['category'].queryset = self.fields['category'].queryset.order_by('name')
|
self.fields['category'].queryset = self.fields['category'].queryset.order_by('name')
|
||||||
self.fields['category'].empty_label = None
|
self.fields['category'].empty_label = None
|
||||||
self.fields['category'].initial = Category.get_default_category()
|
self.fields['category'].initial = Category.get_default_category()
|
||||||
@ -262,6 +263,7 @@ class EventModerateForm(ModelForm):
|
|||||||
fields = [
|
fields = [
|
||||||
"status",
|
"status",
|
||||||
"category",
|
"category",
|
||||||
|
"organisers",
|
||||||
"exact_location",
|
"exact_location",
|
||||||
"tags"
|
"tags"
|
||||||
]
|
]
|
||||||
|
@ -187,6 +187,7 @@ class Extractor(ABC):
|
|||||||
"start_day": start_day,
|
"start_day": start_day,
|
||||||
"uuids": uuids,
|
"uuids": uuids,
|
||||||
"location": location if location else self.default_value_if_exists(default_values, "location"),
|
"location": location if location else self.default_value_if_exists(default_values, "location"),
|
||||||
|
"organisers": self.default_value_if_exists(default_values, "organisers"),
|
||||||
"description": description,
|
"description": description,
|
||||||
"tags": tags + tags_default,
|
"tags": tags + tags_default,
|
||||||
"published": published,
|
"published": published,
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,35 @@
|
|||||||
|
# Generated by Django 4.2.9 on 2024-11-22 10:12
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
import django_ckeditor_5.fields
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('agenda_culturel', '0113_remove_tag_category'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Organisation',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(help_text='Organisation name', max_length=512, unique=True, verbose_name='Name')),
|
||||||
|
('website', models.URLField(blank=True, help_text='Website of the organisation', max_length=1024, null=True, verbose_name='Website')),
|
||||||
|
('description', django_ckeditor_5.fields.CKEditor5Field(blank=True, help_text='Description of the organisation.', null=True, verbose_name='Description')),
|
||||||
|
('principal_place', models.ForeignKey(blank=True, help_text='Place mainly associated with this organizer. Mainly used if there is a similarity in the name, to avoid redundant displays.', null=True, on_delete=django.db.models.deletion.SET_NULL, to='agenda_culturel.place', verbose_name='Principal place')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='event',
|
||||||
|
name='organisers',
|
||||||
|
field=models.ManyToManyField(blank=True, help_text='list of event organisers. Organizers will only be displayed if one of them does not normally use the venue.', related_name='organised_events', to='agenda_culturel.organisation', verbose_name='Location (free form)'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='recurrentimport',
|
||||||
|
name='defaultOrganiser',
|
||||||
|
field=models.ForeignKey(blank=True, default=None, help_text='Organiser of each imported event', null=True, on_delete=django.db.models.deletion.SET_DEFAULT, to='agenda_culturel.organisation', verbose_name='Organiser'),
|
||||||
|
),
|
||||||
|
]
|
@ -0,0 +1,22 @@
|
|||||||
|
# Generated by Django 4.2.9 on 2024-11-22 10:30
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('agenda_culturel', '0114_organisation_event_organisers_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='organisation',
|
||||||
|
options={'verbose_name': 'Organisation', 'verbose_name_plural': 'Organisations'},
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='event',
|
||||||
|
name='organisers',
|
||||||
|
field=models.ManyToManyField(blank=True, help_text='list of event organisers. Organizers will only be displayed if one of them does not normally use the venue.', related_name='organised_events', to='agenda_culturel.organisation', verbose_name='Organisers'),
|
||||||
|
),
|
||||||
|
]
|
@ -479,6 +479,46 @@ class Place(models.Model):
|
|||||||
tags = []
|
tags = []
|
||||||
return tags
|
return tags
|
||||||
|
|
||||||
|
class Organisation(models.Model):
|
||||||
|
name = models.CharField(
|
||||||
|
verbose_name=_("Name"), help_text=_("Organisation name"), max_length=512, null=False, unique=True
|
||||||
|
)
|
||||||
|
|
||||||
|
website = models.URLField(
|
||||||
|
verbose_name=_("Website"),
|
||||||
|
help_text=_("Website of the organisation"),
|
||||||
|
max_length=1024,
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
description = CKEditor5Field(
|
||||||
|
verbose_name=_("Description"),
|
||||||
|
help_text=_("Description of the organisation."),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
principal_place = models.ForeignKey(
|
||||||
|
Place,
|
||||||
|
verbose_name=_("Principal place"),
|
||||||
|
help_text=_("Place mainly associated with this organizer. Mainly used if there is a similarity in the name, to avoid redundant displays."),
|
||||||
|
null=True,
|
||||||
|
on_delete=models.SET_NULL,
|
||||||
|
blank=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _("Organisation")
|
||||||
|
verbose_name_plural = _("Organisations")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
def get_absolute_url(self):
|
||||||
|
return reverse("view_organisation", kwargs={'pk': self.pk})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Event(models.Model):
|
class Event(models.Model):
|
||||||
class STATUS(models.TextChoices):
|
class STATUS(models.TextChoices):
|
||||||
@ -556,6 +596,15 @@ class Event(models.Model):
|
|||||||
blank=True
|
blank=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
organisers = models.ManyToManyField(Organisation,
|
||||||
|
related_name='organised_events',
|
||||||
|
verbose_name=_("Organisers"),
|
||||||
|
help_text=_(
|
||||||
|
"list of event organisers. Organizers will only be displayed if one of them does not normally use the venue."
|
||||||
|
),
|
||||||
|
blank=True
|
||||||
|
)
|
||||||
|
|
||||||
description = models.TextField(
|
description = models.TextField(
|
||||||
verbose_name=_("Description"),
|
verbose_name=_("Description"),
|
||||||
help_text=_("General description of the event"),
|
help_text=_("General description of the event"),
|
||||||
@ -754,6 +803,19 @@ class Event(models.Model):
|
|||||||
|
|
||||||
return self.other_versions.get_local_version()
|
return self.other_versions.get_local_version()
|
||||||
|
|
||||||
|
def get_shown_organisers(self):
|
||||||
|
if self.organisers.count() == 0:
|
||||||
|
return None
|
||||||
|
if self.exact_location is None:
|
||||||
|
has_significant = True
|
||||||
|
else:
|
||||||
|
has_significant = self.organisers.filter(~Q(principal_place=self.exact_location)).count() > 0
|
||||||
|
|
||||||
|
if has_significant:
|
||||||
|
return self.organisers.all()
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
def nb_draft_events():
|
def nb_draft_events():
|
||||||
return Event.objects.filter(status=Event.STATUS.DRAFT).count()
|
return Event.objects.filter(status=Event.STATUS.DRAFT).count()
|
||||||
|
|
||||||
@ -779,6 +841,12 @@ class Event(models.Model):
|
|||||||
# if the download is ok, then create the corresponding file object
|
# if the download is ok, then create the corresponding file object
|
||||||
self.local_image = File(name=basename, file=open(tmpfile, "rb"))
|
self.local_image = File(name=basename, file=open(tmpfile, "rb"))
|
||||||
|
|
||||||
|
def add_pending_organisers(self, organisers):
|
||||||
|
self.pending_organisers = organisers
|
||||||
|
|
||||||
|
def has_pending_organisers(self):
|
||||||
|
return hasattr(self, "pending_organisers")
|
||||||
|
|
||||||
def set_skip_duplicate_check(self):
|
def set_skip_duplicate_check(self):
|
||||||
self.skip_duplicate_check = True
|
self.skip_duplicate_check = True
|
||||||
|
|
||||||
@ -920,29 +988,38 @@ class Event(models.Model):
|
|||||||
self.recurrence_dtend = self.recurrence_dtstart
|
self.recurrence_dtend = self.recurrence_dtstart
|
||||||
|
|
||||||
def prepare_save(self):
|
def prepare_save(self):
|
||||||
|
logger.warning('AAA')
|
||||||
self.update_modification_dates()
|
self.update_modification_dates()
|
||||||
|
logger.warning('BBB')
|
||||||
|
|
||||||
self.update_recurrence_dtstartend()
|
self.update_recurrence_dtstartend()
|
||||||
|
logger.warning('CCC')
|
||||||
|
|
||||||
# if the image is defined but not locally downloaded
|
# if the image is defined but not locally downloaded
|
||||||
if self.image and not self.local_image:
|
if self.image and not self.local_image:
|
||||||
self.download_image()
|
self.download_image()
|
||||||
|
logger.warning('DDD')
|
||||||
|
|
||||||
# remove "/" from tags
|
# remove "/" from tags
|
||||||
if self.tags:
|
if self.tags:
|
||||||
self.tags = [t.replace('/', '-') for t in self.tags]
|
self.tags = [t.replace('/', '-') for t in self.tags]
|
||||||
|
logger.warning('EEE')
|
||||||
|
|
||||||
# in case of importation process
|
# in case of importation process
|
||||||
if self.is_in_importation_process():
|
if self.is_in_importation_process():
|
||||||
|
logger.warning('EE1')
|
||||||
# try to detect location
|
# try to detect location
|
||||||
if not self.exact_location:
|
if not self.exact_location:
|
||||||
for p in Place.objects.all():
|
for p in Place.objects.all():
|
||||||
if p.match(self):
|
if p.match(self):
|
||||||
self.exact_location = p
|
self.exact_location = p
|
||||||
break
|
break
|
||||||
|
logger.warning('EE2')
|
||||||
# try to detect category
|
# try to detect category
|
||||||
if not self.category or self.category.name == Category.default_name:
|
if not self.category or self.category.name == Category.default_name:
|
||||||
CategorisationRule.apply_rules(self)
|
CategorisationRule.apply_rules(self)
|
||||||
|
logger.warning('EE3')
|
||||||
|
logger.warning('FFF')
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
self.prepare_save()
|
self.prepare_save()
|
||||||
@ -991,6 +1068,10 @@ class Event(models.Model):
|
|||||||
e.save()
|
e.save()
|
||||||
|
|
||||||
def from_structure(event_structure, import_source=None):
|
def from_structure(event_structure, import_source=None):
|
||||||
|
logger.warning("from structure")
|
||||||
|
# organisers is a manytomany relation thus cannot be initialised before creation of the event
|
||||||
|
organisers = event_structure.pop('organisers', 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:
|
||||||
event_structure["category"] = Category.objects.get(
|
event_structure["category"] = Category.objects.get(
|
||||||
@ -1066,7 +1147,11 @@ class Event(models.Model):
|
|||||||
if import_source is not None:
|
if import_source is not None:
|
||||||
event_structure["import_sources"] = [import_source]
|
event_structure["import_sources"] = [import_source]
|
||||||
|
|
||||||
return Event(**event_structure)
|
result = Event(**event_structure)
|
||||||
|
result.add_pending_organisers(organisers)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
def find_similar_events(self):
|
def find_similar_events(self):
|
||||||
start_time_test = Q(start_time=self.start_time)
|
start_time_test = Q(start_time=self.start_time)
|
||||||
@ -1164,10 +1249,24 @@ 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_organisers(self):
|
||||||
|
if self.pk:
|
||||||
|
return self.organisers.all()
|
||||||
|
else:
|
||||||
|
if self.has_pending_organisers():
|
||||||
|
return self.pending_organisers
|
||||||
|
else:
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
def get_comparison(events, all=True):
|
def get_comparison(events, all=True):
|
||||||
result = []
|
result = []
|
||||||
for attr in Event.data_fields(all=all, local_img=False, exact_location=False):
|
for attr in Event.data_fields(all=all, local_img=False, exact_location=False):
|
||||||
values = [getattr(e, attr) for e in events]
|
if attr == 'organisers':
|
||||||
|
values = [[str(o) for o in e.get_organisers()] for e in events]
|
||||||
|
logger.warning("values: " + str(values))
|
||||||
|
else:
|
||||||
|
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]
|
||||||
# only consider fixed part of Facebook urls
|
# only consider fixed part of Facebook urls
|
||||||
@ -1218,7 +1317,7 @@ 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(local_img=True, exact_location=True, all=True):
|
def data_fields(local_img=True, exact_location=True, all=True, no_m2m=False):
|
||||||
result = []
|
result = []
|
||||||
|
|
||||||
if all:
|
if all:
|
||||||
@ -1237,6 +1336,8 @@ class Event(models.Model):
|
|||||||
"description",
|
"description",
|
||||||
"image",
|
"image",
|
||||||
]
|
]
|
||||||
|
if not no_m2m:
|
||||||
|
result += ["organisers"]
|
||||||
if all and local_img:
|
if all and local_img:
|
||||||
result += ["local_image"]
|
result += ["local_image"]
|
||||||
if all and exact_location:
|
if all and exact_location:
|
||||||
@ -1264,10 +1365,17 @@ class Event(models.Model):
|
|||||||
|
|
||||||
def update(self, other, all):
|
def update(self, other, all):
|
||||||
|
|
||||||
|
if other.has_pending_organisers():
|
||||||
|
logger.warning("set dans le update")
|
||||||
|
self.organisers.set(other.pending_organisers)
|
||||||
|
|
||||||
# set attributes
|
# set attributes
|
||||||
for attr in Event.data_fields(all=all):
|
for attr in Event.data_fields(all=all, no_m2m=True):
|
||||||
|
logger.warning('on set l attribut ' + attr + ' sur ' + str(self.pk) + ' avec valeur ' + str(getattr(other, attr)))
|
||||||
setattr(self, attr, getattr(other, attr))
|
setattr(self, attr, getattr(other, attr))
|
||||||
|
|
||||||
|
logger.warning('suite')
|
||||||
|
|
||||||
# adjust modified date if required
|
# adjust modified date if required
|
||||||
if other.modified_date and self.modified_date < other.modified_date:
|
if other.modified_date and self.modified_date < other.modified_date:
|
||||||
self.modified_date = other.modified_date
|
self.modified_date = other.modified_date
|
||||||
@ -1281,6 +1389,8 @@ class Event(models.Model):
|
|||||||
|
|
||||||
# Limitation: the given events should not be considered similar one to another...
|
# Limitation: the given events should not be considered similar one to another...
|
||||||
def import_events(events, remove_missing_from_source=None):
|
def import_events(events, remove_missing_from_source=None):
|
||||||
|
logger.warning("import_events")
|
||||||
|
|
||||||
to_import = []
|
to_import = []
|
||||||
to_update = []
|
to_update = []
|
||||||
|
|
||||||
@ -1290,6 +1400,7 @@ class Event(models.Model):
|
|||||||
|
|
||||||
# for each event, check if it's a new one, or a one to be updated
|
# for each event, check if it's a new one, or a one to be updated
|
||||||
for event in events:
|
for event in events:
|
||||||
|
logger.warning("event " + str(event))
|
||||||
sdate = date.fromisoformat(event.start_day)
|
sdate = date.fromisoformat(event.start_day)
|
||||||
if event.end_day:
|
if event.end_day:
|
||||||
edate = date.fromisoformat(event.end_day)
|
edate = date.fromisoformat(event.end_day)
|
||||||
@ -1304,14 +1415,20 @@ class Event(models.Model):
|
|||||||
if event.uuids and len(event.uuids) > 0:
|
if event.uuids and len(event.uuids) > 0:
|
||||||
uuids |= set(event.uuids)
|
uuids |= set(event.uuids)
|
||||||
|
|
||||||
|
logger.warning("avant " + str(event))
|
||||||
|
|
||||||
# imported events should be updated
|
# imported events should be updated
|
||||||
event.set_in_importation_process()
|
event.set_in_importation_process()
|
||||||
|
logger.warning("step " + str(event))
|
||||||
event.prepare_save()
|
event.prepare_save()
|
||||||
|
|
||||||
|
logger.warning("neeext " + str(event))
|
||||||
|
|
||||||
# check if the event has already be imported (using uuid)
|
# check if the event has already be imported (using uuid)
|
||||||
same_events = event.find_same_events_by_uuid()
|
same_events = event.find_same_events_by_uuid()
|
||||||
|
|
||||||
if len(same_events) != 0:
|
if len(same_events) != 0:
|
||||||
|
logger.warning("same non nuls")
|
||||||
# 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_pure_import(same_events)
|
same_imported = Event.find_last_pure_import(same_events)
|
||||||
pure = True
|
pure = True
|
||||||
@ -1331,13 +1448,14 @@ class Event(models.Model):
|
|||||||
if same_imported.other_versions.representative != same_imported:
|
if same_imported.other_versions.representative != same_imported:
|
||||||
same_imported.other_versions.representative = None
|
same_imported.other_versions.representative = None
|
||||||
same_imported.other_versions.save()
|
same_imported.other_versions.save()
|
||||||
|
logger.warning('on va y updater')
|
||||||
same_imported.update(event, pure) # we only update all tags if it"s a pure import
|
same_imported.update(event, pure) # we only update all tags if it"s a pure import
|
||||||
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.
|
||||||
|
logger.warning("hop trash")
|
||||||
|
|
||||||
# check if it should be published
|
# check if it should be published
|
||||||
trash = len([e for e in same_events if e.status != Event.STATUS.TRASH]) == 0
|
trash = len([e for e in same_events if e.status != Event.STATUS.TRASH]) == 0
|
||||||
@ -1359,14 +1477,24 @@ class Event(models.Model):
|
|||||||
# import this new event
|
# import this new event
|
||||||
to_import.append(event)
|
to_import.append(event)
|
||||||
|
|
||||||
|
logger.warning("apres boucle")
|
||||||
# then import all the new events
|
# then import all the new events
|
||||||
imported = Event.objects.bulk_create(to_import)
|
imported = Event.objects.bulk_create(to_import)
|
||||||
|
# update organisers (m2m relation)
|
||||||
|
for i, ti in zip(imported, to_import):
|
||||||
|
if ti.has_pending_organisers():
|
||||||
|
logger.warning("set apres bulk create " + str(i.pk))
|
||||||
|
|
||||||
|
i.organisers.set(ti.pending_organisers)
|
||||||
|
|
||||||
nb_updated = Event.objects.bulk_update(
|
nb_updated = Event.objects.bulk_update(
|
||||||
to_update,
|
to_update,
|
||||||
fields=Event.data_fields()
|
fields=Event.data_fields(no_m2m=True)
|
||||||
+ ["imported_date", "modified_date", "uuids", "status"],
|
+ ["imported_date", "modified_date", "uuids", "status"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
logger.warning("avant remove")
|
||||||
|
|
||||||
nb_draft = 0
|
nb_draft = 0
|
||||||
if remove_missing_from_source is not None and max_date is not None:
|
if remove_missing_from_source is not None and max_date is not None:
|
||||||
# events that are missing from the import but in database are turned into drafts
|
# events that are missing from the import but in database are turned into drafts
|
||||||
@ -1400,6 +1528,8 @@ class Event(models.Model):
|
|||||||
|
|
||||||
nb_draft = Event.objects.bulk_update(to_draft, fields=["status"])
|
nb_draft = Event.objects.bulk_update(to_draft, fields=["status"])
|
||||||
|
|
||||||
|
logger.warning("fin ça fait fin")
|
||||||
|
|
||||||
return imported, nb_updated, nb_draft
|
return imported, nb_updated, nb_draft
|
||||||
|
|
||||||
def set_current_date(self, date):
|
def set_current_date(self, date):
|
||||||
@ -1678,6 +1808,17 @@ class RecurrentImport(models.Model):
|
|||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
defaultOrganiser = models.ForeignKey(
|
||||||
|
Organisation,
|
||||||
|
verbose_name=_("Organiser"),
|
||||||
|
help_text=_("Organiser of each imported event"),
|
||||||
|
default=None,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
on_delete=models.SET_DEFAULT,
|
||||||
|
)
|
||||||
|
|
||||||
defaultCategory = models.ForeignKey(
|
defaultCategory = models.ForeignKey(
|
||||||
Category,
|
Category,
|
||||||
verbose_name=_("Category"),
|
verbose_name=_("Category"),
|
||||||
|
@ -271,6 +271,12 @@ svg {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media only screen and (min-width: 600px) {
|
||||||
|
.details-entete {
|
||||||
|
padding-left: 28%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.ephemeris-hour {
|
.ephemeris-hour {
|
||||||
@extend .ephemeris;
|
@extend .ephemeris;
|
||||||
padding: 1.5em 0.1em;
|
padding: 1.5em 0.1em;
|
||||||
@ -1385,7 +1391,7 @@ img.preview {
|
|||||||
scroll-margin-top: 7em;
|
scroll-margin-top: 7em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.a-venir, .place, .tag, .tag-descriptions {
|
.a-venir, .place, .tag, .tag-descriptions, .organisation {
|
||||||
article#filters {
|
article#filters {
|
||||||
margin: 2em 0;
|
margin: 2em 0;
|
||||||
}
|
}
|
||||||
|
@ -122,5 +122,17 @@ Duplication de {% else %}
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const organisers = document.querySelector('#id_organisers');
|
||||||
|
const choices_organisers = new Choices(organisers,
|
||||||
|
{
|
||||||
|
placeholderValue: 'Sélectionner les organisateurs ',
|
||||||
|
allowHTML: true,
|
||||||
|
delimiter: ',',
|
||||||
|
removeItemButton: true,
|
||||||
|
shouldSort: true,
|
||||||
|
callbackOnCreateTemplates: () => (show_firstgroup)
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -92,6 +92,18 @@
|
|||||||
callbackOnCreateTemplates: () => (show_firstgroup)
|
callbackOnCreateTemplates: () => (show_firstgroup)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
const organisers = document.querySelector('#id_organisers');
|
||||||
|
const choices_organisers = new Choices(organisers,
|
||||||
|
{
|
||||||
|
placeholderValue: 'Sélectionner les organisateurs ',
|
||||||
|
allowHTML: true,
|
||||||
|
delimiter: ',',
|
||||||
|
removeItemButton: true,
|
||||||
|
shouldSort: true,
|
||||||
|
callbackOnCreateTemplates: () => (show_firstgroup)
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -4,9 +4,11 @@
|
|||||||
<a href="?page={{ page_obj.previous_page_number }}" role="button">précédent</a>
|
<a href="?page={{ page_obj.previous_page_number }}" role="button">précédent</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if page_obj.paginator.num_pages != 1 %}
|
||||||
<span>
|
<span>
|
||||||
Page {{ page_obj.number }} sur {{ page_obj.paginator.num_pages }}
|
Page {{ page_obj.number }} sur {{ page_obj.paginator.num_pages }}
|
||||||
</span>
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if page_obj.has_next %}
|
{% if page_obj.has_next %}
|
||||||
<a href="?page={{ page_obj.next_page_number }}" role="button">suivant</a>
|
<a href="?page={{ page_obj.next_page_number }}" role="button">suivant</a>
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
{% extends "agenda_culturel/page.html" %}
|
||||||
|
|
||||||
|
{% block title %}{% block og_title %}Supprimer l'organisateur {{ object.name }}{% endblock %}{% endblock %}
|
||||||
|
|
||||||
|
{% block fluid %}{% endblock %}
|
||||||
|
|
||||||
|
{% block configurer-bouton %}{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<article>
|
||||||
|
<header>
|
||||||
|
<h1>Supprimer l'organisateur {{ object.name }}</h1>
|
||||||
|
</header>
|
||||||
|
<form method="post">{% csrf_token %}
|
||||||
|
<p>Êtes-vous sûr·e de vouloir supprimer l'organisateur « {{ object.name }} ({{ object.pk }}) » ?</p>
|
||||||
|
{{ form }}
|
||||||
|
<div class="grid buttons">
|
||||||
|
<a href="{% if request.META.HTTP_REFERER %}{{ request.META.HTTP_REFERER }}{% else %}{{ object.get_absolute_url }}{% endif %}" role="button" class="secondary">Annuler</a>
|
||||||
|
<input type="submit" value="Confirmer">
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -0,0 +1,84 @@
|
|||||||
|
{% extends "agenda_culturel/page.html" %}
|
||||||
|
|
||||||
|
{% block title %}{% block og_title %}{{ object.name }}{% endblock %}{% endblock %}
|
||||||
|
|
||||||
|
{% load tag_extra %}
|
||||||
|
{% load utils_extra %}
|
||||||
|
{% load cat_extra %}
|
||||||
|
{% load static %}
|
||||||
|
{% load cache %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load l10n %}
|
||||||
|
|
||||||
|
{% block entete_header %}
|
||||||
|
{% css_categories %}
|
||||||
|
<script src="/static/admin/js/vendor/jquery/jquery.js"></script>
|
||||||
|
<script src="/static/admin/js/jquery.init.js"></script>
|
||||||
|
<script src="{% static 'location_field/leaflet/leaflet.js' %}"></script>
|
||||||
|
<link href="{% static 'location_field/leaflet/leaflet.css' %}" type="text/css" media="all" rel="stylesheet">
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block fluid %}{% endblock %}
|
||||||
|
|
||||||
|
{% block body-class %}organisation{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<article>
|
||||||
|
<header>
|
||||||
|
<a href="{% url 'view_organisations' %}" role="button">{% picto_from_name "chevron-left" %} Toutes les organisations</a>
|
||||||
|
{% if perms.agenda_culturel.change_organisation %}
|
||||||
|
<div class="slide-buttons">
|
||||||
|
<a href="{% url 'edit_organisation' object.pk %}" role="button">Modifier {% picto_from_name "edit-3" %}</a>
|
||||||
|
<a href="{% url 'delete_organisation' object.pk %}" role="button">Supprimer {% picto_from_name "trash-2" %}</a>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<h1>{{ object.name }}</h1>
|
||||||
|
{% if object.website or object.principal_place %}
|
||||||
|
<ul>
|
||||||
|
{% if object.website %}
|
||||||
|
<li><strong>Site internet :</strong> <a href="{{ object.website }}">{{ object.website }}</a></li>
|
||||||
|
{% endif %}
|
||||||
|
{% if object.principal_place %}
|
||||||
|
<li><strong>Lieu principal :</strong> <a href="{{ object.principal_place.get_absolute_url }}">{{ object.principal_place }}</a></li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{{ object.description|safe }}
|
||||||
|
</header>
|
||||||
|
|
||||||
|
{% get_current_language as LANGUAGE_CODE %}
|
||||||
|
{% with cache_timeout=user.is_authenticated|yesno:"30,600" %}
|
||||||
|
{% cache cache_timeout organisation_list user.is_authenticated object page_obj.number past %}
|
||||||
|
<div class="slide-buttons">
|
||||||
|
{% if past %}
|
||||||
|
<a href="{{ object.get_absolute_url }}" role="button">Voir les événements à venir</a>
|
||||||
|
{% else %}
|
||||||
|
<a href="{% url 'view_organisation_past' object.pk %}" role="button">Voir les événements passés</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% if past %}
|
||||||
|
<h2>Événements passés</h2>
|
||||||
|
{% else %}
|
||||||
|
<h2>Événements à venir</h2>
|
||||||
|
{% endif %}
|
||||||
|
{% if object_list %}
|
||||||
|
|
||||||
|
{% include "agenda_culturel/navigation.html" with page_obj=page_obj %}
|
||||||
|
|
||||||
|
{% for event in object_list %}
|
||||||
|
{% include "agenda_culturel/single-event/event-elegant-inc.html" with event=event day=0 no_location=1 %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% include "agenda_culturel/navigation.html" with page_obj=page_obj %}
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
<p><em>Aucun événement</em></p>
|
||||||
|
{% endif %}
|
||||||
|
{% endcache %}
|
||||||
|
{% endwith %}
|
||||||
|
<footer>
|
||||||
|
</footer>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -0,0 +1,33 @@
|
|||||||
|
{% extends "agenda_culturel/page-admin.html" %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
|
{% block entete_header %}
|
||||||
|
<script src="{% url 'jsi18n' %}"></script>
|
||||||
|
<script src="/static/admin/js/vendor/jquery/jquery.js"></script>
|
||||||
|
<script src="/static/admin/js/jquery.init.js"></script>
|
||||||
|
<script>window.CKEDITOR_BASEPATH = '/static/ckeditor/ckeditor/';</script>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block title %}{% block og_title %}{% if object %}Description de {{ object.name }}{% else %}Description d'un organisme{% endif %}{% endblock %}{% endblock %}
|
||||||
|
|
||||||
|
{% block fluid %}{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<article>
|
||||||
|
<header>
|
||||||
|
<h1>{% if object %}Description de {{ object.name }}{% else %}Description d'un organisme{% endif %}</h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<form method="post">{% csrf_token %}
|
||||||
|
{{ form.media }}
|
||||||
|
{{ form.as_p }}
|
||||||
|
|
||||||
|
<div class="grid buttons">
|
||||||
|
<a href="{% if request.META.HTTP_REFERER %}{{ request.META.HTTP_REFERER }}{% else %}{% if object %}{{ object.get_absolute_url }}{% else %}{% url 'view_organisations' %}{% endif %}{% endif %}" role="button" class="secondary">Annuler</a>
|
||||||
|
<input type="submit" value="Envoyer">
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -0,0 +1,76 @@
|
|||||||
|
{% extends "agenda_culturel/page.html" %}
|
||||||
|
|
||||||
|
{% block title %}{% block og_title %}Liste des organismes{% endblock %}{% endblock %}
|
||||||
|
|
||||||
|
{% block fluid %}{% endblock %}
|
||||||
|
|
||||||
|
{% load utils_extra %}
|
||||||
|
{% load cat_extra %}
|
||||||
|
{% block entete_header %}
|
||||||
|
{% css_categories %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block sidemenu-bouton %}
|
||||||
|
<li><a href="#contenu-principal" aria-label="Aller au contenu">{% picto_from_name "chevron-up" %}</a></li>
|
||||||
|
<li><a href="#sidebar" aria-label="Aller au menu latéral">{% picto_from_name "chevron-down" %}</a></li>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<article>
|
||||||
|
<header>
|
||||||
|
{% if user.is_authenticated %}
|
||||||
|
<div class="slide-buttons">
|
||||||
|
<a href="{% url 'add_organisation' %}" role="button">Ajouter {% picto_from_name "plus-circle" %}</a>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<h1>Liste des organismes</h1>
|
||||||
|
</header>
|
||||||
|
{% include "agenda_culturel/navigation.html" with page_obj=page_obj %}
|
||||||
|
</article>
|
||||||
|
|
||||||
|
{% if object_list %}
|
||||||
|
{% for organisation in object_list %}
|
||||||
|
<article>
|
||||||
|
<header>
|
||||||
|
{% if user.is_authenticated %}
|
||||||
|
<div class="slide-buttons">
|
||||||
|
<a href="{% url 'edit_organisation' organisation.pk %}" role="button">Modifier {% picto_from_name "edit-3" %}</a>
|
||||||
|
<a href="{% url 'delete_organisation' organisation.pk %}" role="button">Supprimer {% picto_from_name "trash-2" %}</a>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<h2>{{ organisation.name }}</h2>
|
||||||
|
</header>
|
||||||
|
{% if organisation.website or organisation.principal_place %}
|
||||||
|
<ul>
|
||||||
|
{% if organisation.website %}
|
||||||
|
<li><strong>Site internet :</strong> <a href="{{ organisation.website }}">{{ organisation.website }}</a></li>
|
||||||
|
{% endif %}
|
||||||
|
{% if organisation.principal_place %}
|
||||||
|
<li><strong>Lieu principal :</strong> <a href="{{ organisation.principal_place.get_absolute_url }}">{{ organisation.principal_place }}</a></li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
{% if organisation.organised_events.all|length > 1 %}
|
||||||
|
<p class="slide-buttons"><a role="button" href="{{ organisation.get_absolute_url }}">voir les {{ organisation.organised_events.all|length }} événements {% picto_from_name "chevron-right" %}</a></p>
|
||||||
|
{% else %}
|
||||||
|
<p class="slide-buttons"><a role="button" href="{{ organisation.get_absolute_url }}">voir les détails {% picto_from_name "chevron-right" %}</a></p>
|
||||||
|
{% endif %}
|
||||||
|
<div style="clear: both"></div>
|
||||||
|
</footer>
|
||||||
|
</article>
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
<p>Il n'y a aucun organisme défini.</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<article>
|
||||||
|
<footer>
|
||||||
|
{% include "agenda_culturel/navigation.html" with page_obj=page_obj %}
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
</article>
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -107,6 +107,9 @@
|
|||||||
<div>
|
<div>
|
||||||
<a href="{% url 'view_places' %}">{% picto_from_name "map-pin" %} lieux</a>
|
<a href="{% url 'view_places' %}">{% picto_from_name "map-pin" %} lieux</a>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<a href="{% url 'view_places' %}">{% picto_from_name "users" %} organisateurs</a>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a href="{% url 'view_all_tags' %}">{% picto_from_name "tag" %} étiquettes</a>
|
<a href="{% url 'view_all_tags' %}">{% picto_from_name "tag" %} étiquettes</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -49,10 +49,28 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
</ul>
|
</ul>
|
||||||
{% if not object.description|html_vide %}
|
|
||||||
|
{% if object.description and not object.description|html_vide %}
|
||||||
<h2>Description du lieu</h2>
|
<h2>Description du lieu</h2>
|
||||||
{{ object.description|safe }}
|
{{ object.description|safe }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% with object.organisation_set.all as organisations %}
|
||||||
|
{% if organisations|length == 1 %}
|
||||||
|
<p>L'organisme <a href="{{ organisations.0.get_absolute_url }}">{{ organisations.0 }}</a> organise régulièrement des événements dans ce lieu.</p>
|
||||||
|
{% endif %}
|
||||||
|
{% if organisations|length > 1 %}
|
||||||
|
<p>Les organismes suivants utilisent régulièrement ce lieu :</p>
|
||||||
|
<ul>
|
||||||
|
{% for o in organisations %}
|
||||||
|
<li><a href="{{ o.get_absolute_url }}">{{ o }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endwith %}
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div id="map_location" style="width: 100%; aspect-ratio: 16/16"></div>
|
<div id="map_location" style="width: 100%; aspect-ratio: 16/16"></div>
|
||||||
@ -78,12 +96,12 @@
|
|||||||
<a href="{% url 'view_place_past' object.pk %}" role="button">Voir les événements passés</a>
|
<a href="{% url 'view_place_past' object.pk %}" role="button">Voir les événements passés</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
{% if past %}
|
||||||
|
<h2>Événements passés</h2>
|
||||||
|
{% else %}
|
||||||
|
<h2>Événements à venir</h2>
|
||||||
|
{% endif %}
|
||||||
{% if object_list %}
|
{% if object_list %}
|
||||||
{% if past %}
|
|
||||||
<h2>Événements passés</h2>
|
|
||||||
{% else %}
|
|
||||||
<h2>Événements à venir</h2>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% include "agenda_culturel/navigation.html" with page_obj=page_obj %}
|
{% include "agenda_culturel/navigation.html" with page_obj=page_obj %}
|
||||||
|
|
||||||
|
@ -24,13 +24,16 @@
|
|||||||
<li><a {% if current == "activite" %}class="selected" {% endif %}href="{% url 'activite' %}">Résumé des activités</a></li>
|
<li><a {% if current == "activite" %}class="selected" {% endif %}href="{% url 'activite' %}">Résumé des activités</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
{% if perms.agenda_culturel.change_place %}
|
{% if perms.agenda_culturel.change_place or perms.agenda_culturel.change_organisation %}
|
||||||
<h3>Lieux</h3>
|
<h3>Lieux et organisateurs</h3>
|
||||||
<nav>
|
<nav>
|
||||||
<ul>
|
<ul>
|
||||||
{% if perms.agenda_culturel.change_place %}
|
{% if perms.agenda_culturel.change_place %}
|
||||||
<li><a {% if current == "places" %}class="selected" {% endif %}href="{% url 'view_places_admin' %}">Liste des lieux</a></li>
|
<li><a {% if current == "places" %}class="selected" {% endif %}href="{% url 'view_places_admin' %}">Liste des lieux</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if perms.agenda_culturel.change_organisation %}
|
||||||
|
<li><a {% if current == "organisations" %}class="selected" {% endif %}href="{% url 'view_organisations' %}">Liste des organisateurs</a></li>
|
||||||
|
{% endif %}
|
||||||
{% if perms.agenda_culturel.change_place and perms.agenda_culturel.change_event %}
|
{% if perms.agenda_culturel.change_place and perms.agenda_culturel.change_event %}
|
||||||
<li><a {% if current == "unknown_places" %}class="selected" {% endif %}href="{% url 'view_unknown_places' %}">Événements sans lieu</a>{% show_badge_unknown_places "left" %}</li>
|
<li><a {% if current == "unknown_places" %}class="selected" {% endif %}href="{% url 'view_unknown_places' %}">Événements sans lieu</a>{% show_badge_unknown_places "left" %}</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -83,8 +83,7 @@
|
|||||||
<p>{{ event.description |linebreaks2 | truncatewords:60 }}</p>
|
<p>{{ event.description |linebreaks2 | truncatewords:60 }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="right bottom">
|
<div class="right bottom">
|
||||||
<a role="button" href="{{ event.get_absolute_url }}">Voir l'événement <svg width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
<a role="button" href="{{ event.get_absolute_url }}">Voir l'événement {% picto_from_name "chevron-right" %}
|
||||||
<use href="{% static 'images/feather-sprite.svg' %}#chevron-right" />
|
|
||||||
</svg></a>
|
</svg></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
<article>
|
<article>
|
||||||
<header>
|
<header>
|
||||||
{% include "agenda_culturel/ephemeris-inc.html" with event=event filter=filter %}
|
{% include "agenda_culturel/ephemeris-inc.html" with event=event filter=filter %}
|
||||||
|
<div class="details-entete">
|
||||||
{{ event.category | small_cat_recurrent:event.has_recurrences }}
|
{{ event.category | small_cat_recurrent:event.has_recurrences }}
|
||||||
<h1>{{ event|picto_status }} {{ event.title }} {{ event|picto_visibility:user.is_authenticated }}</h1>
|
<h1>{{ event|picto_status }} {{ event.title }} {{ event|picto_visibility:user.is_authenticated }}</h1>
|
||||||
<p>
|
<p>
|
||||||
@ -18,6 +19,17 @@
|
|||||||
{% 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>
|
||||||
|
|
||||||
|
{% with event.get_shown_organisers as organisers %}
|
||||||
|
{% if organisers and organisers|length > 0 %}
|
||||||
|
<p>{% picto_from_name "users" %} organisé par
|
||||||
|
{% for o in organisers %}
|
||||||
|
<a href="{{ o.get_absolute_url }}">{{ o }}</a>{% if not forloop.last %}, {% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
|
|
||||||
{% if user.is_authenticated %}
|
{% if user.is_authenticated %}
|
||||||
|
|
||||||
{% if event.other_versions %}
|
{% if event.other_versions %}
|
||||||
@ -47,7 +59,7 @@
|
|||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<div class="event-body">
|
<div class="event-body">
|
||||||
|
|
||||||
|
@ -131,6 +131,16 @@ urlpatterns = [
|
|||||||
path("duplicates/<int:pk>/update/<int:epk>", update_duplicate_event, name="update_event"),
|
path("duplicates/<int:pk>/update/<int:epk>", update_duplicate_event, name="update_event"),
|
||||||
path("404/", page_not_found, name="page_not_found"),
|
path("404/", page_not_found, name="page_not_found"),
|
||||||
path("500/", internal_server_error, name="internal_server_error"),
|
path("500/", internal_server_error, name="internal_server_error"),
|
||||||
|
|
||||||
|
path("organisme/<int:pk>/past", OrganisationDetailViewPast.as_view(), name="view_organisation_past"),
|
||||||
|
path("organisme/<int:pk>", OrganisationDetailView.as_view(), name="view_organisation"),
|
||||||
|
path("organisme/<int:pk>-<extra>/past", OrganisationDetailViewPast.as_view(), name="view_organisation_past_fullname"),
|
||||||
|
path("organisme/<int:pk>-<extra>", OrganisationDetailView.as_view(), name="view_organisation_fullname"),
|
||||||
|
path("organisme/<int:pk>/edit", OrganisationUpdateView.as_view(), name="edit_organisation"),
|
||||||
|
path("organisme/<int:pk>/delete", OrganisationDeleteView.as_view(), name="delete_organisation"),
|
||||||
|
path("organismes/", OrganisationListView.as_view(), name="view_organisations"),
|
||||||
|
path("organisme/add", OrganisationCreateView.as_view(), name="add_organisation"),
|
||||||
|
|
||||||
path("place/<int:pk>/past", PlaceDetailViewPast.as_view(), name="view_place_past"),
|
path("place/<int:pk>/past", PlaceDetailViewPast.as_view(), name="view_place_past"),
|
||||||
path("place/<int:pk>", PlaceDetailView.as_view(), name="view_place"),
|
path("place/<int:pk>", PlaceDetailView.as_view(), name="view_place"),
|
||||||
path("place/<int:pk>-<extra>/past", PlaceDetailViewPast.as_view(), name="view_place_past_fullname"),
|
path("place/<int:pk>-<extra>/past", PlaceDetailViewPast.as_view(), name="view_place_past_fullname"),
|
||||||
|
@ -60,7 +60,8 @@ from .models import (
|
|||||||
CategorisationRule,
|
CategorisationRule,
|
||||||
remove_accents,
|
remove_accents,
|
||||||
Place,
|
Place,
|
||||||
ReferenceLocation
|
ReferenceLocation,
|
||||||
|
Organisation
|
||||||
)
|
)
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.html import escape
|
from django.utils.html import escape
|
||||||
@ -1229,9 +1230,12 @@ def update_duplicate_event(request, pk, epk):
|
|||||||
else:
|
else:
|
||||||
setattr(event, f["key"], sum(values, []))
|
setattr(event, f["key"], sum(values, []))
|
||||||
else:
|
else:
|
||||||
setattr(event, f["key"], getattr(selected, f["key"]))
|
if f["key"] == 'organisers':
|
||||||
if f["key"] == "image":
|
event.organisers.set(selected.organisers.all())
|
||||||
setattr(event, "local_image", getattr(selected, "local_image"))
|
else:
|
||||||
|
setattr(event, f["key"], getattr(selected, f["key"]))
|
||||||
|
if f["key"] == "image":
|
||||||
|
setattr(event, "local_image", getattr(selected, "local_image"))
|
||||||
|
|
||||||
event.other_versions.fix(event)
|
event.other_versions.fix(event)
|
||||||
event.save()
|
event.save()
|
||||||
@ -1839,6 +1843,69 @@ class PlaceFromEventCreateView(PlaceCreateView):
|
|||||||
return self.event.get_absolute_url()
|
return self.event.get_absolute_url()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#########################
|
||||||
|
## Organisations
|
||||||
|
#########################
|
||||||
|
|
||||||
|
|
||||||
|
class OrganisationListView(ListView):
|
||||||
|
model = Organisation
|
||||||
|
paginate_by = 10
|
||||||
|
ordering = ["name__unaccent"]
|
||||||
|
|
||||||
|
class OrganisationDetailView(ListView):
|
||||||
|
model = Organisation
|
||||||
|
template_name = "agenda_culturel/organisation_detail.html"
|
||||||
|
paginate_by = 10
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
self.organisation = Organisation.objects.filter(pk=self.kwargs["pk"]).prefetch_related('organised_events').first()
|
||||||
|
return self.organisation.organised_events.filter(start_day__gte=datetime.now()).order_by("start_day")
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super().get_context_data(**kwargs)
|
||||||
|
context["object"] = self.organisation
|
||||||
|
return context
|
||||||
|
|
||||||
|
class OrganisationDetailViewPast(OrganisationDetailView):
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
self.organisation = Organisation.objects.filter(pk=self.kwargs["pk"]).prefetch_related('organised_events').first()
|
||||||
|
self.past = True
|
||||||
|
return self.organisation.organised_events.filter(start_day__lte=datetime.now()).order_by("-start_day")
|
||||||
|
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super().get_context_data(**kwargs)
|
||||||
|
context["past"] = self.past
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class OrganisationUpdateView(
|
||||||
|
PermissionRequiredMixin, SuccessMessageMixin, UpdateView
|
||||||
|
):
|
||||||
|
model = Organisation
|
||||||
|
permission_required = "agenda_culturel.change_organisation"
|
||||||
|
success_message = _("The organisation has been successfully updated.")
|
||||||
|
fields = '__all__'
|
||||||
|
|
||||||
|
|
||||||
|
class OrganisationCreateView(
|
||||||
|
PermissionRequiredMixin, SuccessMessageMixin, CreateView
|
||||||
|
):
|
||||||
|
model = Organisation
|
||||||
|
permission_required = "agenda_culturel.add_organisation"
|
||||||
|
success_message = _("The organisation has been successfully created.")
|
||||||
|
fields = '__all__'
|
||||||
|
|
||||||
|
|
||||||
|
class OrganisationDeleteView(PermissionRequiredMixin, DeleteView):
|
||||||
|
model = Organisation
|
||||||
|
permission_required = "agenda_culturel.delete_organisation"
|
||||||
|
success_url = reverse_lazy("view_organisations")
|
||||||
|
|
||||||
#########################
|
#########################
|
||||||
## Tags
|
## Tags
|
||||||
#########################
|
#########################
|
||||||
|
Loading…
x
Reference in New Issue
Block a user