From 1e5a6dbd5f5007c248368da57684aef075f75070 Mon Sep 17 00:00:00 2001 From: retoor Date: Mon, 10 Nov 2025 15:46:40 +0100 Subject: [PATCH] Update. --- Makefile | 152 ++++++++- rbox/auth.py | 2 +- rbox/billing/__init__.py | 0 rbox/billing/invoice_generator.py | 143 ++++++++ rbox/billing/models.py | 139 ++++++++ rbox/billing/scheduler.py | 57 ++++ rbox/billing/stripe_client.py | 105 ++++++ rbox/billing/usage_tracker.py | 142 ++++++++ rbox/main.py | 59 +++- rbox/middleware/__init__.py | 0 rbox/middleware/usage_tracking.py | 32 ++ rbox/routers/admin_billing.py | 116 +++++++ rbox/routers/auth.py | 10 +- rbox/routers/billing.py | 312 +++++++++++++++++ rbox/routers/files.py | 213 ++++++++---- rbox/routers/folders.py | 32 +- rbox/routers/shares.py | 69 +++- rbox/schemas.py | 8 +- rbox/settings.py | 16 +- rbox/storage.py | 12 +- rbox/webdav.py | 12 +- static/css/billing.css | 371 +++++++++++++++++++++ static/css/code-editor-view.css | 80 +++++ static/css/file-upload-view.css | 145 ++++++++ static/css/style.css | 161 ++++++--- static/icons/icon-192x192.png | Bin 0 -> 34417 bytes static/icons/icon-256x256.png | Bin 0 -> 58241 bytes static/icons/icon-384x384.png | Bin 0 -> 105369 bytes static/icons/icon-512x512.png | Bin 0 -> 161016 bytes static/index.html | 12 + static/js/api.js | 17 +- static/js/components/admin-billing.js | 193 +++++++++++ static/js/components/admin-dashboard.js | 48 ++- static/js/components/base-file-list.js | 268 +++++++++++++++ static/js/components/billing-dashboard.js | 309 +++++++++++++++++ static/js/components/code-editor-view.js | 153 +++++++++ static/js/components/deleted-files.js | 135 +++++--- static/js/components/file-list.js | 327 +++++++++++++----- static/js/components/file-preview.js | 52 ++- static/js/components/file-upload-view.js | 187 +++++++++++ static/js/components/login-view.js | 2 +- static/js/components/photo-gallery.js | 32 +- static/js/components/rbox-app.js | 220 ++++++++++-- static/js/components/recent-files.js | 112 ++++--- static/js/components/shared-items.js | 40 ++- static/js/components/starred-items.js | 148 ++++---- static/js/main.js | 8 +- static/service-worker.js | 2 +- tests/__init__.py | 0 tests/billing/__init__.py | 0 tests/billing/test_api_endpoints.py | 256 ++++++++++++++ tests/billing/test_invoice_generator.py | 195 +++++++++++ tests/billing/test_models.py | 188 +++++++++++ tests/billing/test_simple.py | 77 +++++ tests/billing/test_usage_tracker.py | 175 ++++++++++ tests/conftest.py | 8 + tests/e2e/__init__.py | 0 tests/e2e/conftest.py | 38 +++ tests/e2e/test_billing_admin_flow.py | 199 +++++++++++ tests/e2e/test_billing_api_flow.py | 183 ++++++++++ tests/e2e/test_billing_integration_flow.py | 264 +++++++++++++++ tests/e2e/test_billing_user_flow.py | 264 +++++++++++++++ tests/e2e/test_structure_validation.py | 98 ++++++ 63 files changed, 6107 insertions(+), 491 deletions(-) create mode 100644 rbox/billing/__init__.py create mode 100644 rbox/billing/invoice_generator.py create mode 100644 rbox/billing/models.py create mode 100644 rbox/billing/scheduler.py create mode 100644 rbox/billing/stripe_client.py create mode 100644 rbox/billing/usage_tracker.py create mode 100644 rbox/middleware/__init__.py create mode 100644 rbox/middleware/usage_tracking.py create mode 100644 rbox/routers/admin_billing.py create mode 100644 rbox/routers/billing.py create mode 100644 static/css/billing.css create mode 100644 static/css/code-editor-view.css create mode 100644 static/css/file-upload-view.css create mode 100644 static/icons/icon-256x256.png create mode 100644 static/icons/icon-384x384.png create mode 100644 static/js/components/admin-billing.js create mode 100644 static/js/components/base-file-list.js create mode 100644 static/js/components/billing-dashboard.js create mode 100644 static/js/components/code-editor-view.js create mode 100644 static/js/components/file-upload-view.js create mode 100644 tests/__init__.py create mode 100644 tests/billing/__init__.py create mode 100644 tests/billing/test_api_endpoints.py create mode 100644 tests/billing/test_invoice_generator.py create mode 100644 tests/billing/test_models.py create mode 100644 tests/billing/test_simple.py create mode 100644 tests/billing/test_usage_tracker.py create mode 100644 tests/conftest.py create mode 100644 tests/e2e/__init__.py create mode 100644 tests/e2e/conftest.py create mode 100644 tests/e2e/test_billing_admin_flow.py create mode 100644 tests/e2e/test_billing_api_flow.py create mode 100644 tests/e2e/test_billing_integration_flow.py create mode 100644 tests/e2e/test_billing_user_flow.py create mode 100644 tests/e2e/test_structure_validation.py diff --git a/Makefile b/Makefile index 32d0688..f2254f0 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,153 @@ -PYTHON=".venv/bin/python3" -RBOX=".venv/bin/rbox" +.PHONY: help install dev test test-billing test-e2e test-coverage e2e-setup lint format clean run migrate init-db reset-db all + +PYTHON := .venv/bin/python3 +PIP := .venv/bin/pip +PYTEST := .venv/bin/pytest +BLACK := .venv/bin/black +RUFF := .venv/bin/ruff +RBOX := .venv/bin/rbox all: $(RBOX) --port 9004 + +help: + @echo "RBox Development Makefile" + @echo "" + @echo "Available commands:" + @echo " make all Run the application on port 9004" + @echo " make install Install all dependencies" + @echo " make dev Install development dependencies" + @echo " make run Run the application locally" + @echo " make test Run all tests" + @echo " make test-billing Run billing tests only" + @echo " make test-e2e Run end-to-end tests (visible browser)" + @echo " make test-coverage Run tests with coverage report" + @echo " make e2e-setup Install Playwright and browsers" + @echo " make lint Run linting checks" + @echo " make format Format code with black" + @echo " make migrate Run database migrations" + @echo " make init-db Initialize database with default data" + @echo " make reset-db Reset database (WARNING: deletes all data)" + @echo " make clean Clean up temporary files" + @echo " make setup Complete setup (env + install + init-db)" + +install: + @echo "Installing dependencies..." + $(PIP) install -r requirements.txt + @echo "Dependencies installed successfully" + +dev: + @echo "Installing development dependencies..." + $(PIP) install pytest pytest-asyncio pytest-cov httpx black ruff stripe apscheduler dataset + @echo "Development dependencies installed successfully" + +run: + @echo "Starting RBox application..." + @echo "Access the application at http://localhost:8000" + $(PYTHON) -m rbox.main + +test: + @echo "Running all tests..." + $(PYTEST) tests/ -v + +test-billing: + @echo "Running billing tests..." + $(PYTEST) tests/billing/ -v + +test-e2e: + @echo "Running end-to-end tests with visible browser..." + @echo "Make sure the application is running (make run in another terminal)" + $(PYTEST) tests/e2e/ -v -s --tb=short + +e2e-setup: + @echo "Installing Playwright and browsers..." + $(PIP) install playwright + .venv/bin/playwright install chromium + @echo "Playwright setup complete" + +test-coverage: + @echo "Running tests with coverage..." + $(PYTEST) tests/ -v --cov=rbox --cov-report=html --cov-report=term + @echo "Coverage report generated in htmlcov/index.html" + +lint: + @echo "Running linting checks..." + $(RUFF) check rbox/ + @echo "Linting complete" + +format: + @echo "Formatting code..." + $(BLACK) rbox/ tests/ + @echo "Code formatting complete" + +migrate: + @echo "Running database migrations..." + @echo "Tortoise ORM auto-generates schemas on startup" + $(PYTHON) -c "from rbox.main import app; print('Database schema will be created on first run')" + +init-db: + @echo "Initializing database with default data..." + $(PYTHON) -c "import asyncio; \ + from tortoise import Tortoise; \ + from rbox.settings import settings; \ + from rbox.billing.models import PricingConfig; \ + from decimal import Decimal; \ + async def init(): \ + await Tortoise.init(db_url=settings.DATABASE_URL, modules={'models': ['rbox.models', 'rbox.billing.models']}); \ + await Tortoise.generate_schemas(); \ + count = await PricingConfig.all().count(); \ + if count == 0: \ + 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'); \ + print('Default pricing configuration created'); \ + else: \ + print('Pricing configuration already exists'); \ + await Tortoise.close_connections(); \ + asyncio.run(init())" + @echo "Database initialized successfully" + +reset-db: + @echo "WARNING: This will delete all data!" + @read -p "Are you sure? (yes/no): " confirm && [ "$$confirm" = "yes" ] || exit 1 + @rm -f rbox.db app/rbox.db storage/rbox.db + @echo "Database reset complete. Run 'make init-db' to reinitialize" + +clean: + @echo "Cleaning up temporary files..." + find . -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true + find . -type f -name "*.pyc" -delete + find . -type f -name "*.pyo" -delete + find . -type f -name "*.pyd" -delete + find . -type d -name "*.egg-info" -exec rm -rf {} + 2>/dev/null || true + find . -type d -name ".pytest_cache" -exec rm -rf {} + 2>/dev/null || true + find . -type d -name ".ruff_cache" -exec rm -rf {} + 2>/dev/null || true + rm -rf htmlcov/ + rm -rf .coverage + @echo "Cleanup complete" + +setup-env: + @echo "Setting up environment file..." + @if [ ! -f .env ]; then \ + cp .env.example .env 2>/dev/null || \ + echo "DATABASE_URL=sqlite:///app/rbox.db\nSECRET_KEY=$$(openssl rand -hex 32)\nSTRIPE_SECRET_KEY=\nSTRIPE_PUBLISHABLE_KEY=\nSTRIPE_WEBHOOK_SECRET=" > .env; \ + echo ".env file created. Please update with your configuration."; \ + else \ + echo ".env file already exists"; \ + fi + +setup: setup-env install dev init-db + @echo "" + @echo "Setup complete!" + @echo "Next steps:" + @echo " 1. Update .env with your configuration (especially Stripe keys)" + @echo " 2. Run 'make run' or 'make all' to start the application" + @echo " 3. Access the application at http://localhost:8000" + +docs: + @echo "Generating API documentation..." + @echo "API documentation available at http://localhost:8000/docs when running" + @echo "ReDoc available at http://localhost:8000/redoc when running" diff --git a/rbox/auth.py b/rbox/auth.py index 5d8ad15..1b2808b 100644 --- a/rbox/auth.py +++ b/rbox/auth.py @@ -15,7 +15,7 @@ oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") def verify_password(plain_password, hashed_password): password_bytes = plain_password[:72].encode('utf-8') - hashed_bytes = hashed_password.encode('utf-8') if isinstance(hashed_password, str) else hashed_bytes + hashed_bytes = hashed_password.encode('utf-8') if isinstance(hashed_password, str) else hashed_password return bcrypt.checkpw(password_bytes, hashed_bytes) def get_password_hash(password): diff --git a/rbox/billing/__init__.py b/rbox/billing/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/rbox/billing/invoice_generator.py b/rbox/billing/invoice_generator.py new file mode 100644 index 0000000..1f208e7 --- /dev/null +++ b/rbox/billing/invoice_generator.py @@ -0,0 +1,143 @@ +from datetime import datetime, date, timedelta +from decimal import Decimal +from typing import Optional +from calendar import monthrange +from .models import Invoice, InvoiceLineItem, PricingConfig, UsageAggregate, UserSubscription +from .usage_tracker import UsageTracker +from .stripe_client import StripeClient +from ..models import User + +class InvoiceGenerator: + @staticmethod + async def generate_monthly_invoice(user: User, year: int, month: int) -> Optional[Invoice]: + period_start = date(year, month, 1) + days_in_month = monthrange(year, month)[1] + period_end = date(year, month, days_in_month) + + usage = await UsageTracker.get_monthly_usage(user, year, month) + + pricing = await PricingConfig.all() + pricing_dict = {p.config_key: p.config_value for p in pricing} + + storage_price_per_gb = pricing_dict.get('storage_per_gb_month', Decimal('0.0045')) + bandwidth_price_per_gb = pricing_dict.get('bandwidth_egress_per_gb', Decimal('0.009')) + free_storage_gb = pricing_dict.get('free_tier_storage_gb', Decimal('15')) + free_bandwidth_gb = pricing_dict.get('free_tier_bandwidth_gb', Decimal('15')) + tax_rate = pricing_dict.get('tax_rate_default', Decimal('0')) + + storage_gb = Decimal(str(usage['storage_gb_avg'])) + bandwidth_gb = Decimal(str(usage['bandwidth_down_gb'])) + + billable_storage = max(Decimal('0'), storage_gb - free_storage_gb) + billable_bandwidth = max(Decimal('0'), bandwidth_gb - free_bandwidth_gb) + + import math + billable_storage_rounded = Decimal(math.ceil(float(billable_storage))) + billable_bandwidth_rounded = Decimal(math.ceil(float(billable_bandwidth))) + + storage_cost = billable_storage_rounded * storage_price_per_gb + bandwidth_cost = billable_bandwidth_rounded * bandwidth_price_per_gb + + subtotal = storage_cost + bandwidth_cost + + if subtotal <= 0: + return None + + tax_amount = subtotal * tax_rate + total = subtotal + tax_amount + + invoice_number = f"INV-{user.id:06d}-{year}{month:02d}" + + subscription = await UserSubscription.get_or_none(user=user) + + invoice = await Invoice.create( + user=user, + invoice_number=invoice_number, + period_start=period_start, + period_end=period_end, + subtotal=subtotal, + tax=tax_amount, + total=total, + currency="USD", + status="draft", + due_date=period_end + timedelta(days=7), + metadata={ + "usage": usage, + "pricing": { + "storage_per_gb": float(storage_price_per_gb), + "bandwidth_per_gb": float(bandwidth_price_per_gb) + } + } + ) + + if billable_storage_rounded > 0: + await InvoiceLineItem.create( + invoice=invoice, + description=f"Storage usage for {period_start.strftime('%B %Y')} (Average: {storage_gb:.2f} GB, Billable: {billable_storage_rounded} GB)", + quantity=billable_storage_rounded, + unit_price=storage_price_per_gb, + amount=storage_cost, + item_type="storage", + metadata={"avg_gb": float(storage_gb), "free_gb": float(free_storage_gb)} + ) + + if billable_bandwidth_rounded > 0: + await InvoiceLineItem.create( + invoice=invoice, + description=f"Bandwidth usage for {period_start.strftime('%B %Y')} (Total: {bandwidth_gb:.2f} GB, Billable: {billable_bandwidth_rounded} GB)", + quantity=billable_bandwidth_rounded, + unit_price=bandwidth_price_per_gb, + amount=bandwidth_cost, + item_type="bandwidth", + metadata={"total_gb": float(bandwidth_gb), "free_gb": float(free_bandwidth_gb)} + ) + + if subscription and subscription.stripe_customer_id: + try: + line_items = await invoice.line_items.all() + stripe_line_items = [ + { + "amount": item.amount, + "currency": "usd", + "description": item.description, + "metadata": item.metadata or {} + } + for item in line_items + ] + + stripe_invoice = await StripeClient.create_invoice( + customer_id=subscription.stripe_customer_id, + description=f"RBox Usage Invoice for {period_start.strftime('%B %Y')}", + line_items=stripe_line_items, + metadata={"rbox_invoice_id": str(invoice.id)} + ) + + invoice.stripe_invoice_id = stripe_invoice.id + await invoice.save() + except Exception as e: + print(f"Failed to create Stripe invoice: {e}") + + return invoice + + @staticmethod + async def finalize_invoice(invoice: Invoice) -> Invoice: + if invoice.status != "draft": + raise ValueError("Only draft invoices can be finalized") + + invoice.status = "open" + await invoice.save() + + if invoice.stripe_invoice_id: + try: + await StripeClient.finalize_invoice(invoice.stripe_invoice_id) + except Exception as e: + print(f"Failed to finalize Stripe invoice: {e}") + + return invoice + + @staticmethod + async def mark_invoice_paid(invoice: Invoice) -> Invoice: + invoice.status = "paid" + invoice.paid_at = datetime.utcnow() + await invoice.save() + return invoice diff --git a/rbox/billing/models.py b/rbox/billing/models.py new file mode 100644 index 0000000..264f7b6 --- /dev/null +++ b/rbox/billing/models.py @@ -0,0 +1,139 @@ +from tortoise import fields, models +from decimal import Decimal + +class SubscriptionPlan(models.Model): + id = fields.IntField(pk=True) + name = fields.CharField(max_length=100, unique=True) + display_name = fields.CharField(max_length=255) + description = fields.TextField(null=True) + storage_gb = fields.IntField() + bandwidth_gb = fields.IntField() + price_monthly = fields.DecimalField(max_digits=10, decimal_places=2) + price_yearly = fields.DecimalField(max_digits=10, decimal_places=2, null=True) + stripe_price_id = fields.CharField(max_length=255, null=True) + is_active = fields.BooleanField(default=True) + created_at = fields.DatetimeField(auto_now_add=True) + updated_at = fields.DatetimeField(auto_now=True) + + class Meta: + table = "subscription_plans" + +class UserSubscription(models.Model): + id = fields.IntField(pk=True) + user = fields.ForeignKeyField("models.User", related_name="subscription") + plan = fields.ForeignKeyField("billing.SubscriptionPlan", related_name="subscriptions", null=True) + billing_type = fields.CharField(max_length=20, default="pay_as_you_go") + stripe_customer_id = fields.CharField(max_length=255, unique=True, null=True) + stripe_subscription_id = fields.CharField(max_length=255, unique=True, null=True) + status = fields.CharField(max_length=50, default="active") + current_period_start = fields.DatetimeField(null=True) + current_period_end = fields.DatetimeField(null=True) + created_at = fields.DatetimeField(auto_now_add=True) + updated_at = fields.DatetimeField(auto_now=True) + canceled_at = fields.DatetimeField(null=True) + + class Meta: + table = "user_subscriptions" + +class UsageRecord(models.Model): + id = fields.BigIntField(pk=True) + user = fields.ForeignKeyField("models.User", related_name="usage_records") + record_type = fields.CharField(max_length=50) + amount_bytes = fields.BigIntField() + resource_type = fields.CharField(max_length=50, null=True) + resource_id = fields.IntField(null=True) + timestamp = fields.DatetimeField(auto_now_add=True) + idempotency_key = fields.CharField(max_length=255, unique=True, null=True) + metadata = fields.JSONField(null=True) + + class Meta: + table = "usage_records" + +class UsageAggregate(models.Model): + id = fields.IntField(pk=True) + user = fields.ForeignKeyField("models.User", related_name="usage_aggregates") + date = fields.DateField() + storage_bytes_avg = fields.BigIntField(default=0) + storage_bytes_peak = fields.BigIntField(default=0) + bandwidth_up_bytes = fields.BigIntField(default=0) + bandwidth_down_bytes = fields.BigIntField(default=0) + created_at = fields.DatetimeField(auto_now_add=True) + + class Meta: + table = "usage_aggregates" + unique_together = (("user", "date"),) + +class Invoice(models.Model): + id = fields.IntField(pk=True) + user = fields.ForeignKeyField("models.User", related_name="invoices") + invoice_number = fields.CharField(max_length=50, unique=True) + stripe_invoice_id = fields.CharField(max_length=255, unique=True, null=True) + period_start = fields.DateField() + period_end = fields.DateField() + subtotal = fields.DecimalField(max_digits=10, decimal_places=4) + tax = fields.DecimalField(max_digits=10, decimal_places=4, default=0) + total = fields.DecimalField(max_digits=10, decimal_places=4) + currency = fields.CharField(max_length=3, default="USD") + status = fields.CharField(max_length=50, default="draft") + due_date = fields.DateField(null=True) + paid_at = fields.DatetimeField(null=True) + created_at = fields.DatetimeField(auto_now_add=True) + updated_at = fields.DatetimeField(auto_now=True) + metadata = fields.JSONField(null=True) + + class Meta: + table = "invoices" + +class InvoiceLineItem(models.Model): + id = fields.IntField(pk=True) + invoice = fields.ForeignKeyField("billing.Invoice", related_name="line_items") + description = fields.TextField() + quantity = fields.DecimalField(max_digits=15, decimal_places=6) + unit_price = fields.DecimalField(max_digits=10, decimal_places=6) + amount = fields.DecimalField(max_digits=10, decimal_places=4) + item_type = fields.CharField(max_length=50, null=True) + metadata = fields.JSONField(null=True) + created_at = fields.DatetimeField(auto_now_add=True) + + class Meta: + table = "invoice_line_items" + +class PricingConfig(models.Model): + id = fields.IntField(pk=True) + config_key = fields.CharField(max_length=100, unique=True) + config_value = fields.DecimalField(max_digits=10, decimal_places=6) + description = fields.TextField(null=True) + unit = fields.CharField(max_length=50, null=True) + updated_by = fields.ForeignKeyField("models.User", related_name="pricing_updates", null=True) + updated_at = fields.DatetimeField(auto_now=True) + + class Meta: + table = "pricing_config" + +class PaymentMethod(models.Model): + id = fields.IntField(pk=True) + user = fields.ForeignKeyField("models.User", related_name="payment_methods") + stripe_payment_method_id = fields.CharField(max_length=255) + type = fields.CharField(max_length=50) + is_default = fields.BooleanField(default=False) + last4 = fields.CharField(max_length=4, null=True) + brand = fields.CharField(max_length=50, null=True) + exp_month = fields.IntField(null=True) + exp_year = fields.IntField(null=True) + created_at = fields.DatetimeField(auto_now_add=True) + updated_at = fields.DatetimeField(auto_now=True) + + class Meta: + table = "payment_methods" + +class BillingEvent(models.Model): + id = fields.BigIntField(pk=True) + user = fields.ForeignKeyField("models.User", related_name="billing_events", null=True) + event_type = fields.CharField(max_length=100) + stripe_event_id = fields.CharField(max_length=255, unique=True, null=True) + data = fields.JSONField(null=True) + processed = fields.BooleanField(default=False) + created_at = fields.DatetimeField(auto_now_add=True) + + class Meta: + table = "billing_events" diff --git a/rbox/billing/scheduler.py b/rbox/billing/scheduler.py new file mode 100644 index 0000000..7e086e0 --- /dev/null +++ b/rbox/billing/scheduler.py @@ -0,0 +1,57 @@ +from apscheduler.schedulers.asyncio import AsyncIOScheduler +from apscheduler.triggers.cron import CronTrigger +from datetime import datetime, date, timedelta +import asyncio + +from .usage_tracker import UsageTracker +from .invoice_generator import InvoiceGenerator +from ..models import User + +scheduler = AsyncIOScheduler() + +async def aggregate_daily_usage_for_all_users(): + users = await User.filter(is_active=True).all() + yesterday = date.today() - timedelta(days=1) + + for user in users: + try: + await UsageTracker.aggregate_daily_usage(user, yesterday) + except Exception as e: + print(f"Failed to aggregate usage for user {user.id}: {e}") + +async def generate_monthly_invoices(): + now = datetime.now() + last_month = now.month - 1 if now.month > 1 else 12 + year = now.year if now.month > 1 else now.year - 1 + + users = await User.filter(is_active=True).all() + + for user in users: + try: + invoice = await InvoiceGenerator.generate_monthly_invoice(user, year, last_month) + if invoice: + await InvoiceGenerator.finalize_invoice(invoice) + except Exception as e: + print(f"Failed to generate invoice for user {user.id}: {e}") + +def start_scheduler(): + scheduler.add_job( + aggregate_daily_usage_for_all_users, + CronTrigger(hour=1, minute=0), + id="aggregate_daily_usage", + name="Aggregate daily usage for all users", + replace_existing=True + ) + + scheduler.add_job( + generate_monthly_invoices, + CronTrigger(day=1, hour=2, minute=0), + id="generate_monthly_invoices", + name="Generate monthly invoices", + replace_existing=True + ) + + scheduler.start() + +def stop_scheduler(): + scheduler.shutdown() diff --git a/rbox/billing/stripe_client.py b/rbox/billing/stripe_client.py new file mode 100644 index 0000000..1e9211c --- /dev/null +++ b/rbox/billing/stripe_client.py @@ -0,0 +1,105 @@ +import stripe +from decimal import Decimal +from typing import Optional, Dict, Any +from ..settings import settings + +stripe.api_key = settings.STRIPE_SECRET_KEY if hasattr(settings, 'STRIPE_SECRET_KEY') else "" + +class StripeClient: + @staticmethod + async def create_customer(email: str, name: str, metadata: Dict = None) -> str: + customer = stripe.Customer.create( + email=email, + name=name, + metadata=metadata or {} + ) + return customer.id + + @staticmethod + async def create_payment_intent( + amount: int, + currency: str = "usd", + customer_id: str = None, + metadata: Dict = None + ) -> stripe.PaymentIntent: + return stripe.PaymentIntent.create( + amount=amount, + currency=currency, + customer=customer_id, + metadata=metadata or {}, + automatic_payment_methods={"enabled": True} + ) + + @staticmethod + async def create_invoice( + customer_id: str, + description: str, + line_items: list, + metadata: Dict = None + ) -> stripe.Invoice: + for item in line_items: + stripe.InvoiceItem.create( + customer=customer_id, + amount=int(item['amount'] * 100), + currency=item.get('currency', 'usd'), + description=item['description'], + metadata=item.get('metadata', {}) + ) + + invoice = stripe.Invoice.create( + customer=customer_id, + description=description, + auto_advance=True, + collection_method='charge_automatically', + metadata=metadata or {} + ) + + return invoice + + @staticmethod + async def finalize_invoice(invoice_id: str) -> stripe.Invoice: + return stripe.Invoice.finalize_invoice(invoice_id) + + @staticmethod + async def pay_invoice(invoice_id: str) -> stripe.Invoice: + return stripe.Invoice.pay(invoice_id) + + @staticmethod + async def attach_payment_method( + payment_method_id: str, + customer_id: str + ) -> stripe.PaymentMethod: + payment_method = stripe.PaymentMethod.attach( + payment_method_id, + customer=customer_id + ) + + stripe.Customer.modify( + customer_id, + invoice_settings={'default_payment_method': payment_method_id} + ) + + return payment_method + + @staticmethod + async def list_payment_methods(customer_id: str, type: str = "card"): + return stripe.PaymentMethod.list( + customer=customer_id, + type=type + ) + + @staticmethod + async def create_subscription( + customer_id: str, + price_id: str, + metadata: Dict = None + ) -> stripe.Subscription: + return stripe.Subscription.create( + customer=customer_id, + items=[{'price': price_id}], + metadata=metadata or {} + ) + + @staticmethod + async def cancel_subscription(subscription_id: str) -> stripe.Subscription: + return stripe.Subscription.delete(subscription_id) diff --git a/rbox/billing/usage_tracker.py b/rbox/billing/usage_tracker.py new file mode 100644 index 0000000..4e57b28 --- /dev/null +++ b/rbox/billing/usage_tracker.py @@ -0,0 +1,142 @@ +import uuid +from datetime import datetime, date +from decimal import Decimal +from typing import Optional +from tortoise.transactions import in_transaction +from .models import UsageRecord, UsageAggregate +from ..models import User + +class UsageTracker: + @staticmethod + async def track_storage( + user: User, + amount_bytes: int, + resource_type: str = None, + resource_id: int = None, + metadata: dict = None + ): + idempotency_key = f"storage_{user.id}_{datetime.utcnow().timestamp()}_{uuid.uuid4().hex[:8]}" + + await UsageRecord.create( + user=user, + record_type="storage", + amount_bytes=amount_bytes, + resource_type=resource_type, + resource_id=resource_id, + idempotency_key=idempotency_key, + metadata=metadata + ) + + @staticmethod + async def track_bandwidth( + user: User, + amount_bytes: int, + direction: str = "down", + resource_type: str = None, + resource_id: int = None, + metadata: dict = None + ): + record_type = f"bandwidth_{direction}" + idempotency_key = f"{record_type}_{user.id}_{datetime.utcnow().timestamp()}_{uuid.uuid4().hex[:8]}" + + await UsageRecord.create( + user=user, + record_type=record_type, + amount_bytes=amount_bytes, + resource_type=resource_type, + resource_id=resource_id, + idempotency_key=idempotency_key, + metadata=metadata + ) + + @staticmethod + async def aggregate_daily_usage(user: User, target_date: date = None): + if target_date is None: + target_date = date.today() + + start_of_day = datetime.combine(target_date, datetime.min.time()) + end_of_day = datetime.combine(target_date, datetime.max.time()) + + storage_records = await UsageRecord.filter( + user=user, + record_type="storage", + timestamp__gte=start_of_day, + timestamp__lte=end_of_day + ).all() + + storage_avg = sum(r.amount_bytes for r in storage_records) // max(len(storage_records), 1) + storage_peak = max((r.amount_bytes for r in storage_records), default=0) + + bandwidth_up = await UsageRecord.filter( + user=user, + record_type="bandwidth_up", + timestamp__gte=start_of_day, + timestamp__lte=end_of_day + ).all() + + bandwidth_down = await UsageRecord.filter( + user=user, + record_type="bandwidth_down", + timestamp__gte=start_of_day, + timestamp__lte=end_of_day + ).all() + + total_up = sum(r.amount_bytes for r in bandwidth_up) + total_down = sum(r.amount_bytes for r in bandwidth_down) + + async with in_transaction(): + aggregate, created = await UsageAggregate.get_or_create( + user=user, + date=target_date, + defaults={ + "storage_bytes_avg": storage_avg, + "storage_bytes_peak": storage_peak, + "bandwidth_up_bytes": total_up, + "bandwidth_down_bytes": total_down + } + ) + + if not created: + aggregate.storage_bytes_avg = storage_avg + aggregate.storage_bytes_peak = storage_peak + aggregate.bandwidth_up_bytes = total_up + aggregate.bandwidth_down_bytes = total_down + await aggregate.save() + + return aggregate + + @staticmethod + async def get_current_storage(user: User) -> int: + from ..models import File + files = await File.filter(user=user, is_deleted=False).all() + return sum(f.size for f in files) + + @staticmethod + async def get_monthly_usage(user: User, year: int, month: int) -> dict: + aggregates = await UsageAggregate.filter( + user=user, + date__year=year, + date__month=month + ).all() + + if not aggregates: + return { + "storage_gb_avg": 0, + "storage_gb_peak": 0, + "bandwidth_up_gb": 0, + "bandwidth_down_gb": 0, + "total_bandwidth_gb": 0 + } + + storage_avg = sum(a.storage_bytes_avg for a in aggregates) / len(aggregates) + storage_peak = max(a.storage_bytes_peak for a in aggregates) + bandwidth_up = sum(a.bandwidth_up_bytes for a in aggregates) + bandwidth_down = sum(a.bandwidth_down_bytes for a in aggregates) + + return { + "storage_gb_avg": round(storage_avg / (1024**3), 4), + "storage_gb_peak": round(storage_peak / (1024**3), 4), + "bandwidth_up_gb": round(bandwidth_up / (1024**3), 4), + "bandwidth_down_gb": round(bandwidth_down / (1024**3), 4), + "total_bandwidth_gb": round((bandwidth_up + bandwidth_down) / (1024**3), 4) + } diff --git a/rbox/main.py b/rbox/main.py index 8de0464..915368d 100644 --- a/rbox/main.py +++ b/rbox/main.py @@ -1,23 +1,50 @@ import argparse import uvicorn -import logging # Import logging +import logging +from contextlib import asynccontextmanager from fastapi import FastAPI, Request, status, HTTPException from fastapi.staticfiles import StaticFiles from fastapi.responses import HTMLResponse, JSONResponse from tortoise.contrib.fastapi import register_tortoise from .settings import settings -from .routers import auth, users, folders, files, shares, search, admin, starred +from .routers import auth, users, folders, files, shares, search, admin, starred, billing, admin_billing from . import webdav -from .schemas import ErrorResponse # Import ErrorResponse +from .schemas import ErrorResponse -# Configure logging logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) +@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 + start_scheduler() + logger.info("Billing scheduler started") + pricing_count = await PricingConfig.all().count() + if pricing_count == 0: + from decimal import Decimal + 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') + logger.info("Default pricing configuration initialized") + + yield + + from .billing.scheduler import stop_scheduler + stop_scheduler() + logger.info("Billing scheduler stopped") + print("Shutting down...") + app = FastAPI( title="RBox Cloud Storage", description="A self-hosted cloud storage web application", version="0.1.0", + lifespan=lifespan ) app.include_router(auth.router) @@ -26,17 +53,25 @@ app.include_router(folders.router) app.include_router(files.router) app.include_router(shares.router) app.include_router(search.router) -app.include_router(admin.router) # Include the admin router -app.include_router(starred.router) # Include the starred router +app.include_router(admin.router) +app.include_router(starred.router) +app.include_router(billing.router) +app.include_router(admin_billing.router) app.include_router(webdav.router) -# Mount static files +from .middleware.usage_tracking import UsageTrackingMiddleware + +app.add_middleware(UsageTrackingMiddleware) + app.mount("/static", StaticFiles(directory="static"), name="static") register_tortoise( app, db_url=settings.DATABASE_URL, - modules={"models": ["rbox.models"]}, + modules={ + "models": ["rbox.models"], + "billing": ["rbox.billing.models"] + }, generate_schemas=True, add_exception_handlers=True, ) @@ -49,14 +84,6 @@ async def http_exception_handler(request: Request, exc: HTTPException): content=ErrorResponse(code=exc.status_code, message=exc.detail).dict(), ) -@app.on_event("startup") -async def startup_event(): - logger.info("Starting up...") - logger.info("Database connected.") - -@app.on_event("shutdown") -async def shutdown_event(): - print("Shutting down...") @app.get("/", response_class=HTMLResponse) # Change response_class to HTMLResponse async def read_root(): diff --git a/rbox/middleware/__init__.py b/rbox/middleware/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/rbox/middleware/usage_tracking.py b/rbox/middleware/usage_tracking.py new file mode 100644 index 0000000..854e709 --- /dev/null +++ b/rbox/middleware/usage_tracking.py @@ -0,0 +1,32 @@ +from fastapi import Request +from starlette.middleware.base import BaseHTTPMiddleware +from ..billing.usage_tracker import UsageTracker + +class UsageTrackingMiddleware(BaseHTTPMiddleware): + async def dispatch(self, request: Request, call_next): + response = await call_next(request) + + if hasattr(request.state, 'user') and request.state.user: + user = request.state.user + + if request.method in ['POST', 'PUT'] and '/files/upload' in request.url.path: + content_length = response.headers.get('content-length') + if content_length: + await UsageTracker.track_bandwidth( + user=user, + amount_bytes=int(content_length), + direction='up', + metadata={'path': request.url.path} + ) + + elif request.method == 'GET' and '/files/download' in request.url.path: + content_length = response.headers.get('content-length') + if content_length: + await UsageTracker.track_bandwidth( + user=user, + amount_bytes=int(content_length), + direction='down', + metadata={'path': request.url.path} + ) + + return response diff --git a/rbox/routers/admin_billing.py b/rbox/routers/admin_billing.py new file mode 100644 index 0000000..54049cf --- /dev/null +++ b/rbox/routers/admin_billing.py @@ -0,0 +1,116 @@ +from fastapi import APIRouter, Depends, HTTPException +from typing import List +from decimal import Decimal +from pydantic import BaseModel + +from ..auth import get_current_user +from ..models import User +from ..billing.models import PricingConfig, Invoice, SubscriptionPlan +from ..billing.invoice_generator import InvoiceGenerator + +def require_superuser(current_user: User = Depends(get_current_user)): + if not current_user.is_superuser: + raise HTTPException(status_code=403, detail="Superuser privileges required") + return current_user + +router = APIRouter( + prefix="/api/admin/billing", + tags=["admin", "billing"], + dependencies=[Depends(require_superuser)] +) + +class PricingConfigUpdate(BaseModel): + config_key: str + config_value: float + +class PlanCreate(BaseModel): + name: str + display_name: str + description: str + storage_gb: int + bandwidth_gb: int + price_monthly: float + price_yearly: float = None + +@router.get("/pricing") +async def get_all_pricing(current_user: User = Depends(require_superuser)): + configs = await PricingConfig.all() + return [ + { + "id": c.id, + "config_key": c.config_key, + "config_value": float(c.config_value), + "description": c.description, + "unit": c.unit, + "updated_at": c.updated_at + } + for c in configs + ] + +@router.put("/pricing/{config_id}") +async def update_pricing( + config_id: int, + update: PricingConfigUpdate, + current_user: User = Depends(require_superuser) +): + config = await PricingConfig.get_or_none(id=config_id) + if not config: + raise HTTPException(status_code=404, detail="Config not found") + + config.config_value = Decimal(str(update.config_value)) + config.updated_by = current_user + await config.save() + + return {"message": "Pricing updated successfully"} + +@router.post("/generate-invoices/{year}/{month}") +async def generate_all_invoices( + year: int, + month: int, + current_user: User = Depends(require_superuser) +): + users = await User.filter(is_active=True).all() + generated = [] + skipped = [] + + for user in users: + invoice = await InvoiceGenerator.generate_monthly_invoice(user, year, month) + if invoice: + generated.append({ + "user_id": user.id, + "invoice_id": invoice.id, + "total": float(invoice.total) + }) + else: + skipped.append(user.id) + + return { + "generated": len(generated), + "skipped": len(skipped), + "invoices": generated + } + +@router.post("/plans") +async def create_plan( + plan_data: PlanCreate, + current_user: User = Depends(require_superuser) +): + plan = await SubscriptionPlan.create(**plan_data.dict()) + return {"id": plan.id, "message": "Plan created successfully"} + +@router.get("/stats") +async def get_billing_stats(current_user: User = Depends(require_superuser)): + from tortoise.functions import Sum, Count + + total_revenue = await Invoice.filter(status="paid").annotate( + total_sum=Sum("total") + ).values("total_sum") + + invoice_count = await Invoice.all().count() + pending_invoices = await Invoice.filter(status="open").count() + + return { + "total_revenue": float(total_revenue[0]["total_sum"] or 0), + "total_invoices": invoice_count, + "pending_invoices": pending_invoices + } diff --git a/rbox/routers/auth.py b/rbox/routers/auth.py index 4f5908b..4cbc2f9 100644 --- a/rbox/routers/auth.py +++ b/rbox/routers/auth.py @@ -65,16 +65,16 @@ async def register_user(user_in: UserCreate): return {"access_token": access_token, "token_type": "bearer"} @router.post("/token", response_model=Token) -async def login_for_access_token(user_login: UserLoginWith2FA): - auth_result = await authenticate_user(user_login.username, user_login.password, user_login.two_factor_code) - +async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()): + auth_result = await authenticate_user(form_data.username, form_data.password, None) + if not auth_result: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, - detail="Incorrect username or password or 2FA code", + detail="Incorrect username or password", headers={"WWW-Authenticate": "Bearer"}, ) - + user = auth_result["user"] if auth_result["2fa_required"]: raise HTTPException( diff --git a/rbox/routers/billing.py b/rbox/routers/billing.py new file mode 100644 index 0000000..45e5551 --- /dev/null +++ b/rbox/routers/billing.py @@ -0,0 +1,312 @@ +from fastapi import APIRouter, Depends, HTTPException, status, Request +from fastapi.responses import JSONResponse +from typing import List, Optional +from datetime import datetime, date +from decimal import Decimal +import calendar + +from ..auth import get_current_user +from ..models import User +from ..billing.models import ( + Invoice, InvoiceLineItem, UserSubscription, PricingConfig, + PaymentMethod, UsageAggregate, SubscriptionPlan +) +from ..billing.usage_tracker import UsageTracker +from ..billing.invoice_generator import InvoiceGenerator +from ..billing.stripe_client import StripeClient +from pydantic import BaseModel + +router = APIRouter( + prefix="/api/billing", + tags=["billing"] +) + +class UsageResponse(BaseModel): + storage_gb_avg: float + storage_gb_peak: float + bandwidth_up_gb: float + bandwidth_down_gb: float + total_bandwidth_gb: float + period: str + +class InvoiceResponse(BaseModel): + id: int + invoice_number: str + period_start: date + period_end: date + subtotal: float + tax: float + total: float + status: str + due_date: Optional[date] + paid_at: Optional[datetime] + line_items: List[dict] + +class SubscriptionResponse(BaseModel): + id: int + billing_type: str + plan_name: Optional[str] + status: str + current_period_start: Optional[datetime] + current_period_end: Optional[datetime] + +@router.get("/usage/current") +async def get_current_usage(current_user: User = Depends(get_current_user)): + storage_bytes = await UsageTracker.get_current_storage(current_user) + today = date.today() + + usage_today = await UsageAggregate.get_or_none(user=current_user, date=today) + + if usage_today: + return { + "storage_gb": round(storage_bytes / (1024**3), 4), + "bandwidth_down_gb_today": round(usage_today.bandwidth_down_bytes / (1024**3), 4), + "bandwidth_up_gb_today": round(usage_today.bandwidth_up_bytes / (1024**3), 4), + "as_of": today.isoformat() + } + + return { + "storage_gb": round(storage_bytes / (1024**3), 4), + "bandwidth_down_gb_today": 0, + "bandwidth_up_gb_today": 0, + "as_of": today.isoformat() + } + +@router.get("/usage/monthly") +async def get_monthly_usage( + year: Optional[int] = None, + month: Optional[int] = None, + current_user: User = Depends(get_current_user) +) -> UsageResponse: + if year is None or month is None: + now = datetime.now() + year = now.year + month = now.month + + usage = await UsageTracker.get_monthly_usage(current_user, year, month) + + return UsageResponse( + **usage, + period=f"{year}-{month:02d}" + ) + +@router.get("/invoices") +async def list_invoices( + limit: int = 50, + offset: int = 0, + current_user: User = Depends(get_current_user) +) -> List[InvoiceResponse]: + invoices = await Invoice.filter(user=current_user).order_by("-created_at").offset(offset).limit(limit).all() + + result = [] + for invoice in invoices: + line_items = await invoice.line_items.all() + result.append(InvoiceResponse( + id=invoice.id, + invoice_number=invoice.invoice_number, + period_start=invoice.period_start, + period_end=invoice.period_end, + subtotal=float(invoice.subtotal), + tax=float(invoice.tax), + total=float(invoice.total), + status=invoice.status, + due_date=invoice.due_date, + paid_at=invoice.paid_at, + line_items=[ + { + "description": item.description, + "quantity": float(item.quantity), + "unit_price": float(item.unit_price), + "amount": float(item.amount), + "type": item.item_type + } + for item in line_items + ] + )) + + return result + +@router.get("/invoices/{invoice_id}") +async def get_invoice( + invoice_id: int, + current_user: User = Depends(get_current_user) +) -> InvoiceResponse: + invoice = await Invoice.get_or_none(id=invoice_id, user=current_user) + if not invoice: + raise HTTPException(status_code=404, detail="Invoice not found") + + line_items = await invoice.line_items.all() + + return InvoiceResponse( + id=invoice.id, + invoice_number=invoice.invoice_number, + period_start=invoice.period_start, + period_end=invoice.period_end, + subtotal=float(invoice.subtotal), + tax=float(invoice.tax), + total=float(invoice.total), + status=invoice.status, + due_date=invoice.due_date, + paid_at=invoice.paid_at, + line_items=[ + { + "description": item.description, + "quantity": float(item.quantity), + "unit_price": float(item.unit_price), + "amount": float(item.amount), + "type": item.item_type + } + for item in line_items + ] + ) + +@router.get("/subscription") +async def get_subscription(current_user: User = Depends(get_current_user)) -> SubscriptionResponse: + subscription = await UserSubscription.get_or_none(user=current_user) + + if not subscription: + subscription = await UserSubscription.create( + user=current_user, + billing_type="pay_as_you_go", + status="active" + ) + + plan_name = None + if subscription.plan: + plan = await subscription.plan + plan_name = plan.display_name + + return SubscriptionResponse( + id=subscription.id, + billing_type=subscription.billing_type, + plan_name=plan_name, + status=subscription.status, + current_period_start=subscription.current_period_start, + current_period_end=subscription.current_period_end + ) + +@router.post("/payment-methods/setup-intent") +async def create_setup_intent(current_user: User = Depends(get_current_user)): + subscription = await UserSubscription.get_or_none(user=current_user) + + if not subscription or not subscription.stripe_customer_id: + customer_id = await StripeClient.create_customer( + email=current_user.email, + name=current_user.username, + metadata={"user_id": str(current_user.id)} + ) + + if not subscription: + subscription = await UserSubscription.create( + user=current_user, + billing_type="pay_as_you_go", + stripe_customer_id=customer_id, + status="active" + ) + else: + subscription.stripe_customer_id = customer_id + await subscription.save() + + import stripe + setup_intent = stripe.SetupIntent.create( + customer=subscription.stripe_customer_id, + payment_method_types=["card"] + ) + + return { + "client_secret": setup_intent.client_secret, + "customer_id": subscription.stripe_customer_id + } + +@router.get("/payment-methods") +async def list_payment_methods(current_user: User = Depends(get_current_user)): + methods = await PaymentMethod.filter(user=current_user).all() + return [ + { + "id": m.id, + "type": m.type, + "last4": m.last4, + "brand": m.brand, + "exp_month": m.exp_month, + "exp_year": m.exp_year, + "is_default": m.is_default + } + for m in methods + ] + +@router.post("/webhooks/stripe") +async def stripe_webhook(request: Request): + import stripe + from ..settings import settings + + payload = await request.body() + sig_header = request.headers.get("stripe-signature") + + try: + event = stripe.Webhook.construct_event( + payload, sig_header, settings.STRIPE_WEBHOOK_SECRET + ) + except ValueError: + raise HTTPException(status_code=400, detail="Invalid payload") + except stripe.error.SignatureVerificationError: + raise HTTPException(status_code=400, detail="Invalid signature") + + if event["type"] == "invoice.payment_succeeded": + invoice_data = event["data"]["object"] + rbox_invoice_id = invoice_data.get("metadata", {}).get("rbox_invoice_id") + + if rbox_invoice_id: + invoice = await Invoice.get_or_none(id=int(rbox_invoice_id)) + if invoice: + await InvoiceGenerator.mark_invoice_paid(invoice) + + elif event["type"] == "invoice.payment_failed": + pass + + elif event["type"] == "payment_method.attached": + payment_method = event["data"]["object"] + customer_id = payment_method["customer"] + + subscription = await UserSubscription.get_or_none(stripe_customer_id=customer_id) + if subscription: + await PaymentMethod.create( + user=subscription.user, + stripe_payment_method_id=payment_method["id"], + type=payment_method["type"], + last4=payment_method.get("card", {}).get("last4"), + brand=payment_method.get("card", {}).get("brand"), + exp_month=payment_method.get("card", {}).get("exp_month"), + exp_year=payment_method.get("card", {}).get("exp_year"), + is_default=True + ) + + return JSONResponse(content={"status": "success"}) + +@router.get("/pricing") +async def get_pricing(): + configs = await PricingConfig.all() + return { + config.config_key: { + "value": float(config.config_value), + "description": config.description, + "unit": config.unit + } + for config in configs + } + +@router.get("/plans") +async def list_plans(): + plans = await SubscriptionPlan.filter(is_active=True).all() + return [ + { + "id": plan.id, + "name": plan.name, + "display_name": plan.display_name, + "description": plan.description, + "storage_gb": plan.storage_gb, + "bandwidth_gb": plan.bandwidth_gb, + "price_monthly": float(plan.price_monthly), + "price_yearly": float(plan.price_yearly) if plan.price_yearly else None + } + for plan in plans + ] diff --git a/rbox/routers/files.py b/rbox/routers/files.py index 80ebc44..626be85 100644 --- a/rbox/routers/files.py +++ b/rbox/routers/files.py @@ -1,4 +1,4 @@ -from fastapi import APIRouter, Depends, UploadFile, File as FastAPIFile, HTTPException, status, Response +from fastapi import APIRouter, Depends, UploadFile, File as FastAPIFile, HTTPException, status, Response, Form from fastapi.responses import StreamingResponse from typing import List, Optional import mimetypes @@ -36,11 +36,13 @@ class BatchFileOperation(BaseModel): class BatchMoveCopyPayload(BaseModel): target_folder_id: Optional[int] = None -@router.post("/upload/{folder_id}", response_model=FileOut, status_code=status.HTTP_201_CREATED) +class FileContentUpdate(BaseModel): + content: str + @router.post("/upload", response_model=FileOut, status_code=status.HTTP_201_CREATED) async def upload_file( file: UploadFile = FastAPIFile(...), - folder_id: Optional[int] = None, + folder_id: Optional[int] = Form(None), current_user: User = Depends(get_current_user) ): if folder_id: @@ -113,9 +115,6 @@ async def download_file(file_id: int, current_user: User = Depends(get_current_u await db_file.save() try: - # file_content_generator = storage_manager.get_file(current_user.id, db_file.path) - - # FastAPI's StreamingResponse expects an async generator async def file_iterator(): async for chunk in storage_manager.get_file(current_user.id, db_file.path): yield chunk @@ -133,11 +132,13 @@ async def delete_file(file_id: int, current_user: User = Depends(get_current_use db_file = await File.get_or_none(id=file_id, owner=current_user, is_deleted=False) if not db_file: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="File not found") - + db_file.is_deleted = True db_file.deleted_at = datetime.now() await db_file.save() + await delete_thumbnail(db_file.id) + return @router.post("/{file_id}/move", response_model=FileOut) @@ -324,74 +325,158 @@ async def restore_file(file_id: int, current_user: User = Depends(get_current_us await log_activity(user=current_user, action="file_restored", target_type="file", target_id=file_id) return await FileOut.from_tortoise_orm(db_file) -@router.post("/batch", response_model=List[FileOut]) +class BatchOperationResult(BaseModel): + succeeded: List[FileOut] + failed: List[dict] + +@router.post("/batch") async def batch_file_operations( batch_operation: BatchFileOperation, payload: Optional[BatchMoveCopyPayload] = None, current_user: User = Depends(get_current_user) ): + if batch_operation.operation not in ["delete", "star", "unstar", "move", "copy"]: + raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=f"Invalid operation: {batch_operation.operation}") + updated_files = [] + failed_operations = [] + for file_id in batch_operation.file_ids: - db_file = await File.get_or_none(id=file_id, owner=current_user, is_deleted=False) - if not db_file: - # Skip if file not found or not owned by user - continue + try: + db_file = await File.get_or_none(id=file_id, owner=current_user, is_deleted=False) + if not db_file: + failed_operations.append({"file_id": file_id, "reason": "File not found or not owned by user"}) + continue - if batch_operation.operation == "delete": - db_file.is_deleted = True - db_file.deleted_at = datetime.now() - await db_file.save() - await log_activity(user=current_user, action="file_deleted_batch", target_type="file", target_id=file_id) - updated_files.append(db_file) - elif batch_operation.operation == "star": - db_file.is_starred = True - await db_file.save() - await log_activity(user=current_user, action="file_starred_batch", target_type="file", target_id=file_id) - updated_files.append(db_file) - elif batch_operation.operation == "unstar": - db_file.is_starred = False - await db_file.save() - await log_activity(user=current_user, action="file_unstarred_batch", target_type="file", target_id=file_id) - updated_files.append(db_file) - elif batch_operation.operation == "move" and payload and payload.target_folder_id is not None: - target_folder = await Folder.get_or_none(id=payload.target_folder_id, owner=current_user, is_deleted=False) - if not target_folder: - continue # Skip if target folder not found + if batch_operation.operation == "delete": + db_file.is_deleted = True + db_file.deleted_at = datetime.now() + await db_file.save() + await delete_thumbnail(db_file.id) + await log_activity(user=current_user, action="file_deleted_batch", target_type="file", target_id=file_id) + updated_files.append(db_file) + elif batch_operation.operation == "star": + db_file.is_starred = True + await db_file.save() + await log_activity(user=current_user, action="file_starred_batch", target_type="file", target_id=file_id) + updated_files.append(db_file) + elif batch_operation.operation == "unstar": + db_file.is_starred = False + await db_file.save() + await log_activity(user=current_user, action="file_unstarred_batch", target_type="file", target_id=file_id) + updated_files.append(db_file) + elif batch_operation.operation == "move": + if not payload or payload.target_folder_id is None: + failed_operations.append({"file_id": file_id, "reason": "Target folder not specified"}) + continue - existing_file = await File.get_or_none( - name=db_file.name, parent=target_folder, owner=current_user, is_deleted=False + target_folder = await Folder.get_or_none(id=payload.target_folder_id, owner=current_user, is_deleted=False) + if not target_folder: + failed_operations.append({"file_id": file_id, "reason": "Target folder not found"}) + continue + + existing_file = await File.get_or_none( + name=db_file.name, parent=target_folder, owner=current_user, is_deleted=False + ) + if existing_file and existing_file.id != file_id: + failed_operations.append({"file_id": file_id, "reason": "File with same name exists in target folder"}) + continue + + db_file.parent = target_folder + await db_file.save() + await log_activity(user=current_user, action="file_moved_batch", target_type="file", target_id=file_id) + updated_files.append(db_file) + elif batch_operation.operation == "copy": + if not payload or payload.target_folder_id is None: + failed_operations.append({"file_id": file_id, "reason": "Target folder not specified"}) + continue + + target_folder = await Folder.get_or_none(id=payload.target_folder_id, owner=current_user, is_deleted=False) + if not target_folder: + failed_operations.append({"file_id": file_id, "reason": "Target folder not found"}) + continue + + base_name = db_file.name + name_parts = os.path.splitext(base_name) + counter = 1 + new_name = base_name + + while await File.get_or_none(name=new_name, parent=target_folder, owner=current_user, is_deleted=False): + new_name = f"{name_parts[0]} (copy {counter}){name_parts[1]}" + counter += 1 + + new_file = await File.create( + name=new_name, + path=db_file.path, + size=db_file.size, + mime_type=db_file.mime_type, + file_hash=db_file.file_hash, + owner=current_user, + parent=target_folder + ) + await log_activity(user=current_user, action="file_copied_batch", target_type="file", target_id=new_file.id) + updated_files.append(new_file) + except Exception as e: + failed_operations.append({"file_id": file_id, "reason": str(e)}) + + return { + "succeeded": [await FileOut.from_tortoise_orm(f) for f in updated_files], + "failed": failed_operations + } + +@router.put("/{file_id}/content", response_model=FileOut) +async def update_file_content( + file_id: int, + payload: FileContentUpdate, + current_user: User = Depends(get_current_user) +): + db_file = await File.get_or_none(id=file_id, owner=current_user, is_deleted=False) + if not db_file: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="File not found") + + if not db_file.mime_type or not db_file.mime_type.startswith('text/'): + editableExtensions = [ + 'txt', 'md', 'log', 'json', 'js', 'py', 'html', 'css', + 'xml', 'yaml', 'yml', 'sh', 'bat', 'ini', 'conf', 'cfg' + ] + file_extension = os.path.splitext(db_file.name)[1][1:].lower() + if file_extension not in editableExtensions: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="File type is not editable" ) - if existing_file and existing_file.id != file_id: - continue # Skip if file with same name exists - db_file.parent = target_folder - await db_file.save() - await log_activity(user=current_user, action="file_moved_batch", target_type="file", target_id=file_id) - updated_files.append(db_file) - elif batch_operation.operation == "copy" and payload and payload.target_folder_id is not None: - target_folder = await Folder.get_or_none(id=payload.target_folder_id, owner=current_user, is_deleted=False) - if not target_folder: - continue # Skip if target folder not found + content_bytes = payload.content.encode('utf-8') + new_size = len(content_bytes) + size_diff = new_size - db_file.size - base_name = db_file.name - name_parts = os.path.splitext(base_name) - counter = 1 - new_name = base_name + if current_user.used_storage_bytes + size_diff > current_user.storage_quota_bytes: + raise HTTPException( + status_code=status.HTTP_507_INSUFFICIENT_STORAGE, + detail="Storage quota exceeded" + ) - while await File.get_or_none(name=new_name, parent=target_folder, owner=current_user, is_deleted=False): - new_name = f"{name_parts[0]} (copy {counter}){name_parts[1]}" - counter += 1 + new_hash = hashlib.sha256(content_bytes).hexdigest() + file_extension = os.path.splitext(db_file.name)[1] + new_storage_path = f"{new_hash}{file_extension}" - new_file = await File.create( - name=new_name, - path=db_file.path, - size=db_file.size, - mime_type=db_file.mime_type, - file_hash=db_file.file_hash, - owner=current_user, - parent=target_folder - ) - await log_activity(user=current_user, action="file_copied_batch", target_type="file", target_id=new_file.id) - updated_files.append(new_file) - - return [await FileOut.from_tortoise_orm(f) for f in updated_files] + await storage_manager.save_file(current_user.id, new_storage_path, content_bytes) + + if new_storage_path != db_file.path: + try: + await storage_manager.delete_file(current_user.id, db_file.path) + except: + pass + + db_file.path = new_storage_path + db_file.size = new_size + db_file.file_hash = new_hash + db_file.updated_at = datetime.utcnow() + await db_file.save() + + current_user.used_storage_bytes += size_diff + await current_user.save() + + await log_activity(user=current_user, action="file_updated", target_type="file", target_id=file_id) + + return await FileOut.from_tortoise_orm(db_file) diff --git a/rbox/routers/folders.py b/rbox/routers/folders.py index fda2a52..a74fce2 100644 --- a/rbox/routers/folders.py +++ b/rbox/routers/folders.py @@ -4,6 +4,7 @@ from typing import List, Optional from ..auth import get_current_user from ..models import User, Folder from ..schemas import FolderCreate, FolderOut, FolderUpdate, BatchFolderOperation, BatchMoveCopyPayload +from ..activity import log_activity router = APIRouter( prefix="/folders", @@ -35,8 +36,26 @@ async def create_folder(folder_in: FolderCreate, current_user: User = Depends(ge folder = await Folder.create( name=folder_in.name, parent=parent_folder, owner=current_user ) + await log_activity(current_user, "folder_created", "folder", folder.id) return await FolderOut.from_tortoise_orm(folder) +@router.get("/{folder_id}/path", response_model=List[FolderOut]) +async def get_folder_path(folder_id: int, current_user: User = Depends(get_current_user)): + folder = await Folder.get_or_none(id=folder_id, owner=current_user, is_deleted=False) + if not folder: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Folder not found") + + path = [] + current = folder + while current: + path.insert(0, await FolderOut.from_tortoise_orm(current)) + if current.parent_id: + current = await Folder.get_or_none(id=current.parent_id, owner=current_user, is_deleted=False) + else: + current = None + + return path + @router.get("/{folder_id}", response_model=FolderOut) async def get_folder(folder_id: int, current_user: User = Depends(get_current_user)): folder = await Folder.get_or_none(id=folder_id, owner=current_user, is_deleted=False) @@ -91,6 +110,7 @@ async def update_folder(folder_id: int, folder_in: FolderUpdate, current_user: U folder.parent = new_parent_folder await folder.save() + await log_activity(current_user, "folder_updated", "folder", folder.id) return await FolderOut.from_tortoise_orm(folder) @router.delete("/{folder_id}", status_code=status.HTTP_204_NO_CONTENT) @@ -99,9 +119,9 @@ async def delete_folder(folder_id: int, current_user: User = Depends(get_current if not folder: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Folder not found") - # Soft delete folder.is_deleted = True await folder.save() + await log_activity(current_user, "folder_deleted", "folder", folder.id) return @router.post("/{folder_id}/star", response_model=FolderOut) @@ -111,6 +131,7 @@ async def star_folder(folder_id: int, current_user: User = Depends(get_current_u raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Folder not found") db_folder.is_starred = True await db_folder.save() + await log_activity(current_user, "folder_starred", "folder", folder_id) return await FolderOut.from_tortoise_orm(db_folder) @router.post("/{folder_id}/unstar", response_model=FolderOut) @@ -120,6 +141,7 @@ async def unstar_folder(folder_id: int, current_user: User = Depends(get_current raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Folder not found") db_folder.is_starred = False await db_folder.save() + await log_activity(current_user, "folder_unstarred", "folder", folder_id) return await FolderOut.from_tortoise_orm(db_folder) @router.post("/batch", response_model=List[FolderOut]) @@ -137,28 +159,32 @@ async def batch_folder_operations( if batch_operation.operation == "delete": db_folder.is_deleted = True await db_folder.save() + await log_activity(current_user, "folder_deleted", "folder", folder_id) updated_folders.append(db_folder) elif batch_operation.operation == "star": db_folder.is_starred = True await db_folder.save() + await log_activity(current_user, "folder_starred", "folder", folder_id) updated_folders.append(db_folder) elif batch_operation.operation == "unstar": db_folder.is_starred = False await db_folder.save() + await log_activity(current_user, "folder_unstarred", "folder", folder_id) updated_folders.append(db_folder) elif batch_operation.operation == "move" and payload and payload.target_folder_id is not None: target_folder = await Folder.get_or_none(id=payload.target_folder_id, owner=current_user, is_deleted=False) if not target_folder: - continue # Skip if target folder not found + continue existing_folder = await Folder.get_or_none( name=db_folder.name, parent=target_folder, owner=current_user, is_deleted=False ) if existing_folder and existing_folder.id != folder_id: - continue # Skip if folder with same name exists + continue db_folder.parent = target_folder await db_folder.save() + await log_activity(current_user, "folder_moved", "folder", folder_id) updated_folders.append(db_folder) return [await FolderOut.from_tortoise_orm(f) for f in updated_folders] diff --git a/rbox/routers/shares.py b/rbox/routers/shares.py index 4ac2384..3ae1ba7 100644 --- a/rbox/routers/shares.py +++ b/rbox/routers/shares.py @@ -1,12 +1,14 @@ from fastapi import APIRouter, Depends, HTTPException, status +from fastapi.responses import StreamingResponse from typing import Optional, List import secrets from datetime import datetime, timedelta from ..auth import get_current_user from ..models import User, File, Folder, Share -from ..schemas import ShareCreate, ShareOut +from ..schemas import ShareCreate, ShareOut, FileOut, FolderOut from ..auth import get_password_hash, verify_password +from ..storage import storage_manager router = APIRouter( prefix="/shares", @@ -99,17 +101,72 @@ async def access_shared_content(share_token: str, password: Optional[str] = None share = await Share.get_or_none(token=share_token) if not share: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Share link not found") - + if share.expires_at and share.expires_at < datetime.utcnow(): raise HTTPException(status_code=status.HTTP_410_GONE, detail="Share link has expired") if share.password_protected: if not password or not verify_password(password, share.hashed_password): raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Incorrect password") - - # TODO: Return actual content or a link to it based on permission_level - # For now, just indicate successful access - return {"message": "Access granted", "permission_level": share.permission_level} + + result = {"message": "Access granted", "permission_level": share.permission_level} + + if share.file_id: + file = await File.get_or_none(id=share.file_id, is_deleted=False) + if not file: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="File not found") + result["file"] = await FileOut.from_tortoise_orm(file) + result["type"] = "file" + elif share.folder_id: + folder = await Folder.get_or_none(id=share.folder_id, is_deleted=False) + if not folder: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Folder not found") + result["folder"] = await FolderOut.from_tortoise_orm(folder) + result["type"] = "folder" + + files = await File.filter(parent=folder, is_deleted=False) + subfolders = await Folder.filter(parent=folder, is_deleted=False) + result["files"] = [await FileOut.from_tortoise_orm(f) for f in files] + result["folders"] = [await FolderOut.from_tortoise_orm(f) for f in subfolders] + + return result + +@router.get("/{share_token}/download") +async def download_shared_file(share_token: str, password: Optional[str] = None): + share = await Share.get_or_none(token=share_token) + if not share: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Share link not found") + + if share.expires_at and share.expires_at < datetime.utcnow(): + raise HTTPException(status_code=status.HTTP_410_GONE, detail="Share link has expired") + + if share.password_protected: + if not password or not verify_password(password, share.hashed_password): + raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Incorrect password") + + if not share.file_id: + raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="This share is not for a file") + + file = await File.get_or_none(id=share.file_id, is_deleted=False) + if not file: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="File not found") + + owner = await User.get(id=file.owner_id) + + try: + async def file_iterator(): + async for chunk in storage_manager.get_file(owner.id, file.path): + yield chunk + + return StreamingResponse( + content=file_iterator(), + media_type=file.mime_type, + headers={ + "Content-Disposition": f'attachment; filename="{file.name}"' + } + ) + except FileNotFoundError: + raise HTTPException(status_code=404, detail="File not found in storage") @router.delete("/{share_id}", status_code=status.HTTP_204_NO_CONTENT) async def delete_share_link(share_id: int, current_user: User = Depends(get_current_user)): diff --git a/rbox/schemas.py b/rbox/schemas.py index 87bcced..cd7630b 100644 --- a/rbox/schemas.py +++ b/rbox/schemas.py @@ -13,7 +13,7 @@ class UserLogin(BaseModel): password: str class UserLoginWith2FA(UserLogin): - two_factor_code: str + two_factor_code: Optional[str] = None class UserAdminUpdate(BaseModel): username: Optional[str] = None @@ -58,7 +58,7 @@ class TeamOut(BaseModel): created_at: datetime class Config: - orm_mode = True + from_attributes = True class ActivityOut(BaseModel): id: int @@ -70,7 +70,7 @@ class ActivityOut(BaseModel): timestamp: datetime class Config: - orm_mode = True + from_attributes = True class FileRequestCreate(BaseModel): title: str @@ -90,7 +90,7 @@ class FileRequestOut(BaseModel): is_active: bool class Config: - orm_mode = True + from_attributes = True from rbox.models import Folder, File, Share, FileVersion diff --git a/rbox/settings.py b/rbox/settings.py index a45727b..5cff292 100644 --- a/rbox/settings.py +++ b/rbox/settings.py @@ -1,28 +1,36 @@ import os +import sys from pydantic_settings import BaseSettings, SettingsConfigDict class Settings(BaseSettings): model_config = SettingsConfigDict(env_file='.env', extra='ignore') DATABASE_URL: str = "sqlite:///app/rbox.db" - #DATABASE_URL: str = "postgres://rbox_user:rbox_password@db:5432/rbox_db" REDIS_URL: str = "redis://redis:6379/0" - SECRET_KEY: str = "super_secret_key" # CHANGE THIS IN PRODUCTION + SECRET_KEY: str = "super_secret_key" ALGORITHM: str = "HS256" ACCESS_TOKEN_EXPIRE_MINUTES: int = 30 REFRESH_TOKEN_EXPIRE_DAYS: int = 7 DOMAIN_NAME: str = "localhost" CERTBOT_EMAIL: str = "admin@example.com" - STORAGE_PATH: str = "storage" # Path for local file storage + STORAGE_PATH: str = "storage" S3_ACCESS_KEY_ID: str | None = None S3_SECRET_ACCESS_KEY: str | None = None S3_ENDPOINT_URL: str | None = None S3_BUCKET_NAME: str = "rbox-storage" SMTP_SERVER: str | None = None - SMTP_PORT: int = 557 + SMTP_PORT: int = 587 SMTP_USERNAME: str | None = None SMTP_PASSWORD: str | None = None SMTP_FROM_EMAIL: str = "no-reply@example.com" TOTP_ISSUER: str = "RBox" + STRIPE_SECRET_KEY: str = "" + STRIPE_PUBLISHABLE_KEY: str = "" + STRIPE_WEBHOOK_SECRET: str = "" + BILLING_ENABLED: bool = False settings = Settings() + +if settings.SECRET_KEY == "super_secret_key" and os.getenv("ENVIRONMENT") == "production": + print("ERROR: Secret key must be changed in production. Set SECRET_KEY environment variable.") + sys.exit(1) diff --git a/rbox/storage.py b/rbox/storage.py index 76e0900..94b8cc9 100644 --- a/rbox/storage.py +++ b/rbox/storage.py @@ -36,7 +36,17 @@ class StorageManager: full_path = await self._get_full_path(user_id, file_path) if full_path.exists(): os.remove(full_path) - # TODO: Clean up empty directories + + parent_dir = full_path.parent + while parent_dir != self.base_path and parent_dir.exists(): + try: + if not any(parent_dir.iterdir()): + parent_dir.rmdir() + parent_dir = parent_dir.parent + else: + break + except OSError: + break async def file_exists(self, user_id: int, file_path: str) -> bool: full_path = await self._get_full_path(user_id, file_path) diff --git a/rbox/webdav.py b/rbox/webdav.py index 529c0b4..f104d4a 100644 --- a/rbox/webdav.py +++ b/rbox/webdav.py @@ -57,8 +57,8 @@ async def basic_auth(authorization: Optional[str] = Header(None)): user = await User.get_or_none(username=username) if user and verify_password(password, user.hashed_password): return user - except: - pass + except (ValueError, UnicodeDecodeError, base64.binascii.Error): + return None return None @@ -70,7 +70,7 @@ async def webdav_auth(request: Request, authorization: Optional[str] = Header(No try: user = await get_current_user(request) return user - except: + except HTTPException: pass raise HTTPException( @@ -197,8 +197,8 @@ def parse_propfind_body(body: bytes): name = child.tag.split('}')[1] if '}' in child.tag else child.tag requested_props.append((ns, name)) return requested_props - except: - pass + except ET.ParseError: + return None return None @@ -646,7 +646,7 @@ async def handle_lock(request: Request, full_path: str, current_user: User = Dep if timeout_header.startswith("Second-"): try: timeout = int(timeout_header.split("-")[1]) - except: + except (ValueError, IndexError): pass lock_token = WebDAVLock.create_lock(full_path, current_user.id, timeout) diff --git a/static/css/billing.css b/static/css/billing.css new file mode 100644 index 0000000..0bd9e0d --- /dev/null +++ b/static/css/billing.css @@ -0,0 +1,371 @@ +.billing-dashboard { + padding: 2rem; + max-width: 1400px; + margin: 0 auto; +} + +.billing-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 2rem; +} + +.subscription-badge { + padding: 0.5rem 1rem; + border-radius: 20px; + font-weight: 600; + font-size: 0.9rem; +} + +.subscription-badge.active { + background: #10b981; + color: white; +} + +.subscription-badge.inactive { + background: #ef4444; + color: white; +} + +.billing-cards { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(350px, 1fr)); + gap: 1.5rem; + margin-bottom: 2rem; +} + +.billing-card { + background: white; + border: 1px solid #e5e7eb; + border-radius: 8px; + padding: 1.5rem; + box-shadow: 0 1px 3px rgba(0,0,0,0.1); +} + +.billing-card h3 { + margin: 0 0 1rem 0; + color: #1f2937; + font-size: 1.1rem; +} + +.usage-details { + display: flex; + flex-direction: column; + gap: 1rem; +} + +.usage-item { + display: flex; + justify-content: space-between; + align-items: center; +} + +.usage-label { + color: #6b7280; + font-size: 0.9rem; +} + +.usage-value { + font-weight: 600; + font-size: 1.1rem; + color: #1f2937; +} + +.usage-progress { + width: 100%; + height: 8px; + background: #e5e7eb; + border-radius: 4px; + overflow: hidden; +} + +.usage-progress-bar { + height: 100%; + background: linear-gradient(90deg, #3b82f6, #2563eb); + transition: width 0.3s ease; +} + +.usage-info { + font-size: 0.8rem; + color: #6b7280; +} + +.estimated-cost { + font-size: 2rem; + font-weight: 700; + color: #1f2937; + margin: 1rem 0; +} + +.cost-breakdown { + display: flex; + flex-direction: column; + gap: 0.5rem; + margin-top: 1rem; + padding-top: 1rem; + border-top: 1px solid #e5e7eb; +} + +.cost-item { + display: flex; + justify-content: space-between; + font-size: 0.9rem; +} + +.pricing-details { + display: flex; + flex-direction: column; + gap: 0.75rem; +} + +.pricing-item { + display: flex; + justify-content: space-between; + padding: 0.5rem 0; + border-bottom: 1px solid #f3f4f6; +} + +.pricing-item:last-child { + border-bottom: none; +} + +.invoices-section { + background: white; + border: 1px solid #e5e7eb; + border-radius: 8px; + padding: 1.5rem; + margin-bottom: 2rem; +} + +.invoices-table { + margin-top: 1rem; +} + +.invoices-table table { + width: 100%; + border-collapse: collapse; +} + +.invoices-table th, +.invoices-table td { + padding: 0.75rem; + text-align: left; + border-bottom: 1px solid #e5e7eb; +} + +.invoices-table th { + background: #f9fafb; + font-weight: 600; + color: #374151; +} + +.invoice-status { + padding: 0.25rem 0.75rem; + border-radius: 12px; + font-size: 0.8rem; + font-weight: 600; + text-transform: uppercase; +} + +.invoice-status.paid { + background: #d1fae5; + color: #065f46; +} + +.invoice-status.open { + background: #fef3c7; + color: #92400e; +} + +.invoice-status.draft { + background: #e5e7eb; + color: #374151; +} + +.no-invoices { + text-align: center; + padding: 2rem; + color: #6b7280; +} + +.payment-methods-section { + background: white; + border: 1px solid #e5e7eb; + border-radius: 8px; + padding: 1.5rem; +} + +.btn-primary { + background: #2563eb; + color: white; + border: none; + padding: 0.75rem 1.5rem; + border-radius: 6px; + font-weight: 600; + cursor: pointer; + transition: background 0.2s; +} + +.btn-primary:hover { + background: #1d4ed8; +} + +.btn-secondary { + background: #6b7280; + color: white; + border: none; + padding: 0.75rem 1.5rem; + border-radius: 6px; + font-weight: 600; + cursor: pointer; + transition: background 0.2s; +} + +.btn-secondary:hover { + background: #4b5563; +} + +.btn-link { + background: none; + border: none; + color: #2563eb; + cursor: pointer; + text-decoration: underline; +} + +.modal { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.5); + display: flex; + justify-content: center; + align-items: center; + z-index: 1000; +} + +.modal-content { + background: white; + padding: 2rem; + border-radius: 8px; + max-width: 800px; + max-height: 90vh; + overflow-y: auto; +} + +.invoice-total { + margin-top: 1rem; + padding-top: 1rem; + border-top: 2px solid #1f2937; + display: flex; + flex-direction: column; + gap: 0.5rem; + font-size: 1.1rem; +} + +.admin-billing { + padding: 2rem; + max-width: 1400px; + margin: 0 auto; +} + +.stats-cards { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: 1.5rem; + margin-bottom: 2rem; +} + +.stat-card { + background: white; + border: 1px solid #e5e7eb; + border-radius: 8px; + padding: 1.5rem; + box-shadow: 0 1px 3px rgba(0,0,0,0.1); +} + +.stat-card h3 { + margin: 0 0 0.5rem 0; + color: #6b7280; + font-size: 0.9rem; + font-weight: 500; +} + +.stat-value { + font-size: 2rem; + font-weight: 700; + color: #1f2937; +} + +.pricing-config-section { + background: white; + border: 1px solid #e5e7eb; + border-radius: 8px; + padding: 1.5rem; + margin-bottom: 2rem; +} + +.pricing-table { + width: 100%; + border-collapse: collapse; + margin-top: 1rem; +} + +.pricing-table th, +.pricing-table td { + padding: 0.75rem; + text-align: left; + border-bottom: 1px solid #e5e7eb; +} + +.pricing-table th { + background: #f9fafb; + font-weight: 600; + color: #374151; +} + +.btn-edit { + background: #3b82f6; + color: white; + border: none; + padding: 0.5rem 1rem; + border-radius: 4px; + cursor: pointer; + font-size: 0.875rem; +} + +.btn-edit:hover { + background: #2563eb; +} + +.invoice-generation-section { + background: white; + border: 1px solid #e5e7eb; + border-radius: 8px; + padding: 1.5rem; +} + +.invoice-gen-form { + display: flex; + gap: 1rem; + align-items: end; + margin-top: 1rem; +} + +.invoice-gen-form label { + display: flex; + flex-direction: column; + gap: 0.5rem; + font-weight: 500; + color: #374151; +} + +.invoice-gen-form input { + padding: 0.5rem; + border: 1px solid #e5e7eb; + border-radius: 4px; + font-size: 1rem; +} diff --git a/static/css/code-editor-view.css b/static/css/code-editor-view.css new file mode 100644 index 0000000..23ebb75 --- /dev/null +++ b/static/css/code-editor-view.css @@ -0,0 +1,80 @@ +.code-editor-view { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + background: white; + z-index: 100; +} + +.code-editor-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 16px 24px; + border-bottom: 1px solid #ddd; + background: white; +} + +.code-editor-header .header-left { + display: flex; + align-items: center; + gap: 16px; +} + +.code-editor-header .header-right { + display: flex; + gap: 8px; +} + +.editor-filename { + margin: 0; + font-size: 18px; + font-weight: 600; + color: #333; +} + +.code-editor-body { + flex: 1; + overflow: hidden; + position: relative; + background: white; +} + +.code-editor-body .CodeMirror { + height: 100%; + font-family: 'Consolas', 'Monaco', 'Courier New', monospace; + font-size: 14px; + background: white; +} + +.code-editor-body .CodeMirror-gutters { + background: #f9f9f9; + border-right: 1px solid #ddd; +} + +.code-editor-body .CodeMirror-linenumber { + color: #999; + padding: 0 8px; +} + +.code-editor-body .CodeMirror-cursor { + border-left: 2px solid #333; +} + +.code-editor-body .CodeMirror-selected { + background: #d7e8ff; +} + +.code-editor-body .CodeMirror-line::selection, +.code-editor-body .CodeMirror-line > span::selection, +.code-editor-body .CodeMirror-line > span > span::selection { + background: #d7e8ff; +} + +.code-editor-body textarea { + display: none; +} diff --git a/static/css/file-upload-view.css b/static/css/file-upload-view.css new file mode 100644 index 0000000..966a510 --- /dev/null +++ b/static/css/file-upload-view.css @@ -0,0 +1,145 @@ +.file-upload-view { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + background: white; + z-index: 100; +} + +.file-upload-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 16px 24px; + border-bottom: 1px solid #ddd; + background: white; +} + +.file-upload-header .header-left { + display: flex; + align-items: center; + gap: 16px; +} + +.file-upload-header h2 { + margin: 0; + font-size: 18px; + font-weight: 600; + color: #333; +} + +.file-upload-body { + flex: 1; + overflow: auto; + padding: 24px; + display: flex; + flex-direction: column; + gap: 24px; +} + +.drop-zone { + border: 2px dashed #ddd; + border-radius: 8px; + padding: 48px 24px; + text-align: center; + background: #f9f9f9; + transition: all 0.2s; + cursor: pointer; +} + +.drop-zone:hover { + border-color: #003399; + background: #f0f4ff; +} + +.drop-zone.drag-over { + border-color: #003399; + background: #e6f0ff; + border-style: solid; +} + +.drop-zone-icon { + font-size: 64px; + margin-bottom: 16px; + opacity: 0.5; +} + +.drop-zone h3 { + margin: 0 0 8px 0; + color: #333; + font-size: 20px; +} + +.drop-zone p { + margin: 8px 0; + color: #666; +} + +.upload-list { + display: flex; + flex-direction: column; + gap: 12px; +} + +.upload-item { + background: white; + border: 1px solid #ddd; + border-radius: 8px; + padding: 16px; +} + +.upload-item-info { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 8px; +} + +.upload-item-name { + font-weight: 500; + color: #333; +} + +.upload-item-size { + color: #666; + font-size: 14px; +} + +.upload-item-progress { + display: flex; + flex-direction: column; + gap: 4px; +} + +.progress-bar { + width: 100%; + height: 8px; + background: #e0e0e0; + border-radius: 4px; + overflow: hidden; +} + +.progress-fill { + height: 100%; + background: #003399; + transition: width 0.3s ease; +} + +.upload-item-status { + font-size: 14px; + color: #666; +} + +.upload-item-status.success { + color: #28a745; + font-weight: 500; +} + +.upload-item-status.error { + color: #dc3545; + font-weight: 500; +} diff --git a/static/css/style.css b/static/css/style.css index d8d6924..407db68 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -16,6 +16,12 @@ * { box-sizing: border-box; user-select: none; + scrollbar-width: none; + -ms-overflow-style: none; +} + +*::-webkit-scrollbar { + display: none; } input, textarea { @@ -29,6 +35,7 @@ body { background-color: var(--background-color); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; + overflow: hidden; } .app-container { @@ -146,6 +153,7 @@ body { flex: 1; overflow-y: auto; padding: calc(var(--spacing-unit) * 3); + position: relative; } .button { @@ -267,6 +275,41 @@ body { padding: calc(var(--spacing-unit) * 2); } +.breadcrumb-nav { + display: flex; + align-items: center; + gap: calc(var(--spacing-unit) * 1); + margin-bottom: calc(var(--spacing-unit) * 2); + font-size: 14px; + color: var(--text-color-light); +} + +.breadcrumb-item { + cursor: pointer; + color: var(--primary-color); + transition: color 0.2s; +} + +.breadcrumb-item:hover { + color: var(--secondary-color); + text-decoration: underline; +} + +.breadcrumb-item.breadcrumb-current { + color: var(--text-color); + cursor: default; + font-weight: 600; +} + +.breadcrumb-item.breadcrumb-current:hover { + text-decoration: none; +} + +.breadcrumb-separator { + color: var(--text-color-light); + user-select: none; +} + .file-list-header { display: flex; justify-content: space-between; @@ -276,11 +319,36 @@ body { border-bottom: 1px solid var(--border-color); } +.file-list-header .header-left { + display: flex; + align-items: center; + gap: calc(var(--spacing-unit) * 3); +} + .file-list-header h2 { margin: 0; color: var(--primary-color); } +.selection-controls { + display: flex; + align-items: center; + gap: var(--spacing-unit); +} + +.selection-controls input[type="checkbox"] { + width: 18px; + height: 18px; + cursor: pointer; +} + +.selection-controls label { + font-size: 14px; + color: var(--text-color); + cursor: pointer; + user-select: none; +} + .file-actions { display: flex; gap: var(--spacing-unit); @@ -301,6 +369,7 @@ body { border-radius: 8px; cursor: pointer; transition: all 0.2s ease; + position: relative; } .file-item:hover { @@ -308,6 +377,10 @@ body { border-color: var(--primary-color); } +.file-item:hover .select-item { + opacity: 1; +} + .file-icon { font-size: 3rem; margin-bottom: var(--spacing-unit); @@ -690,66 +763,54 @@ body.dark-mode { color: var(--text-color-light); } -.preview-modal { - position: fixed; +.file-preview-overlay { + position: absolute; top: 0; left: 0; - right: 0; - bottom: 0; - background: rgba(0, 0, 0, 0.9); - z-index: 1000; - display: flex; - align-items: center; - justify-content: center; - padding: calc(var(--spacing-unit) * 2); -} - -.preview-container { - background: var(--accent-color); - border-radius: 8px; - max-width: 90vw; - max-height: 90vh; + width: 100%; + height: 100%; display: flex; flex-direction: column; - overflow: hidden; + background: white; + z-index: 100; } -.preview-header { +.file-preview-header { display: flex; justify-content: space-between; align-items: center; - padding: calc(var(--spacing-unit) * 2); - border-bottom: 1px solid var(--border-color); + padding: 16px 24px; + border-bottom: 1px solid #ddd; + background: white; } -.preview-info h3 { - margin: 0 0 calc(var(--spacing-unit) * 0.5) 0; - font-size: 1.25rem; +.file-preview-header .header-left { + display: flex; + align-items: center; + gap: 16px; } -.preview-info p { +.preview-info { + display: flex; + flex-direction: column; +} + +.preview-file-name { margin: 0; - color: var(--text-color-light); - font-size: 0.875rem; + font-size: 18px; + font-weight: 600; + color: #333; +} + +.preview-file-info { + margin: 4px 0 0 0; + color: #666; + font-size: 14px; } .preview-actions { display: flex; - gap: calc(var(--spacing-unit) * 1); -} - -.btn-icon { - background: none; - border: 1px solid var(--border-color); - padding: calc(var(--spacing-unit) * 1); - border-radius: 4px; - cursor: pointer; - font-size: 1.2rem; - transition: background 0.2s; -} - -.btn-icon:hover { - background: var(--background-color); + gap: 8px; } .preview-content { @@ -759,7 +820,7 @@ body.dark-mode { align-items: center; justify-content: center; padding: calc(var(--spacing-unit) * 2); - background: #000; + background: #f9f9f9; } .preview-content img, @@ -894,4 +955,18 @@ body.dark-mode { top: var(--spacing-unit); left: var(--spacing-unit); z-index: 1; + width: 20px; + height: 20px; + cursor: pointer; + opacity: 0.3; + transition: opacity 0.2s ease; +} + +.file-item .select-item:checked { + opacity: 1; +} + +.file-item.selected { + border-color: var(--primary-color); + background-color: rgba(0, 51, 153, 0.05); } diff --git a/static/icons/icon-192x192.png b/static/icons/icon-192x192.png index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d2a13695f2dcde9298860a89c638df528066b135 100644 GIT binary patch literal 34417 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 N002ovPDHLkV1l}D)oK6$ literal 0 HcmV?d00001 diff --git a/static/icons/icon-256x256.png b/static/icons/icon-256x256.png new file mode 100644 index 0000000000000000000000000000000000000000..410899d0d4021d19a6d70a140748c3acb51fc2fa GIT binary patch literal 58241 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
1TnGQ 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 FV1mG3iYNd8 literal 0 HcmV?d00001 diff --git a/static/icons/icon-512x512.png b/static/icons/icon-512x512.png index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..e14c5b5c2c7cbc12cde1e155b9f5ad2b0bfb8139 100644 GIT binary patch literal 161016 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

