Closed hakan-demirli closed 10 months ago
I made a substitute.
#! /usr/bin/env python3
import datetime
import pytz
import pickle
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
import subprocess
import json
from pathlib import Path
TIME_MIN = (datetime.datetime.utcnow() - datetime.timedelta(days=365)).isoformat() + 'Z'
TIME_MAX = (datetime.datetime.utcnow() + datetime.timedelta(days=365)).isoformat() + 'Z'
SCOPES = ['https://www.googleapis.com/auth/calendar']
CREDS_FILE = './cred_tw.json'
SYNCED_PROS = {'school': 'somenumber@group.calendar.google.com'}
class GoogleCalendarAPI:
def __init__(self):
creds = None
root_path = Path(__file__).parent
token_path = root_path / 'token.pickle'
if os.path.exists(token_path):
with open(token_path, 'rb') as token:
creds = pickle.load(token)
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(CREDS_FILE, SCOPES)
creds = flow.run_local_server(port=0)
with open(token_path, 'wb') as token:
pickle.dump(creds, token)
self.service = build('calendar', 'v3', credentials=creds)
def get_events(self,calendar_id):
events = self.service.events().list(calendarId=calendar_id, timeMin=TIME_MIN,
timeMax=TIME_MAX, singleEvents=True,
orderBy='startTime').execute()
return events
def update_event(self,calendar_id,event):
self.service.events().update(calendarId=calendar_id, eventId=event['id'], body=event).execute()
def insert_event(self,calendar_id,event):
self.service.events().insert(calendarId=calendar_id, body=event).execute()
def delete_event(self,calendar_id,event):
self.service.events().delete(calendarId=calendar_id, eventId=event['id']).execute()
def convert_task_date_str_to_obj(task):
date_format = '%Y%m%dT%H%M%SZ'
due_date = datetime.datetime.strptime(task["due"], date_format).replace(tzinfo=pytz.utc).astimezone()
modi_date = datetime.datetime.strptime(task["modified"], date_format).replace(tzinfo=pytz.utc).astimezone()
task["due"] = due_date
task["modified"] = modi_date
return task
def convert_tasks_date_str_to_obj(tasks):
for task in tasks:
task = convert_task_date_str_to_obj(task)
return tasks
if __name__ == "__main__":
gapi = GoogleCalendarAPI()
for pro in SYNCED_PROS:
cal_id = SYNCED_PROS[pro]
events = gapi.get_events(cal_id)
for event in events['items']:
taskuuid = event['extendedProperties']['private']['uuid']
task = json.loads(subprocess.run(f'task {taskuuid} export', shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True).stdout)
if not task:
gapi.delete_event(cal_id, event)
continue
task = convert_task_date_str_to_obj(task[0])
task_last_modified = task['modified']
cal_date = event.get('updated').replace(":","").replace("-","").split(".")[0] + 'Z'
event_last_modified = datetime.datetime.strptime(cal_date, '%Y%m%dT%H%M%SZ').replace(tzinfo=pytz.utc).astimezone()
if(task_last_modified > event_last_modified): # if the calendar modified date is older delete it.
gapi.delete_event(cal_id, event)
else:
subprocess.run(f'task {taskuuid} modify description:{event["summary"]} due:{event["start"]["dateTime"]}', shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
tasks = json.loads(subprocess.run(f'task project:{pro} export', shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True).stdout)
tasks = convert_tasks_date_str_to_obj(tasks)
events = gapi.get_events(cal_id)
for task in tasks:
exists = False
for event in events['items']:
if(task['uuid'] == event['extendedProperties']['private']['uuid']):
exists = True
break
if(not exists):
start_time = (task['due'] - datetime.timedelta(hours=0, minutes=5)).isoformat()
end_time = (task['due'] - datetime.timedelta(hours=0, minutes=5)).isoformat()
description = task['description']
if(task['status'] == 'completed'):
description = '✅' + task['description']
new_event = {
'summary': description,
'start': {
'dateTime': start_time,
},
'end': {
'dateTime': end_time,
},
'extendedProperties': {
'private': {
'uuid': task['uuid'],
'project': task['project']
}
}
}
gapi.insert_event(cal_id,new_event)
Describe the bug
Subprojects are ignored. Only
willsync
is synchronized andtestx
are ignored.To Reproduce
task add willsync project:mainpro due:tuesday
task add test1 project:mainpro.p0 due:tuesday
task add test2 project:mainpro.p1 due:monday
task add test3 project:mainpro.p2 due:tomorrow
tw_gcal_sync -c "deadlines_tw" -p "mainpro" --verbose
Expected Behavior
It should also sync subprojects.