Compare commits
5 Commits
b5cb35256c
...
fec09edb88
Author | SHA1 | Date | |
---|---|---|---|
fec09edb88 | |||
45cd71cc4b | |||
1a5700e9a0 | |||
183bf60fc0 | |||
87a229f791 |
42
Routine.py
42
Routine.py
@ -1,42 +0,0 @@
|
|||||||
from server import db
|
|
||||||
from database.models import User, Calendar
|
|
||||||
from backend import caltojson
|
|
||||||
import os
|
|
||||||
|
|
||||||
import google.oauth2.credentials
|
|
||||||
import json
|
|
||||||
|
|
||||||
class Routine:
|
|
||||||
|
|
||||||
def updateCalendar(self, user, credentials):
|
|
||||||
# check google:
|
|
||||||
if credentials is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
visualCals = []
|
|
||||||
for calendar in user.calendars:
|
|
||||||
if calendar.toggle == 'True':
|
|
||||||
visualCals.append(calendar.calendar_id)
|
|
||||||
googleCreds = google.oauth2.credentials.Credentials(**credentials)
|
|
||||||
calendarjson = caltojson.generateJsonFromCalendarEntries(visualCals, googleCreds)
|
|
||||||
'''
|
|
||||||
directory = 'userinfo/' + user.id + '/'
|
|
||||||
if not os.path.exists(directory):
|
|
||||||
os.makedirs(directory)
|
|
||||||
with open(directory + 'calendarevents.json', 'w', encoding='utf-8') as f:
|
|
||||||
json.dump(calendarjson, f, ensure_ascii=False, indent=4)
|
|
||||||
'''
|
|
||||||
return calendarjson
|
|
||||||
|
|
||||||
|
|
||||||
def credentials_to_dict(credentials):
|
|
||||||
return{'token': credentials.token,
|
|
||||||
'refresh_token': credentials.refresh_token,
|
|
||||||
'token_uri': credentials.token_uri,
|
|
||||||
'client_id': credentials.client_id,
|
|
||||||
'client_secret': credentials.client_secret,
|
|
||||||
'scopes': credentials.scopes}
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
routine = Routine()
|
|
||||||
routine.start()
|
|
211
__init__.py
211
__init__.py
@ -1,3 +1,210 @@
|
|||||||
from backend.Routine import Routine
|
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
|
||||||
|
|
||||||
routine = Routine()
|
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 colorizeEvents(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).isoformat()
|
||||||
|
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().isoformat()
|
||||||
|
|
||||||
|
return today, twodaysfromnow
|
||||||
|
|
||||||
|
def generateJsonFromCalendarEntries(events, colors):
|
||||||
|
|
||||||
|
# fix all colors in events that have a different event color
|
||||||
|
colorizeEvents(events, colors)
|
||||||
|
# if not events:
|
||||||
|
# print('No upcoming events found.')
|
||||||
|
|
||||||
|
return toJson(events)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
267
caltojson.py
267
caltojson.py
@ -1,267 +0,0 @@
|
|||||||
from __future__ import print_function
|
|
||||||
import datetime
|
|
||||||
import dateutil.parser
|
|
||||||
import pickle
|
|
||||||
import json
|
|
||||||
import os.path
|
|
||||||
from googleapiclient.discovery import build
|
|
||||||
from google_auth_oauthlib.flow import InstalledAppFlow
|
|
||||||
from google.auth.transport.requests import Request
|
|
||||||
|
|
||||||
# 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 Event:
|
|
||||||
def __init__(self, name_, start_, end_):
|
|
||||||
self.name = name_
|
|
||||||
self.eventColorId = 0
|
|
||||||
self.calendarColorId = 0
|
|
||||||
self.naturalColorId = 0
|
|
||||||
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")
|
|
||||||
else:
|
|
||||||
print(self.name + ": " + self.naturalColorId)
|
|
||||||
|
|
||||||
|
|
||||||
class Calendar:
|
|
||||||
def __init__(self, summary_, calendarId_, color_):
|
|
||||||
self.summary = summary_
|
|
||||||
self.calendarId = calendarId_
|
|
||||||
self.color = color_
|
|
||||||
|
|
||||||
def calendarCredentials(token = None):
|
|
||||||
creds = None
|
|
||||||
# The file token.pickle stores the user's access and refresh tokens, and is
|
|
||||||
# created automatically when the authorization flow completes for the first
|
|
||||||
# time.
|
|
||||||
|
|
||||||
if token == None:
|
|
||||||
if os.path.exists('token.pickle'):
|
|
||||||
with open('token.pickle', 'rb') as token:
|
|
||||||
token.seek(0)
|
|
||||||
creds = pickle.load(token)
|
|
||||||
|
|
||||||
else:
|
|
||||||
creds = pickle.load(token)
|
|
||||||
|
|
||||||
# If there are no (valid) credentials available, let the user log in.
|
|
||||||
if not creds or not creds.valid:
|
|
||||||
if creds and creds.expired and creds.refresh_token:
|
|
||||||
creds.refresh(Request())
|
|
||||||
else:
|
|
||||||
flow = InstalledAppFlow.from_client_secrets_file(
|
|
||||||
'credentials.json', SCOPES)
|
|
||||||
creds = flow.run_local_server(port=1234)
|
|
||||||
# Save the credentials for the next run
|
|
||||||
with open('token.pickle', 'wb') as token:
|
|
||||||
pickle.dump(creds, token)
|
|
||||||
|
|
||||||
service = build('calendar', 'v3', credentials=creds)
|
|
||||||
|
|
||||||
return service
|
|
||||||
|
|
||||||
def getCalendarColors(service):
|
|
||||||
colors = service.colors().get().execute()
|
|
||||||
return colors
|
|
||||||
|
|
||||||
def getCalendars(service):
|
|
||||||
page_token = None
|
|
||||||
calendars = []
|
|
||||||
while True:
|
|
||||||
calendar_list = service.calendarList().list(pageToken=page_token).execute()
|
|
||||||
for calendar in calendar_list['items']:
|
|
||||||
calendars.append(Calendar(calendar['summary'], calendar['id'], calendar['colorId']))
|
|
||||||
page_token = calendar_list.get('nextPageToken')
|
|
||||||
if not page_token:
|
|
||||||
break
|
|
||||||
|
|
||||||
return calendars
|
|
||||||
|
|
||||||
def purgeCalendars(calendars, visibleCalendars):
|
|
||||||
purged = []
|
|
||||||
for calendar in calendars:
|
|
||||||
if calendar.calendarId in visibleCalendars:
|
|
||||||
purged.append(calendar)
|
|
||||||
return purged
|
|
||||||
|
|
||||||
def getCalendarEvents(service, visibleCalendars, startDate, endDate):
|
|
||||||
|
|
||||||
calendars = getCalendars(service)
|
|
||||||
calendars = purgeCalendars(calendars, visibleCalendars)
|
|
||||||
|
|
||||||
all_events = []
|
|
||||||
|
|
||||||
for calendar in calendars:
|
|
||||||
events_result = service.events().list(calendarId=calendar.calendarId, timeMin=startDate,
|
|
||||||
timeMax=endDate,
|
|
||||||
maxResults=10, singleEvents=True,
|
|
||||||
orderBy='startTime').execute()
|
|
||||||
|
|
||||||
for event in events_result.get('items', []):
|
|
||||||
|
|
||||||
# create simple event
|
|
||||||
name = event.get('summary', '(no Title)')
|
|
||||||
start = event['start'].get('dateTime')
|
|
||||||
end = event['end'].get('dateTime')
|
|
||||||
newEvent = Event(name, start, end)
|
|
||||||
|
|
||||||
# handle weird colors from google
|
|
||||||
color = event.get('colorId')
|
|
||||||
if color == None:
|
|
||||||
newEvent.calendarColorId = calendar.color
|
|
||||||
else:
|
|
||||||
newEvent.eventColorId = color
|
|
||||||
|
|
||||||
|
|
||||||
all_events.append(newEvent)
|
|
||||||
|
|
||||||
return all_events
|
|
||||||
|
|
||||||
def toCalendarColorId(colormap, colorId):
|
|
||||||
for remap in colormap['eventRemap']:
|
|
||||||
if remap['from'] == colorId:
|
|
||||||
return remap['to']
|
|
||||||
|
|
||||||
print(f"failed with {colorId}")
|
|
||||||
return colorId
|
|
||||||
|
|
||||||
def toNaturalColor(colormap, orgColor):
|
|
||||||
for remap in colormap['colors']:
|
|
||||||
if remap['api'] == orgColor:
|
|
||||||
return remap['natural']
|
|
||||||
|
|
||||||
print(f"failed with {orgColor}")
|
|
||||||
return orgColor
|
|
||||||
|
|
||||||
def colorizeEvents(allEvents, service):
|
|
||||||
COLORS_FILE = os.path.join(os.path.dirname(__file__), 'colors.json')
|
|
||||||
with open(COLORS_FILE) as f:
|
|
||||||
colormap = json.load(f)
|
|
||||||
|
|
||||||
colors = getCalendarColors(service)
|
|
||||||
|
|
||||||
for event in allEvents:
|
|
||||||
event.colorHex = forEventGetColor(event, colormap, colors)
|
|
||||||
|
|
||||||
# this function is only used once for calendar generation stuff
|
|
||||||
def fromColorIdGetColor(color, colormap, colors):
|
|
||||||
return toNaturalColor(colormap, colors['calendar'][color]['background'])
|
|
||||||
|
|
||||||
def forEventGetColor(event, colormap, colors):
|
|
||||||
if event.calendarColorId != 0:
|
|
||||||
bg = colors['calendar'][event.calendarColorId]['background']
|
|
||||||
else:
|
|
||||||
calColorId = toCalendarColorId(colormap, event.eventColorId)
|
|
||||||
bg = colors['calendar'][calColorId]['background']
|
|
||||||
return toNaturalColor(colormap, bg)
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
def printColors(colors):
|
|
||||||
for i in range(1, 25):
|
|
||||||
col = colors['event'][str(i)]['background']
|
|
||||||
print(f"{i}: {col}")
|
|
||||||
|
|
||||||
def main():
|
|
||||||
generateJsonFromCalendarEntries()
|
|
||||||
|
|
||||||
def getCalendarList(credentials = None):
|
|
||||||
# create service
|
|
||||||
if credentials == None:
|
|
||||||
credentials = calendarCredentials()
|
|
||||||
service = build(API_SERVICE_NAME, API_VERSION, credentials=credentials)
|
|
||||||
|
|
||||||
calendars = getCalendars(service)
|
|
||||||
|
|
||||||
COLORS_FILE = os.path.join(os.path.dirname(__file__), 'colors.json')
|
|
||||||
with open(COLORS_FILE) as f:
|
|
||||||
colormap = json.load(f)
|
|
||||||
|
|
||||||
colors = getCalendarColors(service)
|
|
||||||
|
|
||||||
for calendar in calendars:
|
|
||||||
calendar.color = fromColorIdGetColor(calendar.color, colormap, colors)
|
|
||||||
return calendars
|
|
||||||
|
|
||||||
def generateJsonFromCalendarEntries(visibleCalendars, credentials = None):
|
|
||||||
|
|
||||||
# create service
|
|
||||||
if credentials == None:
|
|
||||||
credentials = calendarCredentials()
|
|
||||||
service = build(API_SERVICE_NAME, API_VERSION, credentials=credentials)
|
|
||||||
|
|
||||||
# define today and tomorrow
|
|
||||||
now = datetime.datetime.now(datetime.timezone.utc).astimezone()
|
|
||||||
today = now.replace(hour=0, minute=0, second = 0).isoformat()
|
|
||||||
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().isoformat()
|
|
||||||
|
|
||||||
print(tomorrow, flush=True)
|
|
||||||
print('----')
|
|
||||||
print(twodaysfromnow, flush=True)
|
|
||||||
allEvents = getCalendarEvents(service, visibleCalendars, today, twodaysfromnow)
|
|
||||||
|
|
||||||
colorizeEvents(allEvents, service)
|
|
||||||
# if not events:
|
|
||||||
# print('No upcoming events found.')
|
|
||||||
|
|
||||||
return toJson(allEvents)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
Loading…
Reference in New Issue
Block a user