1
0
mirror of https://github.com/b4tman/sync_ics2gcal synced 2024-09-21 08:58:03 +00:00
sync_ics2gcal/gcal_sync/gcal.py

216 lines
8.1 KiB
Python
Raw Normal View History

2018-04-05 08:16:20 +00:00
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()