Skip to content

Commit

Permalink
Merge pull request #29 from K3A-Team/feat/sofiane/shared-storage
Browse files Browse the repository at this point in the history
Feat/sofiane/shared storage
  • Loading branch information
Soapiane authored Sep 17, 2024
2 parents e4cb058 + 8a66846 commit 870b91f
Show file tree
Hide file tree
Showing 5 changed files with 200 additions and 1 deletion.
30 changes: 30 additions & 0 deletions code/Core/Shared/Database.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from firebase_admin import credentials
from firebase_admin import firestore
import os
from google.cloud.firestore_v1 import FieldFilter, Or
from dotenv import load_dotenv
load_dotenv()

Expand Down Expand Up @@ -348,3 +349,32 @@ def setupRefs(cls: List[str]):
refs[collection] = db.collection("users")

return refs

@staticmethod
def createStorage(storage):
storageDict = storage.to_dict()
return db.collection("sharedStorage").document(storage.id).set(storageDict)

@staticmethod
async def getUserSharedStorages(userId):
col_ref = db.collection("sharedStorage")

# Create filters
filter_owner = FieldFilter("ownerId", "==", userId)
filter_read = FieldFilter("readIds", "array_contains", userId)
filter_write = FieldFilter("writeIds", "array_contains", userId)

print("Begun filtering")

# Create the union filter of the three filters
or_filter = Or(filters=[filter_owner, filter_read, filter_write])

print("Filtering")
# Execute the query
docs = col_ref.where(filter=or_filter).stream()

print("Filtered")

user_storages = [doc.to_dict() for doc in docs]

return user_storages
36 changes: 36 additions & 0 deletions code/Models/Entities/SharedStorage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from typing import List
import uuid
import datetime
class SharedStorage:
"""
Represents a shared storage in the file management system.
"""
def __init__(
self,
name: str,
imagePath: str,
rootFolderId: str,
ownerId: str,
readId : List[str],
writeId : List[str],
id : str = None,

):
self.id = id or str(uuid.uuid4())
self.name = name
self.ownerId = ownerId
self.imagePath = imagePath
self.rootFolderId = rootFolderId
self.readId = readId
self.writeId = writeId

def to_dict(self) -> dict:
return {
"id": self.id,
"name": self.name,
"imagePath": self.imagePath,
"rootFolderId": self.rootFolderId,
"ownerId": self.ownerId,
"readId": self.readId,
"writeId": self.writeId
}
33 changes: 33 additions & 0 deletions code/Routers/sharedStorageRouter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from fastapi import APIRouter, Depends
from Core.Shared.Storage import *
from Core.Shared.Security import *
from Core.Shared.Utils import *
from Core.Shared.ErrorResponses import *
from Middlewares.authProtectionMiddlewares import LoginProtected
from handlers.sharedStorageHandlers import getSharedStorage , createSharedStorage , getUserSharedStoragesHandler


# Create a new APIRouter instance for storage-related routes
sharedStorageRouter = APIRouter()

@sharedStorageRouter.get("/storage")
async def getUserSharedStorage( userID: str = Depends(LoginProtected)):
try:
sharedContent = await getUserSharedStoragesHandler(userID)
return {
"success": True,
"content": sharedContent
}
except Exception as e:
return {"success": False, "message": str(e)}

@sharedStorageRouter.post("/")
async def createSharedStorageRoute( storageName , image: UploadFile = File(...), userId : str = Depends(LoginProtected),):
try:
storageId = await createSharedStorage(userId , storageName , image)
return {
"success": True,
"storageId": storageId
}
except Exception as e:
return {"success": False, "message": str(e)}
6 changes: 5 additions & 1 deletion code/Routers/storageRouter.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@
from Middlewares.authProtectionMiddlewares import LoginProtected
from Routers.foldersRouter import foldersRouter
from Routers.filesRouter import filesRouter
from Routers.sharedStorageRouter import sharedStorageRouter
from handlers.storageHandlers.storageHandlers import get_shared_content_handler
from handlers.storageHandlers.storageHandlers import getRecentElementsHandler , removeTrashHandler
from handlers.storageHandlers.foldersHandlers import restoreFileHandler , restoreFolderHandler

# Create a new APIRouter instance for storage-related routes
storageRouter = APIRouter()

@storageRouter.get("/shared")
@storageRouter.get("/sharedContent")
def getSharedContent(search: str = None, userID: str = Depends(LoginProtected)):
"""
Retrieves the shared content (files and folders) that match the search query (if exists).
Expand Down Expand Up @@ -83,3 +84,6 @@ async def restoreFolder(folderId: str, userID: str = Depends(LoginProtected)):

# Nest filesRouter inside storageRouter with the prefix "/folders" and tag "files"
storageRouter.include_router(filesRouter, tags=["files"], prefix="/file")

# Nest sharedStorageRouter inside storageRouter with the prefix "/shared" and tag "shared"
storageRouter.include_router(sharedStorageRouter, tags=["shared"], prefix="/shared")
96 changes: 96 additions & 0 deletions code/handlers/sharedStorageHandlers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
from Core.Shared.Database import Database
from Core.Shared.Storage import Storage
from Models.Entities.SharedStorage import SharedStorage
from Models.Entities.Folder import Folder
from fastapi import UploadFile ,HTTPException
from fastapi import File
from Core.Shared.Utils import storeInStorageHandler

from Core.Shared.Database import db


def validate_image(file: UploadFile = File(...)) -> UploadFile:
valid_image_mime_types = ["image/jpeg", "image/png", "image/gif" , "image/jpg"]
if file.content_type not in valid_image_mime_types:
raise HTTPException(status_code=400, detail="Invalid image type")
return file

async def createSharedStorage(userId , storageName , image: UploadFile = File(...)):
"""
Create a shared storage for a given user.
This function creates a shared storage for a given user.
Args:
userId (str): The unique identifier of the user.
storageName (str): The name of the storage.
Returns:
str: The shared storage's identifier.
"""
print("Creating shared storage")
image = validate_image(image)

# Create root folder
rootFolder = Folder(
name=storageName,
ownerId=userId,
parent=None,
)

#Create the image
await Database.createFolder(rootFolder)
print("Before storage")
imageUrl , fileId = await storeInStorageHandler(image)
print("Creating shared storage")
storage = SharedStorage(
name=storageName,
imagePath=imageUrl,
rootFolderId=rootFolder.id,
ownerId=userId,
readId=[userId],
writeId=[userId]
)
Database.createStorage(storage)


return storage.to_dict()

async def getSharedStorage(storageId: str):
"""
Retrieve the shared storage with the given identifier.
This function retrieves the shared storage with the given identifier.
Args:
storageId (str): The unique identifier of the shared storage.
Returns:
dict: The shared storage's data.
"""

storage = await Database.read("sharedStorage", storageId)


if storage is None:
raise HTTPException(status_code=404, detail="Shared storage not found")

return storage

async def getUserSharedStoragesHandler(userId):

sharedStorages = await Database.getUserSharedStorages(userId)

# Only keep imagePath , id , rootFodlerPath and name
filtered_shared_storages = [
{
"imagePath": storage.get("imagePath"),
"id": storage.get("id"),
"rootFolderId": storage.get("rootFolderId"),
"name": storage.get("name")
}
for storage in sharedStorages
]


return filtered_shared_storages

0 comments on commit 870b91f

Please sign in to comment.