Commit 479e665f authored by Robin Sonnabend's avatar Robin Sonnabend
Browse files

Add ical feed for upcoming protocols

/close #173
parent a7220c89
...@@ -60,6 +60,11 @@ CALENDAR_URL = "https://user:password@calendar.example.com/dav/" ...@@ -60,6 +60,11 @@ CALENDAR_URL = "https://user:password@calendar.example.com/dav/"
CALENDAR_DEFAULT_DURATION = 3 # default meeting length in hours CALENDAR_DEFAULT_DURATION = 3 # default meeting length in hours
CALENDAR_MAX_REQUESTS = 10 # number of retries before giving up (some caldav servers like to randomly reply with errors) CALENDAR_MAX_REQUESTS = 10 # number of retries before giving up (some caldav servers like to randomly reply with errors)
CALENDAR_TIMEZONE_MAP = {
"CET": "Europe/Berlin",
"CEST": "Europe/Berlin",
}
SESSION_PROTECTION = "strong" # do not change SESSION_PROTECTION = "strong" # do not change
# authentication # authentication
......
...@@ -9,6 +9,7 @@ from uuid import uuid4 ...@@ -9,6 +9,7 @@ from uuid import uuid4
from shared import db, date_filter, date_filter_short, escape_tex, DATE_KEY, START_TIME_KEY, END_TIME_KEY, current_user from shared import db, date_filter, date_filter_short, escape_tex, DATE_KEY, START_TIME_KEY, END_TIME_KEY, current_user
from utils import random_string, get_etherpad_url, split_terms, check_ip_in_networks from utils import random_string, get_etherpad_url, split_terms, check_ip_in_networks
from models.errors import DateNotMatchingException from models.errors import DateNotMatchingException
from dateutil import tz
import os import os
...@@ -331,6 +332,10 @@ class Protocol(DatabaseModel): ...@@ -331,6 +332,10 @@ class Protocol(DatabaseModel):
tops_before.append(top) tops_before.append(top)
return tops_before + self.tops + tops_after return tops_before + self.tops + tops_after
def get_timezone_aware_start_date(self):
return datetime.combine(self.date, self.get_time()).replace(
tzinfo=tz.tzlocal())
@staticmethod @staticmethod
def create_new_protocol(protocoltype, date, start_time=None): def create_new_protocol(protocoltype, date, start_time=None):
if start_time is None: if start_time is None:
......
...@@ -14,9 +14,10 @@ from apscheduler.triggers.cron import CronTrigger ...@@ -14,9 +14,10 @@ from apscheduler.triggers.cron import CronTrigger
from apscheduler.triggers.interval import IntervalTrigger from apscheduler.triggers.interval import IntervalTrigger
import atexit import atexit
import feedgen.feed import feedgen.feed
import icalendar
from io import StringIO, BytesIO from io import StringIO, BytesIO
import os import os
from datetime import datetime, time from datetime import datetime, time, timedelta
import math import math
import mimetypes import mimetypes
import subprocess import subprocess
...@@ -1352,9 +1353,7 @@ def create_protocols_feed(protocoltype): ...@@ -1352,9 +1353,7 @@ def create_protocols_feed(protocoltype):
entry.title(protocol.get_title()) entry.title(protocol.get_title())
entry.summary(",\n".join(top.name for top in protocol.get_tops())) entry.summary(",\n".join(top.name for top in protocol.get_tops()))
entry.content(protocol.content_public) entry.content(protocol.content_public)
aware_date = datetime.combine(protocol.date, protocoltype.usual_time).replace( entry.published(protocol.get_timezone_aware_start_date())
tzinfo=tz.tzlocal())
entry.published(aware_date)
return feed return feed
...@@ -1381,10 +1380,13 @@ def create_appointments_feed(protocoltype): ...@@ -1381,10 +1380,13 @@ def create_appointments_feed(protocoltype):
_external=True), rel="alternate") _external=True), rel="alternate")
entry.title(protocol.get_title()) entry.title(protocol.get_title())
entry.summary("\n".join( entry.summary("\n".join(
[",\n".join( [",\n".join([
"{}: {}".format(meta.name, meta.value) "Beginn: {}".format(protocol.get_time())
for meta in protocol.metas ] + [
if not meta.internal "{}: {}".format(meta.name, meta.value)
for meta in protocol.metas
if not meta.internal
]
), ),
"Tagesordnung:", "Tagesordnung:",
",\n".join( ",\n".join(
...@@ -1418,6 +1420,37 @@ def feed_appointments_atom(protocoltype): ...@@ -1418,6 +1420,37 @@ def feed_appointments_atom(protocoltype):
return Response(create_appointments_feed(protocoltype).atom_str(), return Response(create_appointments_feed(protocoltype).atom_str(),
mimetype="application/atom+xml") mimetype="application/atom+xml")
@app.route("/feed/appointments/ical/<int:protocoltype_id>")
@db_lookup(ProtocolType)
def feed_appointsments_ical(protocoltype):
if not protocoltype.has_public_anonymous_view_right():
abort(403)
protocols = [protocol
for protocol in protocoltype.protocols
if not protocol.is_done()
]
calendar = icalendar.Calendar()
calendar["summary"] = protocoltype.short_name
calendar["prodid"] = "Protokollsystem 3"
calendar["version"] = "2.0"
for protocol in protocols:
event = icalendar.Event()
event["uid"] = protocol.id
to_datetime = icalendar.prop.vDatetime
start = protocol.get_timezone_aware_start_date()
event["dtstamp"] = to_datetime(start)
event["dtstart"] = to_datetime(start)
event["dtend"] = to_datetime(start + timedelta(hours=3))
event["summary"] = protocoltype.short_name
event["description"] = "\n".join(top.name
for top in protocol.get_tops())
calendar.add_component(event)
content = calendar.to_ical().decode("utf-8")
for key in config.CALENDAR_TIMEZONE_MAP:
content = content.replace("TZID={}:".format(key),
"TZID={}:".format(config.CALENDAR_TIMEZONE_MAP[key]))
return Response(content.encode("utf-8"), mimetype="text/calendar")
@app.route("/like/new") @app.route("/like/new")
@login_required @login_required
...@@ -1445,6 +1478,7 @@ def new_like(): ...@@ -1445,6 +1478,7 @@ def new_like():
flash("Like!", "alert-success") flash("Like!", "alert-success")
return redirect(request.args.get("next") or url_for("index")) return redirect(request.args.get("next") or url_for("index"))
@app.route("/login", methods=["GET", "POST"]) @app.route("/login", methods=["GET", "POST"])
def login(): def login():
if "auth" in session and current_user() is not None: if "auth" in session and current_user() is not None:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment