Skip to content

Commit

Permalink
Merge pull request #218 from innovencelabs/217-migrate-the-api-busine…
Browse files Browse the repository at this point in the history
…ss-logic-to-service-folder

Migrated business logic to services
  • Loading branch information
ambujraj authored May 11, 2024
2 parents f81451b + 95aa355 commit e50d1dc
Show file tree
Hide file tree
Showing 17 changed files with 789 additions and 586 deletions.
10 changes: 6 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,16 +85,18 @@ git pull
```
├── ui # Frontend application
│ └── src # Source code
| ├── app
├── app
│ ├── authentication
│ ├── components
│ ├── conf
| ├── context
├── context
│ └── lib
├── middeware # Backend application
│ └── app # Source code
| ├── api # API routes
| ├── database # Database code
│ ├── api # APIs
│ │ ├── routes # API endpoint
│ │ └── services # API business logic
│ ├── database # Database code
│ └── storage # Storage code
└── infrastructure # Terraform scripts for cloud and local(docker version)
├── cloud # For clouds
Expand Down
96 changes: 4 additions & 92 deletions middleware/app/api/routes/download.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,14 @@
from datetime import datetime, timezone
from enum import Enum as PythonEnum

import api.services.download as download_service
import utils.logger as logger
from database.db import DynamoDBManager
from fastapi import APIRouter, HTTPException
from storage.cloudflare_r2 import CloudflareR2Manager
from fastapi import APIRouter

router = APIRouter()

# Logger instance
log = logger.get_logger()

# Storage
BUCKET_NAME = "byteshare-blob"
storage = CloudflareR2Manager(BUCKET_NAME)

# DynamoDB
table_name = "byteshare-upload-metadata"
dynamodb = DynamoDBManager(table_name)


class StatusEnum(PythonEnum):
initiated = "initiated"
Expand All @@ -41,85 +31,7 @@ def get_file_url_return_name_link(upload_id: str, user_id: str | None = None):
FUNCTION_NAME = "get_file_url_return_name_link()"
log.info("Entering {}".format(FUNCTION_NAME))

file_data = {}
time_now = datetime.now(timezone.utc).isoformat()
upload_metadata = dynamodb.read_item({"upload_id": upload_id})
if upload_metadata == None:
log.warning(
"BAD REQUEST for UploadID: {}\nERROR: {}".format(
upload_id, "Upload ID not valid."
)
)
raise HTTPException(status_code=400, detail="Upload ID not valid")
if upload_metadata["status"] != StatusEnum.uploaded.name:
log.warning(
"BAD REQUEST for UploadID: {}\nERROR: {}".format(
upload_id, "Incomplete upload."
)
)
raise HTTPException(status_code=400, detail="Incomplete upload")

expires_at = upload_metadata["expires_at"]
if time_now > expires_at:
log.warning(
"BAD REQUEST for UploadID: {}\nERROR: {}".format(
upload_id, "Link is expired."
)
)
raise HTTPException(status_code=400, detail="Link is expired")

download_count = upload_metadata["download_count"]
max_count = upload_metadata["max_download"]
if user_id == None or upload_metadata["creator_id"] != user_id:
if download_count >= max_count:
log.warning(
"BAD REQUEST for UploadID: {}\nERROR: {}".format(
upload_id, "Download limit exceeded"
)
)
raise HTTPException(status_code=400, detail="Download limit exceeded")

file_names = set(upload_metadata["storage_file_names"])
for file_name in file_names:
file_path = upload_id + "/" + file_name

file_format = _get_file_extension(file_name)
file_size = storage.get_file_info(file_path)

download_expiration_time = 21600 # 6 hours
# Generate share download link
file_url = storage.generate_download_url(file_path, download_expiration_time)
if upload_metadata["share_email_as_source"]:
file_data["user_email"] = upload_metadata["creator_email"]
else:
file_data["user_email"] = None
file_data[file_name] = {}
file_data[file_name]["format"] = file_format
file_data[file_name]["size"] = _format_size(file_size)
file_data[file_name]["download_url"] = file_url

if user_id == None or upload_metadata["creator_id"] != user_id:
keys = {"upload_id": upload_id}
update_data = {
"download_count": download_count + 1,
"updated_at": time_now,
}
dynamodb.update_item(keys, update_data)
response = download_service.get_file_url_return_name_link(upload_id, user_id)

log.info("Exiting {}".format(FUNCTION_NAME))
return file_data


def _get_file_extension(file_name):
return file_name.split(".")[-1]


def _format_size(byte_size):
if byte_size < 1024:
return f"{byte_size} B"
elif byte_size < 1024**2:
return f"{byte_size / 1024:.2f} KB"
elif byte_size < 1024**3:
return f"{byte_size / (1024 ** 2):.2f} MB"
else:
return f"{byte_size / (1024 ** 3):.2f} GB"
return response
16 changes: 2 additions & 14 deletions middleware/app/api/routes/feedback.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import uuid

import api.services.feedback as feedback_service
import utils.logger as logger
from database.db import DynamoDBManager
from fastapi import APIRouter
from pydantic import BaseModel

Expand All @@ -10,10 +8,6 @@
# Logger instance
log = logger.get_logger()

# DynamoDB
feedback_table_name = "byteshare-feedback"
feedback_dynamodb = DynamoDBManager(feedback_table_name)


class Feedback(BaseModel):
name: str
Expand All @@ -38,12 +32,6 @@ def post_feedback_return_none(body: Feedback):
FUNCTION_NAME = "post_feedback_return_none()"
log.info("Entering {}".format(FUNCTION_NAME))

feedback = {
"feedback_id": uuid.uuid4().hex,
"email": body.email,
"name": body.name,
"message": body.message,
}
feedback_dynamodb.create_item(feedback)
feedback_service.post_feedback_return_none(body)

log.info("Exiting {}".format(FUNCTION_NAME))
16 changes: 3 additions & 13 deletions middleware/app/api/routes/health.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,12 @@
import api.services.health as health_service
import utils.logger as logger
from database.db import DynamoDBManager
from fastapi import APIRouter
from storage.cloudflare_r2 import CloudflareR2Manager

router = APIRouter()

# Logger instance
log = logger.get_logger()

# DynamoDB
table_name = "byteshare-upload-metadata"
dynamodb = DynamoDBManager(table_name)

# Storage
BUCKET_NAME = "byteshare-blob"
storage = CloudflareR2Manager(BUCKET_NAME)


@router.get("/")
def health_check():
Expand All @@ -32,8 +23,7 @@ def health_check():
FUNCTION_NAME = "health_check()"
log.info("Entering {}".format(FUNCTION_NAME))

dynamodb.health_check()
storage.health_check()
response = health_service.health_check()

log.info("Exiting {}".format(FUNCTION_NAME))
return {"status": "ok", "details": "Service is running"}
return response
70 changes: 3 additions & 67 deletions middleware/app/api/routes/scan.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,13 @@
from datetime import datetime, timezone

import resend
import api.services.scan as scan_service
import utils.logger as logger
from database.db import DynamoDBManager
from fastapi import APIRouter, HTTPException
from fastapi import APIRouter
from pydantic import BaseModel

router = APIRouter()

# Logger instance
log = logger.get_logger()

# DynamoDB
table_name = "byteshare-upload-metadata"
dynamodb = DynamoDBManager(table_name)


class CompleteScan(BaseModel):
safe: bool
Expand All @@ -37,63 +30,6 @@ def finalise_scan_return_none(body: CompleteScan, upload_id: str):
FUNCTION_NAME = "finalise_scan_return_none()"
log.info("Entering {}".format(FUNCTION_NAME))

safe = body.safe

try:
upload_metadata = dynamodb.read_item({"upload_id": upload_id})
except Exception as e:
log.error("EXCEPTION occurred connecting to DB.\nERROR: {}".format(str(e)))
raise HTTPException(status_code=500, detail="Cannot connect to DB")
if not upload_metadata:
log.warning(
"BAD REQUEST for UploadID: {}\nERROR: {}".format(
upload_id, "Upload ID not valid."
)
)
raise HTTPException(status_code=400, detail="Upload ID not valid")

if safe:
time_now = datetime.now(timezone.utc).isoformat()
keys = {"upload_id": upload_id}
update_data = {
"scanned": True,
"updated_at": time_now,
}
dynamodb.update_item(keys, update_data)
else:
keys = {"upload_id": upload_id}
dynamodb.delete_item(keys)

user_email = upload_metadata["creator_email"]
params = {
"from": "ByteShare <security@byteshare.io>",
"to": [user_email],
"subject": "Important: Security Alert Regarding Your Uploaded File",
"html": """
<body style="font-family: Arial, sans-serif; margin: 0; padding: 20px;">
<p>Hey,</p>
<p style="font-size: 18px;"></p>
<p>We hope this email finds you well.</p>
<p>We regret to inform you that upon scanning the upload(Upload ID: {}) you recently uploaded, our system has detected several issues that require immediate attention. As a security measure, we have taken the necessary steps to remove the file from our servers to prevent any potential risks or threats to our system and users.</p>
<p>We kindly request your cooperation in resolving the identified issues. We understand that this might inconvenience you, and we apologize for any disruption this may cause.</p>
<p>To ensure the safety and integrity of our platform, we advise you to review the content of the file and address any issues or vulnerabilities it may contain. Once resolved, you are welcome to re-upload the file for further processing.</p>
<p>If you require any assistance or have any questions regarding this matter, please do not hesitate to contact our support team.</p>
<p>Thank you for your prompt attention to this matter.</p>
<p>Best regards,<br>
ByteShare Team</p>
</body>
""".format(
upload_id
),
}

resend.Emails.send(params)
scan_service.finalise_scan_return_none(body, upload_id)

log.info("Exiting {}".format(FUNCTION_NAME))
16 changes: 3 additions & 13 deletions middleware/app/api/routes/subscribe.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
from datetime import datetime, timezone

import api.services.subscribe as subscribe_service
import utils.logger as logger
from database.db import DynamoDBManager
from fastapi import APIRouter
from pydantic import BaseModel

Expand All @@ -10,10 +8,6 @@
# Logger instance
log = logger.get_logger()

# DynamoDB
subscriber_table_name = "byteshare-subscriber"
subscriber_dynamodb = DynamoDBManager(subscriber_table_name)


class Subscribe(BaseModel):
email: str
Expand All @@ -33,11 +27,7 @@ def add_subscriber_return_done(body: Subscribe):
FUNCTION_NAME = "add_subscriber_return_done()"
log.info("Entering {}".format(FUNCTION_NAME))

subscriber = {
"email": body.email,
"created_at": datetime.now(timezone.utc).isoformat(),
}
subscriber_dynamodb.create_item(subscriber)
response = subscribe_service.add_subscriber_return_done(body)

log.info("Exiting {}".format(FUNCTION_NAME))
return {"status": "Done"}
return response
Loading

0 comments on commit e50d1dc

Please sign in to comment.