diff --git a/README.md b/README.md index baf3fd5..90dd467 100644 --- a/README.md +++ b/README.md @@ -63,18 +63,23 @@ wget https://raw.githubusercontent.com/b4tman/sync_ics2gcal/develop/sample-confi ### Manage calendars ```sh -manage-ics2gcal [-h] [options] +manage-ics2gcal GROUP | COMMAND ``` -subcomands: +**GROUPS**: + +* **property** - get/set properties (see [CalendarList resource](https://developers.google.com/calendar/v3/reference/calendarList#resource)), subcommands: + - **get** - get calendar property + - **set** - set calendar property + +**COMMANDS**: * **list** - list calendars * **create** - create calendar * **add_owner** - add owner to calendar * **remove** - remove calendar * **rename** - rename calendar -* **get** - get calendar property (see [CalendarList resource](https://developers.google.com/calendar/v3/reference/calendarList#resource)) -* **set** - set calendar property + Use **-h** for more info. diff --git a/requirements.txt b/requirements.txt index bf22b57..08659f2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,3 +3,4 @@ google-api-python-client==2.3.0 icalendar==4.0.7 pytz==2021.1 PyYAML==5.4.1 +fire==0.4.0 \ No newline at end of file diff --git a/sync_ics2gcal/manage_calendars.py b/sync_ics2gcal/manage_calendars.py index a2c10a5..f3e9cdc 100644 --- a/sync_ics2gcal/manage_calendars.py +++ b/sync_ics2gcal/manage_calendars.py @@ -1,80 +1,16 @@ -import argparse import logging.config -from typing import Optional, Dict, Any +from typing import Optional, Dict, Any, List +import fire import yaml from . import GoogleCalendar, GoogleCalendarService -def parse_args(): - parser = argparse.ArgumentParser( - description="manage google calendars in service account") - command_subparsers = parser.add_subparsers(help='command', dest='command') - # list - parser_list = command_subparsers.add_parser('list', help='list calendars') - parser_list.add_argument( - '--show-hidden', default=False, - action='store_true', help='show hidden calendars') - parser_list.add_argument( - '--show-deleted', default=False, - action='store_true', help='show deleted calendars') - # create - parser_create = command_subparsers.add_parser( - 'create', help='create calendar') - parser_create.add_argument( - 'summary', action='store', help='new calendar summary') - parser_create.add_argument('--timezone', action='store', - default=None, required=False, - help='new calendar timezone') - parser_create.add_argument( - '--public', default=False, - action='store_true', help='make calendar public') - # add_owner - parser_add_owner = command_subparsers.add_parser( - 'add_owner', help='add owner to calendar') - parser_add_owner.add_argument('id', action='store', help='calendar id') - parser_add_owner.add_argument( - 'owner_email', action='store', help='new owner email') - # remove - parser_remove = command_subparsers.add_parser( - 'remove', help='remove calendar') - parser_remove.add_argument( - 'id', action='store', help='calendar id to remove') - # rename - parser_rename = command_subparsers.add_parser( - 'rename', help='rename calendar') - parser_rename.add_argument( - 'id', action='store', help='calendar id') - parser_rename.add_argument( - 'summary', action='store', help='new summary') - # get - parser_get = command_subparsers.add_parser( - 'get', help='get calendar property') - parser_get.add_argument( - 'id', action='store', help='calendar id') - parser_get.add_argument( - 'property', action='store', help='property key') - # set - parser_set = command_subparsers.add_parser( - 'set', help='set calendar property') - parser_set.add_argument( - 'id', action='store', help='calendar id') - parser_set.add_argument( - 'property', action='store', help='property key') - parser_set.add_argument( - 'property_value', action='store', help='property value') - - args = parser.parse_args() - if args.command is None: - parser.print_usage() - return args - - -def load_config() -> Optional[Dict[str, Any]]: +def load_config(filename: str) -> Optional[Dict[str, Any]]: result = None try: - with open('config.yml', 'r', encoding='utf-8') as f: + with open(filename, 'r', encoding='utf-8') as f: result = yaml.safe_load(f) except FileNotFoundError: pass @@ -82,87 +18,126 @@ def load_config() -> Optional[Dict[str, Any]]: return result -def list_calendars(service, show_hidden: bool, show_deleted: bool) -> None: - fields = 'nextPageToken,items(id,summary)' - calendars = [] - page_token = None - while True: - response = service.calendarList().list(fields=fields, - pageToken=page_token, - showHidden=show_hidden, - showDeleted=show_deleted - ).execute() - if 'items' in response: - calendars.extend(response['items']) - page_token = response.get('nextPageToken') - if not page_token: - break - for calendar in calendars: - print('{summary}: {id}'.format_map(calendar)) +class PropertyCommands: + """ get/set google calendar properties """ + + def __init__(self, _service): + self._service = _service + + def get(self, calendar_id: str, property_name: str) -> None: + """ get calendar property + + Args: + calendar_id: calendar id + property_name: property key + """ + response = self._service.calendarList().get(calendarId=calendar_id, + fields=property_name).execute() + print(response.get(property_name)) + + def set(self, calendar_id: str, property_name: str, property_value: str) -> None: + """ set calendar property + + Args: + calendar_id: calendar id + property_name: property key + property_value: property value + """ + body = {property_name: property_value} + response = self._service.calendarList().patch(body=body, calendarId=calendar_id).execute() + print(response) -def create_calendar(service, summary: str, timezone: str, public: bool) -> None: - calendar = GoogleCalendar(service, None) - calendar.create(summary, timezone) - if public: - calendar.make_public() - print('{}: {}'.format(summary, calendar.calendarId)) +class Commands: + """ manage google calendars in service account """ + def __init__(self, config: str = 'config.yml'): + """ -def add_owner(service, calendar_id: str, owner_email: str) -> None: - calendar = GoogleCalendar(service, calendar_id) - calendar.add_owner(owner_email) - print('to {} added owner: {}'.format(calendar_id, owner_email)) + Args: + config(str): config filename + """ + self._config: Optional[Dict[str, Any]] = load_config(config) + if self._config is not None and 'logging' in self._config: + logging.config.dictConfig(self._config['logging']) + self._service = GoogleCalendarService.from_config(self._config) + self.property = PropertyCommands(self._service) + def list(self, show_hidden: bool = False, show_deleted: bool = False) -> None: + """ list calendars -def remove_calendar(service, calendar_id: str) -> None: - calendar = GoogleCalendar(service, calendar_id) - calendar.delete() - print('removed: {}'.format(calendar_id)) + Args: + show_hidden: show hidden calendars + show_deleted: show deleted calendars + """ + fields: str = 'nextPageToken,items(id,summary)' + calendars: List[Dict[str, Any]] = [] + page_token: Optional[str] = None + while True: + calendars_api = self._service.calendarList() + response = calendars_api.list(fields=fields, + pageToken=page_token, + showHidden=show_hidden, + showDeleted=show_deleted + ).execute() + if 'items' in response: + calendars.extend(response['items']) + page_token = response.get('nextPageToken') + if page_token is None: + break + for calendar in calendars: + print('{summary}: {id}'.format_map(calendar)) -def rename_calendar(service, calendar_id: str, summary: str) -> None: - calendar = {'summary': summary} - service.calendars().patch(body=calendar, calendarId=calendar_id).execute() - print('{}: {}'.format(summary, calendar_id)) + def create(self, summary: str, timezone: Optional[str] = None, public: bool = False) -> None: + """ create calendar + Args: + summary: new calendar summary + timezone: new calendar timezone + public: make calendar public + """ + calendar = GoogleCalendar(self._service, None) + calendar.create(summary, timezone) + if public: + calendar.make_public() + print('{}: {}'.format(summary, calendar.calendarId)) -def get_calendar_property(service, calendar_id: str, property_name: str) -> None: - response = service.calendarList().get(calendarId=calendar_id, - fields=property_name).execute() - print(response.get(property_name)) + def add_owner(self, calendar_id: str, email: str) -> None: + """ add owner to calendar + Args: + calendar_id: calendar id + email: new owner email + """ + calendar = GoogleCalendar(self._service, calendar_id) + calendar.add_owner(email) + print('to {} added owner: {}'.format(calendar_id, email)) -def set_calendar_property(service, calendar_id: str, property_name: str, property_value: str) -> None: - body = {property_name: property_value} - response = service.calendarList().patch(body=body, calendarId=calendar_id).execute() - print(response) + def remove(self, calendar_id: str) -> None: + """ remove calendar + + Args: + calendar_id: calendar id + """ + calendar = GoogleCalendar(self._service, calendar_id) + calendar.delete() + print('removed: {}'.format(calendar_id)) + + def rename(self, calendar_id: str, summary: str) -> None: + """ rename calendar + + Args: + calendar_id: calendar id + summary: + """ + calendar = {'summary': summary} + self._service.calendars().patch(body=calendar, calendarId=calendar_id).execute() + print('{}: {}'.format(summary, calendar_id)) def main(): - args = parse_args() - config = load_config() - - if config is not None and 'logging' in config: - logging.config.dictConfig(config['logging']) - - service = GoogleCalendarService.from_config(config) - - if 'list' == args.command: - list_calendars(service, args.show_hidden, args.show_deleted) - elif 'create' == args.command: - create_calendar(service, args.summary, args.timezone, args.public) - elif 'add_owner' == args.command: - add_owner(service, args.id, args.owner_email) - elif 'remove' == args.command: - remove_calendar(service, args.id) - elif 'rename' == args.command: - rename_calendar(service, args.id, args.summary) - elif 'get' == args.command: - get_calendar_property(service, args.id, args.property) - elif 'set' == args.command: - set_calendar_property( - service, args.id, args.property, args.property_value) + fire.Fire(Commands, name='manage-ics2gcal') if __name__ == '__main__':