diff --git a/backend/core/settings.py b/backend/core/settings.py index c795b7c..0423a00 100644 --- a/backend/core/settings.py +++ b/backend/core/settings.py @@ -162,6 +162,15 @@ DATABASES = { } +# Cache + +CACHES = { + "default": { + "BACKEND": "django.core.cache.backends.db.DatabaseCache", + "LOCATION": "dbtest", + } +} + # Password validation # https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators diff --git a/backend/tasks/api.py b/backend/tasks/api.py new file mode 100644 index 0000000..94a2b8e --- /dev/null +++ b/backend/tasks/api.py @@ -0,0 +1,24 @@ +from datetime import datetime, timedelta +from django.utils import timezone + +from rest_framework import viewsets +from rest_framework.response import Response +from rest_framework.permissions import IsAuthenticated, AllowAny + +from googleapiclient.discovery import build + +from .serializers import GoogleCalendarEventSerializer +from users.access_token_cache import get_credential_from_cache_token + + +class GoogleCalendarEventViewset(viewsets.ViewSet): + permission_classes = (IsAuthenticated,) + + def list(self, request, days=7): + current_time = datetime.now(tz=timezone.utc).isoformat() + max_time = (datetime.now(tz=timezone.utc) + timedelta(days=days)).isoformat() + credentials = get_credential_from_cache_token(request.user.id) + service = build('calendar', 'v3', credentials=credentials) + events = service.events().list(calendarId='primary', timeMin=current_time, timeMax=max_time).execute() + + return Response(events.get('items', []), status=200) diff --git a/backend/tasks/serializers.py b/backend/tasks/serializers.py new file mode 100644 index 0000000..a9f03e2 --- /dev/null +++ b/backend/tasks/serializers.py @@ -0,0 +1,8 @@ +from rest_framework import serializers + + +class GoogleCalendarEventSerializer(serializers.Serializer): + summary = serializers.CharField() + start = serializers.DateTimeField() + end = serializers.DateTimeField() + description = serializers.CharField(required=False) \ No newline at end of file diff --git a/backend/tasks/urls.py b/backend/tasks/urls.py index ef94e06..2308167 100644 --- a/backend/tasks/urls.py +++ b/backend/tasks/urls.py @@ -1,11 +1,13 @@ from django.urls import path, include from rest_framework.routers import DefaultRouter +from .api import GoogleCalendarEventViewset from .tasks.views import TaskCreateView, TaskRetrieveView, TaskUpdateView, TaskDeleteView from .misc.views import TagViewSet, ReminderViewSet router = DefaultRouter() router.register(r'reminders', ReminderViewSet) router.register(r'tags', TagViewSet) +router.register(r'calendar-events', GoogleCalendarEventViewset, basename='calendar-events') urlpatterns = [ path('', include(router.urls)), diff --git a/backend/users/access_token_cache.py b/backend/users/access_token_cache.py new file mode 100644 index 0000000..37dada0 --- /dev/null +++ b/backend/users/access_token_cache.py @@ -0,0 +1,50 @@ +from django.core.cache import cache +from django.conf import settings + +from google.auth.transport.requests import Request +from google.oauth2.credentials import Credentials +from googleapiclient.discovery import build + +from .models import CustomUser + + +def store_token(user_id, token, token_type): + cache_key = f"user_{token_type}_token:{user_id}" + cache.set(cache_key, token, timeout=3600) + + +def get_credential_from_cache_token(user_id): + access_token = cache.get(f"user_access_token:{user_id}") + id_token = cache.get(f"user_id_token:{user_id}") + refresh_token = CustomUser.objects.get(id=user_id).refresh_token + scopes = [ + 'https://www.googleapis.com/auth/userinfo.email', + 'https://www.googleapis.com/auth/userinfo.profile', + 'https://www.googleapis.com/auth/calendar.readonly', + ] + # credentials = Credentials.from_authorized_user_info( + # { + # 'access_token': access_token, + # 'token_uri': 'https://oauth2.googleapis.com/token', + # 'refresh_token': refresh_token, + # 'client_id': settings.GOOGLE_CLIENT_ID, + # 'client_secret': settings.GOOGLE_CLIENT_SECRET, + # 'id_token': id_token, + # } + + credentials = Credentials(token=access_token, + refresh_token=refresh_token, + token_uri='https://oauth2.googleapis.com/token', + client_id=settings.GOOGLE_CLIENT_ID, + client_secret=settings.GOOGLE_CLIENT_SECRET, + scopes=scopes, + id_token=id_token + ) + + # If can refresh, refresh + if credentials.expired and credentials.refresh_token: + credentials.refresh(Request()) + store_token(user_id, credentials.token, 'access') + store_token(user_id, credentials.id_token, 'id') + + return credentials \ No newline at end of file diff --git a/backend/users/views.py b/backend/users/views.py index 591c609..a448ed2 100644 --- a/backend/users/views.py +++ b/backend/users/views.py @@ -19,6 +19,7 @@ from dj_rest_auth.registration.views import SocialLoginView from google_auth_oauthlib.flow import InstalledAppFlow +from .access_token_cache import store_token from .serializers import MyTokenObtainPairSerializer, CustomUserSerializer from .managers import CustomAccountManager from .models import CustomUser @@ -168,6 +169,8 @@ class GoogleRetrieveUserInfo(APIView): user.email = user_info['email'] user.refresh_token = user_info['refresh_token'] user.save() + store_token(user.id, user_info['access_token'], 'access') + store_token(user.id, user_info['id_token'], 'id') return user def call_google_api(self, api_url, access_token):