-
-
Notifications
You must be signed in to change notification settings - Fork 44
feat: [WIP] Automate GDrive Access for approved volunteers #114
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -278,3 +278,9 @@ | |
|
||
MEDIA_URL = "/media/" # URL to serve media files | ||
MEDIA_ROOT = os.path.join(BASE_DIR, "media") # Local filesystem path | ||
|
||
# Google Drive Settings | ||
GOOGLE_SERVICE_ACCOUNT_FILE = os.path.join( | ||
BASE_DIR, "krishnapachauri-208910-574aa1e639b3.json" | ||
) | ||
GOOGLE_DRIVE_FOLDER_ID = "18P_t0wpEXuMQyQkZJxccsacOh-eelLDk" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use env var instead of hardcoding There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I’ve make it a test version to verify the logic is correct or not, will fix it once we agree that this is what we gonna do. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
import logging | ||
|
||
from django.conf import settings | ||
from google.oauth2 import service_account | ||
from googleapiclient.discovery import build | ||
from googleapiclient.errors import HttpError | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
SCOPES = ["https://www.googleapis.com/auth/drive"] | ||
SERVICE_ACCOUNT_FILE = settings.GOOGLE_SERVICE_ACCOUNT_FILE | ||
FOLDER_ID = settings.GOOGLE_DRIVE_FOLDER_ID | ||
|
||
|
||
def validate_folder_id(): | ||
service = get_gdrive_service() | ||
try: | ||
service.files().get(fileId=FOLDER_ID, fields="id,name").execute() | ||
return True | ||
except HttpError as e: | ||
if e.resp.status == 404: | ||
logger.error( | ||
f"Folder ID {FOLDER_ID} not found. Please check the folder ID in settings." | ||
) | ||
else: | ||
logger.error(f"Error validating folder ID: {str(e)}") | ||
return False | ||
except Exception as e: | ||
logger.error(f"Unexpected error validating folder ID: {str(e)}") | ||
return False | ||
|
||
|
||
def get_gdrive_service(): | ||
credentials = service_account.Credentials.from_service_account_file( | ||
SERVICE_ACCOUNT_FILE, scopes=SCOPES | ||
) | ||
return build("drive", "v3", credentials=credentials) | ||
|
||
|
||
def add_to_gdrive(email): | ||
service = get_gdrive_service() | ||
try: | ||
if not validate_folder_id(): | ||
logger.error(f"Cannot add {email} to GDrive: Invalid folder ID") | ||
return | ||
|
||
permissions = ( | ||
service.permissions() | ||
.list(fileId=FOLDER_ID, fields="permissions(id, emailAddress)") | ||
.execute() | ||
.get("permissions", []) | ||
) | ||
|
||
existing = [p for p in permissions if p.get("emailAddress") == email] | ||
|
||
if existing: | ||
logger.info(f"Email {email} already has access.") | ||
return | ||
|
||
permission = {"type": "user", "role": "writer", "emailAddress": email} | ||
|
||
result = ( | ||
service.permissions() | ||
.create( | ||
fileId=FOLDER_ID, | ||
body=permission, | ||
fields="id", | ||
sendNotificationEmail=False, | ||
) | ||
.execute() | ||
) | ||
|
||
logger.info(f"Added {email} to GDrive with permission ID: {result.get('id')}") | ||
|
||
except HttpError as e: | ||
if e.resp.status == 404: | ||
logger.error( | ||
f"Google API error adding {email}: Folder not found. Check GOOGLE_DRIVE_FOLDER_ID in settings." | ||
) | ||
else: | ||
logger.error(f"Google API error adding {email}: {str(e)}") | ||
except Exception as e: | ||
logger.error(f"Error adding {email} to GDrive: {str(e)}") | ||
|
||
|
||
def remove_from_gdrive(email): | ||
service = get_gdrive_service() | ||
try: | ||
if not validate_folder_id(): | ||
logger.error(f"Cannot remove {email} from GDrive: Invalid folder ID") | ||
return | ||
|
||
permissions = ( | ||
service.permissions() | ||
.list(fileId=FOLDER_ID, fields="permissions(id, emailAddress)") | ||
.execute() | ||
.get("permissions", []) | ||
) | ||
|
||
target_permissions = [p for p in permissions if p.get("emailAddress") == email] | ||
|
||
if not target_permissions: | ||
logger.info(f"No permissions found for {email} to remove") | ||
return | ||
|
||
for p in target_permissions: | ||
service.permissions().delete( | ||
fileId=FOLDER_ID, permissionId=p["id"] | ||
).execute() | ||
logger.info(f"Removed {email} from GDrive (permission ID: {p['id']})") | ||
|
||
except HttpError as e: | ||
if e.resp.status == 404: | ||
logger.error( | ||
f"Google API error removing {email}: Folder not found. Check GOOGLE_DRIVE_FOLDER_ID in settings." | ||
) | ||
else: | ||
logger.error(f"Google API error removing {email}: {str(e)}") | ||
except Exception as e: | ||
logger.error(f"Error removing {email} from GDrive: {str(e)}") |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
from django.db.models.signals import post_save, pre_save | ||
from django.dispatch import receiver | ||
|
||
from .constants import ApplicationStatus | ||
from .gdrive_utils import add_to_gdrive, remove_from_gdrive | ||
from .models import VolunteerProfile | ||
|
||
|
||
@receiver(pre_save, sender=VolunteerProfile) | ||
def track_approval_status(sender, instance, **kwargs): | ||
"""Capture previous status before save""" | ||
try: | ||
original = VolunteerProfile.objects.get(pk=instance.pk) | ||
instance._original_application_status = original.application_status | ||
except VolunteerProfile.DoesNotExist: | ||
instance._original_application_status = None | ||
|
||
|
||
@receiver(post_save, sender=VolunteerProfile) | ||
def handle_approval_status(sender, instance, **kwargs): | ||
"""Handle GDrive access based on status changes""" | ||
original_status = instance._original_application_status | ||
new_status = instance.application_status | ||
|
||
email = instance.user.email | ||
|
||
if new_status == ApplicationStatus.APPROVED: | ||
# New approval or re-approval | ||
if original_status != ApplicationStatus.APPROVED and email: | ||
add_to_gdrive(email) | ||
else: | ||
# Revoked approval | ||
if original_status == ApplicationStatus.APPROVED and email: | ||
remove_from_gdrive(email) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use env var instead of hardcoding