Compare commits

...

2 Commits

8 changed files with 82 additions and 19 deletions

2
.gitignore vendored
View File

@ -1,3 +1,5 @@
/target
venv
__pycache__
/.env
/data/

View File

@ -1,11 +1,18 @@
FROM python:3.11
# Use an official Python runtime as a parent image
FROM python:3
WORKDIR /code
# Set the working directory in the container
WORKDIR /app
COPY ./requirements.txt /code/requirements.txt
# Install any needed packages specified in requirements.txt
COPY requirements.txt /app/
RUN pip install --no-cache-dir -r requirements.txt
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
# Copy the current directory contents into the container at /app
COPY . /app/
COPY ./app /code/app
# Make port 8000 available to the world outside this container
EXPOSE 8000
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
# Run api.py when the container launches
CMD ["uvicorn", "api:app", "--host", "0.0.0.0", "--port", "8000"]

9
api.py
View File

@ -16,8 +16,13 @@ async def root():
@app.get("/{url_id}", status_code=301, response_class=RedirectResponse)
async def redirect_urls(url_id):
target_url = couch["urls"][url_id].get('full_url')
return RedirectResponse(target_url)
db = couch["urls"]
if url_id in db:
target_url = db[url_id].get('full_url')
return RedirectResponse(target_url)
else:
return RedirectResponse('static/404.html')
# TODO: Get JWT tokens working and use that to return only the user's urls
# TODO: Look into how FastAPI handles the Authentication header

View File

@ -32,6 +32,10 @@ GET :host/eecd98
# Talk directly to CouchDB
###
# Get value from key
GET http://admin:password@127.0.0.1:5984/_all_dbs
:headers
# Get value from key
GET http://admin:password@127.0.0.1:5984/urls/_all_docs?include_docs=true
:headers

19
docker-compose.yml Normal file
View File

@ -0,0 +1,19 @@
version: '3'
services:
couchdb:
image: couchdb:latest
network_mode: host
volumes:
- ./data:/opt/couchdb/data:Z
env_file:
- .env
fastapi_app:
build:
context: .
dockerfile: Dockerfile
network_mode: host
depends_on:
- couchdb
env_file:
- .env

View File

@ -2,10 +2,10 @@
#+TODO: TODO INPROGRESS | DONE BACKLOG
#+STARTUP: overview
* TODO Move everything into an app directory
* TODO Knock out source code TODOs
* TODO Add button to copy shortened URL to clipboard
* TODO Add a 404 page in case the URL provided is invalid
* DONE Add button to copy shortened URL to clipboard
* DONE Add a 404 page in case the URL provided is invalid
* TODO RTFM on how to create docker compose files
* TODO Containerize couchdb
* TODO Get the container running with the Dockerfile
* TODO Point zipmy.link to joe-vps
- [ ] Add DNS records
@ -14,8 +14,6 @@
* TODO Create a README.org
* TODO Add MIT license
* BACKLOG Containerize couchdb
* BACKLOG RTFM on how to create docker compose files
* BACKLOG RTFM on how to create a container network
* BACKLOG Gitea Actions
* BACKLOG Unit tests

15
static/404.html Normal file
View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Zip My Link</title>
<link rel="stylesheet" href="main.css">
</head>
<body>
<h1>Zip My Link</h1>
<h1>404</h1>
<p>The shortened URL you provided was not found. Sorry about that!</p>
<a href="index.html">zipmy.link</a>
</body>
</html>

View File

@ -1,20 +1,33 @@
function copyUrlToClipboard() {
const urlInput = document.getElementById("url-input");
urlInput.select();
urlInput.setSelectionRange(0, 99999);
navigator.clipboard.writeText(urlInput.value);
}
function resetLinkGeneration() {
}
async function shortenUrl() {
const url = document.getElementById("url-input").value;
const btn = document.getElementById("submit-btn").value;
const urlInput = document.getElementById("url-input");
const btn = document.getElementById("submit-btn");
// btn.enab
const response = await fetch("/api/v1/urls", {
method: 'PUT',
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ url: url, username: "anonymous" })
body: JSON.stringify({ url: urlInput.value, username: "anonymous" })
});
const data = await response.json();
const resultElement = document.getElementById("result");
if (response.ok) {
resultElement.textContent = `Shortened Url: ${data.shortenedUrl}`
resultElement.style.color = "black";
resultElement.textContent = ''
urlInput.value = data.shortenedUrl;
btn.innerText = "📋 Copy to Clipboard!";
btn.onclick = copyUrlToClipboard;
} else {
resultElement.textContent = `Error: ${data.detail}`
resultElement.style.color = "red";
btn.value = "Shorten Url";
}
}