diff --git a/retoors/helpers/env_manager.py b/retoors/helpers/env_manager.py index d860dcf..11cdc03 100644 --- a/retoors/helpers/env_manager.py +++ b/retoors/helpers/env_manager.py @@ -68,9 +68,9 @@ def get_or_create_session_secret_key(env_path: Path) -> bytes: if secret_key_str: try: - # Fernet expects bytes, so encode the string from env var + # Try to validate the key directly + Fernet(secret_key_str.encode('utf-8')) final_secret_key_bytes = secret_key_str.encode('utf-8') - Fernet(final_secret_key_bytes) # Validate the key print(f"Using existing valid {key_name} from environment.") except ValueError: print(f"Existing {key_name} in .env is invalid. Generating a new one.") @@ -83,7 +83,7 @@ def get_or_create_session_secret_key(env_path: Path) -> bytes: # Append to .env file with open(env_path, 'a') as f: - f.write(f'\n{key_name}={generated_key_str}\n') + f.write(f'\n{str(key_name)}={generated_key_str}\n') print(f"Generated and added {key_name} to {env_path}") diff --git a/retoors/main.py b/retoors/main.py index 91e0683..2f6c0ab 100644 --- a/retoors/main.py +++ b/retoors/main.py @@ -4,7 +4,6 @@ import jinja2 from pathlib import Path from aiohttp_session import setup as setup_session from aiohttp_session.cookie_storage import EncryptedCookieStorage -import os import aiojobs # Import aiojobs import dotenv # Import dotenv diff --git a/retoors/routes.py b/retoors/routes.py index 8de7a11..384747d 100644 --- a/retoors/routes.py +++ b/retoors/routes.py @@ -1,5 +1,5 @@ from .views.auth import LoginView, RegistrationView, LogoutView, ForgotPasswordView, ResetPasswordView -from .views.site import SiteView, OrderView +from .views.site import SiteView, OrderView, FileBrowserView from .views.admin import get_users, add_user, update_user_quota, delete_user, get_user_details, delete_team @@ -17,6 +17,13 @@ def setup_routes(app): app.router.add_view("/use_cases", SiteView, name="use_cases") app.router.add_view("/dashboard", SiteView, name="dashboard") app.router.add_view("/order", OrderView, name="order") + app.router.add_view("/terms", SiteView, name="terms") + app.router.add_view("/privacy", SiteView, name="privacy") + app.router.add_view("/shared", SiteView, name="shared") + app.router.add_view("/recent", SiteView, name="recent") + app.router.add_view("/favorites", SiteView, name="favorites") + app.router.add_view("/trash", SiteView, name="trash") + app.router.add_view("/files", FileBrowserView, name="file_browser") # Admin API routes for user and team management app.router.add_get("/api/users", get_users, name="api_get_users") diff --git a/retoors/static/css/components/file_browser.css b/retoors/static/css/components/file_browser.css new file mode 100644 index 0000000..7a17309 --- /dev/null +++ b/retoors/static/css/components/file_browser.css @@ -0,0 +1,50 @@ +/* retoors/static/css/components/file_browser.css */ + +.file-browser-section { + padding: 2rem; + max-width: 800px; + margin: 0 auto; + background-color: var(--color-background-light); + border-radius: var(--border-radius); + box-shadow: var(--shadow-elevation-low); +} + +.file-browser-section h1 { + color: var(--color-primary); + text-align: center; + margin-bottom: 1.5rem; +} + +.file-list ul { + list-style: none; + padding: 0; +} + +.file-list li { + background-color: var(--color-surface); + margin-bottom: 0.5rem; + padding: 0.8rem 1rem; + border-radius: var(--border-radius-small); + display: flex; + align-items: center; + justify-content: space-between; + border: 1px solid var(--color-border); +} + +.file-list li a { + color: var(--color-text); + text-decoration: none; + flex-grow: 1; + font-weight: var(--font-weight-medium); +} + +.file-list li a:hover { + color: var(--color-primary-dark); + text-decoration: underline; +} + +.file-list p { + text-align: center; + color: var(--color-text-secondary); + font-style: italic; +} diff --git a/retoors/static/js/components/order.js b/retoors/static/js/components/order.js index 4e98fb6..2829529 100644 --- a/retoors/static/js/components/order.js +++ b/retoors/static/js/components/order.js @@ -11,6 +11,12 @@ document.addEventListener('DOMContentLoaded', () => { const editQuotaMessage = document.getElementById('edit-quota-message'); const userDetailsContent = document.getElementById('user-details-content'); + // Main order form elements + const mainOrderForm = document.querySelector('.order-form'); + const customSlider = document.querySelector('custom-slider'); + const totalPriceSpan = document.getElementById('total_price'); + const pricePerGb = parseFloat(customSlider.dataset.pricePerGb); + // Function to open a modal function openModal(modal) { modal.style.display = 'block'; @@ -41,6 +47,19 @@ document.addEventListener('DOMContentLoaded', () => { } }); + // Function to update total price display + function updateTotalPrice() { + const storageAmount = parseFloat(customSlider.value); + const total = (storageAmount * pricePerGb).toFixed(2); + totalPriceSpan.textContent = `$${total}`; + } + + // Initial price update and event listener for slider + if (customSlider) { + updateTotalPrice(); // Set initial price + customSlider.addEventListener('input', updateTotalPrice); + } + // Fetch and render users async function fetchAndRenderUsers() { try { @@ -249,6 +268,47 @@ document.addEventListener('DOMContentLoaded', () => { } }); + // Main User Quota Update Form Submission + mainOrderForm.addEventListener('submit', async (event) => { + event.preventDefault(); // Prevent default form submission + + const storageAmount = parseFloat(customSlider.value); + if (isNaN(storageAmount) || storageAmount <= 0) { + alert('Please select a valid storage amount.'); + return; + } + + try { + // Assuming the current user's email can be retrieved or is available globally + // For now, we'll assume a placeholder 'current_user_email' + // In a real application, this would come from a session or a global JS variable + const currentUserEmail = '{{ user.email }}'; // This needs to be passed from the backend + + const response = await fetch(`/api/users/${currentUserEmail}/quota`, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ new_quota_gb: storageAmount }), + }); + + const data = await response.json(); + if (!response.ok) { + throw new Error(data.error || 'Failed to update main user quota.'); + } + + alert(data.message || 'Main user quota updated successfully!'); + // Re-fetch and render users to update the main user's quota display + fetchAndRenderUsers(); + // Optionally, update the main quota display directly if not covered by fetchAndRenderUsers + // For now, relying on fetchAndRenderUsers to update all quota displays + } catch (error) { + console.error('Error updating main user quota:', error); + alert(`Failed to update main user quota: ${error.message}`); + } + }); + + // Initial fetch and render fetchAndRenderUsers(); diff --git a/retoors/static/js/main.js b/retoors/static/js/main.js index 52b1c37..bf38425 100644 --- a/retoors/static/js/main.js +++ b/retoors/static/js/main.js @@ -1,11 +1,12 @@ import './components/slider.js'; +import './components/navigation.js'; // Assuming navigation.js might be needed globally document.addEventListener('DOMContentLoaded', () => { + // Logic for custom-slider on order page const slider = document.querySelector('custom-slider'); - const priceDisplay = document.getElementById('total_price'); // Corrected ID + const priceDisplay = document.getElementById('total_price'); if (slider && priceDisplay) { - // pricePerGb will be read from a data attribute on the slider const pricePerGb = parseFloat(slider.dataset.pricePerGb); const updatePrice = () => { @@ -14,10 +15,71 @@ document.addEventListener('DOMContentLoaded', () => { priceDisplay.textContent = `$${totalPrice}`; }; - // Initial price update updatePrice(); - - // Update price on slider change (using 'input' event for consistency with HTML) slider.addEventListener('input', updatePrice); } + + // Logic for pricing page toggle + const pricingToggle = document.querySelector('.pricing-toggle'); + if (pricingToggle) { + const monthlyBtn = pricingToggle.querySelector('[data-period="monthly"]'); + const annuallyBtn = pricingToggle.querySelector('[data-period="annually"]'); + const pricingCards = document.querySelectorAll('.pricing-card'); + + const monthlyPrices = { + "Free": 0, + "Personal": 9, + "Professional": 29, + "Business": 99 + }; + + const annualPrices = { + "Free": 0, + "Personal": 90, // 9 * 10 (assuming 2 months free) + "Professional": 290, // 29 * 10 + "Business": 990 // 99 * 10 + }; + + function updatePricingDisplay(period) { + pricingCards.forEach(card => { + const planName = card.querySelector('h3').textContent; + const priceElement = card.querySelector('.price'); + let price = 0; + let periodText = ''; + + if (period === 'monthly') { + price = monthlyPrices[planName]; + periodText = '/month'; + } else { + price = annualPrices[planName]; + periodText = '/year'; + } + + if (planName === "Free") { + priceElement.innerHTML = `$${price}${periodText}`; + } else if (planName === "Business") { + // Business plan might have custom pricing, keep it as is or adjust + priceElement.innerHTML = `$${price}${periodText}`; + } + else { + priceElement.innerHTML = `$${price}${periodText}`; + } + }); + } + + monthlyBtn.addEventListener('click', () => { + monthlyBtn.classList.add('active'); + annuallyBtn.classList.remove('active'); + updatePricingDisplay('monthly'); + }); + + annuallyBtn.addEventListener('click', () => { + annuallyBtn.classList.add('active'); + monthlyBtn.classList.remove('active'); + updatePricingDisplay('annually'); + }); + + // Initial display based on active button (default to monthly) + updatePricingDisplay('monthly'); + } }); \ No newline at end of file diff --git a/retoors/templates/components/navigation.html b/retoors/templates/components/navigation.html index 0a731c7..0076e5b 100644 --- a/retoors/templates/components/navigation.html +++ b/retoors/templates/components/navigation.html @@ -11,6 +11,7 @@
  • Support
  • {% if request['user'] %}
  • Dashboard
  • +
  • File Browser
  • Logout
  • {% else %}
  • Sign In
  • diff --git a/retoors/templates/pages/dashboard.html b/retoors/templates/pages/dashboard.html index d24e262..84105ef 100644 --- a/retoors/templates/pages/dashboard.html +++ b/retoors/templates/pages/dashboard.html @@ -12,10 +12,10 @@ @@ -53,11 +53,11 @@

    Welcome back, {{ user.full_name }}!

    - - - - - + + + + +
    diff --git a/retoors/templates/pages/favorites.html b/retoors/templates/pages/favorites.html new file mode 100644 index 0000000..0635894 --- /dev/null +++ b/retoors/templates/pages/favorites.html @@ -0,0 +1,15 @@ +{% extends "layouts/base.html" %} +{% block title %}Favorites - Retoor's Cloud Solutions{% endblock %} +{% block head %} + {{ super() }} + +{% endblock %} +{% block content %} +
    +
    +

    Favorites

    +

    Your favorite files and folders will appear here.

    +

    This feature is coming soon!

    +
    +
    +{% endblock %} \ No newline at end of file diff --git a/retoors/templates/pages/file_browser.html b/retoors/templates/pages/file_browser.html new file mode 100644 index 0000000..05e4b75 --- /dev/null +++ b/retoors/templates/pages/file_browser.html @@ -0,0 +1,24 @@ +{% extends "layouts/base.html" %} +{% block title %}File Browser{% endblock %} +{% block head %} + {{ super() }} + +{% endblock %} +{% block content %} +
    +
    +

    File Browser

    +
    + {% if files %} +
      + {% for file in files %} +
    • {{ file }}
    • + {% endfor %} +
    + {% else %} +

    No files found in the project directory.

    + {% endif %} +
    +
    +
    +{% endblock %} \ No newline at end of file diff --git a/retoors/templates/pages/login.html b/retoors/templates/pages/login.html index d6bee87..30d308b 100644 --- a/retoors/templates/pages/login.html +++ b/retoors/templates/pages/login.html @@ -31,7 +31,7 @@

    {{ errors.password }}

    {% endif %} - Forgot Password? + Forgot Password? diff --git a/retoors/templates/pages/pricing.html b/retoors/templates/pages/pricing.html index 4ae594a..68415e1 100644 --- a/retoors/templates/pages/pricing.html +++ b/retoors/templates/pages/pricing.html @@ -62,7 +62,7 @@
  • Dedicated Account Manager
  • Advanced Analytics
  • - Contact Sales + Contact Sales diff --git a/retoors/templates/pages/privacy.html b/retoors/templates/pages/privacy.html new file mode 100644 index 0000000..d6cbce0 --- /dev/null +++ b/retoors/templates/pages/privacy.html @@ -0,0 +1,55 @@ +{% extends "layouts/base.html" %} +{% block title %}Privacy Policy{% endblock %} +{% block head %} + {{ super() }} + +{% endblock %} +{% block content %} +
    +
    +

    Privacy Policy

    +

    This Privacy Policy describes how Retoor's Cloud Solutions collects, uses, and discloses your information when you use our service.

    +

    1. Information We Collect

    +

    Personal Data

    +

    While using our Service, we may ask you to provide us with certain personally identifiable information that can be used to contact or identify you. Personally identifiable information may include, but is not limited to: Email address, First name and last name, Phone number, Address, State, Province, ZIP/Postal code, City, Usage Data.

    +

    Usage Data

    +

    Usage Data is collected automatically when using the Service. Usage Data may include information such as your Device's Internet Protocol address (e.g. IP address), browser type, browser version, the pages of our Service that you visit, the time and date of your visit, the time spent on those pages, unique device identifiers and other diagnostic data.

    +

    2. How We Use Your Information

    +

    Retoor's Cloud Solutions uses the collected data for various purposes:

    + +

    3. Disclosure Of Your Information

    +

    We may disclose your Personal Data in the good faith belief that such action is necessary to:

    + +

    4. Security Of Your Information

    +

    The security of your data is important to us, but remember that no method of transmission over the Internet, or method of electronic storage is 100% secure. While we strive to use commercially acceptable means to protect your Personal Data, we cannot guarantee its absolute security.

    +

    5. Your Data Protection Rights

    +

    Depending on your location, you may have the following data protection rights:

    + +

    6. Changes to This Privacy Policy

    +

    We may update our Privacy Policy from time to time. We will notify you of any changes by posting the new Privacy Policy on this page.

    +

    7. Contact Us

    +

    If you have any questions about this Privacy Policy, please contact us.

    +
    +
    +{% endblock %} \ No newline at end of file diff --git a/retoors/templates/pages/recent.html b/retoors/templates/pages/recent.html new file mode 100644 index 0000000..2c717e3 --- /dev/null +++ b/retoors/templates/pages/recent.html @@ -0,0 +1,15 @@ +{% extends "layouts/base.html" %} +{% block title %}Recent Files - Retoor's Cloud Solutions{% endblock %} +{% block head %} + {{ super() }} + +{% endblock %} +{% block content %} +
    +
    +

    Recent Files

    +

    Your recently accessed files will appear here.

    +

    This feature is coming soon!

    +
    +
    +{% endblock %} \ No newline at end of file diff --git a/retoors/templates/pages/shared.html b/retoors/templates/pages/shared.html new file mode 100644 index 0000000..fa79053 --- /dev/null +++ b/retoors/templates/pages/shared.html @@ -0,0 +1,15 @@ +{% extends "layouts/base.html" %} +{% block title %}Shared with me - Retoor's Cloud Solutions{% endblock %} +{% block head %} + {{ super() }} + +{% endblock %} +{% block content %} +
    +
    +

    Shared with me

    +

    Files and folders that have been shared with you will appear here.

    +

    This feature is coming soon!

    +
    +
    +{% endblock %} \ No newline at end of file diff --git a/retoors/templates/pages/support.html b/retoors/templates/pages/support.html index edb699e..c57bc64 100644 --- a/retoors/templates/pages/support.html +++ b/retoors/templates/pages/support.html @@ -13,7 +13,7 @@

    Find answers to your questions, troubleshoot issues, or contact our support team for personalized assistance.

    - +
    @@ -24,25 +24,25 @@ Getting Started Icon

    Getting Started

    Guides to help you set up your account and start using Retoor's.

    - View Articles + View Articles
    Billing Icon

    Billing & Payments

    Information about your subscription, invoices, and payment methods.

    - View Articles + View Articles
    Troubleshooting Icon

    Troubleshooting

    Solutions to common issues and technical problems.

    - View Articles + View Articles
    Account Management Icon

    Account Management

    Manage your profile, security settings, and user permissions.

    - View Articles + View Articles
    @@ -54,13 +54,13 @@ Live Chat Icon

    Live Chat

    Get instant support from our team. Available 9 AM - 5 PM EST.

    - +
    Support Ticket Icon

    Submit a Ticket

    For non-urgent inquiries, submit a detailed support ticket.

    - Submit a Ticket + Submit a Ticket
    Phone Support Icon diff --git a/retoors/templates/pages/terms.html b/retoors/templates/pages/terms.html new file mode 100644 index 0000000..56918df --- /dev/null +++ b/retoors/templates/pages/terms.html @@ -0,0 +1,32 @@ +{% extends "layouts/base.html" %} +{% block title %}Terms of Service{% endblock %} +{% block head %} + {{ super() }} + +{% endblock %} +{% block content %} +
    +
    +

    Terms of Service

    +

    These are the terms of service for Retoor's Cloud Solutions. Please read them carefully.

    +

    1. Acceptance of Terms

    +

    By accessing and using our services, you agree to be bound by these Terms of Service and all terms incorporated by reference. If you do not agree to all of these terms, do not use our services.

    +

    2. Changes to Terms

    +

    We reserve the right to modify or revise these Terms at any time. We will notify you of any changes by posting the new Terms on this page. Your continued use of the services after any such changes constitutes your acceptance of the new Terms of Service.

    +

    3. Privacy Policy

    +

    Please refer to our Privacy Policy for information on how we collect, use, and disclose information from our users.

    +

    4. User Conduct

    +

    You agree not to use the services for any unlawful purpose or in any way that might harm, abuse, or otherwise interfere with the services or any other user.

    +

    5. Termination

    +

    We may terminate or suspend your access to our services immediately, without prior notice or liability, for any reason whatsoever, including without limitation if you breach the Terms.

    +

    6. Disclaimer of Warranties

    +

    Our services are provided on an "AS IS" and "AS AVAILABLE" basis. We do not warrant that the services will be uninterrupted, secure, or error-free.

    +

    7. Limitation of Liability

    +

    In no event shall Retoor's Cloud Solutions, nor its directors, employees, partners, agents, suppliers, or affiliates, be liable for any indirect, incidental, special, consequential or punitive damages, including without limitation, loss of profits, data, use, goodwill, or other intangible losses, resulting from (i) your access to or use of or inability to access or use the Service; (ii) any conduct or content of any third party on the Service; (iii) any content obtained from the Service; and (iv) unauthorized access, use or alteration of your transmissions or content, whether based on warranty, contract, tort (including negligence) or any other legal theory, whether or not we have been informed of the possibility of such damage, and even if a remedy set forth herein is found to have failed of its essential purpose.

    +

    8. Governing Law

    +

    These Terms shall be governed and construed in accordance with the laws of [Your Jurisdiction], without regard to its conflict of law provisions.

    +

    9. Contact Us

    +

    If you have any questions about these Terms, please contact us.

    +
    +
    +{% endblock %} \ No newline at end of file diff --git a/retoors/templates/pages/trash.html b/retoors/templates/pages/trash.html new file mode 100644 index 0000000..fbf44ab --- /dev/null +++ b/retoors/templates/pages/trash.html @@ -0,0 +1,15 @@ +{% extends "layouts/base.html" %} +{% block title %}Trash - Retoor's Cloud Solutions{% endblock %} +{% block head %} + {{ super() }} + +{% endblock %} +{% block content %} +
    +
    +

    Trash

    +

    Files and folders you have deleted will appear here.

    +

    This feature is coming soon!

    +
    +
    +{% endblock %} \ No newline at end of file diff --git a/retoors/views/admin.py b/retoors/views/admin.py index 56a1dbd..821eaad 100644 --- a/retoors/views/admin.py +++ b/retoors/views/admin.py @@ -1,10 +1,7 @@ from aiohttp import web -import aiohttp_jinja2 from aiohttp_session import get_session from ..services.user_service import UserService from ..models import QuotaUpdateModel, RegistrationModel -from typing import Dict, Any, List -import json async def get_users(request: web.Request) -> web.Response: user_service: UserService = request.app["user_service"] diff --git a/retoors/views/site.py b/retoors/views/site.py index 0382b9d..37f4abd 100644 --- a/retoors/views/site.py +++ b/retoors/views/site.py @@ -1,13 +1,13 @@ from aiohttp import web import aiohttp_jinja2 -from aiohttp_session import get_session -from pydantic import ValidationError +import os +from pathlib import Path -from ..services.user_service import UserService from ..helpers.auth import login_required -from ..models import QuotaUpdateModel from .auth import CustomPydanticView +PROJECT_DIR = Path(__file__).parent.parent.parent / "project" + class SiteView(web.View): async def get(self): @@ -23,6 +23,18 @@ class SiteView(web.View): return await self.support() elif self.request.path == "/use_cases": return await self.use_cases() + elif self.request.path == "/terms": + return await self.terms() + elif self.request.path == "/privacy": + return await self.privacy() + elif self.request.path == "/shared": + return await self.shared() + elif self.request.path == "/recent": + return await self.recent() + elif self.request.path == "/favorites": + return await self.favorites() + elif self.request.path == "/trash": + return await self.trash() return aiohttp_jinja2.render_template( "pages/index.html", self.request, {"request": self.request, "errors": {}, "user": self.request.get("user")} ) @@ -60,6 +72,52 @@ class SiteView(web.View): "pages/use_cases.html", self.request, {"request": self.request, "errors": {}, "user": self.request.get("user")} ) + async def terms(self): + return aiohttp_jinja2.render_template( + "pages/terms.html", self.request, {"request": self.request, "errors": {}, "user": self.request.get("user")} + ) + + async def privacy(self): + return aiohttp_jinja2.render_template( + "pages/privacy.html", self.request, {"request": self.request, "errors": {}, "user": self.request.get("user")} + ) + + async def shared(self): + return aiohttp_jinja2.render_template( + "pages/shared.html", self.request, {"request": self.request, "errors": {}, "user": self.request.get("user")} + ) + + async def recent(self): + return aiohttp_jinja2.render_template( + "pages/recent.html", self.request, {"request": self.request, "errors": {}, "user": self.request.get("user")} + ) + + async def favorites(self): + return aiohttp_jinja2.render_template( + "pages/favorites.html", self.request, {"request": self.request, "errors": {}, "user": self.request.get("user")} + ) + + async def trash(self): + return aiohttp_jinja2.render_template( + "pages/trash.html", self.request, {"request": self.request, "errors": {}, "user": self.request.get("user")} + ) + + +class FileBrowserView(web.View): + @login_required + async def get(self): + files = [] + if PROJECT_DIR.is_dir(): + for item in os.listdir(PROJECT_DIR): + item_path = PROJECT_DIR / item + if item_path.is_file(): + files.append(item) + return aiohttp_jinja2.render_template( + "pages/file_browser.html", + self.request, + {"request": self.request, "files": files, "user": self.request.get("user")}, + ) + class OrderView(CustomPydanticView): template_name = "pages/order.html" diff --git a/tests/conftest.py b/tests/conftest.py index 1015878..dce8afc 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,11 +2,8 @@ import pytest from pathlib import Path import json from retoors.main import create_app -from retoors.services.user_service import UserService from retoors.services.config_service import ConfigService from pytest_mock import MockerFixture # Import MockerFixture -from unittest import mock # For AsyncMock -import aiojobs # Import aiojobs to patch it import datetime # Import datetime diff --git a/tests/test_admin.py b/tests/test_admin.py index 657d721..f543b9f 100644 --- a/tests/test_admin.py +++ b/tests/test_admin.py @@ -1,9 +1,6 @@ import pytest -from aiohttp import web -from aiohttp_session import get_session -from unittest.mock import AsyncMock, patch, call +from unittest.mock import call -from retoors.services.user_service import UserService @pytest.fixture async def admin_client(client): diff --git a/tests/test_auth.py b/tests/test_auth.py index de212c9..daa3a68 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -1,5 +1,3 @@ -import pytest -from unittest.mock import call import datetime import asyncio diff --git a/tests/test_env_manager.py b/tests/test_env_manager.py index 4017e8a..0eebd1e 100644 --- a/tests/test_env_manager.py +++ b/tests/test_env_manager.py @@ -1,7 +1,5 @@ import pytest -from pathlib import Path -import os -from unittest.mock import patch, MagicMock +from unittest.mock import patch from retoors.helpers.env_manager import ensure_env_file_exists, get_or_create_session_secret_key from cryptography.fernet import Fernet diff --git a/tests/test_site.py b/tests/test_site.py index a690a76..2ae6b66 100644 --- a/tests/test_site.py +++ b/tests/test_site.py @@ -120,4 +120,80 @@ async def test_order_post_authorized(client): assert "Total Storage Used:" in text +async def test_terms_get(client): + resp = await client.get("/terms") + assert resp.status == 200 + text = await resp.text() + assert "Terms of Service" in text + assert "By accessing and using our services, you agree to be bound by these Terms of Service" in text + + +async def test_privacy_get(client): + resp = await client.get("/privacy") + assert resp.status == 200 + text = await resp.text() + assert "Privacy Policy" in text + assert "This Privacy Policy describes how Retoor's Cloud Solutions collects, uses, and discloses your information" in text + + +async def test_shared_get(client): + resp = await client.get("/shared") + assert resp.status == 200 + text = await resp.text() + assert "Shared with me" in text + assert "Files and folders that have been shared with you will appear here." in text + + +async def test_recent_get(client): + resp = await client.get("/recent") + assert resp.status == 200 + text = await resp.text() + assert "Recent Files" in text + assert "Your recently accessed files will appear here." in text + + +async def test_favorites_get(client): + resp = await client.get("/favorites") + assert resp.status == 200 + text = await resp.text() + assert "Favorites" in text + assert "Your favorite files and folders will appear here." in text + + +async def test_trash_get(client): + resp = await client.get("/trash") + assert resp.status == 200 + text = await resp.text() + assert "Trash" in text + assert "Files and folders you have deleted will appear here." in text + + +async def test_file_browser_get_unauthorized(client): + resp = await client.get("/files", allow_redirects=False) + assert resp.status == 302 + assert resp.headers["Location"] == "/login" + + +async def test_file_browser_get_authorized(client): + await client.post( + "/register", + data={ + "full_name": "Test User", + "email": "test@example.com", + "password": "password", + "confirm_password": "password", + }, + ) + await client.post( + "/login", data={"email": "test@example.com", "password": "password"} + ) + resp = await client.get("/files") + assert resp.status == 200 + text = await resp.text() + assert "File Browser" in text + # Check for some expected files from the project directory + assert "example.jpg" in text + assert "rexample7.jpg" in text + + diff --git a/tests/test_user_service.py b/tests/test_user_service.py index 2e6e027..a5e69a8 100644 --- a/tests/test_user_service.py +++ b/tests/test_user_service.py @@ -1,5 +1,4 @@ import pytest -from pathlib import Path import json from retoors.services.user_service import UserService import bcrypt