AdarshDRC commited on
Commit
ef7075f
·
verified ·
1 Parent(s): 318f9d2

Create explorer.py

Browse files
Files changed (1) hide show
  1. src/api/explorer.py +123 -0
src/api/explorer.py ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio
2
+
3
+ from fastapi import APIRouter, Form, HTTPException, Request, Depends
4
+
5
+ from src.core.config import DEFAULT_PINECONE_KEY, IDX_FACES, IDX_OBJECTS
6
+ from src.core.security import get_verified_keys
7
+ from src.services.db_client import (
8
+ cld_delete_folder_resources, cld_delete_resource, cld_list_folder_images,
9
+ cld_remove_folder, cld_root_folders, pinecone_pool,
10
+ )
11
+ from src.core.logging import log, warn
12
+ from src.common.utils import cld_thumb_url, get_ip, url_to_public_id
13
+
14
+ router = APIRouter()
15
+
16
+ @router.post("/api/categories")
17
+ async def get_categories(
18
+ request: Request,
19
+ user_id: str = Form(""),
20
+ keys: dict = Depends(get_verified_keys)
21
+ ):
22
+ ip = get_ip(request)
23
+ try:
24
+ result = await asyncio.to_thread(cld_root_folders, keys["cloudinary_creds"])
25
+ categories = [f["name"] for f in result.get("folders", [])]
26
+ log("INFO", "categories.fetched", user_id=user_id or "anonymous", ip=ip, count=len(categories))
27
+ return {"categories": categories}
28
+ except Exception as e:
29
+ log("ERROR", "categories.error", user_id=user_id or "anonymous", ip=ip, error=str(e))
30
+ return {"categories": []}
31
+
32
+ @router.post("/api/cloudinary/folder-images")
33
+ async def list_folder_images(
34
+ request: Request,
35
+ folder_name: str = Form(...),
36
+ user_id: str = Form(""),
37
+ next_cursor: str = Form(""),
38
+ page_size: int = Form(100),
39
+ keys: dict = Depends(get_verified_keys)
40
+ ):
41
+ ip = get_ip(request)
42
+ result = await asyncio.to_thread(
43
+ cld_list_folder_images,
44
+ folder_name, keys["cloudinary_creds"], next_cursor or None, page_size,
45
+ )
46
+ images = [
47
+ {
48
+ "url": r["secure_url"],
49
+ "thumb_url": cld_thumb_url(r["secure_url"]),
50
+ "public_id": r["public_id"],
51
+ }
52
+ for r in result.get("resources", [])
53
+ ]
54
+ next_cur = result.get("next_cursor") or ""
55
+ log("INFO", "explorer.folder_opened", user_id=user_id or "anonymous", ip=ip,
56
+ folder=folder_name, count=len(images), has_more=bool(next_cur))
57
+ return {"images": images, "count": len(images), "next_cursor": next_cur}
58
+
59
+ @router.post("/api/delete-image")
60
+ async def delete_image(
61
+ request: Request,
62
+ image_url: str = Form(""),
63
+ public_id: str = Form(""),
64
+ user_id: str = Form(""),
65
+ keys: dict = Depends(get_verified_keys)
66
+ ):
67
+ ip = get_ip(request)
68
+ pid = public_id or url_to_public_id(image_url)
69
+ if not pid:
70
+ raise HTTPException(400, "Could not determine public_id.")
71
+
72
+ await asyncio.to_thread(cld_delete_resource, pid, keys["cloudinary_creds"])
73
+
74
+ try:
75
+ pc = pinecone_pool.get(keys["pinecone_key"])
76
+ for idx_name in [IDX_OBJECTS, IDX_FACES]:
77
+ await asyncio.to_thread(
78
+ pc.Index(idx_name).delete, filter={"url": {"$eq": image_url}}
79
+ )
80
+ except Exception as e:
81
+ warn(f"Pinecone delete warning: {e}")
82
+
83
+ log("INFO", "explorer.image_deleted", user_id=user_id or "anonymous", ip=ip, image_url=image_url, public_id=pid)
84
+ return {"message": "Image deleted successfully."}
85
+
86
+ @router.post("/api/delete-folder")
87
+ async def delete_folder(
88
+ request: Request,
89
+ folder_name: str = Form(...),
90
+ user_id: str = Form(""),
91
+ keys: dict = Depends(get_verified_keys)
92
+ ):
93
+ ip = get_ip(request)
94
+ all_images, cursor = [], None
95
+ while True:
96
+ result = await asyncio.to_thread(cld_list_folder_images, folder_name, keys["cloudinary_creds"], cursor)
97
+ all_images.extend(result.get("resources", []))
98
+ cursor = result.get("next_cursor")
99
+ if not cursor:
100
+ break
101
+
102
+ await asyncio.to_thread(cld_delete_folder_resources, folder_name, keys["cloudinary_creds"])
103
+ await asyncio.to_thread(cld_remove_folder, folder_name, keys["cloudinary_creds"])
104
+
105
+ try:
106
+ pc = pinecone_pool.get(keys["pinecone_key"])
107
+ for idx_name in [IDX_OBJECTS, IDX_FACES]:
108
+ idx = pc.Index(idx_name)
109
+ try:
110
+ await asyncio.to_thread(idx.delete, filter={"folder": {"$eq": folder_name}})
111
+ except Exception:
112
+ for img in all_images:
113
+ url = img.get("secure_url", "")
114
+ if url:
115
+ try:
116
+ await asyncio.to_thread(idx.delete, filter={"url": {"$eq": url}})
117
+ except Exception:
118
+ pass
119
+ except Exception as e:
120
+ warn(f"Pinecone folder delete warning: {e}")
121
+
122
+ log("INFO", "explorer.folder_deleted", user_id=user_id or "anonymous", ip=ip, folder=folder_name, deleted_count=len(all_images))
123
+ return {"message": f"Folder '{folder_name}' and contents deleted.", "deleted_count": len(all_images)}