Large restructure of google and backend separation
- googleHandler now takes care of every google communication and mostly nothing else - only backend classes for Calendar and Events are used for communication - backend now takes care of every other interaction - functionality is still the same though
This commit is contained in:
		
							
								
								
									
										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()
 | 
					 | 
				
			||||||
							
								
								
									
										275
									
								
								__init__.py
									
									
									
									
									
								
							
							
						
						
									
										275
									
								
								__init__.py
									
									
									
									
									
								
							@@ -1,3 +1,274 @@
 | 
				
			|||||||
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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 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, toggle='False', color="#000000"):
 | 
				
			||||||
 | 
					        self.name = name
 | 
				
			||||||
 | 
					        self.color = color
 | 
				
			||||||
 | 
					        self.toggle=toggle
 | 
				
			||||||
 | 
					        self.calendarId = calendarId
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Event:
 | 
				
			||||||
 | 
					    def __init__(self, name_, start_, end_):
 | 
				
			||||||
 | 
					        self.name = name_
 | 
				
			||||||
 | 
					        self.eventColorId = 0
 | 
				
			||||||
 | 
					        self.calendarColorId = None 
 | 
				
			||||||
 | 
					        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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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 updateCalendars(user, calendars, colors):
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    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, 
 | 
				
			||||||
 | 
					                           name = calendar.summary,
 | 
				
			||||||
 | 
					                           toggle = "False",
 | 
				
			||||||
 | 
					                           color = color)
 | 
				
			||||||
 | 
					            db.session.add(c)
 | 
				
			||||||
 | 
					            current_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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        pyCalendars.append(Calendar(name, calendarId, toggle, color))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return pyCalendars
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def purgeCalendars(calendars, visibleCalendars):
 | 
				
			||||||
 | 
					    purged = []
 | 
				
			||||||
 | 
					    for calendar in calendars:
 | 
				
			||||||
 | 
					        if calendar.calendarId in visibleCalendars:
 | 
				
			||||||
 | 
					            purged.append(calendar)
 | 
				
			||||||
 | 
					    return purged
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def getCalendarEvents(service, userCalendars, startDate, endDate):
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    visualCals = []
 | 
				
			||||||
 | 
					    for calendar in userCalendars:
 | 
				
			||||||
 | 
					        if calendar.toggle == 'True':
 | 
				
			||||||
 | 
					            visualCals.append(calendar.calendar_id)
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    calendars = getCalendars(service)
 | 
				
			||||||
 | 
					    calendars = purgeCalendars(calendars, visualCals)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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:
 | 
				
			||||||
 | 
					                for userCalendar in userCalendars:
 | 
				
			||||||
 | 
					                    if userCalendar.calendar_id == calendar.calendarId:
 | 
				
			||||||
 | 
					                        newEvent.calendarHex = userCalendar.color
 | 
				
			||||||
 | 
					                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(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.calendarColorId != None:
 | 
				
			||||||
 | 
					            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 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()
 | 
					 | 
				
			||||||
		Reference in New Issue
	
	Block a user