From 36b4b9caeb34c730ad7fbb4262352e9a3eece424 Mon Sep 17 00:00:00 2001 From: wailbentafat Date: Sat, 14 Mar 2026 11:59:54 +0100 Subject: [PATCH 1/3] feat(minio): add the required minio buckets --- app/infra/minio.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/infra/minio.py b/app/infra/minio.py index 162e0f0..67e2cf7 100644 --- a/app/infra/minio.py +++ b/app/infra/minio.py @@ -11,8 +11,8 @@ IMAGES_BUCKET_NAME = "images" DOCUMENTS_BUCKET_NAME = "documents" -WA_SIM_BUCKET_NAME = "wa-sim" - +IMAGE_REQUEST_BUCKET_NAME = "image-request" +HOT_BUCKET_NAME = "hot" async def init_minio_client( minio_host: str, minio_port: int, minio_root_user: str, minio_root_password: str ) -> None: @@ -23,7 +23,7 @@ async def init_minio_client( secure=False, ) - for bucket_name in [IMAGES_BUCKET_NAME, DOCUMENTS_BUCKET_NAME, WA_SIM_BUCKET_NAME]: + for bucket_name in [IMAGES_BUCKET_NAME, DOCUMENTS_BUCKET_NAME, IMAGE_REQUEST_BUCKET_NAME, HOT_BUCKET_NAME]: if not await Bucket.client.bucket_exists(bucket_name): await Bucket.client.make_bucket(bucket_name) From e7427ae9e908c26967d3959cb13d2000ef7911ab Mon Sep 17 00:00:00 2001 From: wailbentafat Date: Sat, 14 Mar 2026 12:10:17 +0100 Subject: [PATCH 2/3] feat: Implement Google Drive file listing and import functionality for staff users. --- app/infra/google_drive.py | 104 +++++++++-- app/router/staff/drive.py | 43 +++++ app/schema/request/staff/drive.py | 11 ++ app/schema/response/staff/drive.py | 25 +++ app/service/staff_drive.py | 225 ++++++++++++++++++++++-- db/generated/staff_drive_connections.py | 48 +++++ db/queries/staff_drive_connections.sql | 11 ++ 7 files changed, 442 insertions(+), 25 deletions(-) create mode 100644 app/schema/request/staff/drive.py diff --git a/app/infra/google_drive.py b/app/infra/google_drive.py index a51413f..bb2ac82 100644 --- a/app/infra/google_drive.py +++ b/app/infra/google_drive.py @@ -5,6 +5,7 @@ import urllib.request from dataclasses import dataclass from datetime import datetime, timedelta, timezone +from typing import BinaryIO from app.core.exceptions import AppException from app.core.config import settings @@ -13,6 +14,8 @@ GOOGLE_AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth" GOOGLE_TOKEN_URL = "https://oauth2.googleapis.com/token" GOOGLE_USERINFO_URL = "https://www.googleapis.com/oauth2/v2/userinfo" +GOOGLE_DRIVE_FILES_URL = "https://www.googleapis.com/drive/v3/files" +GOOGLE_DRIVE_DEFAULT_LIST_FIELDS = "nextPageToken,files(id,name,mimeType,thumbnailLink,iconLink)" @dataclass @@ -87,20 +90,19 @@ async def exchange_code(code: str) -> GoogleTokenResponse: "grant_type": "authorization_code", } data = await GoogleDriveClient._post_form(GOOGLE_TOKEN_URL, payload) - expires_at = None - expires_in = data.get("expires_in") - if isinstance(expires_in, int): - expires_at = datetime.now(timezone.utc) + timedelta(seconds=expires_in) + return GoogleDriveClient._build_token_response(data) - return GoogleTokenResponse( - access_token=GoogleDriveClient._require_str(data, "access_token"), - refresh_token=GoogleDriveClient._optional_str(data, "refresh_token"), - expires_at=expires_at, - scope=GoogleDriveClient._optional_str(data, "scope") - or settings.GOOGLE_OAUTH_SCOPES, - token_type=GoogleDriveClient._optional_str(data, "token_type") - or "Bearer", - ) + @staticmethod + async def refresh_token(refresh_token: str) -> GoogleTokenResponse: + GoogleDriveClient.validate_settings() + payload = { + "refresh_token": refresh_token, + "client_id": settings.GOOGLE_CLIENT_ID, + "client_secret": settings.GOOGLE_CLIENT_SECRET, + "grant_type": "refresh_token", + } + data = await GoogleDriveClient._post_form(GOOGLE_TOKEN_URL, payload) + return GoogleDriveClient._build_token_response(data) @staticmethod async def get_user_info(access_token: str) -> GoogleUserInfo: @@ -114,6 +116,52 @@ async def get_user_info(access_token: str) -> GoogleUserInfo: verified_email=bool(data.get("verified_email", False)), ) + @staticmethod + async def list_files( + access_token: str, + query: str, + page_size: int = 30, + page_token: str | None = None, + fields: str | None = None, + ) -> dict[str, object]: + params: dict[str, str] = { + "q": query, + "pageSize": str(max(1, min(page_size, 1000))), + "fields": fields or GOOGLE_DRIVE_DEFAULT_LIST_FIELDS, + } + + if page_token: + params["pageToken"] = page_token + + return await GoogleDriveClient._get_json( + GOOGLE_DRIVE_FILES_URL, + params=params, + headers=GoogleDriveClient._auth_headers(access_token), + ) + + @staticmethod + async def download_file(access_token: str, file_id: str) -> BinaryIO: + def _request() -> BinaryIO: + url = f"{GOOGLE_DRIVE_FILES_URL}/{file_id}?alt=media" + request = urllib.request.Request( + url, + headers=GoogleDriveClient._auth_headers(access_token), + method="GET", + ) + try: + return urllib.request.urlopen(request, timeout=30) + except urllib.error.HTTPError as exc: + details = exc.read().decode("utf-8", errors="ignore") + raise AppException.bad_request( + f"Drive file download failed: {details or exc.reason}" + ) from exc + except urllib.error.URLError as exc: + raise AppException.internal_error( + "Unable to reach Google Drive API" + ) from exc + + return await asyncio.to_thread(_request) + @staticmethod async def _post_form(url: str, payload: dict[str, str]) -> dict[str, object]: encoded = urllib.parse.urlencode(payload).encode("utf-8") @@ -143,17 +191,22 @@ def _request() -> dict[str, object]: @staticmethod async def _get_json( url: str, + *, + params: dict[str, str] | None = None, headers: dict[str, str] | None = None, ) -> dict[str, object]: def _request() -> dict[str, object]: - request = urllib.request.Request(url, headers=headers or {}, method="GET") + target = url + if params: + target = f"{url}?{urllib.parse.urlencode(params, safe=',()')}" + request = urllib.request.Request(target, headers=headers or {}, method="GET") try: with urllib.request.urlopen(request, timeout=15) as response: return json.loads(response.read().decode("utf-8")) except urllib.error.HTTPError as exc: details = exc.read().decode("utf-8", errors="ignore") raise AppException.bad_request( - f"Google user info request failed: {details or exc.reason}" + f"Google API request failed: {details or exc.reason}" ) from exc except urllib.error.URLError as exc: raise AppException.internal_error( @@ -161,3 +214,24 @@ def _request() -> dict[str, object]: ) from exc return await asyncio.to_thread(_request) + + @staticmethod + def _auth_headers(access_token: str) -> dict[str, str]: + return {"Authorization": f"Bearer {access_token}"} + + @staticmethod + def _build_token_response(data: dict[str, object]) -> GoogleTokenResponse: + expires_at = None + expires_in = data.get("expires_in") + if isinstance(expires_in, int): + expires_at = datetime.now(timezone.utc) + timedelta(seconds=expires_in) + + return GoogleTokenResponse( + access_token=GoogleDriveClient._require_str(data, "access_token"), + refresh_token=GoogleDriveClient._optional_str(data, "refresh_token"), + expires_at=expires_at, + scope=GoogleDriveClient._optional_str(data, "scope") + or settings.GOOGLE_OAUTH_SCOPES, + token_type=GoogleDriveClient._optional_str(data, "token_type") + or "Bearer", + ) diff --git a/app/router/staff/drive.py b/app/router/staff/drive.py index 72daaef..7d78dd3 100644 --- a/app/router/staff/drive.py +++ b/app/router/staff/drive.py @@ -3,12 +3,16 @@ from app.container import Container, get_container from app.core.exceptions import AppException from app.deps.staff_auth import get_current_staff_user +from app.schema.request.staff.drive import GoogleDriveImportRequest from app.schema.response.staff.drive import ( GoogleDriveCallbackResponse, GoogleDriveConnectResponse, GoogleDriveConnectionStatusResponse, GoogleDriveDisconnectResponse, + GoogleDriveFileListResponse, + GoogleDriveImportResponse, ) +from app.service.staff_drive import SelectedDriveFile from db.generated.models import StaffUser @@ -61,6 +65,23 @@ async def google_drive_status( ) +@router.get("/files", response_model=GoogleDriveFileListResponse) +async def list_google_drive_files( + folder_id: str | None = Query(default=None, alias="folderId"), + page_token: str | None = Query(default=None, alias="pageToken"), + page_size: int = Query(default=30, alias="pageSize", ge=1, le=1000), + current_staff_user: StaffUser = Depends(get_current_staff_user), + container: Container = Depends(get_container), +) -> GoogleDriveFileListResponse: + payload = await container.staff_drive_service.list_drive_files( + staff_user=current_staff_user, + folder_id=folder_id, + page_token=page_token, + page_size=page_size, + ) + return GoogleDriveFileListResponse(**payload) + + @router.post("/disconnect", response_model=GoogleDriveDisconnectResponse) async def disconnect_google_drive( current_staff_user: StaffUser = Depends(get_current_staff_user), @@ -68,3 +89,25 @@ async def disconnect_google_drive( ) -> GoogleDriveDisconnectResponse: await container.staff_drive_service.disconnect(current_staff_user.id) return GoogleDriveDisconnectResponse(message="Google Drive disconnected successfully") + + +@router.post("/files/import", response_model=GoogleDriveImportResponse) +async def import_drive_files( + request: GoogleDriveImportRequest, + current_staff_user: StaffUser = Depends(get_current_staff_user), + container: Container = Depends(get_container), +) -> GoogleDriveImportResponse: + selections = [ + SelectedDriveFile( + id=file.id, + name=file.name, + mime_type=file.mime_type, + ) + for file in request.files + ] + + result = await container.staff_drive_service.import_images_from_drive( + staff_user=current_staff_user, + selected_files=selections, + ) + return GoogleDriveImportResponse(files=result) diff --git a/app/schema/request/staff/drive.py b/app/schema/request/staff/drive.py new file mode 100644 index 0000000..4d8060e --- /dev/null +++ b/app/schema/request/staff/drive.py @@ -0,0 +1,11 @@ +from pydantic import BaseModel, Field + + +class GoogleDriveImportFileSelection(BaseModel): + id: str + name: str + mime_type: str | None = Field(default=None, alias="mimeType") + + +class GoogleDriveImportRequest(BaseModel): + files: list[GoogleDriveImportFileSelection] = Field(default_factory=list) diff --git a/app/schema/response/staff/drive.py b/app/schema/response/staff/drive.py index 2a2c7ac..a0cdd36 100644 --- a/app/schema/response/staff/drive.py +++ b/app/schema/response/staff/drive.py @@ -23,3 +23,28 @@ class GoogleDriveCallbackResponse(BaseModel): class GoogleDriveDisconnectResponse(BaseModel): message: str + + +class GoogleDriveFileItem(BaseModel): + id: str + name: str + mime_type: str | None = Field(default=None, alias="mimeType") + thumbnail_link: str | None = Field(default=None, alias="thumbnailLink") + icon_link: str | None = Field(default=None, alias="iconLink") + + +class GoogleDriveFileListResponse(BaseModel): + files: list[GoogleDriveFileItem] + next_page_token: str | None = Field(default=None, alias="nextPageToken") + + +class GoogleDriveImportFileResult(BaseModel): + drive_file_id: str + original_file_name: str + minio_bucket: str + minio_object_name: str + minio_object_path: str + + +class GoogleDriveImportResponse(BaseModel): + files: list[GoogleDriveImportFileResult] diff --git a/app/service/staff_drive.py b/app/service/staff_drive.py index a82fc31..5c08c13 100644 --- a/app/service/staff_drive.py +++ b/app/service/staff_drive.py @@ -3,18 +3,50 @@ import json import secrets import uuid +from dataclasses import asdict, dataclass +from datetime import datetime, timedelta, timezone from cryptography.fernet import Fernet, InvalidToken from app.core.config import settings from app.core.exceptions import AppException from app.infra.google_drive import GoogleDriveClient +from app.infra.minio import ImageBucket from app.infra.redis import RedisClient from db.generated import staff_drive_connections as drive_queries from db.generated import stuff_user as staff_queries from db.generated.models import StaffDriveConnection, StaffUser +DRIVE_BUCKET_PREFIX = "staff-drive" +TOKEN_REFRESH_MARGIN = timedelta(minutes=5) + + +@dataclass +class DriveFilePreview: + id: str + name: str + mime_type: str | None + thumbnail_link: str | None + icon_link: str | None + + +@dataclass +class SelectedDriveFile: + id: str + name: str + mime_type: str | None + + +@dataclass +class DriveImportResult: + drive_file_id: str + original_file_name: str + minio_bucket: str + minio_object_name: str + minio_object_path: str + + class StaffDriveService: STATE_PREFIX = "google_drive_oauth_state:{state}" STATE_TTL_SECONDS = 600 @@ -67,23 +99,115 @@ async def handle_callback(self, code: str, state: str) -> StaffDriveConnection: connection = await self.drive_connection_querier.upsert_staff_drive_connection( arg=drive_queries.UpsertStaffDriveConnectionParams( - staff_user_id=staff_user.id, - provider=self.PROVIDER, - google_email=user_info.email, - google_account_id=user_info.id, - access_token=encrypted_access_token, - refresh_token=encrypted_refresh_token, - token_expires_at=token.expires_at, - scopes=token.scope, - + staff_user_id=staff_user.id, + provider=self.PROVIDER, + google_email=user_info.email, + google_account_id=user_info.id, + access_token=encrypted_access_token, + refresh_token=encrypted_refresh_token, + token_expires_at=token.expires_at, + scopes=token.scope, ) - ) if connection is None: raise AppException.internal_error("Failed to save Google Drive connection") return connection + async def list_drive_files( + self, + staff_user: StaffUser, + folder_id: str | None, + page_token: str | None, + page_size: int = 30, + ) -> dict[str, object]: + connection = await self.get_status(staff_user.id) + if connection is None: + raise AppException.not_found("Google Drive is not connected") + + access_token, _ = await self._ensure_valid_access_token(connection) + query = self._build_folder_query(folder_id) + response = await GoogleDriveClient.list_files( + access_token=access_token, + query=query, + page_size=page_size, + page_token=page_token, + ) + + raw_files = response.get("files") + files: list[dict[str, object]] = [] + if isinstance(raw_files, list): + for entry in raw_files: + if not isinstance(entry, dict): + continue + file_id = entry.get("id") + name = entry.get("name") + if not isinstance(file_id, str) or not file_id: + continue + if not isinstance(name, str) or not name: + continue + preview = DriveFilePreview( + id=file_id, + name=name, + mime_type=self._optional_str(entry, "mimeType"), + thumbnail_link=self._optional_str(entry, "thumbnailLink"), + icon_link=self._optional_str(entry, "iconLink"), + ) + files.append(asdict(preview)) + + return { + "files": files, + "nextPageToken": self._optional_str(response, "nextPageToken"), + } + + async def import_images_from_drive( + self, + staff_user: StaffUser, + selected_files: list[SelectedDriveFile], + ) -> list[dict[str, object]]: + if not selected_files: + return [] + + connection = await self.get_status(staff_user.id) + if connection is None: + raise AppException.not_found("Google Drive is not connected") + + access_token, _ = await self._ensure_valid_access_token(connection) + bucket = ImageBucket(f"{DRIVE_BUCKET_PREFIX}/{staff_user.id}") + results: list[dict[str, object]] = [] + + for selected in selected_files: + drive_stream = await GoogleDriveClient.download_file( + access_token=access_token, + file_id=selected.id, + ) + object_name = self._generate_object_name(selected.name) + prefixed_object_name = self._prefixed_object_name(bucket.file_prefix, object_name) + content_type = selected.mime_type or "application/octet-stream" + try: + await bucket.client.put_object( + bucket_name=bucket.bucket_name, + object_name=prefixed_object_name, + data=drive_stream, + length=-1, + part_size=10 * 1024 * 1024, + content_type=content_type, + metadata={"filename": selected.name}, + ) + finally: + drive_stream.close() + + result = DriveImportResult( + drive_file_id=selected.id, + original_file_name=selected.name, + minio_bucket=bucket.bucket_name, + minio_object_name=object_name, + minio_object_path=prefixed_object_name, + ) + results.append(asdict(result)) + + return results + async def get_status(self, staff_user_id: uuid.UUID) -> StaffDriveConnection | None: return await self.drive_connection_querier.get_active_staff_drive_connection_by_staff_user_id( staff_user_id=staff_user_id, @@ -109,6 +233,87 @@ def decrypt(self, encrypted_value: str) -> str: except InvalidToken as exc: raise AppException.internal_error("Stored Google Drive token cannot be decrypted") from exc + async def _ensure_valid_access_token( + self, + connection: StaffDriveConnection, + ) -> tuple[str, StaffDriveConnection]: + expires_at = connection.token_expires_at + if expires_at is not None and expires_at.tzinfo is None: + expires_at = expires_at.replace(tzinfo=timezone.utc) + + if ( + expires_at is not None + and expires_at - TOKEN_REFRESH_MARGIN > datetime.now(timezone.utc) + ): + return self.decrypt(connection.access_token), connection + + return await self._refresh_connection(tokens=connection) + + async def _refresh_connection( + self, + tokens: StaffDriveConnection, + ) -> tuple[str, StaffDriveConnection]: + if tokens.refresh_token is None: + raise AppException.bad_request( + "Google Drive refresh token is missing; reconnect to continue" + ) + + refresh_token = self.decrypt(tokens.refresh_token) + fresh_token = await GoogleDriveClient.refresh_token(refresh_token) + encrypted_access_token = self._encrypt(fresh_token.access_token) + encrypted_refresh_token = ( + self._encrypt(fresh_token.refresh_token) + if fresh_token.refresh_token + else tokens.refresh_token + ) + + updated_connection = ( + await self.drive_connection_querier.update_staff_drive_connection_tokens( + arg=drive_queries.UpdateStaffDriveConnectionTokensParams( + staff_user_id=tokens.staff_user_id, + provider=self.PROVIDER, + access_token=encrypted_access_token, + refresh_token=encrypted_refresh_token, + token_expires_at=fresh_token.expires_at, + ) + ) + ) + if updated_connection is None: + raise AppException.internal_error( + "Unable to refresh Google Drive connection tokens" + ) + + return self.decrypt(encrypted_access_token), updated_connection + + @staticmethod + def _optional_str(data: dict[str, object], key: str) -> str | None: + value = data.get(key) + if value is None: + return None + if not isinstance(value, str): + return None + return value + + @staticmethod + def _build_folder_query(folder_id: str | None) -> str: + if folder_id: + return f"'{folder_id}' in parents and trashed=false" + return "'root' in parents and trashed=false" + + @staticmethod + def _generate_object_name(filename: str) -> str: + if "." in filename: + suffix = filename[filename.rfind(".") :] + else: + suffix = "" + return f"{uuid.uuid4()}{suffix}" + + @staticmethod + def _prefixed_object_name(prefix: str, object_name: str) -> str: + if prefix: + return f"{prefix}/{object_name}" + return object_name + def _fernet(self) -> Fernet: digest = hashlib.sha256(settings.encryption_key.encode("utf-8")).digest() return Fernet(base64.urlsafe_b64encode(digest)) diff --git a/db/generated/staff_drive_connections.py b/db/generated/staff_drive_connections.py index b62fe1e..3974ed3 100644 --- a/db/generated/staff_drive_connections.py +++ b/db/generated/staff_drive_connections.py @@ -32,6 +32,28 @@ """ +UPDATE_STAFF_DRIVE_CONNECTION_TOKENS = """-- name: update_staff_drive_connection_tokens \\:one +UPDATE staff_drive_connections +SET access_token = :p3, + refresh_token = :p4, + token_expires_at = :p5, + updated_at = NOW() +WHERE staff_user_id = :p1 + AND provider = :p2 + AND revoked_at IS NULL +RETURNING id, staff_user_id, provider, google_email, google_account_id, access_token, refresh_token, token_expires_at, scopes, connected_at, revoked_at, created_at, updated_at +""" + + +@dataclasses.dataclass() +class UpdateStaffDriveConnectionTokensParams: + staff_user_id: uuid.UUID + provider: str + access_token: str + refresh_token: Optional[str] + token_expires_at: Optional[datetime.datetime] + + UPSERT_STAFF_DRIVE_CONNECTION = """-- name: upsert_staff_drive_connection \\:one INSERT INTO staff_drive_connections ( staff_user_id, @@ -102,6 +124,32 @@ async def get_active_staff_drive_connection_by_staff_user_id(self, *, staff_user async def revoke_staff_drive_connection_by_staff_user_id(self, *, staff_user_id: uuid.UUID, provider: str) -> None: await self._conn.execute(sqlalchemy.text(REVOKE_STAFF_DRIVE_CONNECTION_BY_STAFF_USER_ID), {"p1": staff_user_id, "p2": provider}) + async def update_staff_drive_connection_tokens(self, arg: UpdateStaffDriveConnectionTokensParams) -> Optional[models.StaffDriveConnection]: + row = (await self._conn.execute(sqlalchemy.text(UPDATE_STAFF_DRIVE_CONNECTION_TOKENS), { + "p1": arg.staff_user_id, + "p2": arg.provider, + "p3": arg.access_token, + "p4": arg.refresh_token, + "p5": arg.token_expires_at, + })).first() + if row is None: + return None + return models.StaffDriveConnection( + id=row[0], + staff_user_id=row[1], + provider=row[2], + google_email=row[3], + google_account_id=row[4], + access_token=row[5], + refresh_token=row[6], + token_expires_at=row[7], + scopes=row[8], + connected_at=row[9], + revoked_at=row[10], + created_at=row[11], + updated_at=row[12], + ) + async def upsert_staff_drive_connection(self, arg: UpsertStaffDriveConnectionParams) -> Optional[models.StaffDriveConnection]: row = (await self._conn.execute(sqlalchemy.text(UPSERT_STAFF_DRIVE_CONNECTION), { "p1": arg.staff_user_id, diff --git a/db/queries/staff_drive_connections.sql b/db/queries/staff_drive_connections.sql index fe12528..d79ad6c 100644 --- a/db/queries/staff_drive_connections.sql +++ b/db/queries/staff_drive_connections.sql @@ -41,3 +41,14 @@ SET revoked_at = NOW(), WHERE staff_user_id = $1 AND provider = $2 AND revoked_at IS NULL; + +-- name: UpdateStaffDriveConnectionTokens :one +UPDATE staff_drive_connections +SET access_token = $3, + refresh_token = $4, + token_expires_at = $5, + updated_at = NOW() +WHERE staff_user_id = $1 + AND provider = $2 + AND revoked_at IS NULL +RETURNING id, staff_user_id, provider, google_email, google_account_id, access_token, refresh_token, token_expires_at, scopes, connected_at, revoked_at, created_at, updated_at; From 275adf43d7499183263b20f3af32ad2d1636265c Mon Sep 17 00:00:00 2001 From: wailbentafat Date: Sun, 15 Mar 2026 11:14:29 +0100 Subject: [PATCH 3/3] chore: Add example Google OAuth credentials to `.env.example` and comment out staff user dependency in drive routes. --- .env.example | 4 ++-- app/router/staff/drive.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.env.example b/.env.example index 5490735..2c695a3 100644 --- a/.env.example +++ b/.env.example @@ -30,7 +30,7 @@ jwt_algorithm=HS256 encryption_key=super_secret_encryption_key totp_issuer=MultiAI -GOOGLE_CLIENT_ID= -GOOGLE_CLIENT_SECRET= +GOOGLE_CLIENT_ID=817881186650-a2id6qrap9q70idfhjro7ch54j5qv98r.apps.googleusercontent.com +GOOGLE_CLIENT_SECRET=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 GOOGLE_REDIRECT_URI=http://localhost:8000/staff/drive/callback GOOGLE_OAUTH_SCOPES=https://www.googleapis.com/auth/drive.readonly openid email profile diff --git a/app/router/staff/drive.py b/app/router/staff/drive.py index 7d78dd3..61ee09c 100644 --- a/app/router/staff/drive.py +++ b/app/router/staff/drive.py @@ -70,7 +70,7 @@ async def list_google_drive_files( folder_id: str | None = Query(default=None, alias="folderId"), page_token: str | None = Query(default=None, alias="pageToken"), page_size: int = Query(default=30, alias="pageSize", ge=1, le=1000), - current_staff_user: StaffUser = Depends(get_current_staff_user), + # current_staff_user: StaffUser = Depends(get_current_staff_user), container: Container = Depends(get_container), ) -> GoogleDriveFileListResponse: payload = await container.staff_drive_service.list_drive_files( @@ -84,7 +84,7 @@ async def list_google_drive_files( @router.post("/disconnect", response_model=GoogleDriveDisconnectResponse) async def disconnect_google_drive( - current_staff_user: StaffUser = Depends(get_current_staff_user), + # current_staff_user: StaffUser = Depends(get_current_staff_user), container: Container = Depends(get_container), ) -> GoogleDriveDisconnectResponse: await container.staff_drive_service.disconnect(current_staff_user.id) @@ -94,7 +94,7 @@ async def disconnect_google_drive( @router.post("/files/import", response_model=GoogleDriveImportResponse) async def import_drive_files( request: GoogleDriveImportRequest, - current_staff_user: StaffUser = Depends(get_current_staff_user), + # current_staff_user: StaffUser = Depends(get_current_staff_user), container: Container = Depends(get_container), ) -> GoogleDriveImportResponse: selections = [