NotSoShabby
NotSoShabby

Reputation: 3698

using google service account to create public calendar

I have been trying to use a google service account to create a public calendar and then insert some events to it.

After making sure that the events are public ('visibility': 'public') I still couldn't access them. I then read that the calendar itself has to be public but in the google documentation there is no parameter for the insert function of a new calendar that allows creating it as a public calendar (docs).

Here is the small util class I wrote for this:

import json

from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build
from google.oauth2 import service_account


class CalendarUtils:
    SCOPES = ['https://www.googleapis.com/auth/calendar']
    SERVICE_ACCOUNT_FILE = 'token.json'
    CAL_MAPPING_JSON_PATH = 'calendar_mapping.json'

    def __init__(self):
        creds = service_account.Credentials.from_service_account_file(
            self.SERVICE_ACCOUNT_FILE, scopes=self.SCOPES)
        self.service = build('calendar', 'v3', credentials=creds)
        self.mapping = json.load(open(self.CAL_MAPPING_JSON_PATH))

    def list_all_calendars(self):
        res = self.service.calendarList().list().execute()
        return res['items']

    def create_new_calendar(self, location_name):
        calendar = {
            'summary': location_name,
            'timeZone': 'America/Los_Angeles',
            'visibility': 'public',
        }
        return self.service.calendars().insert(body=calendar).execute()

    def insert_event(self, location_name, event):
        exiting_calendars = [i['name'] for i in self.mapping['map']]
        if location_name not in exiting_calendars:
            calendar_id = self.create_new_calendar(location_name)['id']
            self.mapping['map'].append({'name': location_name, 'calendar_id': calendar_id})
            json.dump(self.mapping, open(self.CAL_MAPPING_JSON_PATH, 'w'))
        else:
            calendar_id = [i for i in self.mapping['map'] if i['name'] == location_name][0]['calendar_id']

        event = self.service.events().insert(calendarId=calendar_id, body=event).execute()
        print(f'Event created: {event.get("htmlLink")}')


if __name__ == '__main__':
    cal_util = CalendarUtils()
    event = {
        'summary': 'Google I/O 2015',
        'location': '800 Howard St., San Francisco, CA 94103',
        'description': 'A chance to hear more about Google\'s developer products.',
        'start': {
            'dateTime': '2015-05-28T09:00:00-07:00',
            'timeZone': 'America/Los_Angeles',
        },
        'end': {
            'dateTime': '2015-05-28T17:00:00-07:00',
            'timeZone': 'America/Los_Angeles',
        },
        'visibility': 'public',
        'privateCopy': False,
        'locked': False,
        'anyoneCanAddSelf': True,
    }
    cal_util.insert_event('test', event)

This creates the calendar and insert the event, but it is not public.

Upvotes: 0

Views: 254

Answers (1)

Nikko J.
Nikko J.

Reputation: 5533

To make a calendar public, you need to set scope type of the calendar Acl to default.

Example:

rules = {
  "role": "reader",
  "scope": {
    "type": "default",
  }
}
created_rule = service.acl().insert(calendarId='Insert calendar id here', body=rules).execute()

Here I created an event inside the calendar created using service account and where the Acl is applied

eventDetails = {
  'summary': '67407093 test event',
  'location': 'Dummy',
  'description': 'Dummy',
  'start': {
    'dateTime': '2021-05-28T09:00:00-07:00',
    'timeZone': 'America/Los_Angeles',
  },
  'end': {
    'dateTime': '2021-05-28T17:00:00-07:00',
    'timeZone': 'America/Los_Angeles',
  }
}

event = service.events().insert(calendarId='Insert calendar id here', body=eventDetails).execute()

Output:

enter image description here

Reference:

Upvotes: 1

Related Questions