2025-11-09 23:29:07 +01:00
|
|
|
import argparse
|
|
|
|
|
import uvicorn
|
2025-11-10 15:46:40 +01:00
|
|
|
import logging
|
|
|
|
|
from contextlib import asynccontextmanager
|
2025-11-13 23:22:05 +01:00
|
|
|
from fastapi import FastAPI, Request, HTTPException
|
2025-11-09 23:29:07 +01:00
|
|
|
from fastapi.staticfiles import StaticFiles
|
feat: add 2fa support, starred items, batch operations, and logging infrastructure
- Implement two-factor authentication with TOTP verification, recovery codes, and QR code setup in auth flow
- Add is_starred and last_accessed_at fields to File and Folder models for bookmarking and recency tracking
- Introduce batch operation endpoints for files and folders (delete, star, unstar, move, copy)
- Configure structured logging with timestamps and module names, replacing print statements
- Register admin and starred routers, add global HTTPException handler with JSON error responses
- Update authenticate_user and create_access_token to handle 2FA verification and token claims
2025-11-10 01:58:41 +01:00
|
|
|
from fastapi.responses import HTMLResponse, JSONResponse
|
2025-11-09 23:29:07 +01:00
|
|
|
from tortoise.contrib.fastapi import register_tortoise
|
|
|
|
|
from .settings import settings
|
2025-11-13 23:22:05 +01:00
|
|
|
from .routers import (
|
|
|
|
|
auth,
|
|
|
|
|
users,
|
|
|
|
|
folders,
|
|
|
|
|
files,
|
|
|
|
|
shares,
|
|
|
|
|
search,
|
|
|
|
|
admin,
|
|
|
|
|
starred,
|
|
|
|
|
billing,
|
|
|
|
|
admin_billing,
|
|
|
|
|
)
|
2025-11-09 23:29:07 +01:00
|
|
|
from . import webdav
|
2025-11-10 15:46:40 +01:00
|
|
|
from .schemas import ErrorResponse
|
2025-11-13 23:22:05 +01:00
|
|
|
from .middleware.usage_tracking import UsageTrackingMiddleware
|
feat: add 2fa support, starred items, batch operations, and logging infrastructure
- Implement two-factor authentication with TOTP verification, recovery codes, and QR code setup in auth flow
- Add is_starred and last_accessed_at fields to File and Folder models for bookmarking and recency tracking
- Introduce batch operation endpoints for files and folders (delete, star, unstar, move, copy)
- Configure structured logging with timestamps and module names, replacing print statements
- Register admin and starred routers, add global HTTPException handler with JSON error responses
- Update authenticate_user and create_access_token to handle 2FA verification and token claims
2025-11-10 01:58:41 +01:00
|
|
|
|
2025-11-13 23:22:05 +01:00
|
|
|
logging.basicConfig(
|
|
|
|
|
level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
|
|
|
|
)
|
feat: add 2fa support, starred items, batch operations, and logging infrastructure
- Implement two-factor authentication with TOTP verification, recovery codes, and QR code setup in auth flow
- Add is_starred and last_accessed_at fields to File and Folder models for bookmarking and recency tracking
- Introduce batch operation endpoints for files and folders (delete, star, unstar, move, copy)
- Configure structured logging with timestamps and module names, replacing print statements
- Register admin and starred routers, add global HTTPException handler with JSON error responses
- Update authenticate_user and create_access_token to handle 2FA verification and token claims
2025-11-10 01:58:41 +01:00
|
|
|
logger = logging.getLogger(__name__)
|
2025-11-09 23:29:07 +01:00
|
|
|
|
2025-11-13 23:22:05 +01:00
|
|
|
|
2025-11-10 15:46:40 +01:00
|
|
|
@asynccontextmanager
|
|
|
|
|
async def lifespan(app: FastAPI):
|
|
|
|
|
logger.info("Starting up...")
|
|
|
|
|
logger.info("Database connected.")
|
|
|
|
|
from .billing.scheduler import start_scheduler
|
|
|
|
|
from .billing.models import PricingConfig
|
2025-11-11 12:47:26 +01:00
|
|
|
from .mail import email_service
|
2025-11-13 23:22:05 +01:00
|
|
|
|
2025-11-10 15:46:40 +01:00
|
|
|
start_scheduler()
|
|
|
|
|
logger.info("Billing scheduler started")
|
2025-11-11 12:47:26 +01:00
|
|
|
await email_service.start()
|
|
|
|
|
logger.info("Email service started")
|
2025-11-10 15:46:40 +01:00
|
|
|
pricing_count = await PricingConfig.all().count()
|
|
|
|
|
if pricing_count == 0:
|
|
|
|
|
from decimal import Decimal
|
2025-11-13 23:22:05 +01:00
|
|
|
|
|
|
|
|
await PricingConfig.create(
|
|
|
|
|
config_key="storage_per_gb_month",
|
|
|
|
|
config_value=Decimal("0.0045"),
|
|
|
|
|
description="Storage cost per GB per month",
|
|
|
|
|
unit="per_gb_month",
|
|
|
|
|
)
|
|
|
|
|
await PricingConfig.create(
|
|
|
|
|
config_key="bandwidth_egress_per_gb",
|
|
|
|
|
config_value=Decimal("0.009"),
|
|
|
|
|
description="Bandwidth egress cost per GB",
|
|
|
|
|
unit="per_gb",
|
|
|
|
|
)
|
|
|
|
|
await PricingConfig.create(
|
|
|
|
|
config_key="bandwidth_ingress_per_gb",
|
|
|
|
|
config_value=Decimal("0.0"),
|
|
|
|
|
description="Bandwidth ingress cost per GB (free)",
|
|
|
|
|
unit="per_gb",
|
|
|
|
|
)
|
|
|
|
|
await PricingConfig.create(
|
|
|
|
|
config_key="free_tier_storage_gb",
|
|
|
|
|
config_value=Decimal("15"),
|
|
|
|
|
description="Free tier storage in GB",
|
|
|
|
|
unit="gb",
|
|
|
|
|
)
|
|
|
|
|
await PricingConfig.create(
|
|
|
|
|
config_key="free_tier_bandwidth_gb",
|
|
|
|
|
config_value=Decimal("15"),
|
|
|
|
|
description="Free tier bandwidth in GB per month",
|
|
|
|
|
unit="gb",
|
|
|
|
|
)
|
|
|
|
|
await PricingConfig.create(
|
|
|
|
|
config_key="tax_rate_default",
|
|
|
|
|
config_value=Decimal("0.0"),
|
|
|
|
|
description="Default tax rate (0 = no tax)",
|
|
|
|
|
unit="percentage",
|
|
|
|
|
)
|
2025-11-10 15:46:40 +01:00
|
|
|
logger.info("Default pricing configuration initialized")
|
|
|
|
|
|
|
|
|
|
yield
|
|
|
|
|
|
|
|
|
|
from .billing.scheduler import stop_scheduler
|
2025-11-13 23:22:05 +01:00
|
|
|
|
2025-11-10 15:46:40 +01:00
|
|
|
stop_scheduler()
|
|
|
|
|
logger.info("Billing scheduler stopped")
|
2025-11-11 12:47:26 +01:00
|
|
|
await email_service.stop()
|
|
|
|
|
logger.info("Email service stopped")
|
2025-11-10 15:46:40 +01:00
|
|
|
print("Shutting down...")
|
|
|
|
|
|
2025-11-13 23:22:05 +01:00
|
|
|
|
2025-11-09 23:29:07 +01:00
|
|
|
app = FastAPI(
|
chore: rebrand all user-facing strings from RBox to MyWebdav across docs, emails, and config
Replace every occurrence of "RBox" with "MyWebdav" in README.md, invoice templates, welcome emails, share notifications, FastAPI metadata, default database filename, domain name, S3 bucket name, TOTP issuer, and WebDAV realm header to reflect the commercial rebranding of the application.
2025-11-13 12:05:05 +01:00
|
|
|
title="MyWebdav Cloud Storage",
|
|
|
|
|
description="A commercial cloud storage web application",
|
2025-11-09 23:29:07 +01:00
|
|
|
version="0.1.0",
|
2025-11-13 23:22:05 +01:00
|
|
|
lifespan=lifespan,
|
2025-11-09 23:29:07 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
app.include_router(auth.router)
|
|
|
|
|
app.include_router(users.router)
|
|
|
|
|
app.include_router(folders.router)
|
|
|
|
|
app.include_router(files.router)
|
|
|
|
|
app.include_router(shares.router)
|
|
|
|
|
app.include_router(search.router)
|
2025-11-10 15:46:40 +01:00
|
|
|
app.include_router(admin.router)
|
|
|
|
|
app.include_router(starred.router)
|
|
|
|
|
app.include_router(billing.router)
|
|
|
|
|
app.include_router(admin_billing.router)
|
2025-11-09 23:29:07 +01:00
|
|
|
app.include_router(webdav.router)
|
|
|
|
|
|
2025-11-10 15:46:40 +01:00
|
|
|
app.add_middleware(UsageTrackingMiddleware)
|
|
|
|
|
|
2025-11-09 23:29:07 +01:00
|
|
|
app.mount("/static", StaticFiles(directory="static"), name="static")
|
|
|
|
|
|
|
|
|
|
register_tortoise(
|
|
|
|
|
app,
|
|
|
|
|
db_url=settings.DATABASE_URL,
|
2025-11-13 23:22:05 +01:00
|
|
|
modules={"models": ["mywebdav.models"], "billing": ["mywebdav.billing.models"]},
|
2025-11-09 23:29:07 +01:00
|
|
|
generate_schemas=True,
|
|
|
|
|
add_exception_handlers=True,
|
|
|
|
|
)
|
|
|
|
|
|
2025-11-13 23:22:05 +01:00
|
|
|
|
feat: add 2fa support, starred items, batch operations, and logging infrastructure
- Implement two-factor authentication with TOTP verification, recovery codes, and QR code setup in auth flow
- Add is_starred and last_accessed_at fields to File and Folder models for bookmarking and recency tracking
- Introduce batch operation endpoints for files and folders (delete, star, unstar, move, copy)
- Configure structured logging with timestamps and module names, replacing print statements
- Register admin and starred routers, add global HTTPException handler with JSON error responses
- Update authenticate_user and create_access_token to handle 2FA verification and token claims
2025-11-10 01:58:41 +01:00
|
|
|
@app.exception_handler(HTTPException)
|
|
|
|
|
async def http_exception_handler(request: Request, exc: HTTPException):
|
2025-11-13 23:22:05 +01:00
|
|
|
logger.error(
|
|
|
|
|
f"HTTPException: {exc.status_code} - {exc.detail} for URL: {request.url}"
|
|
|
|
|
)
|
feat: add 2fa support, starred items, batch operations, and logging infrastructure
- Implement two-factor authentication with TOTP verification, recovery codes, and QR code setup in auth flow
- Add is_starred and last_accessed_at fields to File and Folder models for bookmarking and recency tracking
- Introduce batch operation endpoints for files and folders (delete, star, unstar, move, copy)
- Configure structured logging with timestamps and module names, replacing print statements
- Register admin and starred routers, add global HTTPException handler with JSON error responses
- Update authenticate_user and create_access_token to handle 2FA verification and token claims
2025-11-10 01:58:41 +01:00
|
|
|
return JSONResponse(
|
|
|
|
|
status_code=exc.status_code,
|
2025-11-13 23:05:26 +01:00
|
|
|
content=ErrorResponse(code=exc.status_code, message=exc.detail).model_dump(),
|
feat: add 2fa support, starred items, batch operations, and logging infrastructure
- Implement two-factor authentication with TOTP verification, recovery codes, and QR code setup in auth flow
- Add is_starred and last_accessed_at fields to File and Folder models for bookmarking and recency tracking
- Introduce batch operation endpoints for files and folders (delete, star, unstar, move, copy)
- Configure structured logging with timestamps and module names, replacing print statements
- Register admin and starred routers, add global HTTPException handler with JSON error responses
- Update authenticate_user and create_access_token to handle 2FA verification and token claims
2025-11-10 01:58:41 +01:00
|
|
|
)
|
|
|
|
|
|
2025-11-09 23:29:07 +01:00
|
|
|
|
2025-11-13 23:22:05 +01:00
|
|
|
@app.get("/", response_class=HTMLResponse) # Change response_class to HTMLResponse
|
2025-11-09 23:29:07 +01:00
|
|
|
async def read_root():
|
|
|
|
|
with open("static/index.html", "r") as f:
|
|
|
|
|
return f.read()
|
|
|
|
|
|
2025-11-13 23:22:05 +01:00
|
|
|
|
2025-11-09 23:29:07 +01:00
|
|
|
def main():
|
2025-11-13 20:50:03 +01:00
|
|
|
parser = argparse.ArgumentParser(description="Run the MyWebdav application.")
|
2025-11-13 23:22:05 +01:00
|
|
|
parser.add_argument(
|
|
|
|
|
"--host", type=str, default="0.0.0.0", help="Host address to bind to"
|
|
|
|
|
)
|
2025-11-09 23:29:07 +01:00
|
|
|
parser.add_argument("--port", type=int, default=8000, help="Port to listen on")
|
|
|
|
|
args = parser.parse_args()
|
|
|
|
|
|
|
|
|
|
uvicorn.run(app, host=args.host, port=args.port)
|
|
|
|
|
|
2025-11-13 23:22:05 +01:00
|
|
|
|
2025-11-09 23:29:07 +01:00
|
|
|
if __name__ == "__main__":
|
|
|
|
|
main()
|