Ajout import Helloasso

This commit is contained in:
Jean-Marie Favreau 2025-04-12 15:38:54 +02:00
parent b186001132
commit 50579a6597
12 changed files with 431 additions and 185 deletions

1
.gitignore vendored
View File

@ -92,3 +92,4 @@ experimentations/events-augustes.json
# MacOS # MacOS
.DS_Store .DS_Store
src/errors/

View File

@ -23,3 +23,6 @@ APP_DOMAIN=app.backend.dev
# APIs # APIs
ECHOSCIENCES_TOKEN= ECHOSCIENCES_TOKEN=
HELLOASSO_ID=
HELLOASSO_SECRET=

View File

@ -0,0 +1,50 @@
#!/usr/bin/python3
# coding: utf-8
# To be able to run this import out of django, you'll have to set an environment variable with the Helloasso client id/secret:
# export HELLOASSO_SECRET=<your secret>
# export HELLOASSO_ID=<your ID>
import json
import os
import sys
# getting the name of the directory
# where the this file is present.
current = os.path.dirname(os.path.realpath(__file__))
# Getting the parent directory name
# where the current directory is present.
parent = os.path.dirname(current)
# adding the parent directory to
# the sys.path.
sys.path.append(parent)
sys.path.append(parent + "/src")
from src.agenda_culturel.import_tasks.downloader import SimpleDownloader
from src.agenda_culturel.import_tasks.generic_extractors.helloasso import (
CExtractor,
)
from src.agenda_culturel.import_tasks.importer import URL2Events
if __name__ == "__main__":
u2e = URL2Events(SimpleDownloader(), CExtractor())
#url = "https://www.helloasso.com/associations/federation-des-associations-laiques-du-puy-de-dome/evenements/de-fil-en-chemin-2025-11e-edition-rencontres-de-danse-amateur"
url = "https://www.helloasso.com/associations/federation-des-associations-laiques-du-puy-de-dome"
url_human = url
events = u2e.process(
url,
url_human,
cache="cache-helloasso.html",
default_values={},
published=True,
)
exportfile = "events-helloasso.json"
print("Saving events to file {}".format(exportfile))
with open(exportfile, "w") as f:
json.dump(events, f, indent=4, default=str)

View File

@ -39,6 +39,7 @@ from .import_tasks.generic_extractors import (
ical, ical,
fbevents, fbevents,
echosciences, echosciences,
helloasso,
) )
from .import_tasks.importer import URL2Events from .import_tasks.importer import URL2Events
@ -211,6 +212,8 @@ def run_recurrent_import_internal(rimport, downloader, req_id):
extractor = lecameleon.CExtractor() extractor = lecameleon.CExtractor()
elif rimport.processor == RecurrentImport.PROCESSOR.ECHOSCIENCES: elif rimport.processor == RecurrentImport.PROCESSOR.ECHOSCIENCES:
extractor = echosciences.CExtractor() extractor = echosciences.CExtractor()
elif rimport.processor == RecurrentImport.PROCESSOR.HELLOASSO:
extractor = helloasso.CExtractor()
else: else:
extractor = None extractor = None

View File

@ -121,7 +121,10 @@ class ChromiumHeadlessDownloader(Downloader):
self.driver = webdriver.Chrome(service=self.service, options=self.options) self.driver = webdriver.Chrome(service=self.service, options=self.options)
def __del__(self): def __del__(self):
self.driver.quit() try:
self.driver.quit()
except Exception as e:
print('Error: ' + str(e))
def screenshot(self, url, path_image): def screenshot(self, url, path_image):
print("Screenshot {}".format(url)) print("Screenshot {}".format(url))

View File

@ -316,21 +316,23 @@ class Extractor(ABC):
) )
from .generic_extractors.ical import ICALExtractor from .generic_extractors.ical import ICALExtractor
from .custom_extractors.associations_cf import CExtractor as AssociationsCF from .custom_extractors.associations_cf import CExtractor as AssociationsCF
from .generic_extractors.helloasso import CExtractor as HelloAssoExtractor
if single_event: if single_event:
return [ return [
FacebookEventExtractor(), FacebookEventExtractor,
GoogleCalendarLinkEventExtractor(), GoogleCalendarLinkEventExtractor,
AssociationsCF(), AssociationsCF,
ICALExtractor(), ICALExtractor,
EventNotFoundExtractor(), HelloAssoExtractor,
EventNotFoundExtractor,
] ]
else: else:
return [ return [
ICALExtractor(), ICALExtractor,
FacebookEventExtractor(), FacebookEventExtractor,
GoogleCalendarLinkEventExtractor(), GoogleCalendarLinkEventExtractor,
EventNotFoundExtractor(), EventNotFoundExtractor,
] ]

View File

@ -0,0 +1,156 @@
import logging
from datetime import datetime, timedelta
from django.conf import settings
import dateutil.parser
import requests
from bs4 import BeautifulSoup
import re
import json
from ..extractor import Extractor
logger = logging.getLogger(__name__)
# A class dedicated to get events from helloasso
class CExtractor(Extractor):
patternEvent = r'^https://www\.helloasso\.com/associations/([\w\-]+)/evenements/([\w\-]+)'
patternOrg = r'^https://www\.helloasso\.com/associations/([\w\-]+)'
urlAPI = "https://api.helloasso.com"
def __init__(self):
super().__init__()
self.no_downloader = True
def id_and_secret_available(self):
return settings.HELLOASSO_ID != "" and settings.HELLOASSO_SECRET != ""
def is_known_url(url):
return re.match(CExtractor.patternEvent, url) is not None or re.match(CExtractor.patternOrg, url) is not None
def get_header_with_token():
url = CExtractor.urlAPI + "/oauth2/token"
payload = {
"grant_type": "client_credentials",
"client_id": settings.HELLOASSO_ID,
"client_secret": settings.HELLOASSO_SECRET
}
headers = {
"accept": "application/json",
"Content-Type": "application/x-www-form-urlencoded"
}
response = requests.post(url, data=payload, headers=headers)
data = json.loads(response.text)
return {
"accept": "application/json",
"authorization": "Bearer " + data["access_token"]
}
def _get_single_event(org, event, headers=None):
if headers is None:
headers = CExtractor.get_header_with_token()
url = CExtractor.urlAPI + "/v5/organizations/{}/forms/Event/{}/public".format(org, event)
response = requests.get(url, headers=headers)
return json.loads(response.text)
def _get_all_events(org):
url = CExtractor.urlAPI + "/v5/organizations/{}/forms?states=Public&formTypes=Event&pageSize=20".format(org)
headers = CExtractor.get_header_with_token()
result = []
for i in range(1, 200):
response = requests.get(url + "&pageIndex={}".format(i), headers=headers)
events = json.loads(response.text)["data"]
if len(events) == 0:
return result
else:
for e in events:
result.append(CExtractor._get_single_event(org, e["formSlug"], headers))
def _get_events(self, url):
match = re.match(CExtractor.patternEvent, url)
if match:
return [CExtractor._get_single_event(match.group(1), match.group(2))]
else:
match = re.match(CExtractor.patternOrg, url)
if match:
return CExtractor._get_all_events(match.group(1))
return []
def extract(
self,
content,
url,
url_human=None,
default_values=None,
published=False,
):
self.set_header(url)
self.clear_events()
if not self.id_and_secret_available():
logger.error("ID/Secret not available")
raise Exception("ID/Secret not available")
if not CExtractor.is_known_url(url):
logger.error("Unknown url")
raise Exception("Unknown url")
events = self._get_events(url)
for event in events:
title = event["title"]
event_url = event["url"]
image = None
image_alt = None
if "banner" in event:
image = event["banner"]["publicUrl"]
if "description" in event["banner"]:
image_alt = event["banner"]["description"]
location = []
if "place" in event and event["place"] is not None:
for elplace in ["name", "address", "zipCode", "city"]:
if elplace in event["place"]:
location.append(event["place"][elplace])
location = ", ".join(location)
description = event["description"]
start = dateutil.parser.isoparse(event["startDate"])
end = dateutil.parser.isoparse(event["endDate"])
start_day = start.date()
start_time = start.time()
end_day = end.date()
end_time = end.time()
self.add_event(
default_values,
title,
None,
start_day,
location,
description,
[],
uuids=[event_url],
recurrences=None,
url_human=event_url,
start_time=start_time,
published=published,
image=image,
image_alt=image_alt,
end_day=end_day,
end_time=end_time,
)
return self.get_structure()

