#!/usr/bin/env python3 import datetime import json import urllib.request from base64 import b64decode from subprocess import run import cherrypy from icalendar import Calendar, Todo GITEA_REPO_URL="https://git.bitmessage.org/api/v1" combined = {} def retrieve(token, kind): if kind not in ("review_requested", "assigned"): raise cherrypy.HTTPError(401, 'Unauthorized') req = urllib.request.Request(GITEA_REPO_URL + f"/repos/issues/search?state=open&{kind}=true") req.add_header("Accept", "application/json") req.add_header("Authorization", "token " + token) retval = {} with urllib.request.urlopen(req) as response: issues = json.load(response) for issue in issues: _id = issue['id'] retval[_id] = issue retval[_id]['categories'] = [kind] return retval def process(retrieved): cal = Calendar() for _id, issue in retrieved.items(): todo = Todo() todo['uid'] = _id todo['dtstamp'] = issue['created_at'] if issue['due_date']: todo['due'] = issue['due_date'] todo['summary'] = issue['title'] todo['description'] = issue['body'] todo['categories'] = issue['categories'] cal.add_component(todo) return cal.to_ical() def get_token(input_token): token = input_token.removeprefix("Basic ") token = b64decode(token).decode('utf8', 'ignore') with cherrypy.HTTPError.handle(ValueError, 401): _, token = token.split(":", 2) return token class Root: def _authenticate(self, kind): cherrypy.response.headers['WWW-Authenticate'] = \ 'Basic realm="ICS access"' cherrypy.response.headers['Content-Type'] = \ 'text/calendar' cherrypy.response.headers['Content-Disposition'] = \ f'attachment; filename="Gitea {kind}.ics"' authorization = cherrypy.request.headers.get('Authorization', ':') if not authorization: raise cherrypy.HTTPError(401, 'Unauthorized') token = get_token(authorization) if not token: raise cherrypy.HTTPError(401, 'Unauthorized') return token @cherrypy.expose def assigned(self): token = self._authenticate("assigned") retrieved = retrieve(token, "assigned") if not retrieved: raise cherrypy.HTTPError(401, 'Unauthorized') return(process(retrieved)) @cherrypy.expose def review_requested(self): token = self._authenticate("review_requested") retrieved = retrieve(token, "review_requested") if not retrieved: raise cherrypy.HTTPError(401, 'Unauthorized') return(process(retrieved)) if __name__ == '__main__': cherrypy.config.update({'server.socket_host': '0.0.0.0', 'server.socket_port': 8080, }) cherrypy.quickstart(Root(), '/')