mirror of
https://github.com/b4tman/sync_ics2gcal
synced 2024-09-21 08:58:03 +00:00
216 lines
8.1 KiB
Python
216 lines
8.1 KiB
Python
from apiclient import discovery
|
||
import httplib2
|
||
import logging
|
||
from oauth2client import service_account
|
||
from pytz import utc
|
||
import sys
|
||
|
||
|
||
class GoogleCalendarService():
|
||
@staticmethod
|
||
def from_srv_acc_file(service_account_file):
|
||
scopes = 'https://www.googleapis.com/auth/calendar'
|
||
credentials = service_account.ServiceAccountCredentials.from_json_keyfile_name(
|
||
service_account_file, scopes=scopes)
|
||
http = credentials.authorize(httplib2.Http())
|
||
service = discovery.build('calendar', 'v3', http=http)
|
||
return service
|
||
|
||
|
||
class GoogleCalendar():
|
||
logger = logging.getLogger('GoogleCalendar')
|
||
|
||
def __init__(self, service, calendarId):
|
||
self.service = service
|
||
self.calendarId = calendarId
|
||
|
||
def list_events_from(self, start):
|
||
''' Получение списка событий из GCAL начиная с даты start
|
||
'''
|
||
events = []
|
||
page_token = None
|
||
timeMin = utc.normalize(start.astimezone(utc)).replace(
|
||
tzinfo=None).isoformat() + 'Z'
|
||
while True:
|
||
response = self.service.events().list(calendarId=self.calendarId, pageToken=page_token,
|
||
singleEvents=True, timeMin=timeMin, fields='id,iCalUID,updated').execute()
|
||
if 'items' in response:
|
||
events.extend(response['items'])
|
||
page_token = response.get('nextPageToken')
|
||
if not page_token:
|
||
break
|
||
self.logger.info('%d events listed', len(events))
|
||
return events
|
||
|
||
def find_exists(self, events):
|
||
""" Поиск уже существующих в GCAL событий, из списка событий к вставке
|
||
|
||
Arguments:
|
||
events {list} -- list of events
|
||
|
||
Returns:
|
||
tuple -- (events_exist, events_not_found)
|
||
events_exist - list of tuples: (new_event, exists_event)
|
||
"""
|
||
|
||
events_by_req = []
|
||
exists = []
|
||
not_found = []
|
||
|
||
def list_callback(request_id, response, exception):
|
||
found = False
|
||
event = events_by_req[int(request_id)]
|
||
if exception is None:
|
||
found = ([] != response['items'])
|
||
else:
|
||
self.logger.error('exception %s, while listing event with UID: %s', str(
|
||
exception), event['iCalUID'])
|
||
if found:
|
||
exists.append(
|
||
(event, response['items'][0]))
|
||
else:
|
||
not_found.append(events_by_req[int(request_id)])
|
||
|
||
batch = self.service.new_batch_http_request(callback=list_callback)
|
||
i = 0
|
||
for event in events:
|
||
events_by_req.append(event)
|
||
batch.add(self.service.events().list(calendarId=self.calendarId,
|
||
iCalUID=event['iCalUID'], showDeleted=True, fields='id,iCalUID,updated'), request_id=str(i))
|
||
i += 1
|
||
batch.execute()
|
||
self.logger.info('%d events exists, %d not found',
|
||
len(exists), len(not_found))
|
||
return exists, not_found
|
||
|
||
def insert_events(self, events):
|
||
""" Вставка событий в GCAL
|
||
|
||
Arguments:
|
||
events -- список событий
|
||
"""
|
||
|
||
events_by_req = []
|
||
|
||
def insert_callback(request_id, response, exception):
|
||
if exception is not None:
|
||
event = events_by_req[int(request_id)]
|
||
self.logger.error('failed to insert event with UID: %s, exception: %s', event.get(
|
||
'UID'), str(exception))
|
||
else:
|
||
event = response
|
||
self.logger.info('event created, id: %s', event.get('id'))
|
||
|
||
batch = self.service.new_batch_http_request(callback=insert_callback)
|
||
i = 0
|
||
for event in events:
|
||
events_by_req.append(event)
|
||
batch.add(self.service.events().insert(
|
||
calendarId=self.calendarId, body=event, fields='id,iCalUID,updated'), request_id=str(i))
|
||
i += 1
|
||
batch.execute()
|
||
|
||
def patch_events(self, event_tuples):
|
||
""" Обновление (патч) событий в GCAL
|
||
|
||
Arguments:
|
||
calendarId -- ИД календаря
|
||
event_tuples -- список кортежей событий (новое, старое)
|
||
"""
|
||
|
||
events_by_req = []
|
||
|
||
def patch_callback(request_id, response, exception):
|
||
if exception is not None:
|
||
event = events_by_req[int(request_id)]
|
||
self.logger.error('failed to patch event with UID: %s, exception: %s', event.get(
|
||
'UID'), str(exception))
|
||
else:
|
||
event = response
|
||
self.logger.info('event patched, id: %s', event.get('id'))
|
||
|
||
batch = self.service.new_batch_http_request(callback=patch_callback)
|
||
i = 0
|
||
for event_new, event_old in event_tuples:
|
||
if 'id' not in event_old:
|
||
continue
|
||
events_by_req.append(event_new)
|
||
batch.add(self.service.events().patch(
|
||
calendarId=self.calendarId, eventId=event_old['id'], body=event_new), fields='id,iCalUID,updated', request_id=str(i))
|
||
i += 1
|
||
batch.execute()
|
||
|
||
def update_events(self, event_tuples):
|
||
""" Обновление событий в GCAL
|
||
|
||
Arguments:
|
||
event_tuples -- список кортежей событий (новое, старое)
|
||
"""
|
||
|
||
events_by_req = []
|
||
|
||
def update_callback(request_id, response, exception):
|
||
if exception is not None:
|
||
event = events_by_req[int(request_id)]
|
||
self.logger.error('failed to update event with UID: %s, exception: %s', event.get(
|
||
'UID'), str(exception))
|
||
else:
|
||
event = response
|
||
self.logger.info('event updated, id: %s', event.get('id'))
|
||
|
||
batch = self.service.new_batch_http_request(callback=update_callback)
|
||
i = 0
|
||
for event_new, event_old in event_tuples:
|
||
if 'id' not in event_old:
|
||
continue
|
||
events_by_req.append(event_new)
|
||
batch.add(self.service.events().update(
|
||
calendarId=self.calendarId, eventId=event_old['id'], body=event_new, fields='id,iCalUID,updated'), request_id=str(i))
|
||
i += 1
|
||
batch.execute()
|
||
|
||
def delete_events(self, events):
|
||
""" Удаление событий в GCAL
|
||
|
||
Arguments:
|
||
events -- список событий
|
||
"""
|
||
|
||
events_by_req = []
|
||
|
||
def delete_callback(request_id, _, exception):
|
||
event = events_by_req[int(request_id)]
|
||
if exception is not None:
|
||
self.logger.error('failed to delete event with UID: %s, exception: %s', event.get(
|
||
'UID'), str(exception))
|
||
else:
|
||
self.logger.info('event deleted, id: %s', event.get('id'))
|
||
|
||
batch = self.service.new_batch_http_request(callback=delete_callback)
|
||
i = 0
|
||
for event in events:
|
||
events_by_req.append(event)
|
||
batch.add(self.service.events().delete(
|
||
calendarId=self.calendarId, eventId=event['id']), request_id=str(i))
|
||
i += 1
|
||
batch.execute()
|
||
|
||
def make_public(self):
|
||
rule_public = {
|
||
'scope': {
|
||
'type': 'default',
|
||
},
|
||
'role': 'reader'
|
||
}
|
||
return self.service.acl().insert(calendarId=self.calendarId, body=rule_public).execute()
|
||
|
||
def add_owner(self, email):
|
||
rule_owner = {
|
||
'scope': {
|
||
'type': 'user',
|
||
'value': email,
|
||
},
|
||
'role': 'owner'
|
||
}
|
||
return self.service.acl().insert(calendarId=self.calendarId, body=rule_owner).execute()
|