Skip to content

Commit b9e47de

Browse files
authored
Add Google Drive API (#81)
* add basic google drive api usage * finish off lightweight google api module
1 parent ed02b60 commit b9e47de

File tree

8 files changed

+138
-2
lines changed

8 files changed

+138
-2
lines changed

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1+
# main
12
src/run/
23
logs/
34

5+
# google drive api
6+
google_key.json
7+
48
# Python - Byte-compiled / optimized / DLL files
59
__pycache__/
610
*.py[cod]

requirements.txt

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ uvicorn[standard]==0.27.1
55
sqlalchemy==2.0.27
66
asyncpg==0.29.0
77
alembic==1.13.1
8+
google-api-python-client==2.143.0
89

910
# minor
1011
pyOpenSSL==24.0.0 # for generating cryptographically secure random numbers

src/google_api/__init__.py

Whitespace-only changes.

src/google_api/constants.py

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import os
2+
import pathlib
3+
4+
# this google account runs the google workspace for executives
5+
GOOGLE_WORKSPACE_ACCOUNT = "[email protected]"
6+
7+
# any officer from the past 5 semesters has access to these
8+
# TODO: ask the pres if we still want these rules, or not
9+
FIVE_SEM_OFFICER_ACCESS = [
10+
"CSSS@SFU",
11+
]
12+
13+
EXECUTIVE_ACCESS = [
14+
"CSSS Gallery",
15+
"CSSS@SFU",
16+
"Deep-Exec",
17+
"Exec_Photos",
18+
"Private Gallery",
19+
]
20+
21+
# scopes are like permissions to google
22+
GOOGLE_API_SCOPES = [
23+
# google drive permission
24+
"https://www.googleapis.com/auth/drive"
25+
]
26+
27+
# TODO: make this into an enum, or something
28+
GOOGLE_DRIVE_PERMISSION_ROLES = [
29+
"organizer",
30+
"fileOrganizer",
31+
]
32+
33+
_this_file_path = pathlib.Path(__file__).parent.resolve()
34+
SERVICE_ACCOUNT_KEY_PATH = str((_this_file_path / "../../google_key.json").resolve())

src/google_api/internals.py

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# google workspace (shared drives) + google drive api
2+
3+
from google.oauth2 import service_account
4+
from googleapiclient.discovery import build
5+
6+
from google_api.constants import GOOGLE_API_SCOPES, GOOGLE_WORKSPACE_ACCOUNT, SERVICE_ACCOUNT_KEY_PATH
7+
8+
# TODO: understand how these work
9+
credentials = service_account.Credentials.from_service_account_file(
10+
filename=SERVICE_ACCOUNT_KEY_PATH,
11+
scopes=GOOGLE_API_SCOPES
12+
)
13+
delegated_credentials = credentials.with_subject(GOOGLE_WORKSPACE_ACCOUNT)
14+
service = build("drive", "v3", credentials=delegated_credentials)
15+
16+
def _list_shared_drives() -> list:
17+
return (
18+
service
19+
.drives()
20+
.list(
21+
#pageSize = 50,
22+
#q = "name contains 'CSSS'",
23+
#useDomainAdminAccess = True,
24+
)
25+
.execute()
26+
)
27+
28+
def list_drive_permissions(drive_id: str) -> list:
29+
return (
30+
service
31+
.permissions()
32+
.list(
33+
fileId = drive_id,
34+
# important to find the shared drive
35+
supportsAllDrives = True,
36+
fields = "*",
37+
)
38+
.execute()
39+
)
40+
41+
def create_drive_permission(drive_id: str, permission: dict):
42+
return (
43+
service
44+
.permissions()
45+
.create(
46+
fileId = drive_id,
47+
48+
# TODO: update message
49+
emailMessage = "You were just given permission to an SFU CSSS shared google drive!",
50+
sendNotificationEmail = True,
51+
supportsAllDrives = True,
52+
53+
body=permission,
54+
)
55+
.execute()
56+
)
57+
58+
def delete_drive_permission(drive_id: str, permission_id: str):
59+
return (
60+
service
61+
.permissions()
62+
.delete(
63+
fileId = drive_id,
64+
permissionId = permission_id,
65+
supportsAllDrives = True,
66+
)
67+
.execute()
68+
)

src/officers/types.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,8 @@ def serializable_dict(self):
166166

167167
@staticmethod
168168
def from_data(
169-
term: officers.tables.OfficerTerm,
170-
officer_info: officers.tables.OfficerInfo,
169+
term: OfficerTerm,
170+
officer_info: OfficerInfo,
171171
include_private: bool,
172172
is_active: bool,
173173
) -> OfficerData:

src/utils.py

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import re
12
from datetime import datetime
23

34
from officers.tables import OfficerInfo, OfficerTerm
@@ -32,3 +33,6 @@ def is_valid_phone_number(phone_number: str) -> bool:
3233
len(phone_number) == 10
3334
and phone_number.isnumeric()
3435
)
36+
37+
def is_valid_email(email: str):
38+
return not re.match(r"^[^@]+@[^@]+\.[a-zA-Z]*$", email)

tests/integration/test_google.py

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from google_api import internals
2+
3+
4+
def test__list_drives():
5+
"""should not fail"""
6+
drive_list = internals._list_shared_drives()
7+
print(drive_list)
8+
9+
drive_id = drive_list["drives"][0]["id"]
10+
print(drive_id)
11+
12+
permissions = internals.list_drive_permissions(drive_id)
13+
print(permissions)
14+
15+
# NOTE: this will raise an exception if the email address is a non-google account
16+
"""
17+
internals.create_drive_permission(
18+
drive_id,
19+
{
20+
"type": "user",
21+
"emailAddress": "[email protected]",
22+
"role": "fileOrganizer",
23+
}
24+
)
25+
"""

0 commit comments

Comments
 (0)