Skip to content

Commit

Permalink
URL Expiration
Browse files Browse the repository at this point in the history
  • Loading branch information
SAMAD101 committed Jan 28, 2024
1 parent 91825d0 commit d50fdc5
Show file tree
Hide file tree
Showing 8 changed files with 45 additions and 15 deletions.
Binary file removed liberate.db
Binary file not shown.
13 changes: 12 additions & 1 deletion pdm.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@ dependencies = [
"SQLAlchemy>=2.0.25",
"psycopg2-binary>=2.9.9",
"validators>=0.22.0",
"aiosqlite>=0.19.0",
]
requires-python = ">=3.11.6"
readme = "README.md"
license = {text = "MIT"}

[tool.pdm.scripts]
start = "uvicorn src.link_liberate.main:app --host 0.0.0.0 --port 8080 --workers 1 --reload"
start = "uvicorn src.link_liberate.main:app --host 0.0.0.0 --port 8080 --workers 4 --reload"
dev = "uvicorn src.link_liberate.main:app --host 0.0.0.0 --port 8080 --reload"
test = "pytest"
mypy = "mypy src/link_liberate"
Expand Down
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,5 @@ wrapt==1.16.0

SQLAlchemy~=2.0.25
validators~=0.22.0

aiosqlite~=0.19.0
16 changes: 16 additions & 0 deletions src/link_liberate/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

import aiosqlite
import asyncio

SQLALCHEMY_DATABASE_URL = "sqlite:///./liberate.db"

engine = create_engine(
Expand All @@ -19,3 +22,16 @@ def get_db():
yield db
finally:
db.close()


async def create_async_session():
async with aiosqlite.connect(SQLALCHEMY_DATABASE_URL) as db:
yield db


async def expire_uuid(uuid):
print("Expiring uuid:", uuid)
await asyncio.sleep(60) # Default expiration time is 60 mins
async with create_async_session() as db:
await db.execute("DELETE FROM liberatedlinks WHERE uuid = ?", (uuid,))
await db.commit()
5 changes: 3 additions & 2 deletions src/link_liberate/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@

from slowapi.util import get_remote_address
from sqlalchemy.orm import Session

from asyncio import create_task
from starlette.templating import _TemplateResponse

from .utils import generate_uuid, make_proper_url, check_link
from .models import Base, LiberatedLink
from .database import engine, get_db
from .database import engine, get_db, expire_uuid

limiter = Limiter(key_func=get_remote_address)
app: FastAPI = FastAPI(title="link-liberate")
Expand Down Expand Up @@ -77,6 +77,7 @@ async def web_post(
db.add(new_liberated_link)
db.commit()
db.refresh(new_liberated_link)
await create_task(expire_uuid(uuid))
context = {"link": link, "short": f"{BASE_URL}/{uuid}"}
except Exception as e:
raise HTTPException(
Expand Down
16 changes: 8 additions & 8 deletions src/link_liberate/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
margin: 0;
padding: 0;
}

.container {
max-width: 600px;
align-content: center;
Expand All @@ -21,20 +21,20 @@
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}

a {
text-decoration: none !important;
}

h1 {
text-align: center;
color: #333;
}

.form-container {
text-align: center;
}

.link-input {
width: 100%;
padding: 10px;
Expand All @@ -43,7 +43,7 @@
border: 1px solid #ccc;
border-radius: 4px;
}

.submit-button {
background-color: #4CAF50;
color: #fff;
Expand All @@ -53,11 +53,11 @@
cursor: pointer;
font-size: 16px;
}

.submit-button:hover {
background-color: #45a049;
}

</style>
<title>
{% block title %}
Expand Down
5 changes: 2 additions & 3 deletions tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,15 @@ def test_web():

def test_web_post(mocker):
# Patch the get_db function to return the db mock
mocker.patch('src.link_liberate.database.Session_Local', return_value=Mock())
mocker.patch("src.link_liberate.database.Session_Local", return_value=Mock())
client_mock = TestClient(app)
response = client_mock.post("/liberate", data={"content": "valid_content"})
assert response.status_code == 200



def test_get_link(mocker):
# Patch the get_db function to return the db mock
mocker.patch('src.link_liberate.database.Session_Local', return_value=Mock())
mocker.patch("src.link_liberate.database.Session_Local", return_value=Mock())
client_mock = TestClient(app)
response = client_mock.get("/valid_uuid", follow_redirects=False)
assert response.status_code == 301

0 comments on commit d50fdc5

Please sign in to comment.