Search code examples
djangogoogle-oauthgoogle-calendar-apiservice-accountsdjango-signals

using google api eith django


I'm trying to connect events withing py project to google calendar. my application doesn't used google login as it is intended for only a small group of people. I've been looking for hours on how to get it done and it doesnt work. Any help is appreciated.

models.py

class AgendaClient(models.Model): # used to store info(same as enviroment variables)
    name = models.CharField(max_length=30, null=True, blank=True, unique=True)
    json = models.TextField(blank=True, null=True)

class Event(models.Model):
    summary = models.CharField(max_length=50, choices=EVENT_CHOICES)
    description = models.CharField(max_length=50, null=True, blank=True)
    start_date = models.DateField()
    google_link = models.CharField(max_length=150, null=True, blank=True)

signals.py

import datetime
import json

from django.db.models.signals import post_delete, post_save
from google.auth.transport.requests import Request
from google.cloud import storage
from google.oauth2 import service_account
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
from users.models import Lid

from .models import AgendaClient, Event, NIEvent

# If modifying these scopes, delete the file token.json.
try:
    SCOPES = (AgendaClient.objects.get(name='SCOPES').json).strip("][").split(', ')
except: pass
def get_service(refresh = False):
    '''this functions gets and builds the service using the token and the client_secret'''
    creds = None
    # The file token.json stores the user's access and refresh tokens, and is
    # created automatically when the authorization flow completes for the first
    # time.
    if len(AgendaClient.objects.filter(name='token'))==1:
            creds = Credentials.from_authorized_user_info(json.loads(AgendaClient.objects.get(name='token').json), SCOPES)
    else:
        # pprint(json.loads(AgendaClient.objects.get(name='service_account').json))
        creds = service_account.Credentials.from_service_account_info(json.loads(AgendaClient.objects.get(name='service_account').json), scopes=SCOPES)

    # Explicitly use service account credentials by specifying the private key
    # file.
    # If there are no (valid) credentials available, let the user log in.
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            # pprint(json.loads(AgendaClient.objects.get(name='client_secret').json))
            flow = InstalledAppFlow.from_client_config(
                    json.loads(AgendaClient.objects.get(name='client_secret').json), SCOPES)
            creds = flow.run_local_server(port=0)
            # creds = service_account.Credentials.from_service_account_info(json.loads(AgendaClient.objects.get(name='service_account').json), scopes=SCOPES)

    # Save the credentials for the next run
    AgendaClient.objects.update_or_create(name='token', defaults = {'json':creds.to_json()})
    if not refresh:
        service = build('calendar', 'v3', credentials=creds)
        return service
    
def handle_event(sender,created, instance=None,  **kwargs):
    """this function creates the events in the google agenda and updates them if changed in the website
    """
    service = get_service()
    evs = instance
    event ={
    'summary': evs.description,
    'location': evs.location or "",
    'description': (evs.description+' '+ evs.summary),
    'start': {
        'dateTime': datetime.datetime.combine(evs.start_date,evs.start_time).isoformat(),
        'timeZone': 'Europe/Amsterdam',
    },
    'end': {
        'dateTime':datetime.datetime.combine(evs.end_date,evs.end_time).isoformat() ,
        'timeZone': 'Europe/Amsterdam',
    },
    'recurrence': [],'reminders': {}}

    if created or not instance.google_link:
        try:
            event = service.events().insert(calendarId=AgendaClient.objects.get(name='calendarId').json, body=event).execute()
            instance.google_link = event['id']
            instance.save()
        except HttpError as error:
            print('An error occurred: %s' % error)
            pass
    else:  
        try:
            # print(type(AgendaClient.objects.get(name='calendarId').json))
            event = service.events().update(calendarId=AgendaClient.objects.get(name='calendarId').json, body=event, eventId = instance.google_link).execute()
        except HttpError as error:
            print('An error occurred: %s' % error)
            pass

post_save.connect(handle_event, sender=Event)

Ideally, I would use a service account so that users dont have to log in to google. Maybe someone knows a better solution than this but essentially the website should be able to add events to a calendar that users can follow but not add events to each user's calendar.


Solution

  • After looking every where i found the answer. I posted it under Google Calendar Integration with Django because thats where i got the majority of the info needed

    Thanks for the help