You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

188 lines
7.1 KiB
Python

#TODO: All Google/iCloud Calendar syncing logic here
import google_auth_oauthlib.flow
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
import os
import json
import datetime
import schedule
from .database import TodoDatabase
from .tododatatypes import Todo
data = TodoDatabase()
from datetime import datetime, time, timedelta
# import pytz
from zoneinfo import ZoneInfo
from datetime import timezone
# def midnight_UTC(offset):
# # Construct a timezone object
# tz = pytz.timezone('America/Toronto')
# # Work out today/now as a timezone-aware datetime
# today = datetime.now(tz)
# # Adjust by the offset. Note that that adding 1 day might actually move us 23 or 25
# # hours into the future, depending on daylight savings. This works because the {today}
# # variable is timezone aware
# target_day = today + timedelta(days=1) * offset
# # Discard hours, minutes, seconds and microseconds
# midnight_aware = tz.localize(
# datetime.combine(target_day, time(0, 0, 0, 0)), is_dst=None)
# # Convert to UTC
# midnight_UTC = midnight_aware.astimezone(pytz.utc)
# return midnight_UTC
class SyncData():
def __init__(self):
self.SCOPES = ['https://www.googleapis.com/auth/calendar.readonly']
self.creds = None
self.get_new_creds()
self.get_calendar_events()
schedule.every(1).day.at("06:55").do(self.get_calendar_events)
def get_new_creds(self, code=""):
"""Returns True if successfully obtains credentials,
otherwise throws errors according to functions called, unless
code='' in which case if no saved credentials are found, returns False
"""
if os.path.exists('token.json'):
self.creds = Credentials.from_authorized_user_file('token.json', self.SCOPES)
# else:
# flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
# 'client_secret.json',
# scopes=['https://www.googleapis.com/auth/calendar.readonly'],
# redirect_uri="postmessage"
# # state=state
# )
# creds = flow.fetch_token(code=googleCode.code)
# print(creds)
# with open("token.json", 'w') as token:
# token.write(creds.to_json())
if not self.creds or not self.creds.valid:
if self.creds and self.creds.expired and self.creds.refresh_token:
self.creds.refresh(Request())
else:
if code == "":
return False
# flow = InstalledAppFlow.from_client_secrets_file(
# 'credentials.json', SCOPES)
# creds = flow.run_local_server(port=0)
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
'client_secret.json',
scopes=self.SCOPES,
redirect_uri="postmessage"
# state=state
)
flow.fetch_token(code=code)
self.creds = flow.credentials
# print(creds)
# Save the credentials for the next run
with open('token.json', 'w') as token:
token.write(self.creds.to_json())
# json.dump(token, creds)
return True
def get_calendar_events(self, day=None):
if not self.get_new_creds():
return
# now = datetime.now()
# if day:
# now = datetime.datetime.strptime(day, "%Y-%m-%d")
# else:
# now = datetime.datetime.now()
# day_start = now.replace(hour=0, minute=0, second=0, microsecond=0)
# day_end = day_start + datetime.timedelta(hours=24)
# day_start = day_start.isoformat() + "Z"
# day_end = day_end.isoformat() + "Z"
if day:
pass
else:
# day_start = midnight_UTC(0).isoformat() + "Z"
# day_end = midnight_UTC(1).isoformat() + "Z"
day_start = datetime.combine(datetime.now(tz=ZoneInfo("America/Toronto")).date(), time(0, 0), tzinfo=ZoneInfo("America/Toronto"))
day_end = day_start + timedelta(hours=23,minutes=59)
# day_start_for = day_start.astimezone(ZoneInfo("UTC")).isoformat() + "Z"
# day_end_for = day_end.astimezone(ZoneInfo("UTC")).isoformat() + "Z"
day_start_for = day_start.astimezone(ZoneInfo("UTC")).strftime('%Y-%m-%dT%H:%M:%S.%fZ')
day_end_for = day_end.astimezone(ZoneInfo("UTC")).strftime('%Y-%m-%dT%H:%M:%S.%fZ')
# print(day_start.tzname())
# print(day_start)
# print(day_end)
# print(day_start.astimezone(ZoneInfo("UTC")).strftime('%Y-%m-%dT%H:%M:%S.%fZ'))
# print(day_end.astimezone(ZoneInfo("UTC")).strftime('%Y-%m-%dT%H:%M:%S.%fZ'))
# print(datetime.utcnow().isoformat() + 'Z')
try:
service = build('calendar', 'v3', credentials=self.creds)
# Call the Calendar API
# now = datetime.datetime.utcnow().isoformat() + 'Z' # 'Z' indicates UTC time
print('Getting all upcoming events for time range: ' + day_start_for + " to " + day_end_for)
events_result = service.events().list(calendarId='primary', timeMin=day_start_for, timeMax=day_end_for,
singleEvents=True, orderBy='startTime').execute()
events = events_result.get('items', [])
if not events:
print('No upcoming events found.')
return
print(str(len(events)) + " events found")
# Prints the start and name of the next 10 events
# event format: {'kind': 'calendar#event', 'etag': '"3386046190326000"', 'id': '0migcv6t729ph1kirhiauej3eh', 'status': 'confirmed', 'htmlLink': 'https://www.google.com/calendar/event?eid=MG1pZ2N2NnQ3MjlwaDFraXJoaWF1ZWozZWggYmFtLmltLnNhbUBt', 'created': '2023-08-26T04:11:35.000Z', 'updated': '2023-08-26T04:11:35.163Z', 'summary': 'test', 'creator': {'email': 'bam.im.sam@gmail.com', 'self': True}, 'organizer': {'email': 'bam.im.sam@gmail.com', 'self': True}, 'start': {'dateTime': '2023-08-27T14:30:00-04:00', 'timeZone': 'America/Toronto'}, 'end': {'dateTime': '2023-08-27T15:30:00-04:00', 'timeZone': 'America/Toronto'}, 'iCalUID': '0migcv6t729ph1kirhiauej3eh@google.com', 'sequence': 0, 'reminders': {'useDefault': True}, 'eventType': 'default'}
formatted_todo_list = []
# print(events)
for event in events:
# print(event)
start = event['start'].get('dateTime', event['start'].get('date'))
end = event['end'].get('dateTime', event['end'].get('date'))
# print(event)
# print(start, "->", end, event['summary'])
start_parsed = datetime.strptime(start, "%Y-%m-%dT%H:%M:%S%z").strftime("%-I:%M%p") #2023-08-26T15:30:00-04:00
end_parsed = datetime.strptime(end, "%Y-%m-%dT%H:%M:%S%z").strftime("%-I:%M%p") #2023-08-26T15:30:00-04:00
# print("parsed: ", start_parsed, "to", end_parsed, event['summary'])
if 'summary' in event:
# {"time": start_parsed + " to " + end_parsed, "task": event['summary'], "recurring": False}
formatted_todo_list.append(Todo(time=start_parsed + " to " + end_parsed, task=event['summary'], recurring=False))
# formatted_todo_list.append({"time": start_parsed + " to " + end_parsed, "task": event['summary'], "recurring": False})
else:
formatted_todo_list.append(Todo(time=start_parsed + " to " + end_parsed, task='No Title', recurring=False))
# formatted_todo_list.append({"time": start_parsed + " to " + end_parsed, "task": 'No Title', "recurring": False})
# print(formatted_todo_list)
data.save_todos(day_start.strftime("%Y-%m-%d"), formatted_todo_list)
except HttpError as error:
print('An error occurred: %s' % error)
#TODO: Obtain calendar data and save to local database, parse into printable content