View File

@ -54,8 +54,9 @@ class URL2Events:
) )
else: else:
# if the extractor is not defined, use a list of default extractors # if the extractor is not defined, use a list of default extractors
for e in Extractor.get_default_extractors(self.single_event): for extrClass in Extractor.get_default_extractors(self.single_event):
logger.info("Extractor::" + type(e).__name__) e = extrClass()
logger.info("Extractor::" + str(type(e)))
e.set_downloader(self.downloader) e.set_downloader(self.downloader)
try: try:
events = e.extract( events = e.extract(

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: agenda_culturel\n" "Project-Id-Version: agenda_culturel\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-04-06 13:18+0200\n" "POT-Creation-Date: 2025-04-12 14:10+0200\n"
"PO-Revision-Date: 2023-10-29 14:16+0000\n" "PO-Revision-Date: 2023-10-29 14:16+0000\n"
"Last-Translator: Jean-Marie Favreau <jeanmarie.favreau@free.fr>\n" "Last-Translator: Jean-Marie Favreau <jeanmarie.favreau@free.fr>\n"
"Language-Team: Jean-Marie Favreau <jeanmarie.favreau@free.fr>\n" "Language-Team: Jean-Marie Favreau <jeanmarie.favreau@free.fr>\n"
@ -143,11 +143,11 @@ msgid "Imported from"
msgstr "Importé depuis" msgstr "Importé depuis"
#: agenda_culturel/filters.py:470 agenda_culturel/models.py:875 #: agenda_culturel/filters.py:470 agenda_culturel/models.py:875
#: agenda_culturel/models.py:2991 #: agenda_culturel/models.py:3000
msgid "Status" msgid "Status"
msgstr "Status" msgstr "Status"
#: agenda_culturel/filters.py:471 agenda_culturel/models.py:2755 #: agenda_culturel/filters.py:471 agenda_culturel/models.py:2763
msgid "Closed" msgid "Closed"
msgstr "Fermé" msgstr "Fermé"
@ -156,7 +156,7 @@ msgid "Open"
msgstr "Ouvert" msgstr "Ouvert"
#: agenda_culturel/filters.py:475 agenda_culturel/filters.py:476 #: agenda_culturel/filters.py:475 agenda_culturel/filters.py:476
#: agenda_culturel/models.py:2749 #: agenda_culturel/models.py:2757
msgid "Spam" msgid "Spam"
msgstr "Spam" msgstr "Spam"
@ -164,7 +164,7 @@ msgstr "Spam"
msgid "Non spam" msgid "Non spam"
msgstr "Non spam" msgstr "Non spam"
#: agenda_culturel/filters.py:481 agenda_culturel/models.py:2770 #: agenda_culturel/filters.py:481 agenda_culturel/models.py:2778
msgid "Type" msgid "Type"
msgstr "Type" msgstr "Type"
@ -195,11 +195,11 @@ msgstr ""
msgid "Your email" msgid "Your email"
msgstr "Votre adresse email" msgstr "Votre adresse email"
#: agenda_culturel/forms.py:168 agenda_culturel/models.py:2737 #: agenda_culturel/forms.py:168 agenda_culturel/models.py:2745
msgid "Your email address" msgid "Your email address"
msgstr "Votre adresse email" msgstr "Votre adresse email"
#: agenda_culturel/forms.py:174 agenda_culturel/models.py:2762 #: agenda_culturel/forms.py:174 agenda_culturel/models.py:2770
msgid "Comments" msgid "Comments"
msgstr "Commentaires" msgstr "Commentaires"
@ -215,8 +215,8 @@ msgid "Receive notification of publication or leave a message for moderation"
msgstr "Être notifié de la publication ou laisser un message à la modération" msgstr "Être notifié de la publication ou laisser un message à la modération"
#: agenda_culturel/forms.py:208 agenda_culturel/models.py:315 #: agenda_culturel/forms.py:208 agenda_culturel/models.py:315
#: agenda_culturel/models.py:883 agenda_culturel/models.py:2915 #: agenda_culturel/models.py:883 agenda_culturel/models.py:2924
#: agenda_culturel/models.py:3026 #: agenda_culturel/models.py:3035
msgid "Category" msgid "Category"
msgstr "Catégorie" msgstr "Catégorie"
@ -271,7 +271,7 @@ msgid "Details"
msgstr "Détails" msgstr "Détails"
#: agenda_culturel/forms.py:383 agenda_culturel/models.py:912 #: agenda_culturel/forms.py:383 agenda_culturel/models.py:912
#: agenda_culturel/models.py:2890 #: agenda_culturel/models.py:2899
msgid "Location" msgid "Location"
msgstr "Localisation" msgstr "Localisation"
@ -351,7 +351,7 @@ msgid "Apply category {} to the event {}"
msgstr "Appliquer la catégorie {} à l'événement {}" msgstr "Appliquer la catégorie {} à l'événement {}"
#: agenda_culturel/forms.py:868 agenda_culturel/models.py:700 #: agenda_culturel/forms.py:868 agenda_culturel/models.py:700
#: agenda_culturel/models.py:3078 #: agenda_culturel/models.py:3087
msgid "Place" msgid "Place"
msgstr "Lieu" msgstr "Lieu"
@ -389,7 +389,7 @@ msgstr "Informations"
msgid "Add a comment" msgid "Add a comment"
msgstr "Ajouter un commentaire" msgstr "Ajouter un commentaire"
#: agenda_culturel/forms.py:1011 agenda_culturel/models.py:3179 #: agenda_culturel/forms.py:1011 agenda_culturel/models.py:3188
msgid "Period type" msgid "Period type"
msgstr "Type de période" msgstr "Type de période"
@ -505,7 +505,7 @@ msgstr ""
#: agenda_culturel/models.py:198 agenda_culturel/models.py:245 #: agenda_culturel/models.py:198 agenda_culturel/models.py:245
#: agenda_culturel/models.py:324 agenda_culturel/models.py:619 #: agenda_culturel/models.py:324 agenda_culturel/models.py:619
#: agenda_culturel/models.py:660 agenda_culturel/models.py:766 #: agenda_culturel/models.py:660 agenda_culturel/models.py:766
#: agenda_culturel/models.py:2729 agenda_culturel/models.py:2840 #: agenda_culturel/models.py:2737 agenda_culturel/models.py:2849
msgid "Name" msgid "Name"
msgstr "Nom" msgstr "Nom"
@ -574,8 +574,8 @@ msgstr "Description"
msgid "Description of the tag" msgid "Description of the tag"
msgstr "Description de l'étiquette" msgstr "Description de l'étiquette"
#: agenda_culturel/models.py:339 agenda_culturel/models.py:2696 #: agenda_culturel/models.py:339 agenda_culturel/models.py:2704
#: agenda_culturel/models.py:2743 #: agenda_culturel/models.py:2751
msgid "Message" msgid "Message"
msgstr "Message" msgstr "Message"
@ -742,8 +742,8 @@ msgid ""
"Place mainly associated with this organizer. Mainly used if there is a " "Place mainly associated with this organizer. Mainly used if there is a "
"similarity in the name, to avoid redundant displays." "similarity in the name, to avoid redundant displays."
msgstr "" msgstr ""
"Lieu principalement associé à cette organisation. Principalement utilisé s'il " "Lieu principalement associé à cette organisation. Principalement utilisé "
"y a une similarité de nom, pour éviter les affichages redondants." "s'il y a une similarité de nom, pour éviter les affichages redondants."
#: agenda_culturel/models.py:800 #: agenda_culturel/models.py:800
msgid "Organisation" msgid "Organisation"
@ -753,7 +753,7 @@ msgstr "Organisme"
msgid "Organisations" msgid "Organisations"
msgstr "Organismes" msgstr "Organismes"
#: agenda_culturel/models.py:812 agenda_culturel/models.py:2885 #: agenda_culturel/models.py:812 agenda_culturel/models.py:2894
msgid "Published" msgid "Published"
msgstr "Publié" msgstr "Publié"
@ -789,7 +789,7 @@ msgstr "Auteur de la dernière modération"
msgid "Title" msgid "Title"
msgstr "Titre" msgstr "Titre"
#: agenda_culturel/models.py:889 agenda_culturel/models.py:3164 #: agenda_culturel/models.py:889 agenda_culturel/models.py:3173
msgid "Start day" msgid "Start day"
msgstr "Date de début" msgstr "Date de début"
@ -797,7 +797,7 @@ msgstr "Date de début"
msgid "Start time" msgid "Start time"
msgstr "Heure de début" msgstr "Heure de début"
#: agenda_culturel/models.py:897 agenda_culturel/models.py:3165 #: agenda_culturel/models.py:897 agenda_culturel/models.py:3174
msgid "End day" msgid "End day"
msgstr "Date de fin" msgstr "Date de fin"
@ -899,60 +899,60 @@ msgstr "import récurrent"
msgid "a non authenticated user" msgid "a non authenticated user"
msgstr "un utilisateur non connecté" msgstr "un utilisateur non connecté"
#: agenda_culturel/models.py:1777 #: agenda_culturel/models.py:1781
msgid "Your event has been published" msgid "Your event has been published"
msgstr "Ton événement a été publié" msgstr "Ton événement a été publié"
#: agenda_culturel/models.py:1782 #: agenda_culturel/models.py:1786
msgid "Your message has not been retained" msgid "Your message has not been retained"
msgstr "Ton événement n'a pas été retenu" msgstr "Ton événement n'a pas été retenu"
#: agenda_culturel/models.py:1870 agenda_culturel/models.py:2693 #: agenda_culturel/models.py:1874 agenda_culturel/models.py:2701
msgid "Warning" msgid "Warning"
msgstr "Warning" msgstr "Warning"
#: agenda_culturel/models.py:1872 agenda_culturel/models.py:1978 #: agenda_culturel/models.py:1876 agenda_culturel/models.py:1982
msgid "the date has not been imported correctly." msgid "the date has not been imported correctly."
msgstr "la date n'a pas été importée correctement." msgstr "la date n'a pas été importée correctement."
#: agenda_culturel/models.py:1960 #: agenda_culturel/models.py:1964
msgid "during import process" msgid "during import process"
msgstr "pendant le processus d'import" msgstr "pendant le processus d'import"
#: agenda_culturel/models.py:1976 agenda_culturel/models.py:1986 #: agenda_culturel/models.py:1980 agenda_culturel/models.py:1990
#: agenda_culturel/models.py:1997 #: agenda_culturel/models.py:2001
msgid "warning" msgid "warning"
msgstr "attention" msgstr "attention"
#: agenda_culturel/models.py:1988 #: agenda_culturel/models.py:1992
msgid "the title has not been imported correctly." msgid "the title has not been imported correctly."
msgstr "le titre n'a pas été importé correctement." msgstr "le titre n'a pas été importé correctement."
#: agenda_culturel/models.py:2000 #: agenda_culturel/models.py:2004
msgid "The import was unable to find an event in the page." msgid "The import was unable to find an event in the page."
msgstr "L'import a été incapable de trouver un événement dans la page." msgstr "L'import a été incapable de trouver un événement dans la page."
#: agenda_culturel/models.py:2348 #: agenda_culturel/models.py:2356
msgid "Updated field(s): " msgid "Updated field(s): "
msgstr "Champ(s) mis à jour: " msgstr "Champ(s) mis à jour: "
#: agenda_culturel/models.py:2352 #: agenda_culturel/models.py:2360
msgid "Update" msgid "Update"
msgstr "Mise à jour" msgstr "Mise à jour"
#: agenda_culturel/models.py:2353 #: agenda_culturel/models.py:2361
msgid "update process" msgid "update process"
msgstr "processus de mise à jour" msgstr "processus de mise à jour"
#: agenda_culturel/models.py:2422 #: agenda_culturel/models.py:2430
msgid "Import" msgid "Import"
msgstr "Import" msgstr "Import"
#: agenda_culturel/models.py:2423 #: agenda_culturel/models.py:2431
msgid "import process" msgid "import process"
msgstr "processus d'import" msgstr "processus d'import"
#: agenda_culturel/models.py:2425 #: agenda_culturel/models.py:2433
msgid "" msgid ""
"The duration of the event is a little too long for direct publication. " "The duration of the event is a little too long for direct publication. "
"Moderators can choose to publish it or not." "Moderators can choose to publish it or not."
@ -960,195 +960,199 @@ msgstr ""
"La durée de l'événement est un peu trop longue pour qu'il soit publié " "La durée de l'événement est un peu trop longue pour qu'il soit publié "
"directement. Les modérateurs peuvent choisir de le publier ou non." "directement. Les modérateurs peuvent choisir de le publier ou non."
#: agenda_culturel/models.py:2684 #: agenda_culturel/models.py:2692
msgid "From contributor" msgid "From contributor"
msgstr "D'un·e contributeurice" msgstr "D'un·e contributeurice"
#: agenda_culturel/models.py:2685 #: agenda_culturel/models.py:2693
msgid "Import process" msgid "Import process"
msgstr "Processus d'import" msgstr "Processus d'import"
#: agenda_culturel/models.py:2686 #: agenda_culturel/models.py:2694
msgid "Update process" msgid "Update process"
msgstr "Processus de mise à jour" msgstr "Processus de mise à jour"
#: agenda_culturel/models.py:2687 #: agenda_culturel/models.py:2695
msgid "Contact form" msgid "Contact form"
msgstr "Formulaire de contact" msgstr "Formulaire de contact"
#: agenda_culturel/models.py:2688 #: agenda_culturel/models.py:2696
msgid "Event report" msgid "Event report"
msgstr "Signalemet d'événement" msgstr "Signalemet d'événement"
#: agenda_culturel/models.py:2691 #: agenda_culturel/models.py:2699
msgid "From contributor (without message)" msgid "From contributor (without message)"
msgstr "D'un·e contributeurice (sans message)" msgstr "D'un·e contributeurice (sans message)"
#: agenda_culturel/models.py:2697 #: agenda_culturel/models.py:2705
msgid "Messages" msgid "Messages"
msgstr "Messages" msgstr "Messages"
#: agenda_culturel/models.py:2706 #: agenda_culturel/models.py:2714
msgid "Subject" msgid "Subject"
msgstr "Sujet" msgstr "Sujet"
#: agenda_culturel/models.py:2707 #: agenda_culturel/models.py:2715
msgid "The subject of your message" msgid "The subject of your message"
msgstr "Sujet de votre message" msgstr "Sujet de votre message"
#: agenda_culturel/models.py:2713 #: agenda_culturel/models.py:2721
msgid "Related event" msgid "Related event"
msgstr "Événement associé" msgstr "Événement associé"
#: agenda_culturel/models.py:2714 #: agenda_culturel/models.py:2722
msgid "The message is associated with this event." msgid "The message is associated with this event."
msgstr "Le message est associé à cet événement." msgstr "Le message est associé à cet événement."
#: agenda_culturel/models.py:2722 #: agenda_culturel/models.py:2730
msgid "Author of the message" msgid "Author of the message"
msgstr "Auteur du message" msgstr "Auteur du message"
#: agenda_culturel/models.py:2730 #: agenda_culturel/models.py:2738
msgid "Your name" msgid "Your name"
msgstr "Votre nom" msgstr "Votre nom"
#: agenda_culturel/models.py:2736 #: agenda_culturel/models.py:2744
msgid "Email address" msgid "Email address"
msgstr "Adresse email" msgstr "Adresse email"
#: agenda_culturel/models.py:2743 #: agenda_culturel/models.py:2751
msgid "Your message" msgid "Your message"
msgstr "Votre message" msgstr "Votre message"
#: agenda_culturel/models.py:2750 #: agenda_culturel/models.py:2758
msgid "This message is a spam." msgid "This message is a spam."
msgstr "Ce message est un spam." msgstr "Ce message est un spam."
#: agenda_culturel/models.py:2757 #: agenda_culturel/models.py:2765
msgid "this message has been processed and no longer needs to be handled" msgid "this message has been processed and no longer needs to be handled"
msgstr "Ce message a été traité et ne nécessite plus d'être pris en charge" msgstr "Ce message a été traité et ne nécessite plus d'être pris en charge"
#: agenda_culturel/models.py:2763 #: agenda_culturel/models.py:2771
msgid "Comments on the message from the moderation team" msgid "Comments on the message from the moderation team"
msgstr "Commentaires sur ce message par l'équipe de modération" msgstr "Commentaires sur ce message par l'équipe de modération"
#: agenda_culturel/models.py:2796 agenda_culturel/models.py:2973 #: agenda_culturel/models.py:2804 agenda_culturel/models.py:2982
msgid "Recurrent import" msgid "Recurrent import"
msgstr "Import récurrent" msgstr "Import récurrent"
#: agenda_culturel/models.py:2797 #: agenda_culturel/models.py:2805
msgid "Recurrent imports" msgid "Recurrent imports"
msgstr "Imports récurrents" msgstr "Imports récurrents"
#: agenda_culturel/models.py:2801 #: agenda_culturel/models.py:2809
msgid "ical" msgid "ical"
msgstr "ical" msgstr "ical"
#: agenda_culturel/models.py:2802 #: agenda_culturel/models.py:2810
msgid "ical no busy" msgid "ical no busy"
msgstr "ical sans busy" msgstr "ical sans busy"
#: agenda_culturel/models.py:2803 #: agenda_culturel/models.py:2811
msgid "ical no VC" msgid "ical no VC"
msgstr "ical sans VC" msgstr "ical sans VC"
#: agenda_culturel/models.py:2804 #: agenda_culturel/models.py:2812
msgid "ical naive timezone" msgid "ical naive timezone"
msgstr "ical timezone naïve" msgstr "ical timezone naïve"
#: agenda_culturel/models.py:2805 #: agenda_culturel/models.py:2813
msgid "lacoope.org" msgid "lacoope.org"
msgstr "lacoope.org" msgstr "lacoope.org"
#: agenda_culturel/models.py:2806 #: agenda_culturel/models.py:2814
msgid "la comédie" msgid "la comédie"
msgstr "la comédie" msgstr "la comédie"
#: agenda_culturel/models.py:2807 #: agenda_culturel/models.py:2815
msgid "le fotomat" msgid "le fotomat"
msgstr "le fotomat" msgstr "le fotomat"
#: agenda_culturel/models.py:2808 #: agenda_culturel/models.py:2816
msgid "la puce à l'oreille" msgid "la puce à l'oreille"
msgstr "la puce à loreille" msgstr "la puce à loreille"
#: agenda_culturel/models.py:2809 #: agenda_culturel/models.py:2817
msgid "Plugin wordpress MEC" msgid "Plugin wordpress MEC"
msgstr "Plugin wordpress MEC" msgstr "Plugin wordpress MEC"
#: agenda_culturel/models.py:2810 #: agenda_culturel/models.py:2818
msgid "Événements d'une page FB" msgid "Événements d'une page FB"
msgstr "Événements d'une page FB" msgstr "Événements d'une page FB"
#: agenda_culturel/models.py:2811 #: agenda_culturel/models.py:2819
msgid "Billetterie Clermont-Ferrand" msgid "Billetterie Clermont-Ferrand"
msgstr "" msgstr ""
#: agenda_culturel/models.py:2812 #: agenda_culturel/models.py:2820
msgid "Arachnée concert" msgid "Arachnée concert"
msgstr "Arachnée concert" msgstr "Arachnée concert"
#: agenda_culturel/models.py:2813 #: agenda_culturel/models.py:2821
msgid "Le Rio" msgid "Le Rio"
msgstr "Le Rio" msgstr "Le Rio"
#: agenda_culturel/models.py:2814 #: agenda_culturel/models.py:2822
msgid "La Raymonde" msgid "La Raymonde"
msgstr "La Raymone" msgstr "La Raymone"
#: agenda_culturel/models.py:2815 #: agenda_culturel/models.py:2823
msgid "Agenda apidae tourisme" msgid "Agenda apidae tourisme"
msgstr "Agenda apidae tourisme" msgstr "Agenda apidae tourisme"
#: agenda_culturel/models.py:2816 #: agenda_culturel/models.py:2824
msgid "Agenda iguana (médiathèques)" msgid "Agenda iguana (médiathèques)"
msgstr "Agenda iguana (médiathèques)" msgstr "Agenda iguana (médiathèques)"
#: agenda_culturel/models.py:2817 #: agenda_culturel/models.py:2825
msgid "Mille formes" msgid "Mille formes"
msgstr "Mille Formes" msgstr "Mille Formes"
#: agenda_culturel/models.py:2818 #: agenda_culturel/models.py:2826
msgid "Les Amis du Temps des Cerises" msgid "Les Amis du Temps des Cerises"
msgstr "Les Amis du Temps des Cerises" msgstr "Les Amis du Temps des Cerises"
#: agenda_culturel/models.py:2819 #: agenda_culturel/models.py:2827
msgid "Mobilizon" msgid "Mobilizon"
msgstr "Mobilizon" msgstr "Mobilizon"
#: agenda_culturel/models.py:2820 #: agenda_culturel/models.py:2828
msgid "Le caméléon" msgid "Le caméléon"
msgstr "" msgstr ""
#: agenda_culturel/models.py:2821 #: agenda_culturel/models.py:2829
msgid "Echosciences" msgid "Echosciences"
msgstr "" msgstr ""
#: agenda_culturel/models.py:2824 #: agenda_culturel/models.py:2830
msgid "Hello Asso"
msgstr "Hello Asso"
#: agenda_culturel/models.py:2833
msgid "simple" msgid "simple"
msgstr "simple" msgstr "simple"
#: agenda_culturel/models.py:2825 #: agenda_culturel/models.py:2834
msgid "Headless Chromium" msgid "Headless Chromium"
msgstr "chromium sans interface" msgstr "chromium sans interface"
#: agenda_culturel/models.py:2828 #: agenda_culturel/models.py:2837
msgid "Headless Chromium (pause)" msgid "Headless Chromium (pause)"
msgstr "chromium sans interface (pause)" msgstr "chromium sans interface (pause)"
#: agenda_culturel/models.py:2834 #: agenda_culturel/models.py:2843
msgid "daily" msgid "daily"
msgstr "chaque jour" msgstr "chaque jour"
#: agenda_culturel/models.py:2836 #: agenda_culturel/models.py:2845
msgid "weekly" msgid "weekly"
msgstr "chaque semaine" msgstr "chaque semaine"
#: agenda_culturel/models.py:2837 #: agenda_culturel/models.py:2846
msgid "never" msgid "never"
msgstr "jamais" msgstr "jamais"
#: agenda_culturel/models.py:2842 #: agenda_culturel/models.py:2851
msgid "" msgid ""
"Recurrent import name. Be careful to choose a name that is easy to " "Recurrent import name. Be careful to choose a name that is easy to "
"understand, as it will be public and displayed on the sites About page." "understand, as it will be public and displayed on the sites About page."
@ -1156,151 +1160,151 @@ msgstr ""
"Nom de l'import récurrent. Attention à choisir un nom compréhensible, car il " "Nom de l'import récurrent. Attention à choisir un nom compréhensible, car il "
"sera public, et affiché sur la page à propos du site." "sera public, et affiché sur la page à propos du site."
#: agenda_culturel/models.py:2849 #: agenda_culturel/models.py:2858
msgid "Processor" msgid "Processor"
msgstr "Processeur" msgstr "Processeur"
#: agenda_culturel/models.py:2855 #: agenda_culturel/models.py:2864
msgid "Downloader" msgid "Downloader"
msgstr "Téléchargeur" msgstr "Téléchargeur"
#: agenda_culturel/models.py:2862 #: agenda_culturel/models.py:2871
msgid "Import recurrence" msgid "Import recurrence"
msgstr "Récurrence d'import" msgstr "Récurrence d'import"
#: agenda_culturel/models.py:2869 #: agenda_culturel/models.py:2878
msgid "Source" msgid "Source"
msgstr "Source" msgstr "Source"
#: agenda_culturel/models.py:2870 #: agenda_culturel/models.py:2879
msgid "URL of the source document" msgid "URL of the source document"
msgstr "URL du document source" msgstr "URL du document source"
#: agenda_culturel/models.py:2875 #: agenda_culturel/models.py:2884
msgid "Browsable url" msgid "Browsable url"
msgstr "URL navigable" msgstr "URL navigable"
#: agenda_culturel/models.py:2877 #: agenda_culturel/models.py:2886
msgid "URL of the corresponding document that will be shown to visitors." msgid "URL of the corresponding document that will be shown to visitors."
msgstr "URL correspondant au document et qui sera montrée aux visiteurs" msgstr "URL correspondant au document et qui sera montrée aux visiteurs"
#: agenda_culturel/models.py:2886 #: agenda_culturel/models.py:2895
msgid "Status of each imported event (published or draft)" msgid "Status of each imported event (published or draft)"
msgstr "Status de chaque événement importé (publié ou brouillon)" msgstr "Status de chaque événement importé (publié ou brouillon)"
#: agenda_culturel/models.py:2891 #: agenda_culturel/models.py:2900
msgid "Address for each imported event" msgid "Address for each imported event"
msgstr "Adresse de chaque événement importé" msgstr "Adresse de chaque événement importé"
#: agenda_culturel/models.py:2898 #: agenda_culturel/models.py:2907
msgid "Force location" msgid "Force location"
msgstr "Focer la localisation" msgstr "Focer la localisation"
#: agenda_culturel/models.py:2899 #: agenda_culturel/models.py:2908
msgid "force location even if another is detected." msgid "force location even if another is detected."
msgstr "Forcer la localisation même si une autre a été détectée." msgstr "Forcer la localisation même si une autre a été détectée."
#: agenda_culturel/models.py:2905 #: agenda_culturel/models.py:2914
msgid "Organiser" msgid "Organiser"
msgstr "Organisation" msgstr "Organisation"
#: agenda_culturel/models.py:2906 #: agenda_culturel/models.py:2915
msgid "Organiser of each imported event" msgid "Organiser of each imported event"
msgstr "Organisme à l'origine de chaque événement importé" msgstr "Organisme à l'origine de chaque événement importé"
#: agenda_culturel/models.py:2916 #: agenda_culturel/models.py:2925
msgid "Category of each imported event" msgid "Category of each imported event"
msgstr "Catégorie de chaque événement importé" msgstr "Catégorie de chaque événement importé"
#: agenda_culturel/models.py:2924 #: agenda_culturel/models.py:2933
msgid "Tags for each imported event" msgid "Tags for each imported event"
msgstr "Étiquettes de chaque événement importé" msgstr "Étiquettes de chaque événement importé"
#: agenda_culturel/models.py:2925 #: agenda_culturel/models.py:2934
msgid "A list of tags that describe each imported event." msgid "A list of tags that describe each imported event."
msgstr "Une liste d'étiquettes décrivant chaque événement importé" msgstr "Une liste d'étiquettes décrivant chaque événement importé"
#: agenda_culturel/models.py:2954 #: agenda_culturel/models.py:2963
msgid "Running" msgid "Running"
msgstr "En cours" msgstr "En cours"
#: agenda_culturel/models.py:2955 #: agenda_culturel/models.py:2964
msgid "Canceled" msgid "Canceled"
msgstr "Annulé" msgstr "Annulé"
#: agenda_culturel/models.py:2956 #: agenda_culturel/models.py:2965
msgid "Success" msgid "Success"
msgstr "Succès" msgstr "Succès"
#: agenda_culturel/models.py:2957 #: agenda_culturel/models.py:2966
msgid "Failed" msgid "Failed"
msgstr "Erreur" msgstr "Erreur"
#: agenda_culturel/models.py:2960 #: agenda_culturel/models.py:2969
msgid "Batch importation" msgid "Batch importation"
msgstr "Importation par lot" msgstr "Importation par lot"
#: agenda_culturel/models.py:2961 #: agenda_culturel/models.py:2970
msgid "Batch importations" msgid "Batch importations"
msgstr "Importations par lot" msgstr "Importations par lot"
#: agenda_culturel/models.py:2974 #: agenda_culturel/models.py:2983
msgid "Reference to the recurrent import processing" msgid "Reference to the recurrent import processing"
msgstr "Référence du processus d'import récurrent" msgstr "Référence du processus d'import récurrent"
#: agenda_culturel/models.py:2982 #: agenda_culturel/models.py:2991
msgid "URL (if not recurrent import)" msgid "URL (if not recurrent import)"
msgstr "URL (si pas d'import récurrent)" msgstr "URL (si pas d'import récurrent)"
#: agenda_culturel/models.py:2983 #: agenda_culturel/models.py:2992
msgid "Source URL if no RecurrentImport is associated." msgid "Source URL if no RecurrentImport is associated."
msgstr "URL source si aucun import récurrent n'est associé" msgstr "URL source si aucun import récurrent n'est associé"
#: agenda_culturel/models.py:2998 #: agenda_culturel/models.py:3007
msgid "Error message" msgid "Error message"
msgstr "Votre message" msgstr "Votre message"
#: agenda_culturel/models.py:3002 #: agenda_culturel/models.py:3011
msgid "Number of collected events" msgid "Number of collected events"
msgstr "Nombre d'événements collectés" msgstr "Nombre d'événements collectés"
#: agenda_culturel/models.py:3005 #: agenda_culturel/models.py:3014
msgid "Number of imported events" msgid "Number of imported events"
msgstr "Nombre d'événements importés" msgstr "Nombre d'événements importés"
#: agenda_culturel/models.py:3008 #: agenda_culturel/models.py:3017
msgid "Number of updated events" msgid "Number of updated events"
msgstr "Nombre d'événements mis à jour" msgstr "Nombre d'événements mis à jour"
#: agenda_culturel/models.py:3011 #: agenda_culturel/models.py:3020
msgid "Number of removed events" msgid "Number of removed events"
msgstr "Nombre d'événements supprimés" msgstr "Nombre d'événements supprimés"
#: agenda_culturel/models.py:3019 #: agenda_culturel/models.py:3028
msgid "Weight" msgid "Weight"
msgstr "Poids" msgstr "Poids"
#: agenda_culturel/models.py:3020 #: agenda_culturel/models.py:3029
msgid "The lower is the weight, the earlier the filter is applied" msgid "The lower is the weight, the earlier the filter is applied"
msgstr "Plus le poids est léger, plus le filtre sera appliqué tôt" msgstr "Plus le poids est léger, plus le filtre sera appliqué tôt"
#: agenda_culturel/models.py:3027 #: agenda_culturel/models.py:3036
msgid "Category applied to the event" msgid "Category applied to the event"
msgstr "Catégorie appliquée à l'événement" msgstr "Catégorie appliquée à l'événement"
#: agenda_culturel/models.py:3032 #: agenda_culturel/models.py:3041
msgid "Contained in the title" msgid "Contained in the title"
msgstr "Contenu dans le titre" msgstr "Contenu dans le titre"
#: agenda_culturel/models.py:3033 #: agenda_culturel/models.py:3042
msgid "Text contained in the event title" msgid "Text contained in the event title"
msgstr "Texte contenu dans le titre de l'événement" msgstr "Texte contenu dans le titre de l'événement"
#: agenda_culturel/models.py:3039 #: agenda_culturel/models.py:3048
msgid "Exact title extract" msgid "Exact title extract"
msgstr "Extrait exact du titre" msgstr "Extrait exact du titre"
#: agenda_culturel/models.py:3041 #: agenda_culturel/models.py:3050
msgid "" msgid ""
"If checked, the extract will be searched for in the title using the exact " "If checked, the extract will be searched for in the title using the exact "
"form (capitals, accents)." "form (capitals, accents)."
@ -1308,19 +1312,19 @@ msgstr ""
"Si coché, l'extrait sera recherché dans le titre en utilisant la forme " "Si coché, l'extrait sera recherché dans le titre en utilisant la forme "
"exacte (majuscules, accents)" "exacte (majuscules, accents)"
#: agenda_culturel/models.py:3047 #: agenda_culturel/models.py:3056
msgid "Contained in the description" msgid "Contained in the description"
msgstr "Contenu dans la description" msgstr "Contenu dans la description"
#: agenda_culturel/models.py:3048 #: agenda_culturel/models.py:3057
msgid "Text contained in the description" msgid "Text contained in the description"
msgstr "Texte contenu dans la description" msgstr "Texte contenu dans la description"
#: agenda_culturel/models.py:3054 #: agenda_culturel/models.py:3063
msgid "Exact description extract" msgid "Exact description extract"
msgstr "Extrait exact de description" msgstr "Extrait exact de description"
#: agenda_culturel/models.py:3056 #: agenda_culturel/models.py:3065
msgid "" msgid ""
"If checked, the extract will be searched for in the description using the " "If checked, the extract will be searched for in the description using the "
"exact form (capitals, accents)." "exact form (capitals, accents)."
@ -1328,19 +1332,19 @@ msgstr ""
"Si coché, l'extrait sera recherché dans la description en utilisant la forme " "Si coché, l'extrait sera recherché dans la description en utilisant la forme "
"exacte (majuscules, accents)" "exacte (majuscules, accents)"
#: agenda_culturel/models.py:3062 #: agenda_culturel/models.py:3071
msgid "Contained in the location" msgid "Contained in the location"
msgstr "Contenu dans la localisation" msgstr "Contenu dans la localisation"
#: agenda_culturel/models.py:3063 #: agenda_culturel/models.py:3072
msgid "Text contained in the event location" msgid "Text contained in the event location"
msgstr "Texte contenu dans la localisation de l'événement" msgstr "Texte contenu dans la localisation de l'événement"
#: agenda_culturel/models.py:3069 #: agenda_culturel/models.py:3078
msgid "Exact location extract" msgid "Exact location extract"
msgstr "Extrait exact de localisation" msgstr "Extrait exact de localisation"
#: agenda_culturel/models.py:3071 #: agenda_culturel/models.py:3080
msgid "" msgid ""
"If checked, the extract will be searched for in the location using the exact " "If checked, the extract will be searched for in the location using the exact "
"form (capitals, accents)." "form (capitals, accents)."
@ -1348,55 +1352,55 @@ msgstr ""
"Si coché, l'extrait sera recherché dans la localisation en utilisant la " "Si coché, l'extrait sera recherché dans la localisation en utilisant la "
"forme exacte (majuscules, accents)" "forme exacte (majuscules, accents)"
#: agenda_culturel/models.py:3079 #: agenda_culturel/models.py:3088
msgid "Location from place" msgid "Location from place"
msgstr "Localisation depuis le lieu" msgstr "Localisation depuis le lieu"
#: agenda_culturel/models.py:3088 #: agenda_culturel/models.py:3097
msgid "Categorisation rule" msgid "Categorisation rule"
msgstr "Règle de catégorisation" msgstr "Règle de catégorisation"
#: agenda_culturel/models.py:3089 #: agenda_culturel/models.py:3098
msgid "Categorisation rules" msgid "Categorisation rules"
msgstr "Règles de catégorisation" msgstr "Règles de catégorisation"
#: agenda_culturel/models.py:3163 #: agenda_culturel/models.py:3172
msgid "Period name" msgid "Period name"
msgstr "Nom de la période" msgstr "Nom de la période"
#: agenda_culturel/models.py:3168 #: agenda_culturel/models.py:3177
msgid "Special period" msgid "Special period"
msgstr "Période remarquable" msgstr "Période remarquable"
#: agenda_culturel/models.py:3169 #: agenda_culturel/models.py:3178
msgid "Special periods" msgid "Special periods"
msgstr "Périodes remarquables" msgstr "Périodes remarquables"
#: agenda_culturel/models.py:3175 #: agenda_culturel/models.py:3184
msgid "public holidays" msgid "public holidays"
msgstr "Jour férié" msgstr "Jour férié"
#: agenda_culturel/models.py:3176 #: agenda_culturel/models.py:3185
msgid "school vacations" msgid "school vacations"
msgstr "Vacances scolaires" msgstr "Vacances scolaires"
#: agenda_culturel/models.py:3194 #: agenda_culturel/models.py:3203
msgid "The end date must be after or equal to the start date." msgid "The end date must be after or equal to the start date."
msgstr "La date de fin doit être après ou identique à la date de début." msgstr "La date de fin doit être après ou identique à la date de début."
#: agenda_culturel/models.py:3202 #: agenda_culturel/models.py:3211
msgid " on " msgid " on "
msgstr " du " msgstr " du "
#: agenda_culturel/models.py:3205 #: agenda_culturel/models.py:3214
msgid " from " msgid " from "
msgstr " du " msgstr " du "
#: agenda_culturel/models.py:3205 #: agenda_culturel/models.py:3214
msgid " to " msgid " to "
msgstr " au " msgstr " au "
#: agenda_culturel/settings/base.py:184 #: agenda_culturel/settings/base.py:188
msgid "French" msgid "French"
msgstr "français" msgstr "français"
@ -1668,17 +1672,17 @@ msgstr ""
"par défaut ont été catégorisés" "par défaut ont été catégorisés"
#: agenda_culturel/views.py:2495 agenda_culturel/views.py:2557 #: agenda_culturel/views.py:2495 agenda_culturel/views.py:2557
#: agenda_culturel/views.py:2597 #: agenda_culturel/views.py:2601
msgid "{} events have been updated." msgid "{} events have been updated."
msgstr "{} événements ont été mis à jour." msgstr "{} événements ont été mis à jour."
#: agenda_culturel/views.py:2498 agenda_culturel/views.py:2559 #: agenda_culturel/views.py:2498 agenda_culturel/views.py:2559
#: agenda_culturel/views.py:2600 #: agenda_culturel/views.py:2604
msgid "1 event has been updated." msgid "1 event has been updated."
msgstr "1 événement a été mis à jour" msgstr "1 événement a été mis à jour"
#: agenda_culturel/views.py:2500 agenda_culturel/views.py:2561 #: agenda_culturel/views.py:2500 agenda_culturel/views.py:2561
#: agenda_culturel/views.py:2602 #: agenda_culturel/views.py:2606
msgid "No events have been modified." msgid "No events have been modified."
msgstr "Aucun événement n'a été modifié." msgstr "Aucun événement n'a été modifié."
@ -1690,37 +1694,36 @@ msgstr "Le lieu a été modifié avec succès."
msgid "The place has been successfully created." msgid "The place has been successfully created."
msgstr "Le lieu a été créé avec succès." msgstr "Le lieu a été créé avec succès."
#: agenda_culturel/views.py:2584 #: agenda_culturel/views.py:2586
msgid "" msgid ""
"The selected place has been assigned to the event <a href=\"{}\">{}</a>." "The selected place has been assigned to the event <a href=\"{}\">{}</a>."
msgstr "" msgstr "Le lieu sélectionné a été assigné à l'événement <a href=\"{}\">{}</a>."
"Le lieu sélectionné a été assigné à l'événement <a href=\"{}\">{}</a>."
#: agenda_culturel/views.py:2589 #: agenda_culturel/views.py:2593
msgid "A new alias has been added to the selected place." msgid "A new alias has been added to the selected place."
msgstr "Un nouvel alias a été créé pour le lieu sélectionné." msgstr "Un nouvel alias a été créé pour le lieu sélectionné."
#: agenda_culturel/views.py:2716 #: agenda_culturel/views.py:2720
msgid "The organisation has been successfully updated." msgid "The organisation has been successfully updated."
msgstr "L'organisme a été modifié avec succès." msgstr "L'organisme a été modifié avec succès."
#: agenda_culturel/views.py:2723 #: agenda_culturel/views.py:2727
msgid "The organisation has been successfully created." msgid "The organisation has been successfully created."
msgstr "L'organisme a été créé avec succès." msgstr "L'organisme a été créé avec succès."
#: agenda_culturel/views.py:2742 #: agenda_culturel/views.py:2746
msgid "The tag has been successfully updated." msgid "The tag has been successfully updated."
msgstr "L'étiquette a été modifiée avec succès." msgstr "L'étiquette a été modifiée avec succès."
#: agenda_culturel/views.py:2749 #: agenda_culturel/views.py:2753
msgid "The tag has been successfully created." msgid "The tag has been successfully created."
msgstr "L'étiquette a été créée avec succès." msgstr "L'étiquette a été créée avec succès."
#: agenda_culturel/views.py:2849 #: agenda_culturel/views.py:2853
msgid "You have not modified the tag name." msgid "You have not modified the tag name."
msgstr "Vous n'avez pas modifié le nom de l'étiquette." msgstr "Vous n'avez pas modifié le nom de l'étiquette."
#: agenda_culturel/views.py:2864 #: agenda_culturel/views.py:2868
msgid "" msgid ""
"This tag {} is already in use, and is described by different information " "This tag {} is already in use, and is described by different information "
"from the current tag. You can force renaming by checking the corresponding " "from the current tag. You can force renaming by checking the corresponding "
@ -1733,7 +1736,7 @@ msgstr ""
"sera supprimée, et tous les événements associés à l'étiquette {} seront " "sera supprimée, et tous les événements associés à l'étiquette {} seront "
"associés à l'étiquette {}." "associés à l'étiquette {}."
#: agenda_culturel/views.py:2878 #: agenda_culturel/views.py:2882
msgid "" msgid ""
"This tag {} is already in use. You can force renaming by checking the " "This tag {} is already in use. You can force renaming by checking the "
"corresponding option." "corresponding option."
@ -1741,55 +1744,55 @@ msgstr ""
"Cette étiquette {} est déjà utilisée. Vous pouvez forcer le renommage en " "Cette étiquette {} est déjà utilisée. Vous pouvez forcer le renommage en "
"cochant l'option correspondante." "cochant l'option correspondante."
#: agenda_culturel/views.py:2911 #: agenda_culturel/views.py:2915
msgid "The tag {} has been successfully renamed to {}." msgid "The tag {} has been successfully renamed to {}."
msgstr "L'étiquette {} a été renommée avec succès en {}." msgstr "L'étiquette {} a été renommée avec succès en {}."
#: agenda_culturel/views.py:2953 #: agenda_culturel/views.py:2957
msgid "The tag {} has been successfully deleted." msgid "The tag {} has been successfully deleted."
msgstr "L'événement {} a été supprimé avec succès." msgstr "L'événement {} a été supprimé avec succès."
#: agenda_culturel/views.py:3100 #: agenda_culturel/views.py:3104
msgid "Cache successfully cleared." msgid "Cache successfully cleared."
msgstr "Le cache a été vidé avec succès." msgstr "Le cache a été vidé avec succès."
#: agenda_culturel/views.py:3120 #: agenda_culturel/views.py:3124
msgid "Your user profile has been successfully modified." msgid "Your user profile has been successfully modified."
msgstr "Votre profil utilisateur a été modifié avec succès." msgstr "Votre profil utilisateur a été modifié avec succès."
#: agenda_culturel/views.py:3138 #: agenda_culturel/views.py:3142
msgid "The special period has been successfully created." msgid "The special period has been successfully created."
msgstr "La période remarquable a été créée avec succès." msgstr "La période remarquable a été créée avec succès."
#: agenda_culturel/views.py:3159 #: agenda_culturel/views.py:3163
msgid "The special period has been successfully deleted." msgid "The special period has been successfully deleted."
msgstr "La période remarquable a été supprimée avec succès." msgstr "La période remarquable a été supprimée avec succès."
#: agenda_culturel/views.py:3170 #: agenda_culturel/views.py:3174
msgid "The special period has been successfully updated." msgid "The special period has been successfully updated."
msgstr "La période remarquable a été modifiée avec succès." msgstr "La période remarquable a été modifiée avec succès."
#: agenda_culturel/views.py:3187 #: agenda_culturel/views.py:3191
#, python-format #, python-format
msgid "%(nb_created)d interval inserted." msgid "%(nb_created)d interval inserted."
msgid_plural "%(nb_created)d intervals inserted." msgid_plural "%(nb_created)d intervals inserted."
msgstr[0] "%(nb_created)d intervalle inséré." msgstr[0] "%(nb_created)d intervalle inséré."
msgstr[1] "%(nb_created)d intervalles insérés." msgstr[1] "%(nb_created)d intervalles insérés."
#: agenda_culturel/views.py:3198 #: agenda_culturel/views.py:3202
#, python-format #, python-format
msgid "%(nb_overlap)d insersion was not possible due to overlap." msgid "%(nb_overlap)d insersion was not possible due to overlap."
msgid_plural "%(nb_overlap)d insersion were not possible due to overlap." msgid_plural "%(nb_overlap)d insersion were not possible due to overlap."
msgstr[0] "%(nb_overlap)d insersion impossible à cause d'une intersection." msgstr[0] "%(nb_overlap)d insersion impossible à cause d'une intersection."
msgstr[1] "%(nb_overlap)d insersions impossibles à cause d'une intersection." msgstr[1] "%(nb_overlap)d insersions impossibles à cause d'une intersection."
#: agenda_culturel/views.py:3209 #: agenda_culturel/views.py:3213
#, python-format #, python-format
msgid "%(nb_error)d error while reading ical file." msgid "%(nb_error)d error while reading ical file."
msgid_plural "%(nb_error)d error while reading ical file." msgid_plural "%(nb_error)d error while reading ical file."
msgstr[0] "%(nb_error)d erreur pendant la lecture du fichier ical." msgstr[0] "%(nb_error)d erreur pendant la lecture du fichier ical."
msgstr[1] "%(nb_error)d erreurs pendant la lecture du fichier ical." msgstr[1] "%(nb_error)d erreurs pendant la lecture du fichier ical."
#: agenda_culturel/views.py:3217 #: agenda_culturel/views.py:3221
msgid "Error during file reading: {}" msgid "Error during file reading: {}"
msgstr "Erreur pendant la lecture du fichier: {}" msgstr "Erreur pendant la lecture du fichier: {}"

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2.19 on 2025-04-12 14:10
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('agenda_culturel', '0166_specialperiod_agenda_cult_start_d_40e6a4_idx'),
]
operations = [
migrations.AlterField(
model_name='recurrentimport',
name='processor',
field=models.CharField(choices=[('ical', 'ical'), ('icalnobusy', 'ical no busy'), ('icalnovc', 'ical no VC'), ('ical naive tz', 'ical naive timezone'), ('lacoope', 'lacoope.org'), ('lacomedie', 'la comédie'), ('lefotomat', 'le fotomat'), ('lapucealoreille', "la puce à l'oreille"), ('Plugin wordpress MEC', 'Plugin wordpress MEC'), ('Facebook events', "Événements d'une page FB"), ('Billetterie CF', 'Billetterie Clermont-Ferrand'), ('arachnee', 'Arachnée concert'), ('rio', 'Le Rio'), ('raymonde', 'La Raymonde'), ('apidae', 'Agenda apidae tourisme'), ('iguana', 'Agenda iguana (médiathèques)'), ('Mille formes', 'Mille formes'), ('Amis cerises', 'Les Amis du Temps des Cerises'), ('Mobilizon', 'Mobilizon'), ('Le Caméléon', 'Le caméléon'), ('Echosciences', 'Echosciences'), ('HelloAsso', 'Hello Asso')], default='ical', max_length=20, verbose_name='Processor'),
),
]

View File

@ -1717,6 +1717,11 @@ class Event(models.Model):
self.update_recurrence_dtstartend() self.update_recurrence_dtstartend()
# clear cache
for is_auth in [False, True]:
key = make_template_fragment_key("event_body", [is_auth, self.pk])
cache.delete(key)
# if the image is defined but not locally downloaded # if the image is defined but not locally downloaded
if self.image and ( if self.image and (
not self.local_image or not default_storage.exists(self.local_image.name) not self.local_image or not default_storage.exists(self.local_image.name)
@ -1835,11 +1840,6 @@ class Event(models.Model):
if "request" in kwargs: if "request" in kwargs:
self.notify_if_required(kwargs.get("request")) self.notify_if_required(kwargs.get("request"))
# clear cache
for is_auth in [False, True]:
key = make_template_fragment_key("event_body", [is_auth, self.pk])
cache.delete(key)
# save message if required # save message if required
if self.has_message(): if self.has_message():
for msg in self.get_messages(): for msg in self.get_messages():
@ -2053,8 +2053,9 @@ class Event(models.Model):
def get_updateable_uuid(self): def get_updateable_uuid(self):
if self.uuids and len(self.uuids) > 0: if self.uuids and len(self.uuids) > 0:
for s in self.uuids: for s in self.uuids:
if FacebookEventExtractor.is_known_url(s): for e in Extractor.get_default_extractors(True):
return s if e.is_known_url(s):
return s
return None return None
def is_updateable(self): def is_updateable(self):
@ -2827,6 +2828,7 @@ class RecurrentImport(models.Model):
MOBILIZON = "Mobilizon", _("Mobilizon") MOBILIZON = "Mobilizon", _("Mobilizon")
LECAMELEON = "Le Caméléon", _("Le caméléon") LECAMELEON = "Le Caméléon", _("Le caméléon")
ECHOSCIENCES = "Echosciences", _("Echosciences") ECHOSCIENCES = "Echosciences", _("Echosciences")
HELLOASSO = "HelloAsso", _("Hello Asso")
class DOWNLOADER(models.TextChoices): class DOWNLOADER(models.TextChoices):
SIMPLE = "simple", _("simple") SIMPLE = "simple", _("simple")

View File

@ -37,6 +37,10 @@ SERVER_EMAIL = os_getenv("SERVER_EMAIL", "")
ECHOSCIENCES_TOKEN = os_getenv("ECHOSCIENCES_TOKEN", "") ECHOSCIENCES_TOKEN = os_getenv("ECHOSCIENCES_TOKEN", "")
HELLOASSO_ID = os_getenv("HELLOASSO_ID", "")
HELLOASSO_SECRET = os_getenv("HELLOASSO_SECRET", "")
# Application definition # Application definition
INSTALLED_APPS = [ INSTALLED_APPS = [