0

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!

dokichan
  • 857
  • 2
  • 11
  • 44
  • The error you are getting makes me think you don't have reader access to either the source or the destination calendar. Have you checked whether you have access? – Iamblichus Oct 12 '22 at 12:16

2 Answers2

0

Some things that you might look at:

  1. Check the Domain Wide Delegation in your admin console and make sure that the service account ID is the same service account that you are using in your code.
  2. Add the scope that you mentioned in your question 'https://www.googleapis.com/auth/calendar' which is the most restricted scope on the Calendar API.
  3. Try to delegate the user with credentials.create_delegated(email) instead of credentials.with_subject(delegated_user).
Sunderam Dubey
  • 1
  • 11
  • 20
  • 40
Ahmad Othman
  • 853
  • 5
  • 18
0

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

dokichan
  • 857
  • 2
  • 11
  • 44