#!/usr/bin/env python3 import json import urllib.request from base64 import b64decode from subprocess import run import cherrypy from defusedxml.ElementTree import fromstring from icalendar import Calendar, Todo GITEA_REPO_URL="https://git.bitmessage.org/api/v1" combined = {} def get_combined(token): for q in ("assigned", "review_requested"): req = urllib.request.Request(GITEA_REPO_URL + f"/repos/issues/search?{q}=true") req.add_header("Accept", "application/json") req.add_header("Content-Type", "application/json") req.add_header("Authorization", "token " + token) with urllib.request.urlopen(req) \ as response: issues = json.load(response) for issue in issues: _id = issue['id'] if _id in combined: combined[_id]['categories'].append(q) else: combined[_id] = issue combined[_id]['categories'] = [q] return combined def process_combined(combined): cal = Calendar() for _id, issue in combined.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: @cherrypy.expose def index(self): cherrypy.response.headers['WWW-Authenticate'] = \ 'Basic realm="ICS access"' 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') combined = get_combined(token) if not combined: raise cherrypy.HTTPError(401, 'Unauthorized') return(process_combined(combined)) class Dav: exposed = True #@cherrypy.expose @cherrypy.tools.accept(media='application/xml') def PROPFIND(self): cl = cherrypy.request.headers['Content-Length'] rawbody = cherrypy.request.body.read(size=int(cl)) et = fromstring(rawbody) for child in et: if child.tag == '{DAV:}prop': for x in child: print("T:", x.tag, "; A:", x.attrib) #print(et) print(f"BODY {rawbody}") if __name__ == '__main__': conf = { '/dav': { 'request.dispatch': cherrypy.dispatch.MethodDispatcher(), 'request.methods_with_bodies': ('POST', 'PUT', 'PROPFIND'), } } cherrypy.config.update({'server.socket_host': '0.0.0.0', 'server.socket_port': 8080, }) webapp = Root() webapp.dav = Dav() cherrypy.quickstart(webapp, '/', conf)