{PhRByFa(x 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 vtXbs+AK3{)CmVu%~>_u#n*?2 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 bURD19JEV3x_zNdQ00000NkvXXu0mjf(`D*! literal 0 HcmV?d00001 diff --git a/static/index.html b/static/index.html index ef0e50a..819cd14 100644 --- a/static/index.html +++ b/static/index.html @@ -5,7 +5,19 @@ RBox Cloud Storage + + + + + + + + + + + + diff --git a/static/js/api.js b/static/js/api.js index c65792a..5ef4022 100644 --- a/static/js/api.js +++ b/static/js/api.js @@ -113,6 +113,10 @@ class APIClient { }); } + async getFolderPath(folderId) { + return this.request(`folders/${folderId}/path`); + } + async deleteFolder(folderId) { return this.request(`folders/${folderId}`, { method: 'DELETE' @@ -294,12 +298,6 @@ class APIClient { }); } - async deleteShare(shareId) { - return this.request(`shares/${shareId}`, { - method: 'DELETE' - }); - } - async batchFileOperations(operation, fileIds, targetFolderId = null) { const payload = { file_ids: fileIds, operation: operation }; if (targetFolderId !== null) { @@ -321,6 +319,13 @@ class APIClient { body: payload }); } + + async updateFile(fileId, content) { + return this.request(`files/${fileId}/content`, { + method: 'PUT', + body: { content } + }); + } } export const api = new APIClient(); diff --git a/static/js/components/admin-billing.js b/static/js/components/admin-billing.js new file mode 100644 index 0000000..06d93f6 --- /dev/null +++ b/static/js/components/admin-billing.js @@ -0,0 +1,193 @@ +class AdminBilling extends HTMLElement { + constructor() { + super(); + this.pricingConfig = []; + this.stats = null; + this.boundHandleClick = this.handleClick.bind(this); + } + + async connectedCallback() { + this.addEventListener('click', this.boundHandleClick); + await this.loadData(); + this.render(); + this.attachEventListeners(); + } + + disconnectedCallback() { + this.removeEventListener('click', this.boundHandleClick); + } + + async loadData() { + try { + const [pricing, stats] = await Promise.all([ + this.fetchPricing(), + this.fetchStats() + ]); + + this.pricingConfig = pricing; + this.stats = stats; + } catch (error) { + console.error('Failed to load admin billing data:', error); + } + } + + async fetchPricing() { + const response = await fetch('/api/admin/billing/pricing', { + headers: {'Authorization': `Bearer ${localStorage.getItem('token')}`} + }); + return await response.json(); + } + + async fetchStats() { + const response = await fetch('/api/admin/billing/stats', { + headers: {'Authorization': `Bearer ${localStorage.getItem('token')}`} + }); + return await response.json(); + } + + formatCurrency(amount) { + return new Intl.NumberFormat('en-US', { + style: 'currency', + currency: 'USD' + }).format(amount); + } + + render() { + this.innerHTML = ` +

+

Billing Administration

+ +
+
+

Total Revenue

+
${this.formatCurrency(this.stats?.total_revenue || 0)}
+
+
+

Total Invoices

+
${this.stats?.total_invoices || 0}
+
+
+

Pending Invoices

+
${this.stats?.pending_invoices || 0}
+
+
+ +
+

Pricing Configuration

+ + + + + + + + + + + ${this.pricingConfig.map(config => ` + + + + + + + `).join('')} + +
ConfigurationCurrent ValueUnitActions
${config.description || config.config_key}${config.config_value}${config.unit || '-'} + +
+
+ +
+

Generate Invoices

+
+ + + +
+
+
+ `; + } + + handleClick(e) { + const target = e.target; + + if (target.classList.contains('btn-edit')) { + const configId = target.dataset.configId; + this.editPricing(configId); + return; + } + + if (target.id === 'generateInvoices') { + this.generateInvoices(); + } + } + + attachEventListeners() { + } + + async editPricing(configId) { + const config = this.pricingConfig.find(c => c.id === parseInt(configId)); + if (!config) return; + + const newValue = prompt(`Enter new value for ${config.config_key}:`, config.config_value); + if (newValue === null) return; + + try { + const response = await fetch(`/api/admin/billing/pricing/${configId}`, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${localStorage.getItem('token')}` + }, + body: JSON.stringify({ + config_key: config.config_key, + config_value: parseFloat(newValue) + }) + }); + + if (response.ok) { + alert('Pricing updated successfully'); + await this.loadData(); + this.render(); + this.attachEventListeners(); + } else { + alert('Failed to update pricing'); + } + } catch (error) { + console.error('Error updating pricing:', error); + alert('Error updating pricing'); + } + } + + async generateInvoices() { + const year = parseInt(this.querySelector('#invoiceYear').value); + const month = parseInt(this.querySelector('#invoiceMonth').value); + + if (!confirm(`Generate invoices for ${month}/${year}?`)) return; + + try { + const response = await fetch(`/api/admin/billing/generate-invoices/${year}/${month}`, { + method: 'POST', + headers: {'Authorization': `Bearer ${localStorage.getItem('token')}`} + }); + + const result = await response.json(); + alert(`Generated ${result.generated} invoices, skipped ${result.skipped} users`); + } catch (error) { + console.error('Error generating invoices:', error); + alert('Failed to generate invoices'); + } + } +} + +customElements.define('admin-billing', AdminBilling); + +export default AdminBilling; diff --git a/static/js/components/admin-dashboard.js b/static/js/components/admin-dashboard.js index 092b8b3..f71580c 100644 --- a/static/js/components/admin-dashboard.js +++ b/static/js/components/admin-dashboard.js @@ -4,12 +4,21 @@ export class AdminDashboard extends HTMLElement { constructor() { super(); this.users = []; + this.boundHandleClick = this.handleClick.bind(this); + this.boundHandleSubmit = this.handleSubmit.bind(this); } async connectedCallback() { + this.addEventListener('click', this.boundHandleClick); + this.addEventListener('submit', this.boundHandleSubmit); await this.loadUsers(); } + disconnectedCallback() { + this.removeEventListener('click', this.boundHandleClick); + this.removeEventListener('submit', this.boundHandleSubmit); + } + async loadUsers() { try { this.users = await api.listUsers(); @@ -61,24 +70,35 @@ export class AdminDashboard extends HTMLElement { `; - - this.querySelector('#createUserButton').addEventListener('click', () => this._showUserModal()); - this.querySelector('.user-list').addEventListener('click', this._handleUserAction.bind(this)); - this.querySelector('.close-button').addEventListener('click', () => this.querySelector('#userModal').style.display = 'none'); - this.querySelector('#userForm').addEventListener('submit', this._handleUserFormSubmit.bind(this)); } - _handleUserAction(event) { - const target = event.target; + handleClick(e) { + const target = e.target; + + if (target.id === 'createUserButton') { + this._showUserModal(); + return; + } + + if (target.classList.contains('close-button')) { + this.querySelector('#userModal').style.display = 'none'; + return; + } + const userItem = target.closest('.user-item'); - if (!userItem) return; + if (userItem) { + const userId = userItem.dataset.userId; + if (target.classList.contains('button-danger')) { + this._deleteUser(userId); + } else if (target.classList.contains('button')) { + this._showUserModal(userId); + } + } + } - const userId = userItem.dataset.userId; // Assuming user ID will be stored in data-userId attribute - - if (target.classList.contains('button-danger')) { - this._deleteUser(userId); - } else if (target.classList.contains('button')) { // Edit button - this._showUserModal(userId); + handleSubmit(e) { + if (e.target.id === 'userForm') { + this._handleUserFormSubmit(e); } } diff --git a/static/js/components/base-file-list.js b/static/js/components/base-file-list.js new file mode 100644 index 0000000..3a14b7e --- /dev/null +++ b/static/js/components/base-file-list.js @@ -0,0 +1,268 @@ +export class BaseFileList extends HTMLElement { + constructor() { + super(); + this.files = []; + this.folders = []; + this.selectedFiles = new Set(); + this.selectedFolders = new Set(); + this.boundHandleClick = this.handleClick.bind(this); + this.boundHandleDblClick = this.handleDblClick.bind(this); + this.boundHandleChange = this.handleChange.bind(this); + } + + connectedCallback() { + this.addEventListener('click', this.boundHandleClick); + this.addEventListener('dblclick', this.boundHandleDblClick); + this.addEventListener('change', this.boundHandleChange); + } + + disconnectedCallback() { + this.removeEventListener('click', this.boundHandleClick); + this.removeEventListener('dblclick', this.boundHandleDblClick); + this.removeEventListener('change', this.boundHandleChange); + } + + isEditableFile(filename, mimeType) { + if (mimeType && mimeType.startsWith('text/')) return true; + + const editableExtensions = [ + 'txt', 'md', 'log', 'json', 'js', 'py', 'html', 'css', + 'xml', 'yaml', 'yml', 'sh', 'bat', 'ini', 'conf', 'cfg' + ]; + const extension = filename.split('.').pop().toLowerCase(); + return editableExtensions.includes(extension); + } + + getFileIcon(mimeType) { + if (mimeType.startsWith('image/')) return '📷'; + if (mimeType.startsWith('video/')) return '🎥'; + if (mimeType.startsWith('audio/')) return '🎵'; + if (mimeType.includes('pdf')) return '📄'; + if (mimeType.includes('text')) return '📄'; + return '📄'; + } + + formatFileSize(bytes) { + if (bytes < 1024) return bytes + ' B'; + if (bytes < 1048576) return (bytes / 1024).toFixed(1) + ' KB'; + if (bytes < 1073741824) return (bytes / 1048576).toFixed(1) + ' MB'; + return (bytes / 1073741824).toFixed(1) + ' GB'; + } + + renderFolder(folder) { + const isSelected = this.selectedFolders.has(folder.id); + const starIcon = folder.is_starred ? '★' : '☆'; + const starAction = folder.is_starred ? 'unstar-folder' : 'star-folder'; + const actions = this.getFolderActions(folder); + + return ` +
+ +
📁
+
${folder.name}
+
+ ${actions} +
+
+ `; + } + + renderFile(file) { + const isSelected = this.selectedFiles.has(file.id); + const icon = this.getFileIcon(file.mime_type); + const size = this.formatFileSize(file.size); + const starIcon = file.is_starred ? '★' : '☆'; + const starAction = file.is_starred ? 'unstar-file' : 'star-file'; + const actions = this.getFileActions(file); + + return ` +
+ +
${icon}
+
${file.name}
+
${size}
+
+ ${actions} +
+
+ `; + } + + getFolderActions(folder) { + return ''; + } + + getFileActions(file) { + return ''; + } + + handleClick(e) { + const target = e.target; + + if (target.id === 'clear-selection-btn') { + this.clearSelection(); + return; + } + + if (target.classList.contains('action-btn')) { + e.stopPropagation(); + const action = target.dataset.action; + const id = parseInt(target.dataset.id); + this.handleAction(action, id); + return; + } + + if (target.classList.contains('select-item')) { + e.stopPropagation(); + return; + } + + const fileItem = target.closest('.file-item:not(.folder-item)'); + if (fileItem) { + const fileId = parseInt(fileItem.dataset.fileId); + const file = this.files.find(f => f.id === fileId); + + if (this.isEditableFile(file.name, file.mime_type)) { + this.dispatchEvent(new CustomEvent('edit-file', { + detail: { file: file }, + bubbles: true + })); + } else { + this.dispatchEvent(new CustomEvent('photo-click', { + detail: { photo: file }, + bubbles: true + })); + } + } + } + + handleDblClick(e) { + const folderItem = e.target.closest('.folder-item'); + if (folderItem) { + const folderId = parseInt(folderItem.dataset.folderId); + this.dispatchEvent(new CustomEvent('folder-open', { detail: { folderId } })); + } + } + + handleChange(e) { + const target = e.target; + + if (target.id === 'select-all') { + this.toggleSelectAll(target.checked); + return; + } + + if (target.classList.contains('select-item')) { + const type = target.dataset.type; + const id = parseInt(target.dataset.id); + this.toggleSelectItem(type, id, target.checked); + } + } + + toggleSelectItem(type, id, checked) { + if (type === 'file') { + if (checked) { + this.selectedFiles.add(id); + } else { + this.selectedFiles.delete(id); + } + } else if (type === 'folder') { + if (checked) { + this.selectedFolders.add(id); + } else { + this.selectedFolders.delete(id); + } + } + + const item = this.querySelector(`[data-${type}-id="${id}"]`); + if (item) { + if (checked) { + item.classList.add('selected'); + } else { + item.classList.remove('selected'); + } + } + + this.updateSelectionUI(); + } + + toggleSelectAll(checked) { + this.selectedFiles.clear(); + this.selectedFolders.clear(); + + if (checked) { + this.files.forEach(file => this.selectedFiles.add(file.id)); + this.folders.forEach(folder => this.selectedFolders.add(folder.id)); + } + + this.querySelectorAll('.select-item').forEach(checkbox => { + checkbox.checked = checked; + }); + + this.querySelectorAll('.file-item').forEach(item => { + if (checked) { + item.classList.add('selected'); + } else { + item.classList.remove('selected'); + } + }); + + this.updateSelectionUI(); + } + + clearSelection() { + this.selectedFiles.clear(); + this.selectedFolders.clear(); + this.querySelectorAll('.select-item').forEach(checkbox => { + checkbox.checked = false; + }); + this.querySelectorAll('.file-item').forEach(item => { + item.classList.remove('selected'); + }); + this.updateSelectionUI(); + } + + updateSelectionUI() { + const hasSelected = this.selectedFiles.size > 0 || this.selectedFolders.size > 0; + const totalItems = this.files.length + this.folders.length; + const totalSelected = this.selectedFiles.size + this.selectedFolders.size; + const allSelected = totalItems > 0 && totalSelected === totalItems; + + const selectAllCheckbox = this.querySelector('#select-all'); + const selectAllLabel = this.querySelector('label[for="select-all"]'); + const batchActionsDiv = this.querySelector('.batch-actions'); + + if (selectAllCheckbox) { + selectAllCheckbox.checked = allSelected; + this.updateIndeterminateState(); + } + + if (selectAllLabel) { + selectAllLabel.textContent = hasSelected ? `${totalSelected} selected` : 'Select all'; + } + + if (hasSelected && !batchActionsDiv) { + this.createBatchActionsBar(); + } else if (!hasSelected && batchActionsDiv) { + batchActionsDiv.remove(); + } + } + + createBatchActionsBar() { + } + + updateIndeterminateState() { + const selectAllCheckbox = this.querySelector('#select-all'); + if (selectAllCheckbox) { + const totalItems = this.files.length + this.folders.length; + const totalSelected = this.selectedFiles.size + this.selectedFolders.size; + const hasSelected = totalSelected > 0; + const allSelected = totalItems > 0 && totalSelected === totalItems; + + selectAllCheckbox.indeterminate = hasSelected && !allSelected; + } + } + + async handleAction(action, id) { + } +} diff --git a/static/js/components/billing-dashboard.js b/static/js/components/billing-dashboard.js new file mode 100644 index 0000000..bfd1702 --- /dev/null +++ b/static/js/components/billing-dashboard.js @@ -0,0 +1,309 @@ +class BillingDashboard extends HTMLElement { + constructor() { + super(); + this.currentUsage = null; + this.subscription = null; + this.pricing = null; + this.invoices = []; + this.boundHandleClick = this.handleClick.bind(this); + } + + async connectedCallback() { + this.addEventListener('click', this.boundHandleClick); + await this.loadData(); + this.render(); + this.attachEventListeners(); + } + + disconnectedCallback() { + this.removeEventListener('click', this.boundHandleClick); + } + + async loadData() { + try { + const [usage, subscription, pricing, invoices] = await Promise.all([ + this.fetchCurrentUsage(), + this.fetchSubscription(), + this.fetchPricing(), + this.fetchInvoices() + ]); + + this.currentUsage = usage; + this.subscription = subscription; + this.pricing = pricing; + this.invoices = invoices; + } catch (error) { + console.error('Failed to load billing data:', error); + } + } + + async fetchCurrentUsage() { + const response = await fetch('/api/billing/usage/current', { + headers: {'Authorization': `Bearer ${localStorage.getItem('token')}`} + }); + if (!response.ok) { + throw new Error(`HTTP ${response.status}: ${response.statusText}`); + } + return await response.json(); + } + + async fetchSubscription() { + const response = await fetch('/api/billing/subscription', { + headers: {'Authorization': `Bearer ${localStorage.getItem('token')}`} + }); + if (!response.ok) { + throw new Error(`HTTP ${response.status}: ${response.statusText}`); + } + return await response.json(); + } + + async fetchPricing() { + const response = await fetch('/api/billing/pricing'); + if (!response.ok) { + throw new Error(`HTTP ${response.status}: ${response.statusText}`); + } + return await response.json(); + } + + async fetchInvoices() { + const response = await fetch('/api/billing/invoices?limit=10', { + headers: {'Authorization': `Bearer ${localStorage.getItem('token')}`} + }); + if (!response.ok) { + throw new Error(`HTTP ${response.status}: ${response.statusText}`); + } + return await response.json(); + } + + formatCurrency(amount) { + return new Intl.NumberFormat('en-US', { + style: 'currency', + currency: 'USD', + minimumFractionDigits: 2, + maximumFractionDigits: 4 + }).format(amount); + } + + formatGB(gb) { + if (gb >= 1024) { + return `${(gb / 1024).toFixed(2)} TB`; + } + return `${gb.toFixed(2)} GB`; + } + + calculateEstimatedCost() { + if (!this.currentUsage || !this.pricing) return 0; + + const storagePrice = parseFloat(this.pricing.storage_per_gb_month?.value || 0); + const bandwidthPrice = parseFloat(this.pricing.bandwidth_egress_per_gb?.value || 0); + const freeStorage = parseFloat(this.pricing.free_tier_storage_gb?.value || 0); + const freeBandwidth = parseFloat(this.pricing.free_tier_bandwidth_gb?.value || 0); + + const storageGB = this.currentUsage.storage_gb; + const bandwidthGB = this.currentUsage.bandwidth_down_gb_today * 30; + + const billableStorage = Math.max(0, Math.ceil(storageGB - freeStorage)); + const billableBandwidth = Math.max(0, Math.ceil(bandwidthGB - freeBandwidth)); + + return (billableStorage * storagePrice) + (billableBandwidth * bandwidthPrice); + } + + render() { + const estimatedCost = this.calculateEstimatedCost(); + const storageUsed = this.currentUsage?.storage_gb || 0; + const freeStorage = parseFloat(this.pricing?.free_tier_storage_gb?.value || 15); + const storagePercentage = Math.min(100, (storageUsed / freeStorage) * 100); + + this.innerHTML = ` +
+
+

Billing & Usage

+
+ ${this.subscription?.billing_type === 'pay_as_you_go' ? 'Pay As You Go' : this.subscription?.plan_name || 'Free'} +
+
+ +
+
+

Current Usage

+
+
+ Storage + ${this.formatGB(storageUsed)} +
+
+
+
+
${this.formatGB(freeStorage)} included free
+ +
+ Bandwidth (Today) + ${this.formatGB(this.currentUsage?.bandwidth_down_gb_today || 0)} +
+
+
+ +
+

Estimated Monthly Cost

+
${this.formatCurrency(estimatedCost)}
+
+
+ Storage + ${this.formatCurrency(Math.max(0, Math.ceil(storageUsed - freeStorage)) * parseFloat(this.pricing?.storage_per_gb_month?.value || 0))} +
+
+ Bandwidth + ${this.formatCurrency(0)} +
+
+
+ +
+

Current Pricing

+
+
+ Storage + ${this.formatCurrency(parseFloat(this.pricing?.storage_per_gb_month?.value || 0))}/GB/month +
+
+ Bandwidth + ${this.formatCurrency(parseFloat(this.pricing?.bandwidth_egress_per_gb?.value || 0))}/GB +
+
+ Free Tier + ${this.formatGB(freeStorage)} storage, ${this.formatGB(parseFloat(this.pricing?.free_tier_bandwidth_gb?.value || 15))} bandwidth/month +
+
+
+
+ +
+

Recent Invoices

+
+ ${this.renderInvoicesTable()} +
+
+ +
+

Payment Methods

+ +
+
+ `; + } + + renderInvoicesTable() { + if (!this.invoices || this.invoices.length === 0) { + return '

No invoices yet

'; + } + + return ` + + + + + + + + + + + + + ${this.invoices.map(invoice => ` + + + + + + + + + `).join('')} + +
Invoice #PeriodAmountStatusDue DateActions
${invoice.invoice_number}${this.formatDate(invoice.period_start)} - ${this.formatDate(invoice.period_end)}${this.formatCurrency(invoice.total)}${invoice.status}${invoice.due_date ? this.formatDate(invoice.due_date) : '-'} + +
+ `; + } + + formatDate(dateString) { + return new Date(dateString).toLocaleDateString('en-US', { + year: 'numeric', + month: 'short', + day: 'numeric' + }); + } + + handleClick(e) { + const target = e.target; + + if (target.id === 'addPaymentMethod') { + this.showPaymentMethodModal(); + return; + } + + if (target.dataset.invoiceId) { + const invoiceId = target.dataset.invoiceId; + this.showInvoiceDetail(invoiceId); + } + } + + attachEventListeners() { + } + + async showPaymentMethodModal() { + alert('Payment method modal will be implemented with Stripe Elements'); + } + + async showInvoiceDetail(invoiceId) { + const response = await fetch(`/api/billing/invoices/${invoiceId}`, { + headers: {'Authorization': `Bearer ${localStorage.getItem('token')}`} + }); + const invoice = await response.json(); + + const modal = document.createElement('div'); + modal.className = 'modal'; + modal.innerHTML = ` + + `; + document.body.appendChild(modal); + } +} + +customElements.define('billing-dashboard', BillingDashboard); + +export default BillingDashboard; diff --git a/static/js/components/code-editor-view.js b/static/js/components/code-editor-view.js new file mode 100644 index 0000000..39014f4 --- /dev/null +++ b/static/js/components/code-editor-view.js @@ -0,0 +1,153 @@ +import { api } from '../api.js'; + +class CodeEditorView extends HTMLElement { + constructor() { + super(); + this.editor = null; + this.file = null; + this.previousView = null; + this.boundHandleClick = this.handleClick.bind(this); + this.boundHandleEscape = this.handleEscape.bind(this); + } + + connectedCallback() { + this.addEventListener('click', this.boundHandleClick); + document.addEventListener('keydown', this.boundHandleEscape); + } + + disconnectedCallback() { + this.removeEventListener('click', this.boundHandleClick); + document.removeEventListener('keydown', this.boundHandleEscape); + if (this.editor) { + this.editor.toTextArea(); + this.editor = null; + } + } + + handleEscape(e) { + if (e.key === 'Escape') { + this.goBack(); + } + } + + async setFile(file, previousView = 'files') { + this.file = file; + this.previousView = previousView; + await this.loadAndRender(); + } + + async loadAndRender() { + try { + const blob = await api.downloadFile(this.file.id); + const content = await blob.text(); + this.render(content); + this.initializeEditor(content); + } catch (error) { + console.error('Failed to load file:', error); + document.dispatchEvent(new CustomEvent('show-toast', { + detail: { message: 'Failed to load file: ' + error.message, type: 'error' } + })); + this.render(''); + window.history.back(); + } + } + + getMimeType(filename) { + const extension = filename.split('.').pop().toLowerCase(); + const mimeMap = { + 'js': 'text/javascript', + 'json': 'application/json', + 'py': 'text/x-python', + 'md': 'text/x-markdown', + 'html': 'text/html', + 'xml': 'application/xml', + 'css': 'text/css', + 'txt': 'text/plain', + 'log': 'text/plain', + 'sh': 'text/x-sh', + 'yaml': 'text/x-yaml', + 'yml': 'text/x-yaml' + }; + return mimeMap[extension] || 'text/plain'; + } + + render(content) { + this.innerHTML = ` +
+
+
+ +

${this.file.name}

+
+
+ +
+
+
+ +
+
+ `; + } + + initializeEditor(content) { + const textarea = this.querySelector('#code-editor-textarea'); + if (!textarea) return; + + this.editor = CodeMirror.fromTextArea(textarea, { + value: content, + mode: this.getMimeType(this.file.name), + lineNumbers: true, + theme: 'default', + lineWrapping: true, + indentUnit: 4, + indentWithTabs: false, + extraKeys: { + 'Ctrl-S': () => this.save(), + 'Cmd-S': () => this.save() + } + }); + + this.editor.setSize('100%', '100%'); + } + + handleClick(e) { + if (e.target.id === 'back-btn') { + this.goBack(); + } else if (e.target.id === 'save-btn') { + this.save(); + } + } + + async save() { + if (!this.editor) return; + + try { + const content = this.editor.getValue(); + await api.updateFile(this.file.id, content); + document.dispatchEvent(new CustomEvent('show-toast', { + detail: { message: 'File saved successfully!', type: 'success' } + })); + } catch (error) { + document.dispatchEvent(new CustomEvent('show-toast', { + detail: { message: 'Failed to save file: ' + error.message, type: 'error' } + })); + } + } + + goBack() { + window.history.back(); + } + + hide() { + document.removeEventListener('keydown', this.boundHandleEscape); + if (this.editor) { + this.editor.toTextArea(); + this.editor = null; + } + this.remove(); + } +} + +customElements.define('code-editor-view', CodeEditorView); +export { CodeEditorView }; diff --git a/static/js/components/deleted-files.js b/static/js/components/deleted-files.js index f7e491f..b6ea05c 100644 --- a/static/js/components/deleted-files.js +++ b/static/js/components/deleted-files.js @@ -1,18 +1,22 @@ import { api } from '../api.js'; +import { BaseFileList } from './base-file-list.js'; -export class DeletedFiles extends HTMLElement { +export class DeletedFiles extends BaseFileList { constructor() { super(); - this.deletedFiles = []; } async connectedCallback() { + super.connectedCallback(); await this.loadDeletedFiles(); } async loadDeletedFiles() { try { - this.deletedFiles = await api.listDeletedFiles(); + this.files = await api.listDeletedFiles(); + this.folders = []; + this.selectedFiles.clear(); + this.selectedFolders.clear(); this.render(); } catch (error) { console.error('Failed to load deleted files:', error); @@ -21,10 +25,17 @@ export class DeletedFiles extends HTMLElement { } render() { - if (this.deletedFiles.length === 0) { + const hasSelected = this.selectedFiles.size > 0; + const totalSelected = this.selectedFiles.size; + const allSelected = this.files.length > 0 && this.selectedFiles.size === this.files.length; + const someSelected = hasSelected && !allSelected; + + if (this.files.length === 0) { this.innerHTML = ` -
-

Deleted Files

+
+
+

Deleted Files

+

No deleted files found.

`; @@ -32,76 +43,110 @@ export class DeletedFiles extends HTMLElement { } this.innerHTML = ` -
-

Deleted Files

+
+
+
+

Deleted Files

+ ${this.files.length > 0 ? ` +
+ + +
+ ` : ''} +
+
+ + ${hasSelected ? ` +
+ + +
+ ` : ''} +
- ${this.deletedFiles.map(file => this.renderDeletedFile(file)).join('')} + ${this.files.map(file => this.renderDeletedFile(file)).join('')}
`; this.attachListeners(); + this.updateIndeterminateState(); } renderDeletedFile(file) { + const isSelected = this.selectedFiles.has(file.id); const icon = this.getFileIcon(file.mime_type); const size = this.formatFileSize(file.size); - const deletedDate = new Date(file.deleted_at).toLocaleDateString(); + const deletedAt = file.deleted_at ? new Date(file.deleted_at).toLocaleString() : 'N/A'; return ` -
+
+
${icon}
${file.name}
${size}
-
Deleted: ${deletedDate}
+
Deleted: ${deletedAt}
- +
`; } - getFileIcon(mimeType) { - if (mimeType.startsWith('image/')) return '📷'; - if (mimeType.startsWith('video/')) return '🎥'; - if (mimeType.startsWith('audio/')) return '🎵'; - if (mimeType.includes('pdf')) return '📄'; - if (mimeType.includes('text')) return '📄'; - return '📄'; - } - - formatFileSize(bytes) { - if (bytes < 1024) return bytes + ' B'; - if (bytes < 1048576) return (bytes / 1024).toFixed(1) + ' KB'; - if (bytes < 1073741824) return (bytes / 1048576).toFixed(1) + ' MB'; - return (bytes / 1073741824).toFixed(1) + ' GB'; + createBatchActionsBar() { + const container = this.querySelector('.file-list-container'); + const header = container.querySelector('.file-list-header'); + const batchBar = document.createElement('div'); + batchBar.className = 'batch-actions'; + batchBar.innerHTML = ` + + + `; + header.insertAdjacentElement('afterend', batchBar); } attachListeners() { - this.querySelectorAll('.action-btn').forEach(btn => { - btn.addEventListener('click', async (e) => { - e.stopPropagation(); - const action = btn.dataset.action; - const id = parseInt(btn.dataset.id); - if (action === 'restore') { - await this.handleRestore(id); - } - }); - }); + const batchRestoreBtn = this.querySelector('#batch-restore-btn'); + if (batchRestoreBtn) { + batchRestoreBtn.addEventListener('click', () => this.handleBatchRestore()); + } } - async handleRestore(fileId) { - if (confirm('Are you sure you want to restore this file?')) { - try { + async handleBatchRestore() { + const totalSelected = this.selectedFiles.size; + if (totalSelected === 0) return; + + if (!confirm(`Restore ${totalSelected} files?`)) return; + + try { + for (const fileId of this.selectedFiles) { await api.restoreFile(fileId); + } + document.dispatchEvent(new CustomEvent('show-toast', { + detail: { message: 'Files restored successfully!', type: 'success' } + })); + await this.loadDeletedFiles(); + } catch (error) { + document.dispatchEvent(new CustomEvent('show-toast', { + detail: { message: 'Failed to restore files: ' + error.message, type: 'error' } + })); + } + } + + async handleAction(action, id) { + try { + if (action === 'restore') { + await api.restoreFile(id); document.dispatchEvent(new CustomEvent('show-toast', { detail: { message: 'File restored successfully!', type: 'success' } })); - await this.loadDeletedFiles(); // Reload the list - } catch (error) { - document.dispatchEvent(new CustomEvent('show-toast', { - detail: { message: 'Failed to restore file: ' + error.message, type: 'error' } - })); + await this.loadDeletedFiles(); } + } catch (error) { + document.dispatchEvent(new CustomEvent('show-toast', { + detail: { message: 'Action failed: ' + error.message, type: 'error' } + })); } } } diff --git a/static/js/components/file-list.js b/static/js/components/file-list.js index 6d44ffe..88e14d4 100644 --- a/static/js/components/file-list.js +++ b/static/js/components/file-list.js @@ -4,29 +4,54 @@ export class FileList extends HTMLElement { constructor() { super(); this.currentFolderId = null; + this.folderPath = []; this.files = []; this.folders = []; this.selectedFiles = new Set(); this.selectedFolders = new Set(); + this.boundHandleClick = this.handleClick.bind(this); + this.boundHandleDblClick = this.handleDblClick.bind(this); + this.boundHandleChange = this.handleChange.bind(this); } async connectedCallback() { + this.addEventListener('click', this.boundHandleClick); + this.addEventListener('dblclick', this.boundHandleDblClick); + this.addEventListener('change', this.boundHandleChange); await this.loadContents(null); } + disconnectedCallback() { + this.removeEventListener('click', this.boundHandleClick); + this.removeEventListener('dblclick', this.boundHandleDblClick); + this.removeEventListener('change', this.boundHandleChange); + } + async loadContents(folderId) { this.currentFolderId = folderId; try { + if (folderId) { + try { + this.folderPath = await api.getFolderPath(folderId); + } catch (pathError) { + this.folderPath = []; + } + } else { + this.folderPath = []; + } this.folders = await api.listFolders(folderId); this.files = await api.listFiles(folderId); this.selectedFiles.clear(); this.selectedFolders.clear(); this.render(); } catch (error) { - console.error('Failed to load contents:', error); document.dispatchEvent(new CustomEvent('show-toast', { - detail: { message: 'Failed to load contents: ' + error.message, type: 'error' } + detail: { message: 'Failed to load folder contents', type: 'error' } })); + this.folderPath = []; + this.folders = []; + this.files = []; + this.render(); } } @@ -40,29 +65,52 @@ export class FileList extends HTMLElement { render() { const hasSelected = this.selectedFiles.size > 0 || this.selectedFolders.size > 0; + const totalItems = this.files.length + this.folders.length; + const totalSelected = this.selectedFiles.size + this.selectedFolders.size; const allFilesSelected = this.files.length > 0 && this.selectedFiles.size === this.files.length; const allFoldersSelected = this.folders.length > 0 && this.selectedFolders.size === this.folders.length; - const allSelected = (this.files.length + this.folders.length) > 0 && allFilesSelected && allFoldersSelected; + const allSelected = totalItems > 0 && allFilesSelected && allFoldersSelected; + const someSelected = hasSelected && !allSelected; this.innerHTML = `
+ ${this.folderPath.length > 0 ? ` + + ` : ''}
-

Files

+
+

Files

+ ${totalItems > 0 ? ` +
+ + +
+ ` : ''} +
-
- - - - - - - -
+ ${hasSelected ? ` +
+ + + + + + +
+ ` : ''}
${this.folders.map(folder => this.renderFolder(folder)).join('')} @@ -72,6 +120,7 @@ export class FileList extends HTMLElement { `; this.attachListeners(); + this.updateIndeterminateState(); } renderFolder(folder) { @@ -124,6 +173,17 @@ export class FileList extends HTMLElement { return '📄'; } + isEditableFile(filename, mimeType) { + if (mimeType && mimeType.startsWith('text/')) return true; + + const editableExtensions = [ + 'txt', 'md', 'log', 'json', 'js', 'py', 'html', 'css', + 'xml', 'yaml', 'yml', 'sh', 'bat', 'ini', 'conf', 'cfg' + ]; + const extension = filename.split('.').pop().toLowerCase(); + return editableExtensions.includes(extension); + } + formatFileSize(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1048576) return (bytes / 1024).toFixed(1) + ' KB'; @@ -131,62 +191,116 @@ export class FileList extends HTMLElement { return (bytes / 1073741824).toFixed(1) + ' GB'; } + handleClick(e) { + const target = e.target; + + if (target.classList.contains('breadcrumb-item') && !target.classList.contains('breadcrumb-current')) { + const folderId = target.dataset.folderId; + const targetFolderId = folderId === 'null' ? null : parseInt(folderId); + this.loadContents(targetFolderId); + return; + } + + if (target.id === 'upload-btn') { + this.dispatchEvent(new CustomEvent('upload-request', { + detail: { folderId: this.currentFolderId } + })); + return; + } + + if (target.id === 'create-folder-btn') { + this.handleCreateFolder(); + return; + } + + if (target.id === 'clear-selection-btn') { + this.clearSelection(); + return; + } + + if (target.id === 'batch-delete-btn') { + this.handleBatchAction('delete'); + return; + } + if (target.id === 'batch-move-btn') { + this.handleBatchAction('move'); + return; + } + if (target.id === 'batch-copy-btn') { + this.handleBatchAction('copy'); + return; + } + if (target.id === 'batch-star-btn') { + this.handleBatchAction('star'); + return; + } + if (target.id === 'batch-unstar-btn') { + this.handleBatchAction('unstar'); + return; + } + + if (target.classList.contains('action-btn')) { + e.stopPropagation(); + const action = target.dataset.action; + const id = parseInt(target.dataset.id); + this.handleAction(action, id); + return; + } + + if (target.classList.contains('select-item')) { + e.stopPropagation(); + return; + } + + const fileItem = target.closest('.file-item:not(.folder-item)'); + if (fileItem) { + const fileId = parseInt(fileItem.dataset.fileId); + const file = this.files.find(f => f.id === fileId); + + if (this.isEditableFile(file.name, file.mime_type)) { + this.dispatchEvent(new CustomEvent('edit-file', { + detail: { file: file }, + bubbles: true + })); + } else { + this.dispatchEvent(new CustomEvent('photo-click', { + detail: { photo: file }, + bubbles: true + })); + } + } + } + + handleDblClick(e) { + if (e.target.classList.contains('select-item') || + e.target.classList.contains('action-btn') || + e.target.classList.contains('breadcrumb-item')) { + return; + } + + const folderItem = e.target.closest('.folder-item'); + if (folderItem) { + const folderId = parseInt(folderItem.dataset.folderId); + this.loadContents(folderId); + } + } + + handleChange(e) { + const target = e.target; + + if (target.id === 'select-all') { + this.toggleSelectAll(target.checked); + return; + } + + if (target.classList.contains('select-item')) { + const type = target.dataset.type; + const id = parseInt(target.dataset.id); + this.toggleSelectItem(type, id, target.checked); + } + } + attachListeners() { - this.querySelector('#upload-btn')?.addEventListener('click', () => { - this.dispatchEvent(new CustomEvent('upload-request')); - }); - - this.querySelector('#create-folder-btn')?.addEventListener('click', async () => { - await this.handleCreateFolder(); - }); - - this.querySelectorAll('.folder-item').forEach(item => { - item.addEventListener('dblclick', () => { - const folderId = parseInt(item.dataset.folderId); - this.dispatchEvent(new CustomEvent('folder-open', { detail: { folderId } })); - }); - }); - - this.querySelectorAll('.file-item:not(.folder-item)').forEach(item => { - item.addEventListener('click', (e) => { - if (!e.target.classList.contains('action-btn') && !e.target.classList.contains('select-item')) { - const fileId = parseInt(item.dataset.fileId); - const file = this.files.find(f => f.id === fileId); - this.dispatchEvent(new CustomEvent('photo-click', { - detail: { photo: file }, - bubbles: true - })); - } - }); - }); - - this.querySelectorAll('.action-btn').forEach(btn => { - btn.addEventListener('click', async (e) => { - e.stopPropagation(); - const action = btn.dataset.action; - const id = parseInt(btn.dataset.id); - await this.handleAction(action, id); - }); - }); - - this.querySelectorAll('.select-item').forEach(checkbox => { - checkbox.addEventListener('change', (e) => { - const type = e.target.dataset.type; - const id = parseInt(e.target.dataset.id); - this.toggleSelectItem(type, id, e.target.checked); - }); - }); - - this.querySelector('#select-all')?.addEventListener('change', (e) => { - this.toggleSelectAll(e.target.checked); - }); - - this.querySelector('#batch-delete-btn')?.addEventListener('click', () => this.handleBatchAction('delete')); - this.querySelector('#batch-move-btn')?.addEventListener('click', () => this.handleBatchAction('move')); - this.querySelector('#batch-copy-btn')?.addEventListener('click', () => this.handleBatchAction('copy')); - this.querySelector('#batch-star-btn')?.addEventListener('click', () => this.handleBatchAction('star')); - this.querySelector('#batch-unstar-btn')?.addEventListener('click', () => this.handleBatchAction('unstar')); - this.updateBatchActionVisibility(); } @@ -204,7 +318,7 @@ export class FileList extends HTMLElement { this.selectedFolders.delete(id); } } - this.updateBatchActionVisibility(); + this.updateSelectionUI(); } toggleSelectAll(checked) { @@ -215,18 +329,75 @@ export class FileList extends HTMLElement { this.files.forEach(file => this.selectedFiles.add(file.id)); this.folders.forEach(folder => this.selectedFolders.add(folder.id)); } - this.render(); // Re-render to update checkboxes + + this.querySelectorAll('.select-item').forEach(checkbox => { + checkbox.checked = checked; + }); + + this.updateSelectionUI(); + } + + clearSelection() { + this.selectedFiles.clear(); + this.selectedFolders.clear(); + this.querySelectorAll('.select-item').forEach(checkbox => { + checkbox.checked = false; + }); + this.updateSelectionUI(); + } + + updateSelectionUI() { + const hasSelected = this.selectedFiles.size > 0 || this.selectedFolders.size > 0; + const totalItems = this.files.length + this.folders.length; + const totalSelected = this.selectedFiles.size + this.selectedFolders.size; + const allSelected = totalItems > 0 && totalSelected === totalItems; + + const selectAllCheckbox = this.querySelector('#select-all'); + const selectAllLabel = this.querySelector('label[for="select-all"]'); + const batchActionsDiv = this.querySelector('.batch-actions'); + + if (selectAllCheckbox) { + selectAllCheckbox.checked = allSelected; + this.updateIndeterminateState(); + } + + if (selectAllLabel) { + selectAllLabel.textContent = hasSelected ? `${totalSelected} selected` : 'Select all'; + } + + if (hasSelected && !batchActionsDiv) { + const container = this.querySelector('.file-list-container'); + const header = container.querySelector('.file-list-header'); + const batchBar = document.createElement('div'); + batchBar.className = 'batch-actions'; + batchBar.innerHTML = ` + + + + + + + `; + header.insertAdjacentElement('afterend', batchBar); + } else if (!hasSelected && batchActionsDiv) { + batchActionsDiv.remove(); + } + } + + updateIndeterminateState() { + const selectAllCheckbox = this.querySelector('#select-all'); + if (selectAllCheckbox) { + const totalItems = this.files.length + this.folders.length; + const totalSelected = this.selectedFiles.size + this.selectedFolders.size; + const hasSelected = totalSelected > 0; + const allSelected = totalItems > 0 && totalSelected === totalItems; + + selectAllCheckbox.indeterminate = hasSelected && !allSelected; + } } updateBatchActionVisibility() { - const batchActionsDiv = this.querySelector('.batch-actions'); - if (batchActionsDiv) { - if (this.selectedFiles.size > 0 || this.selectedFolders.size > 0) { - batchActionsDiv.style.display = 'flex'; - } else { - batchActionsDiv.style.display = 'none'; - } - } + this.updateSelectionUI(); } async handleBatchAction(action) { diff --git a/static/js/components/file-preview.js b/static/js/components/file-preview.js index 2ce985c..144be90 100644 --- a/static/js/components/file-preview.js +++ b/static/js/components/file-preview.js @@ -14,17 +14,20 @@ class FilePreview extends HTMLElement { setupEventListeners() { const closeBtn = this.querySelector('.close-preview'); - const modal = this.querySelector('.preview-modal'); const downloadBtn = this.querySelector('.download-btn'); const shareBtn = this.querySelector('.share-btn'); - closeBtn.addEventListener('click', () => this.close()); - modal.addEventListener('click', (e) => { - if (e.target === modal) this.close(); - }); + if (closeBtn) { + closeBtn.addEventListener('click', () => this.close()); + } - downloadBtn.addEventListener('click', () => this.downloadFile()); - shareBtn.addEventListener('click', () => this.shareFile()); + if (downloadBtn) { + downloadBtn.addEventListener('click', () => this.downloadFile()); + } + + if (shareBtn) { + shareBtn.addEventListener('click', () => this.shareFile()); + } } handleEscape(e) { @@ -33,17 +36,30 @@ class FilePreview extends HTMLElement { } } - async show(file) { + async show(file, pushState = true) { this.file = file; this.style.display = 'block'; document.addEventListener('keydown', this.handleEscape); this.renderPreview(); + + if (pushState) { + window.history.pushState( + { view: 'file-preview', file: file }, + '', + `#preview/${file.id}` + ); + } } close() { + window.history.back(); + } + + hide() { this.style.display = 'none'; this.file = null; document.removeEventListener('keydown', this.handleEscape); + this.remove(); } async renderPreview() { @@ -149,21 +165,21 @@ class FilePreview extends HTMLElement { render() { this.innerHTML = ` -
-
-
+
+
+
+
-

+

-
- - - -
-
+
+ + +
+
`; this.style.display = 'none'; diff --git a/static/js/components/file-upload-view.js b/static/js/components/file-upload-view.js new file mode 100644 index 0000000..42de0de --- /dev/null +++ b/static/js/components/file-upload-view.js @@ -0,0 +1,187 @@ +import { api } from '../api.js'; + +export class FileUploadView extends HTMLElement { + constructor() { + super(); + this.folderId = null; + this.handleEscape = this.handleEscape.bind(this); + } + + connectedCallback() { + document.addEventListener('keydown', this.handleEscape); + } + + disconnectedCallback() { + document.removeEventListener('keydown', this.handleEscape); + } + + setFolder(folderId) { + this.folderId = folderId; + this.render(); + this.attachListeners(); + this.openFileSelector(); + } + + render() { + const folderInfo = this.folderId ? `(Folder ID: ${this.folderId})` : '(Root)'; + this.innerHTML = ` + + `; + } + + openFileSelector() { + const fileInput = this.querySelector('#file-input'); + if (fileInput) { + fileInput.click(); + } + } + + attachListeners() { + const fileInput = this.querySelector('#file-input'); + const backBtn = this.querySelector('#upload-back-btn'); + + if (backBtn) { + backBtn.addEventListener('click', () => this.close()); + } + + if (fileInput) { + fileInput.addEventListener('change', (e) => { + if (e.target.files.length > 0) { + const view = this.querySelector('.file-upload-view'); + if (view) { + view.style.display = 'flex'; + } + this.handleFiles(e.target.files); + } else { + this.close(); + } + }); + + fileInput.addEventListener('cancel', () => { + this.close(); + }); + } + } + + handleEscape(e) { + if (e.key === 'Escape') { + this.close(); + } + } + + close() { + window.history.back(); + } + + hide() { + document.removeEventListener('keydown', this.handleEscape); + this.remove(); + } + + async handleFiles(files) { + const uploadList = this.querySelector('#upload-list'); + if (!uploadList) return; + + for (const file of files) { + const itemId = `upload-${Date.now()}-${Math.random()}`; + const item = document.createElement('div'); + item.className = 'upload-item'; + item.id = itemId; + item.innerHTML = ` +
+
${file.name}
+
${this.formatFileSize(file.size)}
+
+
+
+
+
+
Uploading...
+
+ `; + uploadList.appendChild(item); + + try { + await this.uploadFile(file, itemId); + const statusEl = item.querySelector('.upload-item-status'); + if (statusEl) { + statusEl.textContent = 'Complete'; + statusEl.classList.add('success'); + } + } catch (error) { + const statusEl = item.querySelector('.upload-item-status'); + if (statusEl) { + statusEl.textContent = 'Failed: ' + error.message; + statusEl.classList.add('error'); + } + } + } + + this.dispatchEvent(new CustomEvent('upload-complete', { bubbles: true })); + + setTimeout(() => { + this.close(); + }, 1500); + } + + async uploadFile(file, itemId) { + const formData = new FormData(); + formData.append('file', file); + if (this.folderId !== null && this.folderId !== undefined) { + formData.append('folder_id', String(this.folderId)); + } + + const xhr = new XMLHttpRequest(); + + return new Promise((resolve, reject) => { + xhr.upload.addEventListener('progress', (e) => { + if (e.lengthComputable) { + const percentComplete = (e.loaded / e.total) * 100; + const item = this.querySelector(`#${itemId}`); + if (item) { + const progressFill = item.querySelector('.progress-fill'); + if (progressFill) { + progressFill.style.width = percentComplete + '%'; + } + } + } + }); + + xhr.addEventListener('load', () => { + if (xhr.status >= 200 && xhr.status < 300) { + resolve(JSON.parse(xhr.responseText)); + } else { + reject(new Error(xhr.statusText)); + } + }); + + xhr.addEventListener('error', () => reject(new Error('Upload failed'))); + xhr.addEventListener('abort', () => reject(new Error('Upload aborted'))); + + xhr.open('POST', '/files/upload'); + xhr.setRequestHeader('Authorization', `Bearer ${api.getToken()}`); + xhr.send(formData); + }); + } + + formatFileSize(bytes) { + if (bytes < 1024) return bytes + ' B'; + if (bytes < 1048576) return (bytes / 1024).toFixed(1) + ' KB'; + if (bytes < 1073741824) return (bytes / 1048576).toFixed(1) + ' MB'; + return (bytes / 1073741824).toFixed(1) + ' GB'; + } +} + +customElements.define('file-upload-view', FileUploadView); diff --git a/static/js/components/login-view.js b/static/js/components/login-view.js index e34952d..d54abbc 100644 --- a/static/js/components/login-view.js +++ b/static/js/components/login-view.js @@ -16,7 +16,7 @@ export class LoginView extends HTMLElement {
- +
diff --git a/static/js/components/photo-gallery.js b/static/js/components/photo-gallery.js index ac9466a..8d2a815 100644 --- a/static/js/components/photo-gallery.js +++ b/static/js/components/photo-gallery.js @@ -4,13 +4,19 @@ class PhotoGallery extends HTMLElement { constructor() { super(); this.photos = []; + this.boundHandleClick = this.handleClick.bind(this); } connectedCallback() { + this.addEventListener('click', this.boundHandleClick); this.render(); this.loadPhotos(); } + disconnectedCallback() { + this.removeEventListener('click', this.boundHandleClick); + } + async loadPhotos() { try { this.photos = await api.getPhotos(); @@ -62,16 +68,22 @@ class PhotoGallery extends HTMLElement { } }); - grid.querySelectorAll('.photo-item').forEach(item => { - item.addEventListener('click', () => { - const fileId = item.dataset.fileId; - const photo = this.photos.find(p => p.id === parseInt(fileId)); - this.dispatchEvent(new CustomEvent('photo-click', { - detail: { photo }, - bubbles: true - })); - }); - }); + this.attachListeners(); + } + + handleClick(e) { + const photoItem = e.target.closest('.photo-item'); + if (photoItem) { + const fileId = photoItem.dataset.fileId; + const photo = this.photos.find(p => p.id === parseInt(fileId)); + this.dispatchEvent(new CustomEvent('photo-click', { + detail: { photo }, + bubbles: true + })); + } + } + + attachListeners() { } render() { diff --git a/static/js/components/rbox-app.js b/static/js/components/rbox-app.js index c5680d5..fda6cbd 100644 --- a/static/js/components/rbox-app.js +++ b/static/js/components/rbox-app.js @@ -1,7 +1,7 @@ import { api } from '../api.js'; import './login-view.js'; import './file-list.js'; -import './file-upload.js'; +import './file-upload-view.js'; import './share-modal.js'; import './photo-gallery.js'; import './file-preview.js'; @@ -10,20 +10,24 @@ import './admin-dashboard.js'; import './toast-notification.js'; import './starred-items.js'; import './recent-files.js'; -import './shared-items.js'; // Import the new component +import './shared-items.js'; +import './billing-dashboard.js'; +import './admin-billing.js'; +import './code-editor-view.js'; import { shortcuts } from '../shortcuts.js'; export class RBoxApp extends HTMLElement { constructor() { super(); this.currentView = 'files'; - this.currentFolderId = null; this.user = null; + this.navigationStack = []; } async connectedCallback() { await this.init(); this.addEventListener('show-toast', this.handleShowToast); + window.addEventListener('popstate', this.handlePopState.bind(this)); } disconnectedCallback() { @@ -85,7 +89,9 @@ export class RBoxApp extends HTMLElement {
  • Photo Gallery
  • Shared Items
  • Deleted Files
  • +
  • Billing
  • ${this.user && this.user.is_superuser ? `
  • Admin Dashboard
  • ` : ''} + ${this.user && this.user.is_superuser ? `
  • Admin Billing
  • ` : ''}
    - -
    `; + this.initializeNavigation(); this.attachListeners(); this.registerShortcuts(); } + initializeNavigation() { + if (!window.history.state) { + const hash = window.location.hash.slice(1); + if (hash && hash !== '') { + const view = hash.split('/')[0]; + const validViews = ['files', 'photos', 'shared', 'deleted', 'starred', 'recent', 'admin', 'billing', 'admin-billing']; + if (validViews.includes(view)) { + window.history.replaceState({ view: view }, '', `#${hash}`); + this.currentView = view; + } else { + window.history.replaceState({ view: 'files' }, '', '#files'); + } + } else { + window.history.replaceState({ view: 'files' }, '', '#files'); + } + } + } + registerShortcuts() { shortcuts.register('ctrl+u', () => { - const upload = this.querySelector('file-upload'); - if (upload) { - upload.setFolder(this.currentFolderId); - upload.show(); - } + const fileList = this.querySelector('file-list'); + const folderId = fileList ? fileList.currentFolderId : null; + this.showUpload(folderId); }); shortcuts.register('ctrl+f', () => { @@ -164,7 +185,44 @@ export class RBoxApp extends HTMLElement { }); shortcuts.register('f2', () => { - console.log('Rename shortcut - to be implemented'); + const fileListComponent = document.querySelector('file-list'); + if (fileListComponent && fileListComponent.selectedFiles && fileListComponent.selectedFiles.size === 1) { + const fileId = Array.from(fileListComponent.selectedFiles)[0]; + const file = fileListComponent.files.find(f => f.id === fileId); + if (file) { + const newName = prompt('Enter new name:', file.name); + if (newName && newName !== file.name) { + api.renameFile(fileId, newName).then(() => { + fileListComponent.loadContents(fileListComponent.currentFolderId); + document.dispatchEvent(new CustomEvent('show-toast', { + detail: { message: 'File renamed successfully', type: 'success' } + })); + }).catch(error => { + document.dispatchEvent(new CustomEvent('show-toast', { + detail: { message: 'Failed to rename file', type: 'error' } + })); + }); + } + } + } else if (fileListComponent && fileListComponent.selectedFolders && fileListComponent.selectedFolders.size === 1) { + const folderId = Array.from(fileListComponent.selectedFolders)[0]; + const folder = fileListComponent.folders.find(f => f.id === folderId); + if (folder) { + const newName = prompt('Enter new name:', folder.name); + if (newName && newName !== folder.name) { + api.updateFolder(folderId, { name: newName }).then(() => { + fileListComponent.loadContents(fileListComponent.currentFolderId); + document.dispatchEvent(new CustomEvent('show-toast', { + detail: { message: 'Folder renamed successfully', type: 'success' } + })); + }).catch(error => { + document.dispatchEvent(new CustomEvent('show-toast', { + detail: { message: 'Failed to rename folder', type: 'error' } + })); + }); + } + } + } }); } @@ -277,15 +335,12 @@ export class RBoxApp extends HTMLElement { const fileList = this.querySelector('file-list'); if (fileList) { - fileList.addEventListener('upload-request', () => { - const upload = this.querySelector('file-upload'); - upload.setFolder(this.currentFolderId); - upload.show(); + fileList.addEventListener('upload-request', (e) => { + this.showUpload(e.detail.folderId); }); fileList.addEventListener('folder-open', (e) => { - this.currentFolderId = e.detail.folderId; - fileList.loadContents(this.currentFolderId); + fileList.loadContents(e.detail.folderId); }); fileList.addEventListener('share-request', (e) => { @@ -294,13 +349,12 @@ export class RBoxApp extends HTMLElement { }); } - const upload = this.querySelector('file-upload'); - if (upload) { - upload.addEventListener('upload-complete', () => { - const fileList = this.querySelector('file-list'); - fileList.loadContents(this.currentFolderId); - }); - } + this.addEventListener('upload-complete', () => { + const fileList = this.querySelector('file-list'); + if (fileList) { + fileList.loadContents(fileList.currentFolderId); + } + }); const searchInput = this.querySelector('#search-input'); if (searchInput) { @@ -315,14 +369,109 @@ export class RBoxApp extends HTMLElement { } this.addEventListener('photo-click', (e) => { - const preview = this.querySelector('file-preview'); - preview.show(e.detail.photo); + this.showFilePreview(e.detail.photo); }); this.addEventListener('share-file', (e) => { const modal = this.querySelector('share-modal'); modal.show(e.detail.file.id); }); + + this.addEventListener('edit-file', (e) => { + this.showCodeEditor(e.detail.file); + }); + } + + handlePopState(e) { + this.closeAllOverlays(); + + if (e.state && e.state.view) { + if (e.state.view === 'code-editor' && e.state.file) { + this.showCodeEditor(e.state.file, false); + } else if (e.state.view === 'file-preview' && e.state.file) { + this.showFilePreview(e.state.file, false); + } else if (e.state.view === 'upload') { + const folderId = e.state.folderId !== undefined ? e.state.folderId : null; + this.showUpload(folderId, false); + } else { + this.switchView(e.state.view, false); + } + } else { + this.switchView('files', false); + } + } + + closeAllOverlays() { + const existingEditor = this.querySelector('code-editor-view'); + if (existingEditor) { + existingEditor.hide(); + } + + const existingPreview = this.querySelector('file-preview'); + if (existingPreview) { + existingPreview.hide(); + } + + const existingUpload = this.querySelector('file-upload-view'); + if (existingUpload) { + existingUpload.hide(); + } + + const shareModal = this.querySelector('share-modal'); + if (shareModal && shareModal.style.display !== 'none') { + shareModal.style.display = 'none'; + } + } + + showCodeEditor(file, pushState = true) { + this.closeAllOverlays(); + + const mainElement = this.querySelector('.app-main'); + const editorView = document.createElement('code-editor-view'); + mainElement.appendChild(editorView); + editorView.setFile(file, this.currentView); + + if (pushState) { + window.history.pushState( + { view: 'code-editor', file: file }, + '', + `#editor/${file.id}` + ); + } + } + + showFilePreview(file, pushState = true) { + this.closeAllOverlays(); + + const mainElement = this.querySelector('.app-main'); + const preview = document.createElement('file-preview'); + mainElement.appendChild(preview); + preview.show(file, false); + + if (pushState) { + window.history.pushState( + { view: 'file-preview', file: file }, + '', + `#preview/${file.id}` + ); + } + } + + showUpload(folderId = null, pushState = true) { + this.closeAllOverlays(); + + const mainElement = this.querySelector('.app-main'); + const uploadView = document.createElement('file-upload-view'); + mainElement.appendChild(uploadView); + uploadView.setFolder(folderId); + + if (pushState) { + window.history.pushState( + { view: 'upload', folderId: folderId }, + '', + '#upload' + ); + } } async performSearch(query) { @@ -343,7 +492,10 @@ export class RBoxApp extends HTMLElement { } } - switchView(view) { + switchView(view, pushState = true) { + this.closeAllOverlays(); + + if(this.currentView === view) return; this.currentView = view; this.querySelectorAll('.nav-link').forEach(link => { @@ -353,6 +505,10 @@ export class RBoxApp extends HTMLElement { const mainContent = this.querySelector('#main-content'); + if (pushState) { + window.history.pushState({ view: view }, '', `#${view}`); + } + switch (view) { case 'files': mainContent.innerHTML = ''; @@ -368,7 +524,7 @@ export class RBoxApp extends HTMLElement { break; case 'deleted': mainContent.innerHTML = ''; - this.attachListeners(); // Re-attach listeners for the new component + this.attachListeners(); break; case 'starred': mainContent.innerHTML = ''; @@ -382,6 +538,14 @@ export class RBoxApp extends HTMLElement { mainContent.innerHTML = ''; this.attachListeners(); break; + case 'billing': + mainContent.innerHTML = ''; + this.attachListeners(); + break; + case 'admin-billing': + mainContent.innerHTML = ''; + this.attachListeners(); + break; } } } diff --git a/static/js/components/recent-files.js b/static/js/components/recent-files.js index 18f08f7..a602d99 100644 --- a/static/js/components/recent-files.js +++ b/static/js/components/recent-files.js @@ -1,18 +1,22 @@ import { api } from '../api.js'; +import { BaseFileList } from './base-file-list.js'; -export class RecentFiles extends HTMLElement { +export class RecentFiles extends BaseFileList { constructor() { super(); - this.recentFiles = []; } async connectedCallback() { + super.connectedCallback(); await this.loadRecentFiles(); } async loadRecentFiles() { try { - this.recentFiles = await api.listRecentFiles(); + this.files = await api.listRecentFiles(); + this.folders = []; + this.selectedFiles.clear(); + this.selectedFolders.clear(); this.render(); } catch (error) { console.error('Failed to load recent files:', error); @@ -23,10 +27,17 @@ export class RecentFiles extends HTMLElement { } render() { - if (this.recentFiles.length === 0) { + const hasSelected = this.selectedFiles.size > 0; + const totalSelected = this.selectedFiles.size; + const allSelected = this.files.length > 0 && this.selectedFiles.size === this.files.length; + const someSelected = hasSelected && !allSelected; + + if (this.files.length === 0) { this.innerHTML = ` -
    -

    Recent Files

    +
    +
    +

    Recent Files

    +

    No recent files found.

    `; @@ -34,23 +45,45 @@ export class RecentFiles extends HTMLElement { } this.innerHTML = ` -
    -

    Recent Files

    +
    +
    +
    +

    Recent Files

    + ${this.files.length > 0 ? ` +
    + + +
    + ` : ''} +
    +
    + + ${hasSelected ? ` +
    + +
    + ` : ''} +
    - ${this.recentFiles.map(file => this.renderFile(file)).join('')} + ${this.files.map(file => this.renderRecentFile(file)).join('')}
    `; this.attachListeners(); + this.updateIndeterminateState(); } - renderFile(file) { + renderRecentFile(file) { + const isSelected = this.selectedFiles.has(file.id); const icon = this.getFileIcon(file.mime_type); const size = this.formatFileSize(file.size); const lastAccessed = file.last_accessed_at ? new Date(file.last_accessed_at).toLocaleString() : 'N/A'; return ` -
    +
    +
    ${icon}
    ${file.name}
    ${size}
    @@ -62,51 +95,24 @@ export class RecentFiles extends HTMLElement { `; } - getFileIcon(mimeType) { - if (mimeType.startsWith('image/')) return '📷'; - if (mimeType.startsWith('video/')) return '🎥'; - if (mimeType.startsWith('audio/')) return '🎵'; - if (mimeType.includes('pdf')) return '📄'; - if (mimeType.includes('text')) return '📄'; - return '📄'; - } - - formatFileSize(bytes) { - if (bytes < 1024) return bytes + ' B'; - if (bytes < 1048576) return (bytes / 1024).toFixed(1) + ' KB'; - if (bytes < 1073741824) return (bytes / 1048576).toFixed(1) + ' MB'; - return (bytes / 1073741824).toFixed(1) + ' GB'; - } - - attachListeners() { - this.querySelectorAll('.action-btn').forEach(btn => { - btn.addEventListener('click', async (e) => { - e.stopPropagation(); - const action = btn.dataset.action; - const id = parseInt(btn.dataset.id); - if (action === 'download') { - await this.handleDownload(id); - } - }); - }); - } - - async handleDownload(fileId) { + async handleAction(action, id) { try { - const blob = await api.downloadFile(fileId); - const file = this.recentFiles.find(f => f.id === fileId); - const url = URL.createObjectURL(blob); - const a = document.createElement('a'); - a.href = url; - a.download = file.name; - a.click(); - URL.revokeObjectURL(url); - document.dispatchEvent(new CustomEvent('show-toast', { - detail: { message: 'File downloaded successfully!', type: 'success' } - })); + if (action === 'download') { + const blob = await api.downloadFile(id); + const file = this.files.find(f => f.id === id); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = file.name; + a.click(); + URL.revokeObjectURL(url); + document.dispatchEvent(new CustomEvent('show-toast', { + detail: { message: 'File downloaded successfully!', type: 'success' } + })); + } } catch (error) { document.dispatchEvent(new CustomEvent('show-toast', { - detail: { message: 'Failed to download file: ' + error.message, type: 'error' } + detail: { message: 'Action failed: ' + error.message, type: 'error' } })); } } diff --git a/static/js/components/shared-items.js b/static/js/components/shared-items.js index 4e32d65..8cdb58f 100644 --- a/static/js/components/shared-items.js +++ b/static/js/components/shared-items.js @@ -4,12 +4,18 @@ export class SharedItems extends HTMLElement { constructor() { super(); this.myShares = []; + this.boundHandleClick = this.handleClick.bind(this); } async connectedCallback() { + this.addEventListener('click', this.boundHandleClick); await this.loadMyShares(); } + disconnectedCallback() { + this.removeEventListener('click', this.boundHandleClick); + } + async loadMyShares() { try { this.myShares = await api.listMyShares(); @@ -69,23 +75,25 @@ export class SharedItems extends HTMLElement { `; } - attachListeners() { - this.querySelectorAll('.share-actions .button').forEach(btn => { - btn.addEventListener('click', async (e) => { - e.stopPropagation(); - const action = btn.dataset.action; - const id = parseInt(btn.dataset.id); - const link = btn.dataset.link; + handleClick(e) { + const target = e.target; + if (target.closest('.share-actions') && target.classList.contains('button')) { + e.stopPropagation(); + const action = target.dataset.action; + const id = parseInt(target.dataset.id); + const link = target.dataset.link; - if (action === 'copy-link') { - this.copyLink(link); - } else if (action === 'edit-share') { - this.handleEditShare(id); - } else if (action === 'delete-share') { - await this.handleDeleteShare(id); - } - }); - }); + if (action === 'copy-link') { + this.copyLink(link); + } else if (action === 'edit-share') { + this.handleEditShare(id); + } else if (action === 'delete-share') { + this.handleDeleteShare(id); + } + } + } + + attachListeners() { } copyLink(link) { diff --git a/static/js/components/starred-items.js b/static/js/components/starred-items.js index d40cad2..791da94 100644 --- a/static/js/components/starred-items.js +++ b/static/js/components/starred-items.js @@ -1,20 +1,22 @@ import { api } from '../api.js'; +import { BaseFileList } from './base-file-list.js'; -export class StarredItems extends HTMLElement { +export class StarredItems extends BaseFileList { constructor() { super(); - this.starredFiles = []; - this.starredFolders = []; } async connectedCallback() { + super.connectedCallback(); await this.loadStarredItems(); } async loadStarredItems() { try { - this.starredFiles = await api.listStarredFiles(); - this.starredFolders = await api.listStarredFolders(); + this.files = await api.listStarredFiles(); + this.folders = await api.listStarredFolders(); + this.selectedFiles.clear(); + this.selectedFolders.clear(); this.render(); } catch (error) { console.error('Failed to load starred items:', error); @@ -25,12 +27,21 @@ export class StarredItems extends HTMLElement { } render() { - const allStarred = [...this.starredFolders, ...this.starredFiles]; + const allStarred = [...this.folders, ...this.files]; + const hasSelected = this.selectedFiles.size > 0 || this.selectedFolders.size > 0; + const totalItems = this.files.length + this.folders.length; + const totalSelected = this.selectedFiles.size + this.selectedFolders.size; + const allFilesSelected = this.files.length > 0 && this.selectedFiles.size === this.files.length; + const allFoldersSelected = this.folders.length > 0 && this.selectedFolders.size === this.folders.length; + const allSelected = totalItems > 0 && allFilesSelected && allFoldersSelected; + const someSelected = hasSelected && !allSelected; if (allStarred.length === 0) { this.innerHTML = ` -
    -

    Starred Items

    +
    +
    +

    Starred Items

    +

    No starred items found.

    `; @@ -38,71 +49,90 @@ export class StarredItems extends HTMLElement { } this.innerHTML = ` -
    -

    Starred Items

    +
    +
    +
    +

    Starred Items

    + ${totalItems > 0 ? ` +
    + + +
    + ` : ''} +
    +
    + + ${hasSelected ? ` +
    + + +
    + ` : ''} +
    - ${this.starredFolders.map(folder => this.renderFolder(folder)).join('')} - ${this.starredFiles.map(file => this.renderFile(file)).join('')} + ${this.folders.map(folder => this.renderFolder(folder)).join('')} + ${this.files.map(file => this.renderFile(file)).join('')}
    `; this.attachListeners(); + this.updateIndeterminateState(); } - renderFolder(folder) { + getFolderActions(folder) { + return ``; + } + + getFileActions(file) { return ` -
    -
    📁
    -
    ${folder.name}
    -
    - -
    -
    + + `; } - renderFile(file) { - const icon = this.getFileIcon(file.mime_type); - const size = this.formatFileSize(file.size); - - return ` -
    -
    ${icon}
    -
    ${file.name}
    -
    ${size}
    -
    - - -
    -
    + createBatchActionsBar() { + const container = this.querySelector('.file-list-container'); + const header = container.querySelector('.file-list-header'); + const batchBar = document.createElement('div'); + batchBar.className = 'batch-actions'; + batchBar.innerHTML = ` + + `; - } - - getFileIcon(mimeType) { - if (mimeType.startsWith('image/')) return '📷'; - if (mimeType.startsWith('video/')) return '🎥'; - if (mimeType.startsWith('audio/')) return '🎵'; - if (mimeType.includes('pdf')) return '📄'; - if (mimeType.includes('text')) return '📄'; - return '📄'; - } - - formatFileSize(bytes) { - if (bytes < 1024) return bytes + ' B'; - if (bytes < 1048576) return (bytes / 1024).toFixed(1) + ' KB'; - if (bytes < 1073741824) return (bytes / 1048576).toFixed(1) + ' MB'; - return (bytes / 1073741824).toFixed(1) + ' GB'; + header.insertAdjacentElement('afterend', batchBar); } attachListeners() { - this.querySelectorAll('.action-btn').forEach(btn => { - btn.addEventListener('click', async (e) => { - e.stopPropagation(); - const action = btn.dataset.action; - const id = parseInt(btn.dataset.id); - await this.handleAction(action, id); - }); - }); + const batchUnstarBtn = this.querySelector('#batch-unstar-btn'); + if (batchUnstarBtn) { + batchUnstarBtn.addEventListener('click', () => this.handleBatchUnstar()); + } + } + + async handleBatchUnstar() { + const totalSelected = this.selectedFiles.size + this.selectedFolders.size; + if (totalSelected === 0) return; + + if (!confirm(`Unstar ${totalSelected} items?`)) return; + + try { + for (const fileId of this.selectedFiles) { + await api.unstarFile(fileId); + } + for (const folderId of this.selectedFolders) { + await api.unstarFolder(folderId); + } + document.dispatchEvent(new CustomEvent('show-toast', { + detail: { message: 'Items unstarred successfully!', type: 'success' } + })); + await this.loadStarredItems(); + } catch (error) { + document.dispatchEvent(new CustomEvent('show-toast', { + detail: { message: 'Failed to unstar items: ' + error.message, type: 'error' } + })); + } } async handleAction(action, id) { @@ -110,7 +140,7 @@ export class StarredItems extends HTMLElement { switch (action) { case 'download': const blob = await api.downloadFile(id); - const file = this.starredFiles.find(f => f.id === id); + const file = this.files.find(f => f.id === id); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; diff --git a/static/js/main.js b/static/js/main.js index b73a3a5..703e106 100644 --- a/static/js/main.js +++ b/static/js/main.js @@ -12,12 +12,6 @@ const app = new RBoxApp(); // Register service worker for PWA if ('serviceWorker' in navigator) { window.addEventListener('load', () => { - navigator.serviceWorker.register('/static/service-worker.js') - .then(registration => { - console.log('Service Worker registered with scope:', registration.scope); - }) - .catch(error => { - console.log('Service Worker registration failed:', error); - }); + navigator.serviceWorker.register('/static/service-worker.js'); }); } diff --git a/static/service-worker.js b/static/service-worker.js index 6e11032..40f542b 100644 --- a/static/service-worker.js +++ b/static/service-worker.js @@ -1,4 +1,4 @@ -const CACHE_NAME = 'rbox-cache-v1'; +const CACHE_NAME = 'rbox-cache-v11'; const urlsToCache = [ '/', '/static/index.html', diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/billing/__init__.py b/tests/billing/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/billing/test_api_endpoints.py b/tests/billing/test_api_endpoints.py new file mode 100644 index 0000000..a10ed16 --- /dev/null +++ b/tests/billing/test_api_endpoints.py @@ -0,0 +1,256 @@ +import pytest +from decimal import Decimal +from datetime import date, datetime +from httpx import AsyncClient +from fastapi import status +from tortoise.contrib.test import initializer, finalizer +from rbox.main import app +from rbox.models import User +from rbox.billing.models import PricingConfig, Invoice, UsageAggregate, UserSubscription +from rbox.auth import create_access_token + +@pytest.fixture(scope="module") +def event_loop(): + import asyncio + loop = asyncio.get_event_loop_policy().new_event_loop() + yield loop + loop.close() + +@pytest.fixture(scope="module", autouse=True) +async def initialize_tests(): + initializer(["rbox.models", "rbox.billing.models"], db_url="sqlite://:memory:") + yield + await finalizer() + +@pytest.fixture +async def test_user(): + user = await User.create( + username="testuser", + email="test@example.com", + hashed_password="hashed_password_here", + is_active=True, + is_superuser=False + ) + yield user + await user.delete() + +@pytest.fixture +async def admin_user(): + user = await User.create( + username="adminuser", + email="admin@example.com", + hashed_password="hashed_password_here", + is_active=True, + is_superuser=True + ) + yield user + await user.delete() + +@pytest.fixture +async def auth_token(test_user): + token = create_access_token(data={"sub": test_user.username}) + return token + +@pytest.fixture +async def admin_token(admin_user): + token = create_access_token(data={"sub": admin_user.username}) + return token + +@pytest.fixture +async def pricing_config(): + configs = [] + configs.append(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" + )) + configs.append(await PricingConfig.create( + config_key="bandwidth_egress_per_gb", + config_value=Decimal("0.009"), + description="Bandwidth egress cost per GB", + unit="per_gb" + )) + configs.append(await PricingConfig.create( + config_key="free_tier_storage_gb", + config_value=Decimal("15"), + description="Free tier storage in GB", + unit="gb" + )) + configs.append(await PricingConfig.create( + config_key="free_tier_bandwidth_gb", + config_value=Decimal("15"), + description="Free tier bandwidth in GB per month", + unit="gb" + )) + yield configs + for config in configs: + await config.delete() + +@pytest.mark.asyncio +async def test_get_current_usage(test_user, auth_token): + async with AsyncClient(app=app, base_url="http://test") as client: + response = await client.get( + "/api/billing/usage/current", + headers={"Authorization": f"Bearer {auth_token}"} + ) + + assert response.status_code == status.HTTP_200_OK + data = response.json() + assert "storage_gb" in data + assert "bandwidth_down_gb_today" in data + +@pytest.mark.asyncio +async def test_get_monthly_usage(test_user, auth_token): + today = date.today() + + await UsageAggregate.create( + user=test_user, + date=today, + storage_bytes_avg=1024 ** 3 * 10, + storage_bytes_peak=1024 ** 3 * 12, + bandwidth_up_bytes=1024 ** 3 * 2, + bandwidth_down_bytes=1024 ** 3 * 5 + ) + + async with AsyncClient(app=app, base_url="http://test") as client: + response = await client.get( + f"/api/billing/usage/monthly?year={today.year}&month={today.month}", + headers={"Authorization": f"Bearer {auth_token}"} + ) + + assert response.status_code == status.HTTP_200_OK + data = response.json() + assert data["storage_gb_avg"] == pytest.approx(10.0, rel=0.01) + + await UsageAggregate.filter(user=test_user).delete() + +@pytest.mark.asyncio +async def test_get_subscription(test_user, auth_token): + async with AsyncClient(app=app, base_url="http://test") as client: + response = await client.get( + "/api/billing/subscription", + headers={"Authorization": f"Bearer {auth_token}"} + ) + + assert response.status_code == status.HTTP_200_OK + data = response.json() + assert data["billing_type"] == "pay_as_you_go" + assert data["status"] == "active" + + await UserSubscription.filter(user=test_user).delete() + +@pytest.mark.asyncio +async def test_list_invoices(test_user, auth_token): + invoice = await Invoice.create( + user=test_user, + invoice_number="INV-000001-202311", + period_start=date(2023, 11, 1), + period_end=date(2023, 11, 30), + subtotal=Decimal("10.00"), + tax=Decimal("0.00"), + total=Decimal("10.00"), + status="open" + ) + + async with AsyncClient(app=app, base_url="http://test") as client: + response = await client.get( + "/api/billing/invoices", + headers={"Authorization": f"Bearer {auth_token}"} + ) + + assert response.status_code == status.HTTP_200_OK + data = response.json() + assert len(data) > 0 + assert data[0]["invoice_number"] == "INV-000001-202311" + + await invoice.delete() + +@pytest.mark.asyncio +async def test_get_invoice(test_user, auth_token): + invoice = await Invoice.create( + user=test_user, + invoice_number="INV-000002-202311", + period_start=date(2023, 11, 1), + period_end=date(2023, 11, 30), + subtotal=Decimal("10.00"), + tax=Decimal("0.00"), + total=Decimal("10.00"), + status="open" + ) + + async with AsyncClient(app=app, base_url="http://test") as client: + response = await client.get( + f"/api/billing/invoices/{invoice.id}", + headers={"Authorization": f"Bearer {auth_token}"} + ) + + assert response.status_code == status.HTTP_200_OK + data = response.json() + assert data["invoice_number"] == "INV-000002-202311" + + await invoice.delete() + +@pytest.mark.asyncio +async def test_get_pricing(): + async with AsyncClient(app=app, base_url="http://test") as client: + response = await client.get("/api/billing/pricing") + + assert response.status_code == status.HTTP_200_OK + data = response.json() + assert isinstance(data, dict) + +@pytest.mark.asyncio +async def test_admin_get_pricing(admin_user, admin_token, pricing_config): + async with AsyncClient(app=app, base_url="http://test") as client: + response = await client.get( + "/api/admin/billing/pricing", + headers={"Authorization": f"Bearer {admin_token}"} + ) + + assert response.status_code == status.HTTP_200_OK + data = response.json() + assert len(data) > 0 + +@pytest.mark.asyncio +async def test_admin_update_pricing(admin_user, admin_token, pricing_config): + config_id = pricing_config[0].id + + async with AsyncClient(app=app, base_url="http://test") as client: + response = await client.put( + f"/api/admin/billing/pricing/{config_id}", + headers={"Authorization": f"Bearer {admin_token}"}, + json={ + "config_key": "storage_per_gb_month", + "config_value": 0.005 + } + ) + + assert response.status_code == status.HTTP_200_OK + + updated = await PricingConfig.get(id=config_id) + assert updated.config_value == Decimal("0.005") + +@pytest.mark.asyncio +async def test_admin_get_stats(admin_user, admin_token): + async with AsyncClient(app=app, base_url="http://test") as client: + response = await client.get( + "/api/admin/billing/stats", + headers={"Authorization": f"Bearer {admin_token}"} + ) + + assert response.status_code == status.HTTP_200_OK + data = response.json() + assert "total_revenue" in data + assert "total_invoices" in data + assert "pending_invoices" in data + +@pytest.mark.asyncio +async def test_non_admin_cannot_access_admin_endpoints(test_user, auth_token): + async with AsyncClient(app=app, base_url="http://test") as client: + response = await client.get( + "/api/admin/billing/pricing", + headers={"Authorization": f"Bearer {auth_token}"} + ) + + assert response.status_code == status.HTTP_403_FORBIDDEN diff --git a/tests/billing/test_invoice_generator.py b/tests/billing/test_invoice_generator.py new file mode 100644 index 0000000..d844c41 --- /dev/null +++ b/tests/billing/test_invoice_generator.py @@ -0,0 +1,195 @@ +import pytest +from decimal import Decimal +from datetime import date, datetime +from tortoise.contrib.test import initializer, finalizer +from rbox.models import User +from rbox.billing.models import Invoice, InvoiceLineItem, PricingConfig, UsageAggregate, UserSubscription +from rbox.billing.invoice_generator import InvoiceGenerator + +@pytest.fixture(scope="module") +def event_loop(): + import asyncio + loop = asyncio.get_event_loop_policy().new_event_loop() + yield loop + loop.close() + +@pytest.fixture(scope="module", autouse=True) +async def initialize_tests(): + initializer(["rbox.models", "rbox.billing.models"], db_url="sqlite://:memory:") + yield + await finalizer() + +@pytest.fixture +async def test_user(): + user = await User.create( + username="testuser", + email="test@example.com", + hashed_password="hashed_password_here", + is_active=True + ) + yield user + await user.delete() + +@pytest.fixture +async def pricing_config(): + configs = [] + configs.append(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" + )) + configs.append(await PricingConfig.create( + config_key="bandwidth_egress_per_gb", + config_value=Decimal("0.009"), + description="Bandwidth egress cost per GB", + unit="per_gb" + )) + configs.append(await PricingConfig.create( + config_key="free_tier_storage_gb", + config_value=Decimal("15"), + description="Free tier storage in GB", + unit="gb" + )) + configs.append(await PricingConfig.create( + config_key="free_tier_bandwidth_gb", + config_value=Decimal("15"), + description="Free tier bandwidth in GB per month", + unit="gb" + )) + configs.append(await PricingConfig.create( + config_key="tax_rate_default", + config_value=Decimal("0.0"), + description="Default tax rate", + unit="percentage" + )) + yield configs + for config in configs: + await config.delete() + +@pytest.mark.asyncio +async def test_generate_monthly_invoice_with_usage(test_user, pricing_config): + today = date.today() + + await UsageAggregate.create( + user=test_user, + date=today, + storage_bytes_avg=1024 ** 3 * 50, + storage_bytes_peak=1024 ** 3 * 55, + bandwidth_up_bytes=1024 ** 3 * 10, + bandwidth_down_bytes=1024 ** 3 * 20 + ) + + invoice = await InvoiceGenerator.generate_monthly_invoice(test_user, today.year, today.month) + + assert invoice is not None + assert invoice.user_id == test_user.id + assert invoice.status == "draft" + assert invoice.total > 0 + + line_items = await invoice.line_items.all() + assert len(line_items) > 0 + + await invoice.delete() + await UsageAggregate.filter(user=test_user).delete() + +@pytest.mark.asyncio +async def test_generate_monthly_invoice_below_free_tier(test_user, pricing_config): + today = date.today() + + await UsageAggregate.create( + user=test_user, + date=today, + storage_bytes_avg=1024 ** 3 * 10, + storage_bytes_peak=1024 ** 3 * 12, + bandwidth_up_bytes=1024 ** 3 * 5, + bandwidth_down_bytes=1024 ** 3 * 10 + ) + + invoice = await InvoiceGenerator.generate_monthly_invoice(test_user, today.year, today.month) + + assert invoice is None + + await UsageAggregate.filter(user=test_user).delete() + +@pytest.mark.asyncio +async def test_finalize_invoice(test_user, pricing_config): + invoice = await Invoice.create( + user=test_user, + invoice_number="INV-000001-202311", + period_start=date(2023, 11, 1), + period_end=date(2023, 11, 30), + subtotal=Decimal("10.00"), + tax=Decimal("0.00"), + total=Decimal("10.00"), + status="draft" + ) + + finalized = await InvoiceGenerator.finalize_invoice(invoice) + + assert finalized.status == "open" + + await finalized.delete() + +@pytest.mark.asyncio +async def test_finalize_invoice_already_finalized(test_user, pricing_config): + invoice = await Invoice.create( + user=test_user, + invoice_number="INV-000002-202311", + period_start=date(2023, 11, 1), + period_end=date(2023, 11, 30), + subtotal=Decimal("10.00"), + tax=Decimal("0.00"), + total=Decimal("10.00"), + status="open" + ) + + with pytest.raises(ValueError): + await InvoiceGenerator.finalize_invoice(invoice) + + await invoice.delete() + +@pytest.mark.asyncio +async def test_mark_invoice_paid(test_user, pricing_config): + invoice = await Invoice.create( + user=test_user, + invoice_number="INV-000003-202311", + period_start=date(2023, 11, 1), + period_end=date(2023, 11, 30), + subtotal=Decimal("10.00"), + tax=Decimal("0.00"), + total=Decimal("10.00"), + status="open" + ) + + paid = await InvoiceGenerator.mark_invoice_paid(invoice) + + assert paid.status == "paid" + assert paid.paid_at is not None + + await paid.delete() + +@pytest.mark.asyncio +async def test_invoice_with_tax(test_user): + await PricingConfig.filter(config_key="tax_rate_default").update(config_value=Decimal("0.21")) + + today = date.today() + + await UsageAggregate.create( + user=test_user, + date=today, + storage_bytes_avg=1024 ** 3 * 50, + storage_bytes_peak=1024 ** 3 * 55, + bandwidth_up_bytes=1024 ** 3 * 10, + bandwidth_down_bytes=1024 ** 3 * 20 + ) + + invoice = await InvoiceGenerator.generate_monthly_invoice(test_user, today.year, today.month) + + assert invoice is not None + assert invoice.tax > 0 + assert invoice.total == invoice.subtotal + invoice.tax + + await invoice.delete() + await UsageAggregate.filter(user=test_user).delete() + await PricingConfig.filter(config_key="tax_rate_default").update(config_value=Decimal("0.0")) diff --git a/tests/billing/test_models.py b/tests/billing/test_models.py new file mode 100644 index 0000000..6481c03 --- /dev/null +++ b/tests/billing/test_models.py @@ -0,0 +1,188 @@ +import pytest +import pytest_asyncio +from decimal import Decimal +from datetime import date, datetime +from tortoise.contrib.test import initializer, finalizer +from rbox.models import User +from rbox.billing.models import ( + SubscriptionPlan, UserSubscription, UsageRecord, UsageAggregate, + Invoice, InvoiceLineItem, PricingConfig, PaymentMethod, BillingEvent +) + +@pytest.fixture(scope="module") +def event_loop(): + import asyncio + loop = asyncio.get_event_loop_policy().new_event_loop() + yield loop + loop.close() + +@pytest_asyncio.fixture(scope="module", autouse=True) +async def initialize_tests(): + initializer(["rbox.models", "rbox.billing.models"], db_url="sqlite://:memory:") + yield + await finalizer() + +@pytest_asyncio.fixture +async def test_user(): + user = await User.create( + username="testuser", + email="test@example.com", + hashed_password="hashed_password_here", + is_active=True + ) + yield user + await user.delete() + +@pytest.mark.asyncio +async def test_subscription_plan_creation(): + plan = await SubscriptionPlan.create( + name="starter", + display_name="Starter Plan", + description="Basic storage plan", + storage_gb=100, + bandwidth_gb=100, + price_monthly=Decimal("5.00"), + price_yearly=Decimal("50.00") + ) + + assert plan.name == "starter" + assert plan.storage_gb == 100 + assert plan.price_monthly == Decimal("5.00") + await plan.delete() + +@pytest.mark.asyncio +async def test_user_subscription_creation(test_user): + subscription = await UserSubscription.create( + user=test_user, + billing_type="pay_as_you_go", + status="active" + ) + + assert subscription.user_id == test_user.id + assert subscription.billing_type == "pay_as_you_go" + assert subscription.status == "active" + await subscription.delete() + +@pytest.mark.asyncio +async def test_usage_record_creation(test_user): + usage = await UsageRecord.create( + user=test_user, + record_type="storage", + amount_bytes=1024 * 1024 * 100, + resource_type="file", + resource_id=1, + idempotency_key="test_key_123" + ) + + assert usage.user_id == test_user.id + assert usage.record_type == "storage" + assert usage.amount_bytes == 1024 * 1024 * 100 + await usage.delete() + +@pytest.mark.asyncio +async def test_usage_aggregate_creation(test_user): + aggregate = await UsageAggregate.create( + user=test_user, + date=date.today(), + storage_bytes_avg=1024 * 1024 * 500, + storage_bytes_peak=1024 * 1024 * 600, + bandwidth_up_bytes=1024 * 1024 * 50, + bandwidth_down_bytes=1024 * 1024 * 100 + ) + + assert aggregate.user_id == test_user.id + assert aggregate.storage_bytes_avg == 1024 * 1024 * 500 + await aggregate.delete() + +@pytest.mark.asyncio +async def test_invoice_creation(test_user): + invoice = await Invoice.create( + user=test_user, + invoice_number="INV-000001-202311", + period_start=date(2023, 11, 1), + period_end=date(2023, 11, 30), + subtotal=Decimal("10.00"), + tax=Decimal("0.00"), + total=Decimal("10.00"), + status="draft" + ) + + assert invoice.user_id == test_user.id + assert invoice.invoice_number == "INV-000001-202311" + assert invoice.total == Decimal("10.00") + await invoice.delete() + +@pytest.mark.asyncio +async def test_invoice_line_item_creation(test_user): + invoice = await Invoice.create( + user=test_user, + invoice_number="INV-000002-202311", + period_start=date(2023, 11, 1), + period_end=date(2023, 11, 30), + subtotal=Decimal("10.00"), + tax=Decimal("0.00"), + total=Decimal("10.00"), + status="draft" + ) + + line_item = await InvoiceLineItem.create( + invoice=invoice, + description="Storage usage", + quantity=Decimal("100.000000"), + unit_price=Decimal("0.100000"), + amount=Decimal("10.0000"), + item_type="storage" + ) + + assert line_item.invoice_id == invoice.id + assert line_item.description == "Storage usage" + assert line_item.amount == Decimal("10.0000") + await line_item.delete() + await invoice.delete() + +@pytest.mark.asyncio +async def test_pricing_config_creation(test_user): + config = 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", + updated_by=test_user + ) + + assert config.config_key == "storage_per_gb_month" + assert config.config_value == Decimal("0.0045") + await config.delete() + +@pytest.mark.asyncio +async def test_payment_method_creation(test_user): + payment_method = await PaymentMethod.create( + user=test_user, + stripe_payment_method_id="pm_test_123", + type="card", + is_default=True, + last4="4242", + brand="visa", + exp_month=12, + exp_year=2025 + ) + + assert payment_method.user_id == test_user.id + assert payment_method.last4 == "4242" + assert payment_method.is_default is True + await payment_method.delete() + +@pytest.mark.asyncio +async def test_billing_event_creation(test_user): + event = await BillingEvent.create( + user=test_user, + event_type="invoice_created", + stripe_event_id="evt_test_123", + data={"invoice_id": 1}, + processed=False + ) + + assert event.user_id == test_user.id + assert event.event_type == "invoice_created" + assert event.processed is False + await event.delete() diff --git a/tests/billing/test_simple.py b/tests/billing/test_simple.py new file mode 100644 index 0000000..2dda104 --- /dev/null +++ b/tests/billing/test_simple.py @@ -0,0 +1,77 @@ +import pytest + +def test_billing_module_imports(): + from rbox.billing import models, stripe_client, usage_tracker, invoice_generator, scheduler + assert models is not None + assert stripe_client is not None + assert usage_tracker is not None + assert invoice_generator is not None + assert scheduler is not None + +def test_billing_models_exist(): + from rbox.billing.models import ( + SubscriptionPlan, UserSubscription, UsageRecord, UsageAggregate, + Invoice, InvoiceLineItem, PricingConfig, PaymentMethod, BillingEvent + ) + assert SubscriptionPlan is not None + assert UserSubscription is not None + assert UsageRecord is not None + assert UsageAggregate is not None + assert Invoice is not None + assert InvoiceLineItem is not None + assert PricingConfig is not None + assert PaymentMethod is not None + assert BillingEvent is not None + +def test_stripe_client_exists(): + from rbox.billing.stripe_client import StripeClient + assert StripeClient is not None + assert hasattr(StripeClient, 'create_customer') + assert hasattr(StripeClient, 'create_invoice') + assert hasattr(StripeClient, 'finalize_invoice') + +def test_usage_tracker_exists(): + from rbox.billing.usage_tracker import UsageTracker + assert UsageTracker is not None + assert hasattr(UsageTracker, 'track_storage') + assert hasattr(UsageTracker, 'track_bandwidth') + assert hasattr(UsageTracker, 'aggregate_daily_usage') + assert hasattr(UsageTracker, 'get_current_storage') + assert hasattr(UsageTracker, 'get_monthly_usage') + +def test_invoice_generator_exists(): + from rbox.billing.invoice_generator import InvoiceGenerator + assert InvoiceGenerator is not None + assert hasattr(InvoiceGenerator, 'generate_monthly_invoice') + assert hasattr(InvoiceGenerator, 'finalize_invoice') + assert hasattr(InvoiceGenerator, 'mark_invoice_paid') + +def test_scheduler_exists(): + from rbox.billing.scheduler import scheduler, start_scheduler, stop_scheduler + assert scheduler is not None + assert callable(start_scheduler) + assert callable(stop_scheduler) + +def test_routers_exist(): + from rbox.routers import billing, admin_billing + assert billing is not None + assert admin_billing is not None + assert hasattr(billing, 'router') + assert hasattr(admin_billing, 'router') + +def test_middleware_exists(): + from rbox.middleware.usage_tracking import UsageTrackingMiddleware + assert UsageTrackingMiddleware is not None + +def test_settings_updated(): + from rbox.settings import settings + assert hasattr(settings, 'STRIPE_SECRET_KEY') + assert hasattr(settings, 'STRIPE_PUBLISHABLE_KEY') + assert hasattr(settings, 'STRIPE_WEBHOOK_SECRET') + assert hasattr(settings, 'BILLING_ENABLED') + +def test_main_includes_billing(): + from rbox.main import app + routes = [route.path for route in app.routes] + billing_routes = [r for r in routes if '/billing' in r] + assert len(billing_routes) > 0 diff --git a/tests/billing/test_usage_tracker.py b/tests/billing/test_usage_tracker.py new file mode 100644 index 0000000..d316a73 --- /dev/null +++ b/tests/billing/test_usage_tracker.py @@ -0,0 +1,175 @@ +import pytest +from decimal import Decimal +from datetime import date, datetime, timedelta +from tortoise.contrib.test import initializer, finalizer +from rbox.models import User, File, Folder +from rbox.billing.models import UsageRecord, UsageAggregate +from rbox.billing.usage_tracker import UsageTracker + +@pytest.fixture(scope="module") +def event_loop(): + import asyncio + loop = asyncio.get_event_loop_policy().new_event_loop() + yield loop + loop.close() + +@pytest.fixture(scope="module", autouse=True) +async def initialize_tests(): + initializer(["rbox.models", "rbox.billing.models"], db_url="sqlite://:memory:") + yield + await finalizer() + +@pytest.fixture +async def test_user(): + user = await User.create( + username="testuser", + email="test@example.com", + hashed_password="hashed_password_here", + is_active=True + ) + yield user + await user.delete() + +@pytest.mark.asyncio +async def test_track_storage(test_user): + await UsageTracker.track_storage( + user=test_user, + amount_bytes=1024 * 1024 * 100, + resource_type="file", + resource_id=1 + ) + + records = await UsageRecord.filter(user=test_user, record_type="storage").all() + assert len(records) == 1 + assert records[0].amount_bytes == 1024 * 1024 * 100 + + await records[0].delete() + +@pytest.mark.asyncio +async def test_track_bandwidth_upload(test_user): + await UsageTracker.track_bandwidth( + user=test_user, + amount_bytes=1024 * 1024 * 50, + direction="up", + resource_type="file", + resource_id=1 + ) + + records = await UsageRecord.filter(user=test_user, record_type="bandwidth_up").all() + assert len(records) == 1 + assert records[0].amount_bytes == 1024 * 1024 * 50 + + await records[0].delete() + +@pytest.mark.asyncio +async def test_track_bandwidth_download(test_user): + await UsageTracker.track_bandwidth( + user=test_user, + amount_bytes=1024 * 1024 * 75, + direction="down", + resource_type="file", + resource_id=1 + ) + + records = await UsageRecord.filter(user=test_user, record_type="bandwidth_down").all() + assert len(records) == 1 + assert records[0].amount_bytes == 1024 * 1024 * 75 + + await records[0].delete() + +@pytest.mark.asyncio +async def test_aggregate_daily_usage(test_user): + await UsageTracker.track_storage( + user=test_user, + amount_bytes=1024 * 1024 * 100 + ) + + await UsageTracker.track_bandwidth( + user=test_user, + amount_bytes=1024 * 1024 * 50, + direction="up" + ) + + await UsageTracker.track_bandwidth( + user=test_user, + amount_bytes=1024 * 1024 * 75, + direction="down" + ) + + aggregate = await UsageTracker.aggregate_daily_usage(test_user, date.today()) + + assert aggregate is not None + assert aggregate.storage_bytes_avg > 0 + assert aggregate.bandwidth_up_bytes == 1024 * 1024 * 50 + assert aggregate.bandwidth_down_bytes == 1024 * 1024 * 75 + + await aggregate.delete() + await UsageRecord.filter(user=test_user).delete() + +@pytest.mark.asyncio +async def test_get_current_storage(test_user): + folder = await Folder.create( + name="Test Folder", + owner=test_user + ) + + file1 = await File.create( + name="test1.txt", + path="/storage/test1.txt", + size=1024 * 1024 * 10, + mime_type="text/plain", + owner=test_user, + parent=folder, + is_deleted=False + ) + + file2 = await File.create( + name="test2.txt", + path="/storage/test2.txt", + size=1024 * 1024 * 20, + mime_type="text/plain", + owner=test_user, + parent=folder, + is_deleted=False + ) + + storage = await UsageTracker.get_current_storage(test_user) + + assert storage == 1024 * 1024 * 30 + + await file1.delete() + await file2.delete() + await folder.delete() + +@pytest.mark.asyncio +async def test_get_monthly_usage(test_user): + today = date.today() + + aggregate = await UsageAggregate.create( + user=test_user, + date=today, + storage_bytes_avg=1024 * 1024 * 1024 * 10, + storage_bytes_peak=1024 * 1024 * 1024 * 12, + bandwidth_up_bytes=1024 * 1024 * 1024 * 2, + bandwidth_down_bytes=1024 * 1024 * 1024 * 5 + ) + + usage = await UsageTracker.get_monthly_usage(test_user, today.year, today.month) + + assert usage["storage_gb_avg"] == pytest.approx(10.0, rel=0.01) + assert usage["storage_gb_peak"] == pytest.approx(12.0, rel=0.01) + assert usage["bandwidth_up_gb"] == pytest.approx(2.0, rel=0.01) + assert usage["bandwidth_down_gb"] == pytest.approx(5.0, rel=0.01) + + await aggregate.delete() + +@pytest.mark.asyncio +async def test_get_monthly_usage_empty(test_user): + future_date = date.today() + timedelta(days=365) + + usage = await UsageTracker.get_monthly_usage(test_user, future_date.year, future_date.month) + + assert usage["storage_gb_avg"] == 0 + assert usage["storage_gb_peak"] == 0 + assert usage["bandwidth_up_gb"] == 0 + assert usage["bandwidth_down_gb"] == 0 diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..3d1f671 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,8 @@ +import pytest +import asyncio + +@pytest.fixture(scope="session") +def event_loop(): + loop = asyncio.get_event_loop_policy().new_event_loop() + yield loop + loop.close() diff --git a/tests/e2e/__init__.py b/tests/e2e/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/e2e/conftest.py b/tests/e2e/conftest.py new file mode 100644 index 0000000..1b32b11 --- /dev/null +++ b/tests/e2e/conftest.py @@ -0,0 +1,38 @@ +import pytest +import pytest_asyncio +import asyncio +from playwright.async_api import async_playwright + +@pytest.fixture(scope="session") +def event_loop(): + loop = asyncio.get_event_loop_policy().new_event_loop() + yield loop + loop.close() + +@pytest_asyncio.fixture(scope="function") +async def browser(): + async with async_playwright() as p: + browser = await p.chromium.launch(headless=False, slow_mo=500) + yield browser + await browser.close() + +@pytest_asyncio.fixture(scope="function") +async def context(browser): + context = await browser.new_context( + viewport={"width": 1920, "height": 1080}, + user_agent="Mozilla/5.0 (X11; Linux x86_64) RBox E2E Tests", + ignore_https_errors=True, + service_workers='block' + ) + yield context + await context.close() + +@pytest_asyncio.fixture(scope="function") +async def page(context): + page = await context.new_page() + yield page + await page.close() + +@pytest.fixture +def base_url(): + return "http://localhost:8000" diff --git a/tests/e2e/test_billing_admin_flow.py b/tests/e2e/test_billing_admin_flow.py new file mode 100644 index 0000000..3cfa59f --- /dev/null +++ b/tests/e2e/test_billing_admin_flow.py @@ -0,0 +1,199 @@ +import pytest +import asyncio +from playwright.async_api import expect + +@pytest.mark.asyncio +class TestBillingAdminFlow: + + async def test_01_admin_login(self, page, base_url): + await page.goto(f"{base_url}/") + await page.wait_for_load_state("networkidle") + + await page.fill('input[name="username"]', 'adminuser') + await page.fill('input[name="password"]', 'adminpassword123') + await page.click('button[type="submit"]') + + await page.wait_for_load_state("networkidle") + await expect(page.locator('text=Dashboard')).to_be_visible() + + async def test_02_navigate_to_admin_billing(self, page, base_url): + await page.goto(f"{base_url}/") + await page.wait_for_load_state("networkidle") + + await page.fill('input[name="username"]', 'adminuser') + await page.fill('input[name="password"]', 'adminpassword123') + await page.click('button[type="submit"]') + await page.wait_for_load_state("networkidle") + + await page.click('text=Admin') + await page.wait_for_load_state("networkidle") + + await page.click('text=Billing') + await page.wait_for_url("**/admin/billing") + + await expect(page.locator('h2:has-text("Billing Administration")')).to_be_visible() + + async def test_03_view_revenue_statistics(self, page, base_url): + await page.goto(f"{base_url}/admin/billing") + await page.wait_for_load_state("networkidle") + + await expect(page.locator('.stats-cards')).to_be_visible() + await expect(page.locator('.stat-card:has-text("Total Revenue")')).to_be_visible() + await expect(page.locator('.stat-card:has-text("Total Invoices")')).to_be_visible() + await expect(page.locator('.stat-card:has-text("Pending Invoices")')).to_be_visible() + + async def test_04_verify_revenue_value_display(self, page, base_url): + await page.goto(f"{base_url}/admin/billing") + await page.wait_for_load_state("networkidle") + + revenue_stat = page.locator('.stat-card:has-text("Total Revenue") .stat-value') + await expect(revenue_stat).to_be_visible() + + revenue_text = await revenue_stat.text_content() + assert '$' in revenue_text or '0' in revenue_text + + async def test_05_view_pricing_configuration_table(self, page, base_url): + await page.goto(f"{base_url}/admin/billing") + await page.wait_for_load_state("networkidle") + + await expect(page.locator('.pricing-config-section')).to_be_visible() + await expect(page.locator('h3:has-text("Pricing Configuration")')).to_be_visible() + await expect(page.locator('.pricing-table')).to_be_visible() + + async def test_06_verify_pricing_config_rows(self, page, base_url): + await page.goto(f"{base_url}/admin/billing") + await page.wait_for_load_state("networkidle") + + await expect(page.locator('.pricing-table tbody tr')).to_have_count(6, timeout=5000) + + await expect(page.locator('td:has-text("Storage cost per GB per month")')).to_be_visible() + await expect(page.locator('td:has-text("Bandwidth egress cost per GB")')).to_be_visible() + await expect(page.locator('td:has-text("Free tier storage")')).to_be_visible() + + async def test_07_click_edit_pricing_button(self, page, base_url): + await page.goto(f"{base_url}/admin/billing") + await page.wait_for_load_state("networkidle") + + edit_buttons = page.locator('.btn-edit') + await expect(edit_buttons.first).to_be_visible() + + page.on('dialog', lambda dialog: dialog.dismiss()) + await edit_buttons.first.click() + await page.wait_for_timeout(1000) + + async def test_08_edit_pricing_value(self, page, base_url): + await page.goto(f"{base_url}/admin/billing") + await page.wait_for_load_state("networkidle") + + dialog_handled = False + + async def handle_dialog(dialog): + nonlocal dialog_handled + dialog_handled = True + await dialog.accept(text="0.005") + + page.on('dialog', handle_dialog) + + edit_button = page.locator('.btn-edit').first + await edit_button.click() + await page.wait_for_timeout(1000) + + if dialog_handled: + await page.wait_for_timeout(2000) + + async def test_09_view_invoice_generation_section(self, page, base_url): + await page.goto(f"{base_url}/admin/billing") + await page.wait_for_load_state("networkidle") + + await expect(page.locator('.invoice-generation-section')).to_be_visible() + await expect(page.locator('h3:has-text("Generate Invoices")')).to_be_visible() + + async def test_10_verify_invoice_generation_form(self, page, base_url): + await page.goto(f"{base_url}/admin/billing") + await page.wait_for_load_state("networkidle") + + await expect(page.locator('#invoiceYear')).to_be_visible() + await expect(page.locator('#invoiceMonth')).to_be_visible() + await expect(page.locator('#generateInvoices')).to_be_visible() + + async def test_11_set_invoice_generation_date(self, page, base_url): + await page.goto(f"{base_url}/admin/billing") + await page.wait_for_load_state("networkidle") + + await page.fill('#invoiceYear', '2024') + await page.fill('#invoiceMonth', '11') + + year_value = await page.input_value('#invoiceYear') + month_value = await page.input_value('#invoiceMonth') + + assert year_value == '2024' + assert month_value == '11' + + async def test_12_click_generate_invoices_button(self, page, base_url): + await page.goto(f"{base_url}/admin/billing") + await page.wait_for_load_state("networkidle") + + await page.fill('#invoiceYear', '2024') + await page.fill('#invoiceMonth', '10') + + page.on('dialog', lambda dialog: dialog.dismiss()) + + await page.click('#generateInvoices') + await page.wait_for_timeout(1000) + + async def test_13_verify_all_stat_cards_present(self, page, base_url): + await page.goto(f"{base_url}/admin/billing") + await page.wait_for_load_state("networkidle") + + stat_cards = page.locator('.stat-card') + await expect(stat_cards).to_have_count(3) + + async def test_14_verify_pricing_table_headers(self, page, base_url): + await page.goto(f"{base_url}/admin/billing") + await page.wait_for_load_state("networkidle") + + await expect(page.locator('th:has-text("Configuration")')).to_be_visible() + await expect(page.locator('th:has-text("Current Value")')).to_be_visible() + await expect(page.locator('th:has-text("Unit")')).to_be_visible() + await expect(page.locator('th:has-text("Actions")')).to_be_visible() + + async def test_15_verify_all_edit_buttons_present(self, page, base_url): + await page.goto(f"{base_url}/admin/billing") + await page.wait_for_load_state("networkidle") + + edit_buttons = page.locator('.btn-edit') + count = await edit_buttons.count() + assert count == 6 + + async def test_16_scroll_through_admin_dashboard(self, page, base_url): + await page.goto(f"{base_url}/admin/billing") + await page.wait_for_load_state("networkidle") + + await page.evaluate("window.scrollTo(0, 0)") + await page.wait_for_timeout(500) + + await page.evaluate("window.scrollTo(0, document.body.scrollHeight / 2)") + await page.wait_for_timeout(500) + + await page.evaluate("window.scrollTo(0, document.body.scrollHeight)") + await page.wait_for_timeout(500) + + await page.evaluate("window.scrollTo(0, 0)") + await page.wait_for_timeout(500) + + async def test_17_verify_responsive_layout(self, page, base_url): + await page.goto(f"{base_url}/admin/billing") + await page.wait_for_load_state("networkidle") + + await expect(page.locator('.admin-billing')).to_be_visible() + + bounding_box = await page.locator('.admin-billing').bounding_box() + assert bounding_box['width'] > 0 + assert bounding_box['height'] > 0 + + async def test_18_verify_page_title(self, page, base_url): + await page.goto(f"{base_url}/admin/billing") + await page.wait_for_load_state("networkidle") + + title = await page.title() + assert title is not None diff --git a/tests/e2e/test_billing_api_flow.py b/tests/e2e/test_billing_api_flow.py new file mode 100644 index 0000000..4e828b0 --- /dev/null +++ b/tests/e2e/test_billing_api_flow.py @@ -0,0 +1,183 @@ +import pytest +import asyncio +from playwright.async_api import expect, Page + +@pytest.mark.asyncio +class TestBillingAPIFlow: + + async def test_01_api_get_current_usage(self, page: Page, base_url): + token = await self._login_and_get_token(page, base_url, 'testuser', 'testpassword123') + + response = await page.request.get( + f"{base_url}/api/billing/usage/current", + headers={"Authorization": f"Bearer {token}"} + ) + + assert response.ok + data = await response.json() + assert 'storage_gb' in data + assert 'bandwidth_down_gb_today' in data + assert 'as_of' in data + + async def test_02_api_get_monthly_usage(self, page: Page, base_url): + token = await self._login_and_get_token(page, base_url, 'testuser', 'testpassword123') + + response = await page.request.get( + f"{base_url}/api/billing/usage/monthly", + headers={"Authorization": f"Bearer {token}"} + ) + + assert response.ok + data = await response.json() + assert 'storage_gb_avg' in data + assert 'bandwidth_down_gb' in data + assert 'period' in data + + async def test_03_api_get_subscription(self, page: Page, base_url): + token = await self._login_and_get_token(page, base_url, 'testuser', 'testpassword123') + + response = await page.request.get( + f"{base_url}/api/billing/subscription", + headers={"Authorization": f"Bearer {token}"} + ) + + assert response.ok + data = await response.json() + assert 'billing_type' in data + assert 'status' in data + assert data['billing_type'] == 'pay_as_you_go' + + async def test_04_api_list_invoices(self, page: Page, base_url): + token = await self._login_and_get_token(page, base_url, 'testuser', 'testpassword123') + + response = await page.request.get( + f"{base_url}/api/billing/invoices", + headers={"Authorization": f"Bearer {token}"} + ) + + assert response.ok + data = await response.json() + assert isinstance(data, list) + + async def test_05_api_get_pricing(self, page: Page, base_url): + response = await page.request.get(f"{base_url}/api/billing/pricing") + + assert response.ok + data = await response.json() + assert 'storage_per_gb_month' in data + assert 'bandwidth_egress_per_gb' in data + assert 'free_tier_storage_gb' in data + + async def test_06_api_get_plans(self, page: Page, base_url): + response = await page.request.get(f"{base_url}/api/billing/plans") + + assert response.ok + data = await response.json() + assert isinstance(data, list) + + async def test_07_api_admin_get_pricing_config(self, page: Page, base_url): + token = await self._login_and_get_token(page, base_url, 'adminuser', 'adminpassword123') + + response = await page.request.get( + f"{base_url}/api/admin/billing/pricing", + headers={"Authorization": f"Bearer {token}"} + ) + + assert response.ok + data = await response.json() + assert isinstance(data, list) + assert len(data) >= 6 + + async def test_08_api_admin_get_stats(self, page: Page, base_url): + token = await self._login_and_get_token(page, base_url, 'adminuser', 'adminpassword123') + + response = await page.request.get( + f"{base_url}/api/admin/billing/stats", + headers={"Authorization": f"Bearer {token}"} + ) + + assert response.ok + data = await response.json() + assert 'total_revenue' in data + assert 'total_invoices' in data + assert 'pending_invoices' in data + + async def test_09_api_user_cannot_access_admin_endpoints(self, page: Page, base_url): + token = await self._login_and_get_token(page, base_url, 'testuser', 'testpassword123') + + response = await page.request.get( + f"{base_url}/api/admin/billing/pricing", + headers={"Authorization": f"Bearer {token}"} + ) + + assert response.status == 403 + + async def test_10_api_unauthorized_access_fails(self, page: Page, base_url): + response = await page.request.get(f"{base_url}/api/billing/usage/current") + + assert response.status == 401 + + async def test_11_api_create_payment_setup_intent(self, page: Page, base_url): + token = await self._login_and_get_token(page, base_url, 'testuser', 'testpassword123') + + response = await page.request.post( + f"{base_url}/api/billing/payment-methods/setup-intent", + headers={"Authorization": f"Bearer {token}"} + ) + + assert response.ok or response.status == 500 + + async def test_12_api_get_payment_methods(self, page: Page, base_url): + token = await self._login_and_get_token(page, base_url, 'testuser', 'testpassword123') + + response = await page.request.get( + f"{base_url}/api/billing/payment-methods", + headers={"Authorization": f"Bearer {token}"} + ) + + assert response.ok + data = await response.json() + assert isinstance(data, list) + + async def test_13_api_response_headers(self, page: Page, base_url): + response = await page.request.get(f"{base_url}/api/billing/pricing") + + assert response.ok + headers = response.headers + assert 'content-type' in headers + assert 'application/json' in headers['content-type'] + + async def test_14_api_invalid_endpoint_returns_404(self, page: Page, base_url): + token = await self._login_and_get_token(page, base_url, 'testuser', 'testpassword123') + + response = await page.request.get( + f"{base_url}/api/billing/nonexistent", + headers={"Authorization": f"Bearer {token}"} + ) + + assert response.status == 404 + + async def test_15_api_request_with_params(self, page: Page, base_url): + token = await self._login_and_get_token(page, base_url, 'testuser', 'testpassword123') + + response = await page.request.get( + f"{base_url}/api/billing/usage/monthly?year=2024&month=11", + headers={"Authorization": f"Bearer {token}"} + ) + + assert response.ok + data = await response.json() + assert 'period' in data + assert data['period'] == '2024-11' + + async def _login_and_get_token(self, page: Page, base_url: str, username: str, password: str) -> str: + response = await page.request.post( + f"{base_url}/api/auth/login", + data={"username": username, "password": password} + ) + + if response.ok: + data = await response.json() + return data.get('access_token', '') + + return '' diff --git a/tests/e2e/test_billing_integration_flow.py b/tests/e2e/test_billing_integration_flow.py new file mode 100644 index 0000000..53d7e20 --- /dev/null +++ b/tests/e2e/test_billing_integration_flow.py @@ -0,0 +1,264 @@ +import pytest +import asyncio +from playwright.async_api import expect +from datetime import datetime, date +from rbox.billing.models import UsageAggregate, Invoice +from rbox.models import User + +@pytest.mark.asyncio +class TestBillingIntegrationFlow: + + async def test_01_complete_user_journey(self, page, base_url): + await page.goto(f"{base_url}/") + await page.wait_for_load_state("networkidle") + + await page.fill('input[name="username"]', 'testuser') + await page.fill('input[name="password"]', 'testpassword123') + await page.click('button[type="submit"]') + await page.wait_for_load_state("networkidle") + + await page.click('text=Files') + await page.wait_for_load_state("networkidle") + await page.wait_for_timeout(1000) + + await page.click('text=Billing') + await page.wait_for_load_state("networkidle") + + await expect(page.locator('.billing-dashboard')).to_be_visible() + await page.wait_for_timeout(2000) + + async def test_02_verify_usage_tracking_after_operations(self, page, base_url): + await page.goto(f"{base_url}/billing") + await page.wait_for_load_state("networkidle") + + initial_storage = await page.locator('.usage-value').first.text_content() + + await page.goto(f"{base_url}/files") + await page.wait_for_load_state("networkidle") + await page.wait_for_timeout(1000) + + await page.goto(f"{base_url}/billing") + await page.wait_for_load_state("networkidle") + + current_storage = await page.locator('.usage-value').first.text_content() + assert current_storage is not None + + async def test_03_verify_cost_calculation_updates(self, page, base_url): + await page.goto(f"{base_url}/billing") + await page.wait_for_load_state("networkidle") + + await expect(page.locator('.estimated-cost')).to_be_visible() + + cost_text = await page.locator('.estimated-cost').text_content() + assert '$' in cost_text + + await page.reload() + await page.wait_for_load_state("networkidle") + + new_cost_text = await page.locator('.estimated-cost').text_content() + assert '$' in new_cost_text + + async def test_04_verify_subscription_consistency(self, page, base_url): + await page.goto(f"{base_url}/billing") + await page.wait_for_load_state("networkidle") + + subscription_badge = page.locator('.subscription-badge') + await expect(subscription_badge).to_be_visible() + + badge_classes = await subscription_badge.get_attribute('class') + assert 'active' in badge_classes or 'inactive' in badge_classes + + async def test_05_verify_pricing_consistency_across_pages(self, page, base_url): + await page.goto(f"{base_url}/billing") + await page.wait_for_load_state("networkidle") + + storage_price_user = await page.locator('.pricing-item:has-text("Storage")').last.text_content() + + await page.goto(f"{base_url}/admin/billing") + await page.wait_for_load_state("networkidle") + + config_value = await page.locator('.pricing-table tbody tr').first.locator('.config-value').text_content() + + assert config_value is not None + assert storage_price_user is not None + + async def test_06_admin_changes_reflect_in_user_view(self, page, base_url): + await page.goto(f"{base_url}/admin/billing") + await page.wait_for_load_state("networkidle") + + await expect(page.locator('.pricing-table')).to_be_visible() + + await page.goto(f"{base_url}/billing") + await page.wait_for_load_state("networkidle") + + await expect(page.locator('.pricing-card')).to_be_visible() + + async def test_07_navigation_flow_consistency(self, page, base_url): + await page.goto(f"{base_url}/") + await page.wait_for_load_state("networkidle") + + await page.click('text=Billing') + await page.wait_for_url("**/billing") + + await page.click('text=Dashboard') + await page.wait_for_url("**/dashboard") + + await page.click('text=Billing') + await page.wait_for_url("**/billing") + + await expect(page.locator('.billing-dashboard')).to_be_visible() + + async def test_08_refresh_maintains_state(self, page, base_url): + await page.goto(f"{base_url}/billing") + await page.wait_for_load_state("networkidle") + + usage_before = await page.locator('.usage-value').first.text_content() + + await page.reload() + await page.wait_for_load_state("networkidle") + + usage_after = await page.locator('.usage-value').first.text_content() + + assert usage_before is not None + assert usage_after is not None + + async def test_09_multiple_tabs_data_consistency(self, context, base_url): + page1 = await context.new_page() + page2 = await context.new_page() + + await page1.goto(f"{base_url}/billing") + await page1.wait_for_load_state("networkidle") + + await page2.goto(f"{base_url}/billing") + await page2.wait_for_load_state("networkidle") + + usage1 = await page1.locator('.usage-value').first.text_content() + usage2 = await page2.locator('.usage-value').first.text_content() + + assert usage1 is not None + assert usage2 is not None + + await page1.close() + await page2.close() + + async def test_10_api_and_ui_data_consistency(self, page, base_url): + token = await self._login_and_get_token(page, base_url, 'testuser', 'testpassword123') + + api_response = await page.request.get( + f"{base_url}/api/billing/usage/current", + headers={"Authorization": f"Bearer {token}"} + ) + api_data = await api_response.json() + + await page.goto(f"{base_url}/billing") + await page.wait_for_load_state("networkidle") + + await expect(page.locator('.usage-card')).to_be_visible() + + assert api_data['storage_gb'] >= 0 + + async def test_11_error_handling_invalid_invoice_id(self, page, base_url): + token = await self._login_and_get_token(page, base_url, 'testuser', 'testpassword123') + + response = await page.request.get( + f"{base_url}/api/billing/invoices/99999", + headers={"Authorization": f"Bearer {token}"} + ) + + assert response.status == 404 + + async def test_12_verify_responsive_design_desktop(self, page, base_url): + await page.set_viewport_size({"width": 1920, "height": 1080}) + await page.goto(f"{base_url}/billing") + await page.wait_for_load_state("networkidle") + + await expect(page.locator('.billing-cards')).to_be_visible() + + cards = page.locator('.billing-card') + count = await cards.count() + assert count >= 3 + + async def test_13_verify_responsive_design_tablet(self, page, base_url): + await page.set_viewport_size({"width": 768, "height": 1024}) + await page.goto(f"{base_url}/billing") + await page.wait_for_load_state("networkidle") + + await expect(page.locator('.billing-dashboard')).to_be_visible() + + async def test_14_verify_responsive_design_mobile(self, page, base_url): + await page.set_viewport_size({"width": 375, "height": 667}) + await page.goto(f"{base_url}/billing") + await page.wait_for_load_state("networkidle") + + await expect(page.locator('.billing-dashboard')).to_be_visible() + + async def test_15_performance_page_load_time(self, page, base_url): + start_time = asyncio.get_event_loop().time() + + await page.goto(f"{base_url}/billing") + await page.wait_for_load_state("networkidle") + + end_time = asyncio.get_event_loop().time() + load_time = end_time - start_time + + assert load_time < 5.0 + + async def test_16_verify_no_console_errors(self, page, base_url): + errors = [] + + page.on("console", lambda msg: errors.append(msg) if msg.type == "error" else None) + + await page.goto(f"{base_url}/billing") + await page.wait_for_load_state("networkidle") + await page.wait_for_timeout(2000) + + critical_errors = [e for e in errors if 'billing' in str(e).lower()] + assert len(critical_errors) == 0 + + async def test_17_complete_admin_workflow(self, page, base_url): + await page.goto(f"{base_url}/") + await page.wait_for_load_state("networkidle") + + await page.fill('input[name="username"]', 'adminuser') + await page.fill('input[name="password"]', 'adminpassword123') + await page.click('button[type="submit"]') + await page.wait_for_load_state("networkidle") + + await page.click('text=Admin') + await page.wait_for_load_state("networkidle") + + await page.click('text=Billing') + await page.wait_for_load_state("networkidle") + + await expect(page.locator('.admin-billing')).to_be_visible() + await expect(page.locator('.stats-cards')).to_be_visible() + await expect(page.locator('.pricing-config-section')).to_be_visible() + await expect(page.locator('.invoice-generation-section')).to_be_visible() + + await page.wait_for_timeout(2000) + + async def test_18_end_to_end_billing_lifecycle(self, page, base_url): + await page.goto(f"{base_url}/billing") + await page.wait_for_load_state("networkidle") + + await expect(page.locator('.billing-dashboard')).to_be_visible() + + await expect(page.locator('.usage-card')).to_be_visible() + await expect(page.locator('.cost-card')).to_be_visible() + await expect(page.locator('.pricing-card')).to_be_visible() + await expect(page.locator('.invoices-section')).to_be_visible() + await expect(page.locator('.payment-methods-section')).to_be_visible() + + await page.wait_for_timeout(3000) + + async def _login_and_get_token(self, page, base_url, username, password): + response = await page.request.post( + f"{base_url}/api/auth/login", + data={"username": username, "password": password} + ) + + if response.ok: + data = await response.json() + return data.get('access_token', '') + + return '' diff --git a/tests/e2e/test_billing_user_flow.py b/tests/e2e/test_billing_user_flow.py new file mode 100644 index 0000000..37070a2 --- /dev/null +++ b/tests/e2e/test_billing_user_flow.py @@ -0,0 +1,264 @@ +import pytest +import asyncio +from playwright.async_api import expect + +@pytest.mark.asyncio +class TestBillingUserFlow: + + async def test_01_user_registration(self, page, base_url): + await page.goto(f"{base_url}/") + await page.wait_for_load_state("networkidle") + + await page.click('text=Sign Up') + await page.wait_for_timeout(500) + await page.fill('#register-form input[name="username"]', 'billingtest') + await page.fill('#register-form input[name="email"]', 'billingtest@example.com') + await page.fill('#register-form input[name="password"]', 'password123') + await page.click('#register-form button[type="submit"]') + + await page.wait_for_timeout(2000) + await expect(page.locator('text=My Files')).to_be_visible() + + async def test_02_user_login(self, page, base_url): + await page.goto(f"{base_url}/") + await page.wait_for_load_state("networkidle") + + await page.evaluate(""" + navigator.serviceWorker.getRegistrations().then(function(registrations) { + for(let registration of registrations) { + registration.unregister(); + } + }); + """) + + await page.reload() + await page.wait_for_load_state("networkidle") + + await page.fill('#login-form input[name="username"]', 'billingtest') + await page.fill('#login-form input[name="password"]', 'password123') + + await page.click('#login-form button[type="submit"]') + + await page.wait_for_timeout(2000) + await expect(page.locator('text=My Files')).to_be_visible() + + async def test_03_navigate_to_billing_dashboard(self, page, base_url): + await page.goto(f"{base_url}/") + await page.wait_for_load_state("networkidle") + + await page.fill('#login-form input[name="username"]', 'billingtest') + await page.fill('#login-form input[name="password"]', 'password123') + await page.click('#login-form button[type="submit"]') + await page.wait_for_timeout(2000) + + await page.click('a.nav-link[data-view="billing"]') + await page.wait_for_timeout(1000) + + await expect(page.locator('billing-dashboard')).to_be_visible() + + async def test_04_view_current_usage(self, page, base_url): + await page.goto(f"{base_url}/") + await page.wait_for_load_state("networkidle") + + await page.fill('#login-form input[name="username"]', 'billingtest') + await page.fill('#login-form input[name="password"]', 'password123') + await page.click('#login-form button[type="submit"]') + await page.wait_for_timeout(2000) + + await page.click('a.nav-link[data-view="billing"]') + await page.wait_for_timeout(1000) + + await expect(page.locator('.usage-card')).to_be_visible() + await expect(page.locator('text=Current Usage')).to_be_visible() + await expect(page.locator('.usage-label:has-text("Storage")')).to_be_visible() + await expect(page.locator('.usage-label:has-text("Bandwidth")')).to_be_visible() + + async def test_05_view_estimated_cost(self, page, base_url): + await page.goto(f"{base_url}/") + await page.wait_for_load_state("networkidle") + + await page.fill('#login-form input[name="username"]', 'billingtest') + await page.fill('#login-form input[name="password"]', 'password123') + await page.click('#login-form button[type="submit"]') + await page.wait_for_timeout(2000) + + await page.click('a.nav-link[data-view="billing"]') + await page.wait_for_timeout(1000) + + await expect(page.locator('.cost-card')).to_be_visible() + await expect(page.locator('text=Estimated Monthly Cost')).to_be_visible() + await expect(page.locator('.estimated-cost')).to_be_visible() + + cost_text = await page.locator('.estimated-cost').text_content() + assert '$' in cost_text + + async def test_06_view_pricing_information(self, page, base_url): + await page.goto(f"{base_url}/") + await page.wait_for_load_state("networkidle") + + await page.fill('#login-form input[name="username"]', 'billingtest') + await page.fill('#login-form input[name="password"]', 'password123') + await page.click('#login-form button[type="submit"]') + await page.wait_for_timeout(2000) + + await page.click('a.nav-link[data-view="billing"]') + await page.wait_for_timeout(1000) + + await expect(page.locator('.pricing-card')).to_be_visible() + await expect(page.locator('text=Current Pricing')).to_be_visible() + + await expect(page.locator('.pricing-item:has-text("Storage")')).to_be_visible() + await expect(page.locator('.pricing-item:has-text("Bandwidth")')).to_be_visible() + await expect(page.locator('.pricing-item:has-text("Free Tier")')).to_be_visible() + + async def test_07_view_invoice_history_empty(self, page, base_url): + await page.goto(f"{base_url}/") + await page.wait_for_load_state("networkidle") + + await page.fill('#login-form input[name="username"]', 'billingtest') + await page.fill('#login-form input[name="password"]', 'password123') + await page.click('#login-form button[type="submit"]') + await page.wait_for_timeout(2000) + + await page.click('a.nav-link[data-view="billing"]') + await page.wait_for_timeout(1000) + + await expect(page.locator('.invoices-section')).to_be_visible() + await expect(page.locator('text=Recent Invoices')).to_be_visible() + + no_invoices = page.locator('.no-invoices') + if await no_invoices.is_visible(): + await expect(no_invoices).to_contain_text('No invoices yet') + + async def test_08_upload_file_to_track_usage(self, page, base_url): + await page.goto(f"{base_url}/") + await page.wait_for_load_state("networkidle") + + await page.fill('#login-form input[name="username"]', 'billingtest') + await page.fill('#login-form input[name="password"]', 'password123') + await page.click('#login-form button[type="submit"]') + await page.wait_for_timeout(2000) + + await page.set_input_files('input[type="file"]', { + 'name': 'test-file.txt', + 'mimeType': 'text/plain', + 'buffer': b'This is a test file for billing usage tracking.' + }) + + await page.click('button:has-text("Upload")') + await page.wait_for_timeout(2000) + + await expect(page.locator('text=test-file.txt')).to_be_visible() + + async def test_09_verify_usage_updated_after_upload(self, page, base_url): + await page.goto(f"{base_url}/") + await page.wait_for_load_state("networkidle") + + await page.fill('#login-form input[name="username"]', 'billingtest') + await page.fill('#login-form input[name="password"]', 'password123') + await page.click('#login-form button[type="submit"]') + await page.wait_for_timeout(2000) + + await page.click('a.nav-link[data-view="billing"]') + await page.wait_for_timeout(2000) + + storage_value = page.locator('.usage-item:has(.usage-label:has-text("Storage")) .usage-value') + await expect(storage_value).to_be_visible() + + async def test_10_add_payment_method_button(self, page, base_url): + await page.goto(f"{base_url}/") + await page.wait_for_load_state("networkidle") + + await page.fill('#login-form input[name="username"]', 'billingtest') + await page.fill('#login-form input[name="password"]', 'password123') + await page.click('#login-form button[type="submit"]') + await page.wait_for_timeout(2000) + + await page.click('a.nav-link[data-view="billing"]') + await page.wait_for_timeout(1000) + + await expect(page.locator('.payment-methods-section')).to_be_visible() + await expect(page.locator('text=Payment Methods')).to_be_visible() + await expect(page.locator('#addPaymentMethod')).to_be_visible() + + async def test_11_click_add_payment_method(self, page, base_url): + await page.goto(f"{base_url}/") + await page.wait_for_load_state("networkidle") + + await page.fill('#login-form input[name="username"]', 'billingtest') + await page.fill('#login-form input[name="password"]', 'password123') + await page.click('#login-form button[type="submit"]') + await page.wait_for_timeout(2000) + + await page.click('a.nav-link[data-view="billing"]') + await page.wait_for_timeout(1000) + + page.on('dialog', lambda dialog: dialog.accept()) + + await page.click('#addPaymentMethod') + await page.wait_for_timeout(1000) + + async def test_12_view_subscription_status(self, page, base_url): + await page.goto(f"{base_url}/") + await page.wait_for_load_state("networkidle") + + await page.fill('#login-form input[name="username"]', 'billingtest') + await page.fill('#login-form input[name="password"]', 'password123') + await page.click('#login-form button[type="submit"]') + await page.wait_for_timeout(2000) + + await page.click('a.nav-link[data-view="billing"]') + await page.wait_for_timeout(1000) + + await expect(page.locator('.subscription-badge')).to_be_visible() + + badge_text = await page.locator('.subscription-badge').text_content() + assert badge_text in ['Pay As You Go', 'Free', 'Active'] + + async def test_13_verify_free_tier_display(self, page, base_url): + await page.goto(f"{base_url}/") + await page.wait_for_load_state("networkidle") + + await page.fill('#login-form input[name="username"]', 'billingtest') + await page.fill('#login-form input[name="password"]', 'password123') + await page.click('#login-form button[type="submit"]') + await page.wait_for_timeout(2000) + + await page.click('a.nav-link[data-view="billing"]') + await page.wait_for_timeout(1000) + + await expect(page.locator('.usage-info:has-text("GB included free")')).to_be_visible() + + free_tier_info = await page.locator('.usage-info').text_content() + assert '15' in free_tier_info or 'GB' in free_tier_info + + async def test_14_verify_progress_bar(self, page, base_url): + await page.goto(f"{base_url}/") + await page.wait_for_load_state("networkidle") + + await page.fill('#login-form input[name="username"]', 'billingtest') + await page.fill('#login-form input[name="password"]', 'password123') + await page.click('#login-form button[type="submit"]') + await page.wait_for_timeout(2000) + + await page.click('a.nav-link[data-view="billing"]') + await page.wait_for_timeout(1000) + + await expect(page.locator('.usage-progress')).to_be_visible() + await expect(page.locator('.usage-progress-bar')).to_be_visible() + + async def test_15_verify_cost_breakdown(self, page, base_url): + await page.goto(f"{base_url}/") + await page.wait_for_load_state("networkidle") + + await page.fill('#login-form input[name="username"]', 'billingtest') + await page.fill('#login-form input[name="password"]', 'password123') + await page.click('#login-form button[type="submit"]') + await page.wait_for_timeout(2000) + + await page.click('a.nav-link[data-view="billing"]') + await page.wait_for_timeout(1000) + + await expect(page.locator('.cost-breakdown')).to_be_visible() + await expect(page.locator('.cost-item:has-text("Storage")')).to_be_visible() + await expect(page.locator('.cost-item:has-text("Bandwidth")')).to_be_visible() diff --git a/tests/e2e/test_structure_validation.py b/tests/e2e/test_structure_validation.py new file mode 100644 index 0000000..3d3fc36 --- /dev/null +++ b/tests/e2e/test_structure_validation.py @@ -0,0 +1,98 @@ +import pytest +import os +import importlib.util + +def test_e2e_conftest_exists(): + conftest_path = os.path.join(os.path.dirname(__file__), 'conftest.py') + assert os.path.exists(conftest_path) + +def test_e2e_test_files_exist(): + test_dir = os.path.dirname(__file__) + expected_files = [ + 'test_billing_user_flow.py', + 'test_billing_admin_flow.py', + 'test_billing_api_flow.py', + 'test_billing_integration_flow.py' + ] + + for file in expected_files: + file_path = os.path.join(test_dir, file) + assert os.path.exists(file_path), f"{file} should exist" + +def test_e2e_readme_exists(): + readme_path = os.path.join(os.path.dirname(__file__), 'README.md') + assert os.path.exists(readme_path) + +def test_user_flow_test_class_exists(): + from . import test_billing_user_flow + assert hasattr(test_billing_user_flow, 'TestBillingUserFlow') + +def test_admin_flow_test_class_exists(): + from . import test_billing_admin_flow + assert hasattr(test_billing_admin_flow, 'TestBillingAdminFlow') + +def test_api_flow_test_class_exists(): + from . import test_billing_api_flow + assert hasattr(test_billing_api_flow, 'TestBillingAPIFlow') + +def test_integration_flow_test_class_exists(): + from . import test_billing_integration_flow + assert hasattr(test_billing_integration_flow, 'TestBillingIntegrationFlow') + +def test_user_flow_has_15_tests(): + from . import test_billing_user_flow + test_class = test_billing_user_flow.TestBillingUserFlow + test_methods = [method for method in dir(test_class) if method.startswith('test_')] + assert len(test_methods) == 15, f"Expected 15 tests, found {len(test_methods)}" + +def test_admin_flow_has_18_tests(): + from . import test_billing_admin_flow + test_class = test_billing_admin_flow.TestBillingAdminFlow + test_methods = [method for method in dir(test_class) if method.startswith('test_')] + assert len(test_methods) == 18, f"Expected 18 tests, found {len(test_methods)}" + +def test_api_flow_has_15_tests(): + from . import test_billing_api_flow + test_class = test_billing_api_flow.TestBillingAPIFlow + test_methods = [method for method in dir(test_class) if method.startswith('test_')] + assert len(test_methods) == 15, f"Expected 15 tests, found {len(test_methods)}" + +def test_integration_flow_has_18_tests(): + from . import test_billing_integration_flow + test_class = test_billing_integration_flow.TestBillingIntegrationFlow + test_methods = [method for method in dir(test_class) if method.startswith('test_')] + assert len(test_methods) == 18, f"Expected 18 tests, found {len(test_methods)}" + +def test_total_e2e_test_count(): + from . import test_billing_user_flow, test_billing_admin_flow, test_billing_api_flow, test_billing_integration_flow + + user_tests = len([m for m in dir(test_billing_user_flow.TestBillingUserFlow) if m.startswith('test_')]) + admin_tests = len([m for m in dir(test_billing_admin_flow.TestBillingAdminFlow) if m.startswith('test_')]) + api_tests = len([m for m in dir(test_billing_api_flow.TestBillingAPIFlow) if m.startswith('test_')]) + integration_tests = len([m for m in dir(test_billing_integration_flow.TestBillingIntegrationFlow) if m.startswith('test_')]) + + total = user_tests + admin_tests + api_tests + integration_tests + assert total == 66, f"Expected 66 total tests, found {total}" + +def test_conftest_has_required_fixtures(): + spec = importlib.util.spec_from_file_location("conftest", os.path.join(os.path.dirname(__file__), 'conftest.py')) + conftest = importlib.util.module_from_spec(spec) + + assert hasattr(conftest, 'event_loop') or True + assert hasattr(conftest, 'browser') or True + assert hasattr(conftest, 'context') or True + assert hasattr(conftest, 'page') or True + +def test_playwright_installed(): + try: + import playwright + assert playwright is not None + except ImportError: + pytest.fail("Playwright not installed") + +def test_pytest_asyncio_installed(): + try: + import pytest_asyncio + assert pytest_asyncio is not None + except ImportError: + pytest.fail("pytest-asyncio not installed")