Compare commits
No commits in common. "main" and "415_Réorganiser_models" have entirely different histories.
main
...
415_Réorga
@ -14,21 +14,14 @@ repos:
|
||||
- id: trailing-whitespace
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: v0.11.8
|
||||
rev: v0.9.9
|
||||
hooks:
|
||||
# Run the linter.
|
||||
- id: ruff
|
||||
types_or: [ python, pyi ]
|
||||
args: [ --fix ]
|
||||
- repo: https://github.com/Riverside-Healthcare/djLint
|
||||
rev: v1.36.4
|
||||
rev: v1.32.0
|
||||
hooks:
|
||||
- id: djlint-reformat-django
|
||||
- id: djlint-django
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: check-untracked
|
||||
name: "Check untracked and unignored files"
|
||||
entry: ./scripts/check-untracked.sh
|
||||
language: script
|
||||
always_run: true
|
||||
|
@ -8,9 +8,9 @@ http {
|
||||
gzip on;
|
||||
gzip_types text/plain text/css text/javascript;
|
||||
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
log_format main 'remote_addr -remote_user [time_local] "request" '
|
||||
'statusbody_bytes_sent "http_referer" '
|
||||
'"http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
upstream backend {
|
||||
server backend:8000;
|
||||
@ -38,7 +38,7 @@ http {
|
||||
error_page 502 /static/html/502.html;
|
||||
error_page 503 /static/html/503.html;
|
||||
|
||||
if ($http_user_agent ~* "Amazonbot|meta-externalagent|ClaudeBot|ahrefsbot|semrushbot|PerplexityBot|GPTBot") {
|
||||
if ($http_user_agent ~* "Amazonbot|meta-externalagent|ClaudeBot|ahrefsbot|semrushbot") {
|
||||
return 444;
|
||||
}
|
||||
access_log /var/log/nginx/access.log main;
|
||||
|
@ -1,9 +0,0 @@
|
||||
#!/bin/bash
|
||||
untracked=$(git ls-files --others --exclude-standard)
|
||||
|
||||
if [ -n "$untracked" ]; then
|
||||
echo "Error: The following files are untracked and not ignored:"
|
||||
echo "$untracked"
|
||||
echo "Please add them to Git or ignore them in .gitignore before committing."
|
||||
exit 1
|
||||
fi
|
@ -9,7 +9,6 @@ from django.core.files.storage import default_storage
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
import recurrence
|
||||
import recurrence.fields
|
||||
from .models.constants import TITLE_ISSUE_DATE_IMPORTATION, TITLE_ISSUE_TIME_IMPORTATION
|
||||
|
||||
from django.utils import timezone
|
||||
|
||||
@ -372,9 +371,19 @@ class DBImporterEvents:
|
||||
|
||||
for w in warnings:
|
||||
if w == Extractor.Warning.NO_START_DATE:
|
||||
event_structure["title"] += TITLE_ISSUE_DATE_IMPORTATION
|
||||
event_structure["title"] += (
|
||||
" - "
|
||||
+ _("Warning")
|
||||
+ ": "
|
||||
+ _("the date has not been imported correctly.")
|
||||
)
|
||||
if w == Extractor.Warning.NO_START_TIME:
|
||||
event_structure["title"] += TITLE_ISSUE_TIME_IMPORTATION
|
||||
event_structure["title"] += (
|
||||
" - "
|
||||
+ _("Warning")
|
||||
+ ": "
|
||||
+ _("the time has not been imported correctly.")
|
||||
)
|
||||
|
||||
if "category" in event_structure and event_structure["category"] is not None:
|
||||
try:
|
||||
|
@ -506,7 +506,7 @@ class SimpleSearchEventFilter(django_filters.FilterSet):
|
||||
q = django_filters.CharFilter(
|
||||
method="custom_filter",
|
||||
label=_("Search"),
|
||||
widget=forms.TextInput(attrs={"type": "search", "autofocus": True}),
|
||||
widget=forms.TextInput(attrs={"type": "search"}),
|
||||
)
|
||||
|
||||
status = django_filters.MultipleChoiceFilter(
|
||||
|
@ -42,12 +42,6 @@ from .models import (
|
||||
from .templatetags.event_extra import event_field_verbose_name, field_to_html
|
||||
from .templatetags.utils_extra import int_to_abc
|
||||
|
||||
from .models.constants import (
|
||||
TITLE_ISSUE_DATE_IMPORTATION,
|
||||
TITLE_ISSUE_TIME_IMPORTATION,
|
||||
PUBLICATION_ISSUE,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@ -452,37 +446,7 @@ class EventForm(GroupFormMixin, ModelForm):
|
||||
return list(set(self.cleaned_data.get("new_tags")))
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super().clean()
|
||||
|
||||
issues = Event.get_title_publication_issues(cleaned_data["title"])
|
||||
|
||||
if len(issues) > 0 and cleaned_data["status"] == Event.STATUS.PUBLISHED:
|
||||
r_issues = []
|
||||
|
||||
for i in issues:
|
||||
if i == PUBLICATION_ISSUE.DATE_IMPORTATION_IN_TITLE:
|
||||
if cleaned_data.get("start_day") != self.instance.start_day:
|
||||
cleaned_data["title"] = cleaned_data.get("title").replace(
|
||||
TITLE_ISSUE_DATE_IMPORTATION, ""
|
||||
)
|
||||
else:
|
||||
r_issues.append(i)
|
||||
elif i == PUBLICATION_ISSUE.TIME_IMPORTATION_IN_TITLE:
|
||||
if cleaned_data.get("start_time") is not None:
|
||||
cleaned_data["title"] = cleaned_data["title"].replace(
|
||||
TITLE_ISSUE_TIME_IMPORTATION, ""
|
||||
)
|
||||
else:
|
||||
r_issues.append(i)
|
||||
else:
|
||||
r_issues.append(i)
|
||||
|
||||
if len(r_issues) > 0:
|
||||
raise ValidationError(
|
||||
_(
|
||||
"You can't publish an event without correcting the problems it contains ({})."
|
||||
).format(", ".join([str(r) for r in r_issues]))
|
||||
)
|
||||
super().clean()
|
||||
|
||||
if self.is_moderation_expert and self.cleaned_data.get("new_tags") is not None:
|
||||
self.cleaned_data["tags"] += self.cleaned_data.get("new_tags")
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,26 +0,0 @@
|
||||
# Generated by Django 4.2.19 on 2025-04-29 22:19
|
||||
|
||||
from django.db import migrations
|
||||
import django_extensions.db.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("agenda_culturel", "0167_alter_recurrentimport_processor"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="referencelocation",
|
||||
name="slug",
|
||||
field=django_extensions.db.fields.AutoSlugField(
|
||||
blank=True,
|
||||
default=None,
|
||||
editable=False,
|
||||
null=True,
|
||||
populate_from="name",
|
||||
unique=True,
|
||||
),
|
||||
),
|
||||
]
|
@ -1,26 +0,0 @@
|
||||
from django.utils.translation import gettext as _
|
||||
from enum import IntEnum
|
||||
|
||||
|
||||
TITLE_ISSUE_WARNING = _("Warning")
|
||||
TITLE_ISSUE_PREFIX = " - " + TITLE_ISSUE_WARNING + ": "
|
||||
|
||||
TITLE_ISSUE_DATE_IMPORTATION = TITLE_ISSUE_PREFIX + _(
|
||||
"the date has not been imported correctly."
|
||||
)
|
||||
|
||||
|
||||
TITLE_ISSUE_TIME_IMPORTATION = TITLE_ISSUE_PREFIX + _(
|
||||
"the time has not been imported correctly."
|
||||
)
|
||||
|
||||
|
||||
class PUBLICATION_ISSUE(IntEnum):
|
||||
DATE_IMPORTATION_IN_TITLE = 1
|
||||
TIME_IMPORTATION_IN_TITLE = 2
|
||||
|
||||
def __str__(self):
|
||||
return {
|
||||
PUBLICATION_ISSUE.DATE_IMPORTATION_IN_TITLE: _("date import problem"),
|
||||
PUBLICATION_ISSUE.TIME_IMPORTATION_IN_TITLE: _("time import problem"),
|
||||
}[self.value]
|
@ -37,11 +37,7 @@ from ..models.utils import remove_accents
|
||||
from ..models.configuration import SiteConfiguration
|
||||
from ..calendar import CalendarDay
|
||||
from ..import_tasks.extractor import Extractor
|
||||
from .constants import (
|
||||
TITLE_ISSUE_DATE_IMPORTATION,
|
||||
TITLE_ISSUE_TIME_IMPORTATION,
|
||||
PUBLICATION_ISSUE,
|
||||
)
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -178,6 +174,7 @@ class DuplicatedEvents(models.Model):
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
def get_import_messages(self):
|
||||
from . import Message
|
||||
|
||||
msgs = []
|
||||
for e in self.get_duplicated():
|
||||
@ -429,7 +426,7 @@ class Event(models.Model):
|
||||
if not self.is_modification_locked(now):
|
||||
self.editing_start = now
|
||||
self.editing_user = user
|
||||
self.save(update_fields=["editing_start", "editing_user"], no_prepare=True)
|
||||
self.save(update_fields=["editing_start", "editing_user"])
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
@ -441,9 +438,7 @@ class Event(models.Model):
|
||||
self.editing_start = None
|
||||
self.editing_user = None
|
||||
if save:
|
||||
self.save(
|
||||
update_fields=["editing_start", "editing_user"], no_prepare=True
|
||||
)
|
||||
self.save(update_fields=["editing_start", "editing_user"])
|
||||
return True
|
||||
|
||||
def get_dates(self):
|
||||
@ -943,7 +938,7 @@ class Event(models.Model):
|
||||
def download_missing_image(self):
|
||||
if self.local_image and not default_storage.exists(self.local_image.name):
|
||||
self.download_image()
|
||||
self.save(update_fields=["local_image"], no_prepare=True)
|
||||
self.save(update_fields=["local_image"])
|
||||
|
||||
def download_image(self):
|
||||
# first download file
|
||||
@ -1248,10 +1243,7 @@ class Event(models.Model):
|
||||
return notif
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if "no_prepare" in kwargs:
|
||||
del kwargs["no_prepare"]
|
||||
else:
|
||||
self.prepare_save()
|
||||
self.prepare_save()
|
||||
|
||||
# check for similar events if no duplicated is known and only if the event is created
|
||||
if (
|
||||
@ -1796,19 +1788,3 @@ class Event(models.Model):
|
||||
|
||||
def get_count_modifications(when_list):
|
||||
return [Event.get_count_modification(w) for w in when_list]
|
||||
|
||||
@classmethod
|
||||
def get_title_publication_issues(cls, title):
|
||||
result = []
|
||||
if TITLE_ISSUE_DATE_IMPORTATION in title:
|
||||
result.append(PUBLICATION_ISSUE.DATE_IMPORTATION_IN_TITLE)
|
||||
if TITLE_ISSUE_TIME_IMPORTATION in title:
|
||||
result.append(PUBLICATION_ISSUE.TIME_IMPORTATION_IN_TITLE)
|
||||
|
||||
return result
|
||||
|
||||
def get_publication_issues(self):
|
||||
return Event.get_title_publication_issues(self.title)
|
||||
|
||||
def has_publication_issues(self):
|
||||
return len(self.get_publication_issues()) > 0
|
||||
|
@ -1 +0,0 @@
|
||||
from .place_serializer import PlaceSerializer
|
@ -1,30 +0,0 @@
|
||||
from rest_framework import serializers
|
||||
from ..models import Place
|
||||
|
||||
|
||||
class PlaceSerializer(serializers.ModelSerializer):
|
||||
lat = serializers.SerializerMethodField()
|
||||
lng = serializers.SerializerMethodField()
|
||||
url = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = Place
|
||||
fields = [
|
||||
"name",
|
||||
"address",
|
||||
"postcode",
|
||||
"city",
|
||||
"description",
|
||||
"lat",
|
||||
"lng",
|
||||
"url",
|
||||
]
|
||||
|
||||
def get_lat(self, obj):
|
||||
return obj.location[1] if obj.location else None
|
||||
|
||||
def get_lng(self, obj):
|
||||
return obj.location[0] if obj.location else None
|
||||
|
||||
def get_url(self, obj):
|
||||
return obj.get_absolute_url()
|
@ -72,7 +72,6 @@ INSTALLED_APPS = [
|
||||
"django_cleanup.apps.CleanupConfig",
|
||||
"django_unused_media",
|
||||
"solo.apps.SoloAppConfig",
|
||||
"rest_framework",
|
||||
]
|
||||
|
||||
SOLO_CACHE_TIMEOUT = 60 * 15 # 15 minutes
|
||||
|
@ -375,10 +375,6 @@ var SequentialLoader = function() {
|
||||
_getMap: function(mapOptions) {
|
||||
var map = new L.Map(this.options.id, mapOptions), layer;
|
||||
|
||||
if (window.loadTiles !== undefined) {
|
||||
window.loadTiles(map);
|
||||
}
|
||||
|
||||
if (this.options.provider == 'google') {
|
||||
layer = new L.gridLayer.googleMutant({
|
||||
type: this.options.providerOptions.google.mapType.toLowerCase(),
|
||||
@ -401,6 +397,25 @@ var SequentialLoader = function() {
|
||||
|
||||
map.addLayer(layer);
|
||||
|
||||
if ((window.other_markers !== null) && (window.other_markers.length > 0)) {
|
||||
var layerGroup = L.layerGroup().addTo(map);
|
||||
window.other_markers.forEach(x => layerGroup.addLayer(x));
|
||||
map.removeLayer(layerGroup);
|
||||
map.on('zoomend', function () {
|
||||
var currentZoom = map.getZoom();
|
||||
|
||||
if (currentZoom > 12) {
|
||||
if (!map.hasLayer(layerGroup)) {
|
||||
map.addLayer(layerGroup);
|
||||
}
|
||||
} else {
|
||||
if (map.hasLayer(layerGroup)) {
|
||||
map.removeLayer(layerGroup);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return map;
|
||||
},
|
||||
|
||||
@ -419,8 +434,7 @@ var SequentialLoader = function() {
|
||||
var self = this,
|
||||
markerOptions = {
|
||||
draggable: true,
|
||||
icon: window.pinIcon,
|
||||
zIndexOffset: 1000,
|
||||
icon: window.pinIcon
|
||||
};
|
||||
|
||||
var marker = L.marker(center, markerOptions).addTo(map);
|
||||
|
@ -349,7 +349,7 @@ footer [data-tooltip] {
|
||||
|
||||
#calendar.week {
|
||||
.grid {
|
||||
grid-template-columns: repeat(7, calc(100vw - 4 * var(--block-spacing-horizontal)));
|
||||
grid-template-columns: repeat(7, 85vw);
|
||||
width: fit-content;
|
||||
}
|
||||
}
|
||||
@ -1351,7 +1351,6 @@ img.preview {
|
||||
#map_location {
|
||||
width: 100%;
|
||||
aspect-ratio: 16/16;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.leaflet-container {
|
||||
@ -1462,9 +1461,6 @@ img.preview {
|
||||
|
||||
.choices__input-wrapper {
|
||||
position: relative;
|
||||
.choices__input {
|
||||
padding-right: 2.2em;
|
||||
}
|
||||
}
|
||||
|
||||
.clear-btn {
|
||||
@ -1565,7 +1561,6 @@ img.preview {
|
||||
z-index: 1000;
|
||||
li {
|
||||
list-style: none;
|
||||
a {
|
||||
@extend [role="button"], .secondary;
|
||||
height: 1.8em;
|
||||
width: 1.8em;
|
||||
@ -1576,10 +1571,11 @@ img.preview {
|
||||
text-align: center;
|
||||
z-index: 10;
|
||||
opacity: 0.9;
|
||||
color: var(--primary-inverse);
|
||||
a {
|
||||
color: var(--primary-inverse);
|
||||
}
|
||||
float: left;
|
||||
clear: both;
|
||||
}
|
||||
}
|
||||
position: fixed;
|
||||
bottom: calc(var(--spacing) + .4em);
|
||||
|
@ -43,15 +43,8 @@
|
||||
{% endfor %}
|
||||
<li>
|
||||
État :
|
||||
{% if e.pure_import %}
|
||||
version fidèle à la source importée
|
||||
{% else %}
|
||||
{% if e.local_version %}
|
||||
<strong>version modifiée localement</strong>
|
||||
{% else %}
|
||||
<strong>version créée localement</strong>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if e.pure_import %}version fidèle à la source importée{% endif %}
|
||||
{% if e.local_version %}<strong>version modifiée localement</strong>{% endif %}
|
||||
</li>
|
||||
</ul>
|
||||
{% with e.get_import_messages as messages %}
|
||||
|
@ -1,44 +1,40 @@
|
||||
{% load utils_extra %}
|
||||
{% with event.has_publication_issues as pub_issues %}
|
||||
{% if not pub_issues %}
|
||||
{% if event.moderated_date %}
|
||||
<a href="{% url 'moderate_event' event.id %}" role="button">modérer de nouveau {% picto_from_name "check-square" %}</a>
|
||||
{% if event.moderated_date %}
|
||||
<a href="{% url 'moderate_event' event.id %}" role="button">modérer de nouveau {% picto_from_name "check-square" %}</a>
|
||||
{% else %}
|
||||
<a href="{% url 'moderate_event' event.id %}" role="button">modérer {% picto_from_name "check-square" %}</a>
|
||||
{% endif %}
|
||||
{% if event.pure_import %}
|
||||
{% with event.get_local_version as local %}
|
||||
{% if local %}
|
||||
<a href="{{ local.get_absolute_url }}" role="button">Voir la version locale {% picto_from_name "eye" %}</a>
|
||||
{% else %}
|
||||
<a href="{% url 'moderate_event' event.id %}" role="button">modérer {% picto_from_name "check-square" %}</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if event.pure_import %}
|
||||
{% with event.get_local_version as local %}
|
||||
{% if local %}
|
||||
<a href="{{ local.get_absolute_url }}" role="button">Voir la version locale {% picto_from_name "eye" %}</a>
|
||||
{% else %}
|
||||
{% if user.userprofile.is_moderation_expert %}
|
||||
<a href="{% url 'clone_edit' event.id %}" role="button">modifier & modérer {% picto_from_name "edit-3" %}</a>
|
||||
{% endif %}
|
||||
{% if user.userprofile.is_moderation_expert %}
|
||||
<a href="{% url 'clone_edit' event.id %}" role="button">modifier & modérer {% picto_from_name "edit-3" %}</a>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% else %}
|
||||
<a href="{% url 'edit_event' event.id %}" role="button">modifier & modérer {% picto_from_name "edit-3" %}</a>
|
||||
{% endif %}
|
||||
{% if event.is_updateable %}
|
||||
<a href="{% url 'update_from_source' event.id %}" role="button">réimporter {% picto_from_name "download-cloud" %}</a>
|
||||
{% endif %}
|
||||
{% if event.status == "draft" and details == 1 and not pub_issues %}
|
||||
<a href="{% url 'change_status_event' event.id 'published' %}"
|
||||
role="button">publier {% picto_from_name "eye" %}</a>
|
||||
{% endif %}
|
||||
{% if event.status == "trash" %}
|
||||
{% if details == 1 %}
|
||||
<a href="{% url 'change_status_event' event.id 'published' %}"
|
||||
role="button">restaurer {% picto_from_name "eye" %}</a>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<a href="{% url 'change_status_event' event.id 'trash' %}" role="button">supprimer {% picto_from_name "trash-2" %}</a>
|
||||
{% endif %}
|
||||
{% if event.status == "trash" %}
|
||||
<a href="{% url 'delete_event' event.id %}" role="button">supprimer définitivement {% picto_from_name "x-circle" %}</a>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% else %}
|
||||
<a href="{% url 'edit_event' event.id %}" role="button">modifier & modérer {% picto_from_name "edit-3" %}</a>
|
||||
{% endif %}
|
||||
{% if event.is_updateable %}
|
||||
<a href="{% url 'update_from_source' event.id %}" role="button">réimporter {% picto_from_name "download-cloud" %}</a>
|
||||
{% endif %}
|
||||
{% if event.status == "draft" and details == 1 %}
|
||||
<a href="{% url 'change_status_event' event.id 'published' %}"
|
||||
role="button">publier {% picto_from_name "eye" %}</a>
|
||||
{% endif %}
|
||||
{% if event.status == "trash" %}
|
||||
{% if details == 1 %}
|
||||
<a href="{% url 'simple_clone_edit' event.id %}" role="button">dupliquer {% picto_from_name "copy" %}</a>
|
||||
<a href="{% url 'change_status_event' event.id 'published' %}"
|
||||
role="button">restaurer {% picto_from_name "eye" %}</a>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% else %}
|
||||
<a href="{% url 'change_status_event' event.id 'trash' %}" role="button">supprimer {% picto_from_name "trash-2" %}</a>
|
||||
{% endif %}
|
||||
{% if event.status == "trash" %}
|
||||
<a href="{% url 'delete_event' event.id %}" role="button">supprimer définitivement {% picto_from_name "x-circle" %}</a>
|
||||
{% endif %}
|
||||
{% if details == 1 %}
|
||||
<a href="{% url 'simple_clone_edit' event.id %}" role="button">dupliquer {% picto_from_name "copy" %}</a>
|
||||
{% endif %}
|
||||
|
@ -61,7 +61,10 @@
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
{% load static_content_extra %}
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
{% if form.is_clone_from_url or form.is_simple_clone_from_url %}
|
||||
{% url "add_event_details" as urlparam %}
|
||||
{% endif %}
|
||||
<form method="post" action="{{ urlparam }}" enctype="multipart/form-data">
|
||||
{% if object %}
|
||||
<article>
|
||||
<header>
|
||||
@ -146,15 +149,6 @@
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</header>
|
||||
{% if event.has_publication_issues %}
|
||||
<div class="message warning">
|
||||
Attention, l'événement n'est pas publiable en l'état :
|
||||
{% for i in event.get_publication_issues %}
|
||||
{{ i }}
|
||||
{% if not forloop.last %},{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% csrf_token %}
|
||||
{{ form.media }}
|
||||
{{ form }}
|
||||
|
@ -15,8 +15,9 @@
|
||||
<article>
|
||||
<header>
|
||||
<div class="buttons slide-buttons">
|
||||
<a href="{% url 'moderation_rules' %}" role="button">Règles de modération {% picto_from_name "book-open" %}</a>
|
||||
<a href="{% url 'add_event_details' %}" role="button">Règles de modération {% picto_from_name "book-open" %}</a>
|
||||
</div>
|
||||
|
||||
<h1>Ajouter un événement</h1>
|
||||
{% url 'event_import' as local_url %}
|
||||
{% include "agenda_culturel/static_content.html" with name="import_proxy" url_path=local_url %}
|
||||
@ -28,17 +29,17 @@
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<input type="submit" value="Importer un événement depuis son url">
|
||||
</form>
|
||||
<footer>
|
||||
<p>
|
||||
Si l'événement n'est pas disponible en ligne, tu peux ajouter un événement en utilisant un formulaire complet :
|
||||
</p>
|
||||
<a href="{% url 'add_event_details' %}" role="button" class="large">Remplir le formulaire d'événement</a>
|
||||
{% if user.is_authenticated %}
|
||||
</form>
|
||||
|
||||
<footer>
|
||||
<p>
|
||||
<strong>Post Scriptum :</strong> tu peux aussi <a href="{% url 'add_event_urls' %}">importer des événements en batches de plein d'urls</a>.
|
||||
Si l'événement n'est pas disponible en ligne, tu peux ajouter un événement en utilisant un formulaire complet :
|
||||
</p>
|
||||
<a href="{% url 'add_event_details' %}" role="button" class="large">Remplir le formulaire d'événement</a>
|
||||
|
||||
{% if user.is_authenticated %}
|
||||
<p><strong>Post Scriptum :</strong> tu peux aussi <a href="{% url 'add_event_urls' %}">importer des événements en batches de plein d'urls</a>.</p>
|
||||
{% endif %}
|
||||
</footer>
|
||||
</article>
|
||||
</footer>
|
||||
</article>
|
||||
{% endblock %}
|
||||
|
@ -76,7 +76,7 @@
|
||||
choices.showDropdown();
|
||||
|
||||
setTimeout(() => {
|
||||
const searchTerm = htmlDecode('{{ object.location }}').replace(/\(?\d{5}\)?/, '').replace(/\s*,?\s*France\s*/, '');
|
||||
const searchTerm = htmlDecode('{{ object.location }}').replace(/\(?\d{5}\)?/, '');
|
||||
choices.input.focus();
|
||||
choices.input.value = searchTerm;
|
||||
choices._handleSearch(searchTerm);
|
||||
|
@ -37,51 +37,18 @@
|
||||
shadowSize: [19, 19]
|
||||
});
|
||||
|
||||
window.loadedTiles = new Set();
|
||||
window.loadTiles = (map) => {
|
||||
var layerGroup = L.layerGroup().addTo(map);
|
||||
var dl_places = () => {
|
||||
const zoom = map.getZoom();
|
||||
if (zoom < 12) {
|
||||
if (map.hasLayer(layerGroup))
|
||||
map.removeLayer(layerGroup);
|
||||
return;
|
||||
}
|
||||
else
|
||||
if (!map.hasLayer(layerGroup)) {
|
||||
map.addLayer(layerGroup);
|
||||
layerGroup.bringToBack();
|
||||
}
|
||||
|
||||
const bounds = map.getBounds();
|
||||
const tileSize = 0.1;
|
||||
|
||||
const latStart = Math.floor(bounds.getSouth() / tileSize);
|
||||
const latEnd = Math.ceil(bounds.getNorth() / tileSize);
|
||||
const lngStart = Math.floor(bounds.getWest() / tileSize);
|
||||
const lngEnd = Math.ceil(bounds.getEast() / tileSize);
|
||||
|
||||
for (let x = lngStart; x <= lngEnd; x++) {
|
||||
for (let y = latStart; y <= latEnd; y++) {
|
||||
const tileKey = `${x}_${y}`;
|
||||
if (window.loadedTiles.has(tileKey)) continue;
|
||||
|
||||
fetch(`/api/places/tile/?tile_x=${x}&tile_y=${y}&tile_size=${tileSize}`)
|
||||
.then((res) => res.json())
|
||||
.then((data) => {
|
||||
data.forEach((place) => {
|
||||
layerGroup.addLayer(L.marker([place.lat, place.lng], {'icon': circleIcon})
|
||||
.bindPopup(`<a href="${place.url}">${place.name}</a>`));
|
||||
});
|
||||
window.loadedTiles.add(tileKey);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
map.on("moveend", dl_places);
|
||||
dl_places();
|
||||
};
|
||||
window.other_markers = [];
|
||||
{% with cache_timeout=user.is_authenticated|yesno:"300,6000" %}
|
||||
{% cache cache_timeout place_lists_js user.is_authenticated %}
|
||||
|
||||
{% if place_list %}
|
||||
{% for place in place_list %}
|
||||
window.other_markers.push(L.marker([{{ place.location|tocoords }}], {'icon': circleIcon}).bindPopup('<a href="{{ place.get_absolute_url }}">{{ place.name }}</a><br />{% if place.address %}{{ place.address }}, {% endif %}{{ place.city }}'));
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endcache %}
|
||||
{% endwith %}
|
||||
</script>
|
||||
<link href="{% static 'css/django_better_admin_arrayfield.min.css' %}"
|
||||
type="text/css"
|
||||
|
@ -40,38 +40,30 @@
|
||||
</header>
|
||||
<div class="grid">
|
||||
<div id="map_location"></div>
|
||||
<div>
|
||||
<div class="vertical-max">
|
||||
{% with cache_timeout=user.is_authenticated|yesno:"300,6000" %}
|
||||
{% cache cache_timeout place_lists user.is_authenticated %}
|
||||
{% if object_list %}
|
||||
<input type="search"
|
||||
id="searchInput"
|
||||
placeholder="Rechercher un lieu..."
|
||||
autofocus>
|
||||
<div class="vertical-max" id="placeList">
|
||||
{% for place in object_list %}
|
||||
<div class="item">
|
||||
<h3>
|
||||
<a href="{{ place.get_absolute_url }}">{{ place.name }}</a> — <a id="open-map-{{ place.id }}"
|
||||
{% for place in object_list %}
|
||||
<h3>
|
||||
<a href="{{ place.get_absolute_url }}">{{ place.name }}</a> — <a id="open-map-{{ place.id }}"
|
||||
href="#map_location"
|
||||
data-tooltip="afficher sur la carte">{% picto_from_name "map" %}</a>
|
||||
</h3>
|
||||
<ul>
|
||||
<li class="address">
|
||||
<strong>Adresse :</strong>
|
||||
{% if place.address %}{{ place.address }},{% endif %}
|
||||
{{ place.city }}
|
||||
</li>
|
||||
<li>
|
||||
<strong>Coordonnée GPS :</strong> {{ place.location }}
|
||||
</li>
|
||||
{% with place.nb_events_future as nb %}
|
||||
{% if nb > 0 %}<li>{{ nb }} événement{{ nb|pluralize }} à venir</li>{% endif %}
|
||||
{% endwith %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</h3>
|
||||
<ul>
|
||||
<li>
|
||||
<strong>Adresse :</strong>
|
||||
{% if place.address %}{{ place.address }},{% endif %}
|
||||
{{ place.city }}
|
||||
</li>
|
||||
<li>
|
||||
<strong>Coordonnée GPS :</strong> {{ place.location }}
|
||||
</li>
|
||||
{% with place.nb_events_future as nb %}
|
||||
{% if nb > 0 %}<li>{{ nb }} événement{{ nb|pluralize }} à venir</li>{% endif %}
|
||||
{% endwith %}
|
||||
</ul>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<p>Il n'y a aucun lieu défini.</p>
|
||||
{% endif %}
|
||||
@ -99,37 +91,20 @@
|
||||
markerArray = [];
|
||||
var markers = L.markerClusterGroup({disableClusteringAtZoom:16});
|
||||
window.mMapping = {};
|
||||
{% with cache_timeout=user.is_authenticated|yesno:"300,6000" %}
|
||||
{% cache cache_timeout place_lists_js_all user.is_authenticated %}
|
||||
|
||||
{% if object_list %}
|
||||
{% for place in object_list %}
|
||||
markerArray.push(L.marker([{{ place.location|tocoords }}], {'icon': pinIcon}).bindPopup('<a href="{{ place.get_absolute_url }}">{{ place.name }}</a><br />{% if place.address %}{{ place.address }}, {% endif %}{{ place.city }}'))
|
||||
markers.addLayer(markerArray[markerArray.length - 1]);
|
||||
window.mMapping[{{ place.id }}] = markerArray[markerArray.length - 1];
|
||||
window.django.jQuery('a#open-map-{{ place.id }}').click(function(){
|
||||
window.mMapping[{{ place.id }}].openPopup();
|
||||
map.panTo(window.mMapping[{{ place.id }}].getLatLng());
|
||||
});
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endcache %}
|
||||
{% endwith %}
|
||||
{% if object_list %}
|
||||
{% for place in object_list %}
|
||||
markerArray.push(L.marker([{{ place.location|tocoords }}], {'icon': pinIcon}).bindPopup('<a href="{{ place.get_absolute_url }}">{{ place.name }}</a><br />{% if place.address %}{{ place.address }}, {% endif %}{{ place.city }}'))
|
||||
markers.addLayer(markerArray[markerArray.length - 1]);
|
||||
window.mMapping[{{ place.id }}] = markerArray[markerArray.length - 1];
|
||||
window.django.jQuery('a#open-map-{{ place.id }}').click(function(){
|
||||
window.mMapping[{{ place.id }}].openPopup();
|
||||
map.panTo(window.mMapping[{{ place.id }}].getLatLng());
|
||||
});
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
map.addLayer(markers);
|
||||
//var group = L.featureGroup(window.markerArray).addTo(map);
|
||||
map.fitBounds(markers.getBounds());
|
||||
|
||||
document.getElementById("searchInput").addEventListener("input", function () {
|
||||
const filter = this.value.toLowerCase();
|
||||
const items = document.querySelectorAll("#placeList .item");
|
||||
|
||||
items.forEach(item => {
|
||||
const title = item.querySelector("h3")?.textContent.toLowerCase() || "";
|
||||
const address = item.querySelector("li.address")?.textContent.toLowerCase() || "";
|
||||
const content = title + " " + address;
|
||||
|
||||
item.style.display = content.includes(filter) ? "" : "none";
|
||||
});});
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
@ -35,9 +35,6 @@ from .views import (
|
||||
recent,
|
||||
EventDetailView,
|
||||
EventUpdateView,
|
||||
EventCreateIndependantView,
|
||||
EventCreateLocalView,
|
||||
EventUpdateForceView,
|
||||
EventCreateView,
|
||||
update_from_source,
|
||||
change_status_event,
|
||||
@ -91,12 +88,8 @@ from .views import (
|
||||
view_messages,
|
||||
# Moderation
|
||||
EventModerateView,
|
||||
EventModerateBackView,
|
||||
EventModerateForceView,
|
||||
EventModerateNextView,
|
||||
moderate_event_next,
|
||||
moderate_from_date,
|
||||
moderate_from_now,
|
||||
# Organisations
|
||||
OrganisationCreateView,
|
||||
OrganisationDeleteView,
|
||||
@ -116,7 +109,6 @@ from .views import (
|
||||
UnknownPlaceAddView,
|
||||
UnknownPlacesListView,
|
||||
fix_unknown_places,
|
||||
PlaceTileView,
|
||||
# Search
|
||||
event_search,
|
||||
event_search_full,
|
||||
@ -248,18 +240,16 @@ urlpatterns = [
|
||||
path("event/<int:pk>/", EventDetailView.as_view(), name="edit_event_pk"),
|
||||
path("event/<int:pk>/edit", EventUpdateView.as_view(), name="edit_event"),
|
||||
path(
|
||||
"event/<int:pk>/edit-force",
|
||||
EventUpdateForceView.as_view(),
|
||||
name="edit_event_force",
|
||||
"event/<int:pk>/edit-force", EventUpdateView.as_view(), name="edit_event_force"
|
||||
),
|
||||
path( # clone function used to create an independant copy
|
||||
path(
|
||||
"event/<int:pk>/simple-clone/edit",
|
||||
EventCreateIndependantView.as_view(),
|
||||
EventUpdateView.as_view(),
|
||||
name="simple_clone_edit",
|
||||
),
|
||||
path( # clone function to have a local version of the event, thus modify it
|
||||
path(
|
||||
"event/<int:pk>/clone/edit",
|
||||
EventCreateLocalView.as_view(),
|
||||
EventUpdateView.as_view(),
|
||||
name="clone_edit",
|
||||
),
|
||||
path(
|
||||
@ -378,7 +368,7 @@ urlpatterns = [
|
||||
),
|
||||
path("messages", view_messages, name="messages"),
|
||||
# Moderation
|
||||
path("moderate", moderate_from_now, name="moderate"),
|
||||
path("moderate", EventModerateView.as_view(), name="moderate"),
|
||||
path(
|
||||
"event/<int:pk>/moderate",
|
||||
EventModerateView.as_view(),
|
||||
@ -386,17 +376,17 @@ urlpatterns = [
|
||||
),
|
||||
path(
|
||||
"event/<int:pk>/moderate-force",
|
||||
EventModerateForceView.as_view(),
|
||||
EventModerateView.as_view(),
|
||||
name="moderate_event_force",
|
||||
),
|
||||
path(
|
||||
"event/<int:pk>/moderate/after/<int:pred>",
|
||||
EventModerateNextView.as_view(),
|
||||
EventModerateView.as_view(),
|
||||
name="moderate_event_step",
|
||||
),
|
||||
path(
|
||||
"event/<int:pk>/moderate/back/<int:pred>",
|
||||
EventModerateBackView.as_view(),
|
||||
EventModerateView.as_view(),
|
||||
name="moderate_event_backstep",
|
||||
),
|
||||
path(
|
||||
@ -551,8 +541,6 @@ urlpatterns = [
|
||||
load_specialperiods_from_ical,
|
||||
name="load_specialperiods_from_ical",
|
||||
),
|
||||
# API
|
||||
path("api/places/tile/", PlaceTileView.as_view(), name="place_list"),
|
||||
]
|
||||
|
||||
if settings.DEBUG:
|
||||
|
@ -98,6 +98,9 @@ class EventUpdateView(
|
||||
kwargs["is_moderation_expert"] = (
|
||||
self.request.user.userprofile.is_moderation_expert
|
||||
)
|
||||
kwargs["is_cloning"] = self.is_cloning
|
||||
kwargs["is_edit_from_moderation"] = self.is_edit_force()
|
||||
kwargs["is_simple_cloning"] = self.is_simple_cloning
|
||||
return kwargs
|
||||
|
||||
def get_success_message(self, cleaned_data):
|
||||
@ -108,10 +111,15 @@ class EventUpdateView(
|
||||
)
|
||||
return mark_safe(_("The event has been successfully modified.") + txt)
|
||||
|
||||
def is_edit_force(self):
|
||||
return "edit-force" in self.request.path.split("/")
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
event = super().get_object(queryset)
|
||||
if event.status == Event.STATUS.DRAFT:
|
||||
event.status = Event.STATUS.PUBLISHED
|
||||
if self.is_edit_force():
|
||||
event.free_modification_lock(self.request.user)
|
||||
return event
|
||||
|
||||
def form_valid(self, form):
|
||||
@ -119,6 +127,41 @@ class EventUpdateView(
|
||||
self.with_message = form.instance.notify_if_required(self.request)
|
||||
return super().form_valid(form)
|
||||
|
||||
def get_initial(self):
|
||||
self.is_cloning = "clone" in self.request.path.split("/")
|
||||
if self.is_cloning:
|
||||
messages.info(
|
||||
self.request,
|
||||
_(
|
||||
"Changes will be visible on a local copy of the event. The version identical to the imported source will be hidden."
|
||||
),
|
||||
)
|
||||
self.is_simple_cloning = "simple-clone" in self.request.path.split("/")
|
||||
result = super().get_initial()
|
||||
|
||||
if self.is_cloning and "other_versions" not in result:
|
||||
obj = self.get_object()
|
||||
# if no DuplicatedEvents is associated, create one
|
||||
obj.other_versions = DuplicatedEvents.objects.create()
|
||||
obj.other_versions.save()
|
||||
# save them without updating modified date
|
||||
obj.set_no_modification_date_changed()
|
||||
obj.save()
|
||||
result["other_versions"] = obj.other_versions
|
||||
result["status"] = Event.STATUS.PUBLISHED
|
||||
result["cloning"] = True
|
||||
|
||||
if self.is_simple_cloning:
|
||||
result["other_versions"] = None
|
||||
result["simple_cloning"] = True
|
||||
|
||||
if self.is_cloning or self.is_simple_cloning:
|
||||
obj = self.get_object()
|
||||
if obj.local_image:
|
||||
result["old_local_image"] = obj.local_image.name
|
||||
|
||||
return result
|
||||
|
||||
def get_success_url(self):
|
||||
if "save_and_next" in self.request.POST:
|
||||
return reverse_lazy("moderate_event_next", args=[self.object.pk])
|
||||
@ -126,109 +169,6 @@ class EventUpdateView(
|
||||
return self.object.get_absolute_url()
|
||||
|
||||
|
||||
class EventUpdateForceView(EventUpdateView):
|
||||
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super().get_form_kwargs()
|
||||
kwargs["is_edit_from_moderation"] = True
|
||||
return kwargs
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
event = super().get_object(queryset)
|
||||
event.free_modification_lock(self.request.user)
|
||||
return event
|
||||
|
||||
|
||||
class EventCloneView(EventUpdateView):
|
||||
|
||||
def form_valid(self, form):
|
||||
# Clone the object removing the key
|
||||
self.object = form.save(commit=False)
|
||||
self.object.pk = None
|
||||
self.object.save()
|
||||
form.save_m2m()
|
||||
form.instance.import_sources = None
|
||||
form.instance.set_processing_user(self.request.user)
|
||||
return super().form_valid(form)
|
||||
|
||||
def get_initial(self):
|
||||
result = super().get_initial()
|
||||
|
||||
obj = self.get_object()
|
||||
if obj.local_image:
|
||||
result["old_local_image"] = obj.local_image.name
|
||||
|
||||
result["imported_date"] = None
|
||||
|
||||
return result
|
||||
|
||||
|
||||
class EventCreateLocalView(EventCloneView):
|
||||
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super().get_form_kwargs()
|
||||
kwargs["is_cloning"] = True
|
||||
return kwargs
|
||||
|
||||
def get_initial(self):
|
||||
messages.info(
|
||||
self.request,
|
||||
_(
|
||||
"Changes will be visible on a local copy of the event. The version identical to the imported source will be hidden."
|
||||
),
|
||||
)
|
||||
result = super().get_initial()
|
||||
|
||||
if "other_versions" not in result:
|
||||
obj = self.get_object()
|
||||
# if no DuplicatedEvents is associated, create one
|
||||
if obj.other_versions is None:
|
||||
obj.other_versions = DuplicatedEvents.objects.create()
|
||||
obj.other_versions.save()
|
||||
# save them without updating modified date
|
||||
obj.set_no_modification_date_changed()
|
||||
obj.save()
|
||||
result["other_versions"] = obj.other_versions
|
||||
|
||||
result["status"] = Event.STATUS.PUBLISHED
|
||||
|
||||
return result
|
||||
|
||||
def form_valid(self, form):
|
||||
form.instance.set_in_moderation_process()
|
||||
with_msg = form.instance.notify_if_required(self.request)
|
||||
if with_msg:
|
||||
messages.success(
|
||||
self.request,
|
||||
_(
|
||||
"A message has been sent to the person who proposed the initial event."
|
||||
),
|
||||
)
|
||||
|
||||
return super().form_valid(form)
|
||||
|
||||
|
||||
class EventCreateIndependantView(EventCloneView):
|
||||
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super().get_form_kwargs()
|
||||
kwargs["is_simple_cloning"] = True
|
||||
return kwargs
|
||||
|
||||
def get_initial(self):
|
||||
|
||||
result = super().get_initial()
|
||||
|
||||
result["other_versions"] = None
|
||||
result["simple_cloning"] = True
|
||||
|
||||
return result
|
||||
|
||||
def form_valid(self, form):
|
||||
form.instance.set_skip_duplicate_check()
|
||||
return super().form_valid(form)
|
||||
|
||||
|
||||
class EventDeleteView(
|
||||
SuccessMessageMixin,
|
||||
PermissionRequiredMixin,
|
||||
@ -472,6 +412,11 @@ class EventCreateView(SuccessMessageMixin, CreateView):
|
||||
)
|
||||
|
||||
def form_valid(self, form):
|
||||
if form.cleaned_data["simple_cloning"]:
|
||||
form.instance.set_skip_duplicate_check()
|
||||
|
||||
if form.cleaned_data["cloning"]:
|
||||
form.instance.set_in_moderation_process()
|
||||
|
||||
if form.cleaned_data.get("email") or form.cleaned_data.get("comments"):
|
||||
has_comments = form.cleaned_data.get("comments") not in ["", None]
|
||||
@ -492,7 +437,19 @@ class EventCreateView(SuccessMessageMixin, CreateView):
|
||||
form.instance.import_sources = None
|
||||
form.instance.set_processing_user(self.request.user)
|
||||
|
||||
return super().form_valid(form)
|
||||
result = super().form_valid(form)
|
||||
|
||||
if form.cleaned_data["cloning"]:
|
||||
with_msg = form.instance.notify_if_required(self.request)
|
||||
if with_msg:
|
||||
messages.success(
|
||||
self.request,
|
||||
_(
|
||||
"A message has been sent to the person who proposed the initial event."
|
||||
),
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
# A class to evaluate the URL according to the existing events and the authentification
|
||||
|
@ -4,14 +4,13 @@ from django.contrib.auth.decorators import login_required, permission_required
|
||||
from django.contrib.auth.mixins import PermissionRequiredMixin, LoginRequiredMixin
|
||||
from django.contrib.messages.views import SuccessMessageMixin
|
||||
from django.http import Http404, HttpResponseRedirect
|
||||
from django.shortcuts import render, redirect
|
||||
from django.shortcuts import render
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.views.generic import UpdateView
|
||||
from django.db.models import Q, F
|
||||
from django.utils.timezone import datetime
|
||||
from django.contrib import messages
|
||||
from ..forms import EventModerateForm
|
||||
from ..models import Event
|
||||
|
||||
@ -47,6 +46,21 @@ class EventModerateView(
|
||||
+ txt
|
||||
)
|
||||
|
||||
def is_moderate_next(self):
|
||||
return "after" in self.request.path.split("/")
|
||||
|
||||
def is_moderate_back(self):
|
||||
return "back" in self.request.path.split("/")
|
||||
|
||||
def is_moderate_force(self):
|
||||
return "moderate-force" in self.request.path.split("/")
|
||||
|
||||
def is_starting_moderation(self):
|
||||
return "pk" not in self.kwargs
|
||||
|
||||
def is_moderation_from_date(self):
|
||||
return "m" in self.kwargs and "y" in self.kwargs and "d" in self.kwargs
|
||||
|
||||
def get_next_event(start_day, start_time, opk):
|
||||
# select non moderated events
|
||||
qs = Event.objects.filter(moderated_date__isnull=True)
|
||||
@ -78,10 +92,25 @@ class EventModerateView(
|
||||
|
||||
return qs.first()
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
if self.is_moderate_next():
|
||||
context["pred"] = self.kwargs["pred"]
|
||||
return context
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
event = super().get_object(queryset)
|
||||
if self.is_starting_moderation():
|
||||
now = datetime.now()
|
||||
event = EventModerateView.get_next_event(now.date(), now.time(), None)
|
||||
else:
|
||||
event = super().get_object(queryset)
|
||||
if event.status == Event.STATUS.DRAFT:
|
||||
event.status = Event.STATUS.PUBLISHED
|
||||
if self.is_moderate_back():
|
||||
pred = Event.objects.filter(pk=self.kwargs["pred"]).first()
|
||||
pred.free_modification_lock(self.request.user)
|
||||
if self.is_moderate_force():
|
||||
event.free_modification_lock(self.request.user, False)
|
||||
return event
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
@ -107,138 +136,6 @@ class EventModerateView(
|
||||
else:
|
||||
return self.object.get_absolute_url()
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
|
||||
msg = False
|
||||
if (
|
||||
self.object.other_versions is not None
|
||||
and self.object.other_versions.nb_duplicated() > 1
|
||||
):
|
||||
representative = self.object.other_versions.representative
|
||||
if representative is not None:
|
||||
if representative != self.object:
|
||||
msg = True
|
||||
messages.warning(
|
||||
request,
|
||||
mark_safe(
|
||||
_(
|
||||
"There are several versions of this event, and you're moderating a version that isn't the one being promoted. Most of the time, you don't need to do this, just move on to the next one."
|
||||
)
|
||||
),
|
||||
)
|
||||
else:
|
||||
msg = True
|
||||
messages.warning(
|
||||
request,
|
||||
mark_safe(
|
||||
_(
|
||||
'This event exists in several versions, and has no highlighted version. You should <a href="{}">correct this situation</a> before moderating only the selected event.'
|
||||
).format(
|
||||
reverse_lazy(
|
||||
"fix_duplicate",
|
||||
kwargs={"pk": self.object.other_versions.pk},
|
||||
)
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
issues = self.object.get_publication_issues()
|
||||
print([str(i) for i in issues])
|
||||
if len(issues) > 0 and not msg:
|
||||
if self.object.pure_import:
|
||||
lv = self.object.get_local_version()
|
||||
if lv is None:
|
||||
messages.warning(
|
||||
request,
|
||||
mark_safe(
|
||||
_(
|
||||
"This event is synchronized to a source, and has properties that prevent it from being published as is ({}). We've redirected your moderation to event editing to correct these problems before publication."
|
||||
).format(", ".join([str(i) for i in issues]))
|
||||
),
|
||||
)
|
||||
# clone edit
|
||||
return redirect(
|
||||
reverse_lazy("clone_edit", kwargs={"pk": self.object.pk})
|
||||
)
|
||||
else:
|
||||
# msg is False, thus representative = self.object. Strange configuration. Anyway...
|
||||
issues_lv = lv.get_publication_issues()
|
||||
if len(issues_lv) == 0:
|
||||
messages.warning(
|
||||
request,
|
||||
mark_safe(
|
||||
_(
|
||||
'The event is synchronized to a source and is not publishable as is ({}), but there is <a href="{}">local version</a> that is publishable. You may wish to <a href="{}">modify the highlighted event</a>.'
|
||||
).format(
|
||||
", ".join([str(i) for i in issues]),
|
||||
lv.get_absolute_url(),
|
||||
reverse_lazy("fix_duplicate"),
|
||||
kwargs={"pk": self.object.other_versions.pk},
|
||||
)
|
||||
),
|
||||
)
|
||||
else:
|
||||
messages.warning(
|
||||
request,
|
||||
mark_safe(
|
||||
_(
|
||||
'The event is synchronized on a source and is not publishable as is ({}), and the <a href="{}">local version</a> is not publishable ({}). You should first <a href="{}">fix it</a>, then <a href="{}">modify the event displayed</a>.'
|
||||
).format(
|
||||
", ".join([str(i) for i in issues]),
|
||||
lv.get_absolute_url(),
|
||||
", ".join([str(i) for i in issues_lv]),
|
||||
reverse_lazy("edit_event", kwargs={"pk": lv.pk}),
|
||||
reverse_lazy(
|
||||
"fix_duplicate",
|
||||
kwargs={"pk": self.object.other_versions.pk},
|
||||
),
|
||||
)
|
||||
),
|
||||
)
|
||||
else:
|
||||
messages.info(
|
||||
request,
|
||||
mark_safe(
|
||||
_(
|
||||
"Simple moderation is not available as the event is not publishable in its current state ({}). We therefore switch to editing mode."
|
||||
).format(", ".join([str(i) for i in issues]))
|
||||
),
|
||||
)
|
||||
return redirect(
|
||||
reverse_lazy("edit_event", kwargs={"pk": self.object.pk})
|
||||
)
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
|
||||
class EventModerateNextView(EventModerateView):
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["pred"] = self.kwargs["pred"]
|
||||
return context
|
||||
|
||||
|
||||
class EventModerateBackView(EventModerateView):
|
||||
def get_object(self, queryset=None):
|
||||
pred = Event.objects.filter(pk=self.kwargs["pred"]).first()
|
||||
pred.free_modification_lock(self.request.user)
|
||||
return super().get_object(queryset)
|
||||
|
||||
|
||||
class EventModerateForceView(EventModerateView):
|
||||
def get_object(self, queryset=None):
|
||||
event = super().get_object(queryset)
|
||||
event.free_modification_lock(self.request.user, False)
|
||||
return super().get_object(queryset)
|
||||
|
||||
|
||||
@login_required(login_url="/accounts/login/")
|
||||
@permission_required("agenda_culturel.change_event")
|
||||
def moderate_from_now(request):
|
||||
now = datetime.now()
|
||||
obj = EventModerateView.get_next_event(now.date(), now.time(), None)
|
||||
return HttpResponseRedirect(reverse_lazy("moderate_event", args=[obj.pk]))
|
||||
|
||||
|
||||
@login_required(login_url="/accounts/login/")
|
||||
@permission_required("agenda_culturel.change_event")
|
||||
|
@ -11,15 +11,11 @@ from django.utils.translation import gettext_lazy as _
|
||||
from django.views.generic import ListView, UpdateView, CreateView, DeleteView
|
||||
from django.contrib.gis.measure import D
|
||||
from django.utils.safestring import mark_safe
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.response import Response
|
||||
from django.contrib.gis.geos import Polygon
|
||||
|
||||
from .utils import get_event_qs
|
||||
from ..forms import PlaceForm, EventAddPlaceForm
|
||||
from ..models import Place, Event
|
||||
from ..utils import PlaceGuesser
|
||||
from ..serializers import PlaceSerializer
|
||||
|
||||
|
||||
class PlaceListView(ListView):
|
||||
@ -127,6 +123,11 @@ class PlaceCreateView(
|
||||
success_message = _("The place has been successfully created.")
|
||||
form_class = PlaceForm
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["place_list"] = Place.objects.all().only("location", "name", "pk")
|
||||
return context
|
||||
|
||||
|
||||
class PlaceDeleteView(PermissionRequiredMixin, DeleteView):
|
||||
model = Place
|
||||
@ -255,21 +256,3 @@ class PlaceFromEventCreateView(PlaceCreateView):
|
||||
|
||||
def get_success_url(self):
|
||||
return self.event.get_absolute_url()
|
||||
|
||||
|
||||
class PlaceTileView(APIView):
|
||||
|
||||
def get(self, request):
|
||||
tile_x = int(request.query_params.get("tile_x"))
|
||||
tile_y = int(request.query_params.get("tile_y"))
|
||||
tile_size = float(request.query_params.get("tile_size", 0.005))
|
||||
|
||||
min_lng = tile_x * tile_size
|
||||
min_lat = tile_y * tile_size
|
||||
max_lng = min_lng + tile_size
|
||||
max_lat = min_lat + tile_size
|
||||
|
||||
bbox = Polygon.from_bbox((min_lng, min_lat, max_lng, max_lat))
|
||||
places = Place.objects.filter(location__within=bbox)
|
||||
serializer = PlaceSerializer(places, many=True)
|
||||
return Response(serializer.data)
|
||||
|
@ -52,4 +52,3 @@ django-unused-media==0.2.2
|
||||
django-resized==1.0.3
|
||||
django-solo==2.4.0
|
||||
chronostring==0.1.2
|
||||
djangorestframework==3.16.0
|
||||
|
Loading…
x
Reference in New Issue
Block a user