calendarwatch_backend/__init__.py
raphael 056779f7d2 adds ical url handling
- icalToCalendarDB converts the information the user puts into the form
  on the calendar.html page and pulls the calendar from the url.
  It then passes it into the database.

- fetchCanedarEvents gets all events within a startDate and an endDate
  and removes any all day events. This is currently a bit costly, because
  it takes some time for the ics library to download the entire .ical
  file from the url. Then it goes through every entry ever added to the
  file and saves only the future events.
2020-07-25 18:03:02 +02:00

212 lines
6.4 KiB
Python

from __future__ import print_function
import datetime
import dateutil.parser
import pickle
import json
import os.path
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from server import db
from database.models import Calendar as dbCalendar
# If modifying these scopes, delete the file token.pickle.
SCOPES = ["https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/userinfo.profile", "https://www.googleapis.com/auth/calendar.readonly", "openid"]
API_SERVICE_NAME = 'calendar'
API_VERSION = 'v3'
class Calendar:
def __init__(self, name, calendarId, calType, toggle='False', color="#000000"):
self.name = name
self.calType = calType
self.color = color
self.toggle=toggle
self.calendarId = calendarId
class Event:
def __init__(self, name_, start_, end_):
self.name = name_
self.eventColorId = None
self.start = start_
self.end = end_
self.colorHex = '#adfff5'
if self.start == None or self.end == None :
self.allDay = True
else:
self.allDay = False
def startDateTime(self):
if self.allDay:
return None
return self.jsonFromDT(self.start)
def stopDateTime(self):
if self.allDay:
return None
return self.jsonFromDT(self.end)
def jsonFromDT(self, string):
sdt = dateutil.parser.parse(string)
data = {
'date': {
'year': sdt.year,
'month': sdt.month,
'day': sdt.day
},
'time': {
'hour': sdt.hour,
'minute': sdt.minute,
'second': sdt.second
}
}
return data
def print(self):
if self.allDay:
print(self.name + "All Day")
def updateCalendars(user, calendars, colors):
if user == None or calendars == None or colors == None:
return
COLORS_FILE = os.path.join(os.path.dirname(__file__), 'colors.json')
with open(COLORS_FILE) as f:
colormap = json.load(f)
# add all new calendars into the database
# TODO update existing Name and Calendar ( do this in User class at db? )
# Take care, that you don't overwrite the custom color selection of the user
for calendar in calendars:
if not user.hasCalendar(calendar.calendarId):
color = fromColorIdGetColor(calendar.color, colormap, colors)
c = dbCalendar(calendar_id = calendar.calendarId,
calendar_type = calendar.calType,
name = calendar.name,
toggle = "False",
color = color)
db.session.add(c)
user.calendars.append(c)
db.session.commit()
def calendarsFromDb(user):
pyCalendars = []
for calendar in user.calendars:
name = (calendar.name[:16] + '..') if len(calendar.name)> 18 else calendar.name
calendarId = calendar.calendar_id
toggle = calendar.toggle
color = calendar.color
calType = calendar.calendar_type
pyCalendars.append(Calendar(name, calendarId, calType, toggle, color))
return pyCalendars
# removes not visible calendars from the list of all calendars
def purgeCalendars(calendars, visibleCalendars):
purged = []
for calendar in calendars:
if calendar.calendarId in visibleCalendars:
purged.append(calendar)
return purged
# remaps a event color id to a calendar color id
# for google calendars
def toCalendarColorId(colormap, colorId):
for remap in colormap['eventRemap']:
if remap['from'] == colorId:
return remap['to']
print(f"failed with {colorId}")
return colorId
# remaps a calendar color ID to its natural color
# for google calendars
def toNaturalColor(colormap, orgColor):
for remap in colormap['colors']:
if remap['api'] == orgColor:
return remap['natural']
print(f"failed with {orgColor}")
return orgColor
# uses the event color id to convert it to a hex color
# does this for every event in events
# this is used for Google Calendars
def colorizeGoogleEvents(events, colors):
COLORS_FILE = os.path.join(os.path.dirname(__file__), 'colors.json')
with open(COLORS_FILE) as f:
colormap = json.load(f)
for event in events:
if event.eventColorId != None:
event.colorHex = forEventGetColor(event, colormap, colors)
# returns a color for a specific calendar color id
# for google calendars
def fromColorIdGetColor(color, colormap, colors):
return toNaturalColor(colormap, colors['calendar'][color]['background'])
# generates the natural color for a event color id
# for google calendars
def forEventGetColor(event, colormap, colors):
calColorId = toCalendarColorId(colormap, event.eventColorId)
bg = colors['calendar'][calColorId]['background']
return toNaturalColor(colormap, bg)
# exports all events into a jsonable format (excluding all day events)
def toJson(events):
data = {}
data['kind'] = 'calendar#events'
data['events'] = []
for event in events:
if event.allDay:
continue
data['events'].append({
'name': event.name,
'isAllDay': event.allDay,
'color': event.colorHex,
'startDateTime': event.startDateTime(),
'stopDateTime': event.stopDateTime()
})
return data
# debug functions which prints color names
def printColors(colors):
for i in range(1, 25):
col = colors['event'][str(i)]['background']
print(f"{i}: {col}")
def main():
return
def getTimeStamps():
# define today and tomorrow
now = datetime.datetime.now(datetime.timezone.utc).astimezone()
today = now.replace(hour=0, minute=0, second = 0)
tomorrow = now.replace(hour=23, minute=59, second=59).isoformat() # + '+01:00'
twodaysfromnow = datetime.datetime.today() + datetime.timedelta(days=2)
twodaysfromnow = twodaysfromnow.replace(hour=23, minute=59, second=59).astimezone()
return today, twodaysfromnow
def generateJsonFromCalendarEntries(events, colors):
# fix all colors in events that have a different event color
if colors != None:
colorizeGoogleEvents(events, colors)
# if not events:
# print('No upcoming events found.')
return toJson(events)
if __name__ == '__main__':
main()