@@ -111,15 +111,19 @@ def _drive_extract_id(link_or_id: str) -> Optional[str]:
111111
112112def drive_find_or_create_folder (service , parent_id : str , name : str ) -> str :
113113 """Find a folder by name under parent; create if missing. Returns folder ID."""
114+ # Escape single quotes for Drive query syntax: name = '...'
115+ safe_name = (name or "" ).replace ("'" , "\\ '" )
116+
114117 q = (
115- f "mimeType='application/vnd.google-apps.folder' "
116- f"and name='{ name . replace ( \" ' \" , \" \\ ' \" ) } ' "
118+ "mimeType='application/vnd.google-apps.folder' "
119+ f"and name='{ safe_name } ' "
117120 f"and '{ parent_id } ' in parents and trashed=false"
118121 )
119122 res = service .files ().list (q = q , fields = "files(id,name)" , pageSize = 1 ).execute ()
120123 items = res .get ("files" , [])
121124 if items :
122125 return items [0 ]["id" ]
126+
123127 meta = {
124128 "name" : name ,
125129 "mimeType" : "application/vnd.google-apps.folder" ,
@@ -128,6 +132,7 @@ def drive_find_or_create_folder(service, parent_id: str, name: str) -> str:
128132 created = service .files ().create (body = meta , fields = "id" ).execute ()
129133 return created ["id" ]
130134
135+
131136def drive_ensure_property_tab_folder (service , root_folder_id : str , prop : str , tab : str ) -> str :
132137 """
133138 Ensures a structure: <root>/<prop>/<tab> exists, returns final folder ID.
@@ -236,74 +241,17 @@ def file_to_table_name(filename: str) -> str:
236241
237242#==================================================#
238243
239- # Google Drive integration using service account creds
240-
241- def drive ():
242- """Build a Drive service using service-account creds from env."""
243- sa_path = os .environ .get ("GDRIVE_SA_JSON" , "" ).strip ()
244- sa_b64 = os .environ .get ("GDRIVE_SA_JSON_BASE64" , "" ).strip ()
245- if sa_path and os .path .isfile (sa_path ):
246- creds = Credentials .from_service_account_file (sa_path , scopes = GDRIVE_SCOPES )
247- elif sa_b64 :
248- import base64 , json , tempfile
249- data = json .loads (base64 .b64decode (sa_b64 ).decode ("utf-8" ))
250- creds = Credentials .from_service_account_info (data , scopes = GDRIVE_SCOPES )
251- else :
252- raise RuntimeError ("No service account credentials provided (GDRIVE_SA_JSON or GDRIVE_SA_JSON_BASE64)." )
253- return build ("drive" , "v3" , credentials = creds , cache_discovery = False )
254-
255244def make_file_public (file_id : str ):
256245 """Ensure the file is readable by 'anyone with the link'."""
257- svc = drive ()
246+ svc = get_drive_service ()
258247 try :
259248 svc .permissions ().create (
260249 fileId = file_id ,
261250 body = {"role" : "reader" , "type" : "anyone" },
262251 fields = "id" ,
263252 ).execute ()
264253 except Exception :
265- # If permission already exists, ignore.
266- pass
267-
268- def drive_links (file_id : str ):
269- """Return (preview_url, download_url)."""
270- return (f"https://drive.google.com/file/d/{ file_id } /preview" ,
271- f"https://drive.google.com/uc?export=download&id={ file_id } " )
272-
273- def _is_folder (item ):
274- return item .get ("mimeType" ) == "application/vnd.google-apps.folder"
275-
276- def _drive_list_children (parent_id : str ):
277- """Yield children of a Drive folder."""
278- svc = drive ()
279- q = f"'{ parent_id } ' in parents and trashed=false"
280- token = None
281- while True :
282- resp = svc .files ().list (
283- q = q , spaces = "drive" ,
284- fields = "nextPageToken, files(id,name,mimeType,modifiedTime)" ,
285- pageToken = token , pageSize = 1000 ).execute ()
286- for f in resp .get ("files" , []):
287- yield f
288- token = resp .get ("nextPageToken" )
289- if not token :
290- break
291-
292- def _find_child_by_name (parent_id : str , name : str ):
293- for f in _drive_list_children (parent_id ):
294- if f .get ("name" ) == name :
295- return f
296- return None
297-
298- def _ensure_folder (parent_id : str , name : str ):
299- """Find or create a subfolder."""
300- svc = drive ()
301- existing = _find_child_by_name (parent_id , name )
302- if existing and _is_folder (existing ):
303- return existing ["id" ]
304- meta = {"name" : name , "mimeType" : "application/vnd.google-apps.folder" , "parents" : [parent_id ]}
305- created = svc .files ().create (body = meta , fields = "id" ).execute ()
306- return created ["id" ]
254+ pass # ignore if permission already exists
307255
308256#==================================================#
309257
0 commit comments