Skip to content

Commit

Permalink
Add web calendar
Browse files Browse the repository at this point in the history
  • Loading branch information
RealOrangeOne committed May 14, 2024
1 parent 5780782 commit 2bde60e
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 19 deletions.
8 changes: 7 additions & 1 deletion calmerge/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
from pathlib import Path

import aiohttp_jinja2
from aiohttp import web
from jinja2 import FileSystemLoader

from . import templates, views
from .config import Config

STATIC_DIR = Path(__file__).resolve().parent / "static"


def get_aiohttp_app(config: Config) -> web.Application:
app = web.Application()
Expand All @@ -18,14 +22,16 @@ def get_aiohttp_app(config: Config) -> web.Application:
],
)

jinja2_env.filters["webcal_url"] = templates.webcal_url
jinja2_env.filters["calendar_url"] = templates.calendar_url

app["config"] = config

app.add_routes(
[
web.static("/static", STATIC_DIR),
web.get("/.health/", views.healthcheck, name="healthcheck"),
web.get("/{slug}.ics", views.calendar, name="calendar"),
web.get("/{slug}.html", views.calendar_html, name="calendar-html"),
]
)

Expand Down
8 changes: 8 additions & 0 deletions calmerge/static/calendar.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#calendar {
max-width: 75vw;
max-height: 75vh;
margin: 0 auto;
}
#calendar-message {
text-align: center;
}
25 changes: 25 additions & 0 deletions calmerge/static/calendar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
document.addEventListener('DOMContentLoaded', function() {
var calendarEl = document.getElementById('calendar');
var calendarMessage = document.getElementById('calendar-message');

var calendar = new FullCalendar.Calendar(calendarEl, {
headerToolbar: {
start: 'title',
center: '',
end: 'today prev,next dayGridMonth,listYear,multiMonthYear'
},
initialView: 'listYear',
events: {
url: calendarEl.dataset.url,
format: 'ics',
},
eventSourceSuccess: function() {
calendarMessage.style.display = 'none';
},
eventSourceFailure: function() {
calendarMessage.innerText = "Loading the calendar failed. Please try again later, or check your browser's developer console for more details."
}
});

calendar.render();
});
4 changes: 2 additions & 2 deletions calmerge/templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ async def config_context_processor(request: web.Request) -> dict:


@jinja2.pass_context
def webcal_url(context: dict, calendar_config: CalendarConfig) -> URL:
def calendar_url(context: dict, calendar_config: CalendarConfig) -> URL:
request: web.Request = context["request"]
config = context["config"]
calendar_url = context["url"](context, "calendar", slug=calendar_config.slug)

url = request.url.with_scheme("webcal").with_path(calendar_url.path)
url = request.url.with_path(calendar_url.path)

if config.listing.include_credentials and calendar_config.auth is not None:
url = url.with_user(calendar_config.auth.username).with_password(
Expand Down
22 changes: 22 additions & 0 deletions calmerge/templates/calendar.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{% set calendar_name = calendar.name|default(calendar.slug, true) %}
<!DOCTYPE html>
<html>
<head>
<title>{{ calendar_name }}</title>
<meta name="robots" content="noindex" />
<link rel="stylesheet" href="/static/calendar.css" />
</head>
<body>
<h1>{{ calendar_name }}</h1>
<p>{{ calendar.description }}</p>
<p><a href="{{ calendar|calendar_url }}">{{ calendar|calendar_url }}</a></p>

<p id="calendar-message">Events are loading...</p>
<div id='calendar' data-url="{{ calendar|calendar_url }}"></div>

<script src="https://cdn.jsdelivr.net/npm/[email protected]/build/ical.min.js" integrity="sha256-uotVKltUv5neKsIlZxrxUccba0PaptusFj6p+w8Sons=" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/index.global.min.js" integrity="sha256-i4vDW9EgtaJmeauDDymtNF2omPZ1fCKpf4w1gBlU1IE=" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdn.jsdelivr.net/npm/@fullcalendar/[email protected]/index.global.min.js" integrity="sha256-WwbtQlF1JHoTRN5Ma84E0HPmjgvdbMzJ5bzJFarfQRE=" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="/static/calendar.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
</body>
</html>
32 changes: 16 additions & 16 deletions calmerge/templates/listing.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,26 +25,26 @@ <h1>Calmerge</h1>
<th>Offsets</th>
<th>TTL</th>
<th>Auth</th>
<th>Preview</th>
<th>+</th>
</tr>
{% for calendar in config.calendars|sort(attribute="slug") %}
<tr>
{% with calendar_url = url('calendar', slug=calendar.slug) %}
<td><a href="{{ calendar_url }}">{{ calendar_url }}</a></td>
<td>{{ calendar.name|default("-", true) }}</td>
<td>{{ calendar.description|default("-", true) }}</td>
<td>{{ calendar.offset_days|sort|join(", ") }}</td>
<td>{{ calendar.ttl_hours }} hours</td>
{% if config.listing.include_credentials and calendar.auth %}
<td><code>{{ calendar.auth.username }}:{{ calendar.auth.password }}</code></td>
{% else %}
<td>{{ "Yes" if calendar.auth else "No" }}</td>
{% endif %}
<td>
<a href="{{ calendar_url }}">{{ calendar_url.scheme|default("http", true) }}</a>
<a href="{{ calendar|webcal_url }}">webcal</a>
</td>
{% endwith %}
<td><a href="{{ url('calendar', slug=calendar.slug) }}">{{ calendar.slug }}</a></td>
<td>{{ calendar.name|default("-", true) }}</td>
<td>{{ calendar.description|default("-", true) }}</td>
<td>{{ calendar.offset_days|sort|join(", ") }}</td>
<td>{{ calendar.ttl_hours }} hours</td>
{% if config.listing.include_credentials and calendar.auth %}
<td><code>{{ calendar.auth.username }}:{{ calendar.auth.password }}</code></td>
{% else %}
<td>{{ "Yes" if calendar.auth else "No" }}</td>
{% endif %}
<td><a href="{{ url('calendar-html', slug=calendar.slug) }}">preview</a></td>
<td>
<a href="{{ calendar|calendar_url }}">{{ (calendar|calendar_url).scheme|default('http', true) }}</a>
<a href="{{ (calendar|calendar_url).with_scheme('webcal') }}">webcal</a>
</td>
</tr>
{% endfor %}
</table>
Expand Down
13 changes: 13 additions & 0 deletions calmerge/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,16 @@ async def calendar_listing(request: web.Request) -> web.Response:
"default-src 'self'; style-src 'unsafe-inline'"
)
return response


async def calendar_html(request: web.Request) -> web.Response:
config = request.app["config"]

calendar_config = config.get_calendar_by_slug(request.match_info["slug"])

if calendar_config is None:
raise web.HTTPNotFound()

return aiohttp_jinja2.render_template(
"calendar.html", request, {"calendar": calendar_config}
)

0 comments on commit 2bde60e

Please sign in to comment.