Fastapi refactor update
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
from .file_storage import IFileStorage
|
||||
from .document_store import IDocumentStore
|
||||
|
||||
__all__ = [
|
||||
"IFileStorage",
|
||||
"IDocumentStore"
|
||||
from .file_storage import IFileStorage
|
||||
from .document_store import IDocumentStore
|
||||
|
||||
__all__ = [
|
||||
"IFileStorage",
|
||||
"IDocumentStore"
|
||||
]
|
||||
@@ -1,16 +1,15 @@
|
||||
from abc import ABC
|
||||
|
||||
|
||||
class IDocumentStore(ABC):
|
||||
|
||||
async def save_to_db(self, collection: str, item):
|
||||
pass
|
||||
|
||||
async def save_to_db_with_id(self, collection: str, item, id: str):
|
||||
pass
|
||||
|
||||
async def get_all(self, collection: str):
|
||||
pass
|
||||
|
||||
async def get_doc_by_id(self, collection: str, doc_id: str):
|
||||
pass
|
||||
from abc import ABC
|
||||
|
||||
from typing import Dict, Optional, List
|
||||
|
||||
|
||||
class IDocumentStore(ABC):
|
||||
|
||||
async def save_to_db(self, collection: str, item: Dict, doc_id: Optional[str]) -> Optional[str]:
|
||||
pass
|
||||
|
||||
async def get_all(self, collection: str) -> List[Dict]:
|
||||
pass
|
||||
|
||||
async def get_doc_by_id(self, collection: str, doc_id: str) -> Optional[Dict]:
|
||||
pass
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
|
||||
class IFileStorage(ABC):
|
||||
|
||||
@abstractmethod
|
||||
async def download_firebase_file(self, source_blob_name, destination_file_name):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def upload_file_firebase_get_url(self, destination_blob_name, source_file_name):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def make_public(self, blob_name: str):
|
||||
pass
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
|
||||
class IFileStorage(ABC):
|
||||
|
||||
@abstractmethod
|
||||
async def download_firebase_file(self, source_blob_name, destination_file_name):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def upload_file_firebase_get_url(self, destination_blob_name, source_file_name):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def make_public(self, blob_name: str):
|
||||
pass
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
from .document_stores import *
|
||||
from .firebase import FirebaseStorage
|
||||
|
||||
__all__ = [
|
||||
"FirebaseStorage"
|
||||
]
|
||||
|
||||
__all__.extend(document_stores.__all__)
|
||||
from .document_stores import *
|
||||
from app.repositories.impl.file_storage.firebase import FirebaseStorage
|
||||
|
||||
__all__ = [
|
||||
"FirebaseStorage"
|
||||
]
|
||||
|
||||
__all__.extend(document_stores.__all__)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from .firestore import Firestore
|
||||
#from .mongo import MongoDB
|
||||
|
||||
__all__ = [
|
||||
"Firestore",
|
||||
#"MongoDB"
|
||||
]
|
||||
from .firestore import Firestore
|
||||
#from .mongo import MongoDB
|
||||
|
||||
__all__ = [
|
||||
"Firestore",
|
||||
#"MongoDB"
|
||||
]
|
||||
|
||||
@@ -1,47 +1,47 @@
|
||||
import logging
|
||||
from google.cloud.firestore_v1.async_client import AsyncClient
|
||||
from google.cloud.firestore_v1.async_collection import AsyncCollectionReference
|
||||
from google.cloud.firestore_v1.async_document import AsyncDocumentReference
|
||||
from app.repositories.abc import IDocumentStore
|
||||
|
||||
|
||||
class Firestore(IDocumentStore):
|
||||
def __init__(self, client: AsyncClient):
|
||||
self._client = client
|
||||
self._logger = logging.getLogger(__name__)
|
||||
|
||||
async def save_to_db(self, collection: str, item):
|
||||
collection_ref: AsyncCollectionReference = self._client.collection(collection)
|
||||
update_time, document_ref = await collection_ref.add(item)
|
||||
if document_ref:
|
||||
self._logger.info(f"Document added with ID: {document_ref.id}")
|
||||
return document_ref.id
|
||||
else:
|
||||
return None
|
||||
|
||||
async def save_to_db_with_id(self, collection: str, item, id: str):
|
||||
collection_ref: AsyncCollectionReference = self._client.collection(collection)
|
||||
document_ref: AsyncDocumentReference = collection_ref.document(id)
|
||||
await document_ref.set(item)
|
||||
doc_snapshot = await document_ref.get()
|
||||
if doc_snapshot.exists:
|
||||
self._logger.info(f"Document added with ID: {document_ref.id}")
|
||||
return document_ref.id
|
||||
else:
|
||||
return None
|
||||
|
||||
async def get_all(self, collection: str):
|
||||
collection_ref: AsyncCollectionReference = self._client.collection(collection)
|
||||
docs = []
|
||||
async for doc in collection_ref.stream():
|
||||
docs.append(doc.to_dict())
|
||||
return docs
|
||||
|
||||
async def get_doc_by_id(self, collection: str, doc_id: str):
|
||||
collection_ref: AsyncCollectionReference = self._client.collection(collection)
|
||||
doc_ref: AsyncDocumentReference = collection_ref.document(doc_id)
|
||||
doc = await doc_ref.get()
|
||||
|
||||
if doc.exists:
|
||||
return doc.to_dict()
|
||||
return None
|
||||
import logging
|
||||
from typing import Optional, List, Dict
|
||||
|
||||
from google.cloud.firestore_v1.async_client import AsyncClient
|
||||
from google.cloud.firestore_v1.async_collection import AsyncCollectionReference
|
||||
from google.cloud.firestore_v1.async_document import AsyncDocumentReference
|
||||
from app.repositories.abc import IDocumentStore
|
||||
|
||||
|
||||
class Firestore(IDocumentStore):
|
||||
def __init__(self, client: AsyncClient):
|
||||
self._client = client
|
||||
self._logger = logging.getLogger(__name__)
|
||||
|
||||
async def save_to_db(self, collection: str, item, doc_id: Optional[str] = None) -> Optional[str]:
|
||||
collection_ref: AsyncCollectionReference = self._client.collection(collection)
|
||||
|
||||
if doc_id:
|
||||
document_ref: AsyncDocumentReference = collection_ref.document(doc_id)
|
||||
await document_ref.set(item)
|
||||
doc_snapshot = await document_ref.get()
|
||||
if doc_snapshot.exists:
|
||||
self._logger.info(f"Document added with ID: {document_ref.id}")
|
||||
return document_ref.id
|
||||
else:
|
||||
update_time, document_ref = await collection_ref.add(item)
|
||||
if document_ref:
|
||||
self._logger.info(f"Document added with ID: {document_ref.id}")
|
||||
return document_ref.id
|
||||
|
||||
return None
|
||||
|
||||
async def get_all(self, collection: str) -> List[Dict]:
|
||||
collection_ref: AsyncCollectionReference = self._client.collection(collection)
|
||||
docs = []
|
||||
async for doc in collection_ref.stream():
|
||||
docs.append(doc.to_dict())
|
||||
return docs
|
||||
|
||||
async def get_doc_by_id(self, collection: str, doc_id: str) -> Optional[Dict]:
|
||||
collection_ref: AsyncCollectionReference = self._client.collection(collection)
|
||||
doc_ref: AsyncDocumentReference = collection_ref.document(doc_id)
|
||||
doc = await doc_ref.get()
|
||||
|
||||
if doc.exists:
|
||||
return doc.to_dict()
|
||||
return None
|
||||
|
||||
@@ -1,36 +1,37 @@
|
||||
"""import logging
|
||||
from pymongo import MongoClient
|
||||
|
||||
from app.repositories.abc import IDocumentStore
|
||||
|
||||
|
||||
class MongoDB(IDocumentStore):
|
||||
|
||||
def __init__(self, client: MongoClient):
|
||||
self._client = client
|
||||
self._logger = logging.getLogger(__name__)
|
||||
|
||||
def save_to_db(self, collection: str, item):
|
||||
collection_ref = self._client[collection]
|
||||
result = collection_ref.insert_one(item)
|
||||
if result.inserted_id:
|
||||
self._logger.info(f"Document added with ID: {result.inserted_id}")
|
||||
return True, str(result.inserted_id)
|
||||
else:
|
||||
return False, None
|
||||
|
||||
def save_to_db_with_id(self, collection: str, item, doc_id: str):
|
||||
collection_ref = self._client[collection]
|
||||
item['_id'] = doc_id
|
||||
result = collection_ref.replace_one({'_id': id}, item, upsert=True)
|
||||
if result.upserted_id or result.matched_count:
|
||||
self._logger.info(f"Document added with ID: {doc_id}")
|
||||
return True, doc_id
|
||||
else:
|
||||
return False, None
|
||||
|
||||
def get_all(self, collection: str):
|
||||
collection_ref = self._client[collection]
|
||||
all_documents = list(collection_ref.find())
|
||||
return all_documents
|
||||
"""
|
||||
import logging
|
||||
import uuid
|
||||
from typing import Optional, List, Dict
|
||||
|
||||
from motor.motor_asyncio import AsyncIOMotorDatabase
|
||||
|
||||
from app.repositories.abc import IDocumentStore
|
||||
|
||||
|
||||
class MongoDB(IDocumentStore):
|
||||
|
||||
def __init__(self, mongo_db: AsyncIOMotorDatabase):
|
||||
self._mongo_db = mongo_db
|
||||
self._logger = logging.getLogger(__name__)
|
||||
|
||||
async def save_to_db(self, collection: str, item, doc_id: Optional[str] = None) -> Optional[str]:
|
||||
collection_ref = self._mongo_db[collection]
|
||||
|
||||
if doc_id is None:
|
||||
doc_id = str(uuid.uuid4())
|
||||
|
||||
item['id'] = doc_id
|
||||
|
||||
result = await collection_ref.insert_one(item)
|
||||
if result.inserted_id:
|
||||
# returning id instead of _id
|
||||
self._logger.info(f"Document added with ID: {doc_id}")
|
||||
return doc_id
|
||||
|
||||
return None
|
||||
|
||||
async def get_all(self, collection: str) -> List[Dict]:
|
||||
cursor = self._mongo_db[collection].find()
|
||||
return [document async for document in cursor]
|
||||
|
||||
async def get_doc_by_id(self, collection: str, doc_id: str) -> Optional[Dict]:
|
||||
return await self._mongo_db[collection].find_one({"id": doc_id})
|
||||
|
||||
5
app/repositories/impl/file_storage/__init__.py
Normal file
5
app/repositories/impl/file_storage/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from .firebase import FirebaseStorage
|
||||
|
||||
__all__ = [
|
||||
"FirebaseStorage"
|
||||
]
|
||||
@@ -1,83 +1,83 @@
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
import aiofiles
|
||||
from httpx import AsyncClient
|
||||
|
||||
from app.repositories.abc import IFileStorage
|
||||
|
||||
|
||||
class FirebaseStorage(IFileStorage):
|
||||
|
||||
def __init__(self, client: AsyncClient, token: str, bucket: str):
|
||||
self._httpx_client = client
|
||||
self._token = token
|
||||
self._storage_url = f'https://firebasestorage.googleapis.com/v0/b/{bucket}'
|
||||
self._logger = logging.getLogger(__name__)
|
||||
|
||||
async def download_firebase_file(self, source_blob_name: str, destination_file_name: str) -> Optional[str]:
|
||||
source_blob_name = source_blob_name.replace('/', '%2F')
|
||||
download_url = f"{self._storage_url}/o/{source_blob_name}?alt=media"
|
||||
|
||||
response = await self._httpx_client.get(
|
||||
download_url,
|
||||
headers={'Authorization': f'Firebase {self._token}'}
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
async with aiofiles.open(destination_file_name, 'wb') as file:
|
||||
await file.write(response.content)
|
||||
self._logger.info(f"File downloaded to {destination_file_name}")
|
||||
return destination_file_name
|
||||
else:
|
||||
self._logger.error(f"Failed to download blob {source_blob_name}. {response.status_code} - {response.content}")
|
||||
return None
|
||||
|
||||
async def upload_file_firebase_get_url(self, destination_blob_name: str, source_file_name: str) -> Optional[str]:
|
||||
destination_blob_name = destination_blob_name.replace('/', '%2F')
|
||||
upload_url = f"{self._storage_url}/o/{destination_blob_name}"
|
||||
|
||||
async with aiofiles.open(source_file_name, 'rb') as file:
|
||||
file_bytes = await file.read()
|
||||
|
||||
response = await self._httpx_client.post(
|
||||
upload_url,
|
||||
headers={
|
||||
'Authorization': f'Firebase {self._token}',
|
||||
"X-Goog-Upload-Protocol": "multipart"
|
||||
},
|
||||
files={
|
||||
'metadata': (None, '{"metadata":{"test":"testMetadata"}}', 'application/json'),
|
||||
'file': file_bytes
|
||||
}
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
self._logger.info(f"File {source_file_name} uploaded to {self._storage_url}/o/{destination_blob_name}.")
|
||||
|
||||
# TODO: Test this
|
||||
#await self.make_public(destination_blob_name)
|
||||
|
||||
file_url = f"{self._storage_url}/o/{destination_blob_name}"
|
||||
return file_url
|
||||
else:
|
||||
self._logger.error(f"Failed to upload file {source_file_name}. Error: {response.status_code} - {str(response.content)}")
|
||||
return None
|
||||
|
||||
async def make_public(self, destination_blob_name: str):
|
||||
acl_url = f"{self._storage_url}/o/{destination_blob_name}/acl"
|
||||
acl = {'entity': 'allUsers', 'role': 'READER'}
|
||||
|
||||
response = await self._httpx_client.post(
|
||||
acl_url,
|
||||
headers={
|
||||
'Authorization': f'Bearer {self._token}',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
json=acl
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
self._logger.info(f"Blob {destination_blob_name} is now public.")
|
||||
else:
|
||||
self._logger.error(f"Failed to make blob {destination_blob_name} public. {response.status_code} - {response.content}")
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
import aiofiles
|
||||
from httpx import AsyncClient
|
||||
|
||||
from app.repositories.abc import IFileStorage
|
||||
|
||||
|
||||
class FirebaseStorage(IFileStorage):
|
||||
|
||||
def __init__(self, client: AsyncClient, token: str, bucket: str):
|
||||
self._httpx_client = client
|
||||
self._token = token
|
||||
self._storage_url = f'https://firebasestorage.googleapis.com/v0/b/{bucket}'
|
||||
self._logger = logging.getLogger(__name__)
|
||||
|
||||
async def download_firebase_file(self, source_blob_name: str, destination_file_name: str) -> Optional[str]:
|
||||
source_blob_name = source_blob_name.replace('/', '%2F')
|
||||
download_url = f"{self._storage_url}/o/{source_blob_name}?alt=media"
|
||||
|
||||
response = await self._httpx_client.get(
|
||||
download_url,
|
||||
headers={'Authorization': f'Firebase {self._token}'}
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
async with aiofiles.open(destination_file_name, 'wb') as file:
|
||||
await file.write(response.content)
|
||||
self._logger.info(f"File downloaded to {destination_file_name}")
|
||||
return destination_file_name
|
||||
else:
|
||||
self._logger.error(f"Failed to download blob {source_blob_name}. {response.status_code} - {response.content}")
|
||||
return None
|
||||
|
||||
async def upload_file_firebase_get_url(self, destination_blob_name: str, source_file_name: str) -> Optional[str]:
|
||||
destination_blob_name = destination_blob_name.replace('/', '%2F')
|
||||
upload_url = f"{self._storage_url}/o/{destination_blob_name}"
|
||||
|
||||
async with aiofiles.open(source_file_name, 'rb') as file:
|
||||
file_bytes = await file.read()
|
||||
|
||||
response = await self._httpx_client.post(
|
||||
upload_url,
|
||||
headers={
|
||||
'Authorization': f'Firebase {self._token}',
|
||||
"X-Goog-Upload-Protocol": "multipart"
|
||||
},
|
||||
files={
|
||||
'metadata': (None, '{"metadata":{"test":"testMetadata"}}', 'application/json'),
|
||||
'file': file_bytes
|
||||
}
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
self._logger.info(f"File {source_file_name} uploaded to {self._storage_url}/o/{destination_blob_name}.")
|
||||
|
||||
# TODO: Test this
|
||||
#await self.make_public(destination_blob_name)
|
||||
|
||||
file_url = f"{self._storage_url}/o/{destination_blob_name}"
|
||||
return file_url
|
||||
else:
|
||||
self._logger.error(f"Failed to upload file {source_file_name}. Error: {response.status_code} - {str(response.content)}")
|
||||
return None
|
||||
|
||||
async def make_public(self, destination_blob_name: str):
|
||||
acl_url = f"{self._storage_url}/o/{destination_blob_name}/acl"
|
||||
acl = {'entity': 'allUsers', 'role': 'READER'}
|
||||
|
||||
response = await self._httpx_client.post(
|
||||
acl_url,
|
||||
headers={
|
||||
'Authorization': f'Bearer {self._token}',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
json=acl
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
self._logger.info(f"Blob {destination_blob_name} is now public.")
|
||||
else:
|
||||
self._logger.error(f"Failed to make blob {destination_blob_name} public. {response.status_code} - {response.content}")
|
||||
Reference in New Issue
Block a user