|
1 | | -from urllib.parse import urljoin, urlparse |
2 | | - |
| 1 | +from urllib.parse import urljoin, urlparse, urlunparse |
3 | 2 | from app.settings import settings |
| 3 | +import typer |
4 | 4 |
|
5 | 5 |
|
6 | 6 | class UrlBuilder: |
7 | | - def __init__(self, instance_url: str): |
8 | | - # Add https:// if scheme is missing |
9 | | - parsed = urlparse(instance_url) |
10 | | - if not parsed.scheme: |
11 | | - instance_url = "https://" + instance_url |
| 7 | + def __init__(self, backend_url: str, frontend_url: str): |
| 8 | + # Ensure schemes are present |
| 9 | + self.__backend_url = self.__ensure_scheme(backend_url) |
| 10 | + self.__frontend_url = self.__ensure_scheme(frontend_url) |
| 11 | + |
| 12 | + @staticmethod |
| 13 | + def __ensure_scheme(url: str) -> str: |
| 14 | + if not urlparse(url).scheme: |
| 15 | + return "https://" + url.lstrip("/") |
| 16 | + return url |
12 | 17 |
|
13 | | - self.__instance_url = instance_url.rstrip("/") + "/" |
| 18 | + @staticmethod |
| 19 | + def __ensure_trailing_slash(url: str) -> str: |
| 20 | + parsed = urlparse(url) |
| 21 | + if not parsed.path.endswith("/"): |
| 22 | + new_path = parsed.path + "/" |
| 23 | + parsed = parsed._replace(path=new_path) |
| 24 | + return urlunparse(parsed) |
14 | 25 |
|
15 | 26 | @classmethod |
16 | | - def resolve(cls, instance_url: str | None = None) -> "UrlBuilder": |
17 | | - """Resolve instance URL from arg/env/prompt and return UrlBuilder.""" |
18 | | - import typer # local import to avoid hard dep at module level |
19 | | - |
20 | | - url = instance_url or settings.INSTANCE_URL |
21 | | - if not url: |
22 | | - url = typer.prompt( |
23 | | - "Enter the Chithi instance URL (e.g. https://chithi.dev)" |
| 27 | + def resolve(cls, initial_url: str | None = None) -> "UrlBuilder": |
| 28 | + """ |
| 29 | + Logic: |
| 30 | + 1. If a URL is passed from CLI/Link, use it. |
| 31 | + 2. If not, check settings. |
| 32 | + 3. If still nothing, prompt user for 'Same Domain' setup. |
| 33 | + """ |
| 34 | + url_candidate = initial_url or settings.INSTANCE_URL |
| 35 | + |
| 36 | + if url_candidate: |
| 37 | + # If we already have a URL, we treat it as both for simplicity |
| 38 | + return cls(backend_url=url_candidate, frontend_url=url_candidate) |
| 39 | + |
| 40 | + # Interactive Setup |
| 41 | + same_domain = typer.confirm( |
| 42 | + "Are the backend and frontend hosted on the same domain?", default=True |
| 43 | + ) |
| 44 | + |
| 45 | + if same_domain: |
| 46 | + domain = typer.prompt("Enter the base domain", default="chithi.dev").strip( |
| 47 | + "/" |
| 48 | + ) |
| 49 | + # Standard structure: root for frontend, /api/ for backend |
| 50 | + return cls( |
| 51 | + backend_url=f"https://{domain}/api/", frontend_url=f"https://{domain}/" |
| 52 | + ) |
| 53 | + else: |
| 54 | + frontend = typer.prompt("Enter the Frontend URL (e.g. https://chithi.dev)") |
| 55 | + backend = typer.prompt( |
| 56 | + "Enter the Backend URL (e.g. https://api.chithi.dev)" |
24 | 57 | ) |
25 | | - return cls(url) |
| 58 | + return cls(backend_url=backend, frontend_url=frontend) |
26 | 59 |
|
27 | 60 | @property |
28 | 61 | def instance_url(self): |
29 | | - return self.__instance_url |
| 62 | + """Standardized backend base URL.""" |
| 63 | + return self.__ensure_trailing_slash(self.__backend_url) |
30 | 64 |
|
31 | 65 | @property |
32 | | - def __api_url(self): |
33 | | - return urljoin(self.instance_url, "api/") |
| 66 | + def frontend_url(self): |
| 67 | + """Standardized frontend base URL.""" |
| 68 | + return self.__ensure_trailing_slash(self.__frontend_url) |
34 | 69 |
|
35 | 70 | def upload_url(self): |
36 | | - # SENSITIVE URL |
37 | | - return urljoin(self.__api_url, "upload") |
| 71 | + return urljoin(self.instance_url, "upload") |
38 | 72 |
|
39 | 73 | def config_url(self): |
40 | | - return urljoin(self.__api_url, "config") |
| 74 | + return urljoin(self.instance_url, "config") |
41 | 75 |
|
42 | 76 | def download_url(self): |
43 | | - return urljoin(self.__api_url, "download/") |
| 77 | + return urljoin(self.instance_url, "download/") |
44 | 78 |
|
45 | 79 | def share_url(self, slug: str, key_secret: str) -> str: |
46 | | - """Web-facing download link: ``https://instance/download/<slug>#<key>``.""" |
47 | | - return f"{self.instance_url}download/{slug}#{key_secret}" |
| 80 | + # Share URLs should point to the Frontend UI |
| 81 | + return f"{self.frontend_url}download/{slug}#{key_secret}" |
0 commit comments