Search code examples
pythongoogle-apigoogle-calendar-apigoogle-admin-sdkgoogle-api-python-client

Cannot transfer google calendar events using Google API Python SDK


I have created function that is supposed to move all events from one Google calendar to another. Here is how it looks like:

def merge_calendar(email_from, email_to, service):
    off_board_user_calendar = service.events().list(calendarId=email_from).execute()
    off_board_user_events = off_board_user_calendar.get('items', [])

    # I tried to use this code, to resolve this "You need to have reader access to this calendar." error,
    # but it didn't work
    #
    # rule = {
    #     'scope': {
    #         'type': 'user',
    #         'value': email_from,
    #     },
    #     'role': 'reader'
    # }
    #
    # created_rule = service.acl().insert(calendarId=email_from, body=rule).execute()
    # print(f'Updated ACL rule {created_rule}')

    for event in off_board_user_events:
        updated_event = service.events().move(
            calendarId=email_from,
            eventId=event['id'],
            destination=email_to
        ).execute()
        print(f'Event has been transferred: {updated_event["updated"]}')

    print('All events have been transferred successfully.')

Right after execution I get this error - "You need to have reader access to this calendar.". And so, as see from comment, I tried to resolve this error, but this commented code brings me another error - just "Forbidden".

I am not quite sure what I am doing wrong. How can I transfer all events from on calendar to another


Also I think it is important to mention how I create service entity. I was trying to do this using 2 methods:

  • Normal credentials:
creds = None

    if os.path.exists('token.json'):
        creds = Credentials.from_authorized_user_file('token.json', SCOPES[api_name])

    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(client_secret_file, SCOPES[api_name])
            creds = flow.run_local_server()

        with open('token.json', 'w') as token:
            token.write(creds.to_json())
if delegated_user is not None:
    credentials = service_account.Credentials.from_service_account_file(
        'service.json', scopes=SCOPES[api_name])
    creds = credentials.with_subject(delegated_user)

Both didn't work.

PS. Calendar scope I have is 'https://www.googleapis.com/auth/calendar'.

Thanks in advance!


Solution

  • Actually, there is no need to transfer event by event. It'll be enough just to update ACL, just like this:

    def merge_calendar(email_from, email_to, service):
        rule = {
            'scope': {
                'type': 'user',
                'value': email_to,
            },
            'role': 'owner'
        }
        service.acl().insert(calendarId=email_from, body=rule).execute()
    

    You will just get an email with proposition to add this calendar to your Google Calendar.

    Talking about authentication I had this user delegation:

    credentials = service_account.Credentials.from_service_account_file(
        'service.json', scopes=['https://www.googleapis.com/auth/calendar'])
    creds = credentials.with_subject(email_from)
    

    References