Remote calendar link for external sync

This commit is contained in:
Antoine Bartuccio 2025-04-07 13:58:08 +02:00
parent 811c83552f
commit b09d5e5ffd
5 changed files with 70 additions and 6 deletions

View File

@ -1,9 +1,11 @@
from pathlib import Path from pathlib import Path
from typing import final
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
from django.conf import settings from django.conf import settings
from django.contrib.sites.models import Site
from django.contrib.syndication.views import add_domain
from django.db.models import F, QuerySet from django.db.models import F, QuerySet
from django.http import HttpRequest
from django.urls import reverse from django.urls import reverse
from django.utils import timezone from django.utils import timezone
from ical.calendar import Calendar from ical.calendar import Calendar
@ -14,7 +16,14 @@ from com.models import NewsDate
from core.models import User from core.models import User
@final def as_absolute_url(url: str, request: HttpRequest | None = None) -> str:
return add_domain(
Site.objects.get_current(request=request),
url,
secure=request.is_secure() if request is not None else settings.HTTPS,
)
class IcsCalendar: class IcsCalendar:
_CACHE_FOLDER: Path = settings.MEDIA_ROOT / "com" / "calendars" _CACHE_FOLDER: Path = settings.MEDIA_ROOT / "com" / "calendars"
_INTERNAL_CALENDAR = _CACHE_FOLDER / "internal.ics" _INTERNAL_CALENDAR = _CACHE_FOLDER / "internal.ics"
@ -58,7 +67,9 @@ class IcsCalendar:
summary=news_date.news_title, summary=news_date.news_title,
start=news_date.start_date, start=news_date.start_date,
end=news_date.end_date, end=news_date.end_date,
url=reverse("com:news_detail", kwargs={"news_id": news_date.news.id}), url=as_absolute_url(
reverse("com:news_detail", kwargs={"news_id": news_date.news.id})
),
) )
calendar.events.append(event) calendar.events.append(event)

View File

@ -303,10 +303,36 @@ export class IcsCalendar extends inheritHtmlElement("div") {
this.calendar = new Calendar(this.node, { this.calendar = new Calendar(this.node, {
plugins: [dayGridPlugin, iCalendarPlugin, listPlugin], plugins: [dayGridPlugin, iCalendarPlugin, listPlugin],
locales: [frLocale, enLocale], locales: [frLocale, enLocale],
customButtons: {
getCalendarLink: {
text: gettext("Copy calendar link"),
click: async (event: Event) => {
const button = event.target as HTMLButtonElement;
button.classList.add("text-copy");
button.setAttribute(
"tooltip",
gettext("Calendar link copied to the clipboard"),
);
navigator.clipboard.writeText(
new URL(
await makeUrl(calendarCalendarInternal),
window.location.origin,
).toString(),
);
setTimeout(() => {
button.classList.remove("text-copied");
button.classList.add("text-copied");
button.classList.remove("text-copy");
button.removeAttribute("tooltip");
}, 700);
},
},
},
height: "auto", height: "auto",
locale: this.locale, locale: this.locale,
initialView: this.currentView(), initialView: this.currentView(),
headerToolbar: this.currentToolbar(), headerToolbar: this.currentToolbar(),
footerToolbar: { start: "getCalendarLink" },
eventSources: await this.getEventSources(), eventSources: await this.getEventSources(),
windowResize: () => { windowResize: () => {
this.calendar.changeView(this.currentView()); this.calendar.changeView(this.currentView());

View File

@ -98,4 +98,21 @@ ics-calendar {
background: white; background: white;
} }
} }
.fc .fc-toolbar.fc-footer-toolbar {
margin-bottom: 0.5em;
}
button.text-copy,
button.text-copy:focus,
button.text-copy:hover {
background-color: green !important;
transition: 200ms linear;
}
button.text-copied,
button.text-copied:focus,
button.text-copied:hover {
transition: 200ms linear;
}
} }

View File

@ -7,7 +7,7 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-04-06 15:47+0200\n" "POT-Creation-Date: 2025-04-07 13:56+0200\n"
"PO-Revision-Date: 2024-09-17 11:54+0200\n" "PO-Revision-Date: 2024-09-17 11:54+0200\n"
"Last-Translator: Sli <antoine@bartuccio.fr>\n" "Last-Translator: Sli <antoine@bartuccio.fr>\n"
"Language-Team: AE info <ae.info@utbm.fr>\n" "Language-Team: AE info <ae.info@utbm.fr>\n"
@ -33,6 +33,14 @@ msgstr "Dépublier"
msgid "Delete" msgid "Delete"
msgstr "Supprimer" msgstr "Supprimer"
#: com/static/bundled/com/components/ics-calendar-index.ts
msgid "Copy calendar link"
msgstr "Copier le lien du calendrier"
#: com/static/bundled/com/components/ics-calendar-index.ts
msgid "Calendar link copied to the clipboard"
msgstr "Lien du calendrier copié dans le presse papier"
#: com/static/bundled/com/components/moderation-alert-index.ts #: com/static/bundled/com/components/moderation-alert-index.ts
#, javascript-format #, javascript-format
msgid "" msgid ""

View File

@ -78,10 +78,12 @@ DEBUG = env.bool("SITH_DEBUG", default=False)
TESTING = "pytest" in sys.modules TESTING = "pytest" in sys.modules
INTERNAL_IPS = ["127.0.0.1"] INTERNAL_IPS = ["127.0.0.1"]
HTTPS = env.bool("HTTPS", default=True)
# force csrf tokens and cookies to be secure when in https # force csrf tokens and cookies to be secure when in https
CSRF_COOKIE_SECURE = env.bool("HTTPS", default=True) CSRF_COOKIE_SECURE = HTTPS
CSRF_TRUSTED_ORIGINS = env.list("CSRF_TRUSTED_ORIGINS", default=[]) CSRF_TRUSTED_ORIGINS = env.list("CSRF_TRUSTED_ORIGINS", default=[])
SESSION_COOKIE_SECURE = env.bool("HTTPS", default=True) SESSION_COOKIE_SECURE = HTTPS
X_FRAME_OPTIONS = "SAMEORIGIN" X_FRAME_OPTIONS = "SAMEORIGIN"
ALLOWED_HOSTS = ["*"] ALLOWED_HOSTS = ["*"]