diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..ed48fdf --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,28 @@ +name: Deploy App +run-name: Deploy Tiny App to Cloud Server + +on: + push: + branches: [release] + +jobs: + deploy: + runs-on: ubuntu-latest + environment: production + steps: + - name: Deploy via SSH + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.HOST }} + username: ${{ secrets.USERNAME }} + key: ${{ secrets.SSH_PRIVATE_KEY }} + script: | + cd /opt/tz_apps/tiny + # Fetch latest code + git pull origin release + + # Install dependencies (Production mode, no dev deps) + /root/.local/bin/poetry install --only main --sync + + # Restart the service + sudo systemctl restart tiny.service diff --git a/.vscode/dictionaries/project-words.txt b/.vscode/dictionaries/project-words.txt index 40463fa..5d55556 100755 --- a/.vscode/dictionaries/project-words.txt +++ b/.vscode/dictionaries/project-words.txt @@ -1,2 +1,4 @@ +appleboy projectx +RZRO xkeshav diff --git a/CHANGELOG.md b/CHANGELOG.md index ad57eb9..bb510a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,3 +11,9 @@ All notable changes to this repository will be documented in this file. - Restructure folder structure - added poetry dev script + +## [1.0.0] Sun, Feb 15, 2026 + +- Added In-Memory cache strategy +- DB dependency optional +- Change UI diff --git a/app/main.py b/app/main.py index 09bb540..9c438a2 100644 --- a/app/main.py +++ b/app/main.py @@ -2,7 +2,7 @@ from pathlib import Path from typing import Optional -from fastapi import FastAPI, Form, Request +from fastapi import FastAPI, Form, Request, status from fastapi.responses import HTMLResponse, PlainTextResponse, RedirectResponse from fastapi.staticfiles import StaticFiles from fastapi.templating import Jinja2Templates @@ -28,7 +28,6 @@ from app.utils.qr import generate_qr_with_logo - # ----------------------------- # Lifespan: env + DB connect ONCE # ----------------------------- @@ -103,37 +102,27 @@ async def create_short_url( original_url: str = Form(""), generate_qr: Optional[str] = Form(None), qr_type: str = Form("short"), -): +) -> RedirectResponse: session = request.session qr_enabled = bool(generate_qr) original_url = sanitize_url(original_url) - if not original_url: - session["error"] = "URL cannot be empty." - return RedirectResponse("/", status_code=303) - - if not is_valid_url(original_url): - session["error"] = ( - "Please enter a valid URL (must start with http:// or https://)." - ) - return RedirectResponse("/", status_code=303) + # Basic validation (FastAPI can also handle this via Pydantic) + if not original_url or not is_valid_url(original_url): + session["error"] = "Please enter a valid URL." + return RedirectResponse("/", status_code=status.HTTP_303_SEE_OTHER) # 1. Try Cache First short_code: Optional[str] = get_short_from_cache(original_url) - if short_code: - session["info_message"] = "Already shortened before — fetched from cache." - else: + if not short_code: # 2. Try Database existing = db_data.find_by_original_url(original_url) # Pull the value and check it in one go db_code = existing.get("short_code") if existing else None if isinstance(db_code, str): short_code = db_code - set_cache_pair(short_code, original_url) # Cache it for future - session["info_message"] = ( - "Already shortened before — fetched from database." - ) + set_cache_pair(short_code, original_url) # Cache it for future requests # 3. Generate New if still None if not short_code: @@ -147,7 +136,7 @@ async def create_short_url( if not isinstance(short_code, str): # This acts as a final safety net for production session["error"] = "Internal server error: Code generation failed." - return RedirectResponse("/", status_code=303) + return RedirectResponse("/", status_code=status.HTTP_303_SEE_OTHER) # Mypy now knows short_code is strictly 'str' new_short_url = build_short_url(short_code, DOMAIN) @@ -162,7 +151,7 @@ async def create_short_url( } ) - return RedirectResponse("/", status_code=303) + return RedirectResponse("/", status_code=status.HTTP_303_SEE_OTHER) @app.get("/recent", response_class=HTMLResponse) diff --git a/pyproject.toml b/pyproject.toml index 413922a..0e66c38 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "tiny" -version = "1.0.1" +version = "1.0.2" description = "A package for URL Shortener with QR Code generation" authors = [ { name = "recursivezero", email = "152776938+recursivezero@users.noreply.github.com" },