From 459a96f71167ad90131fa58a44217a9343db3e3d Mon Sep 17 00:00:00 2001 From: Elia el Lazkani Date: Wed, 25 Dec 2024 15:20:18 +0100 Subject: [PATCH 1/5] fix(): Fixes unexpected default export of anonymous function warning --- frontend/src/components/URLShortener/URLShortener.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/URLShortener/URLShortener.tsx b/frontend/src/components/URLShortener/URLShortener.tsx index 492a964..9f52852 100644 --- a/frontend/src/components/URLShortener/URLShortener.tsx +++ b/frontend/src/components/URLShortener/URLShortener.tsx @@ -4,7 +4,7 @@ import axios from "axios"; import { ToastContainer, toast } from "react-toastify"; import "react-toastify/dist/ReactToastify.css"; -export default function () { +export default function URLShortener() { const [url, setUrl] = useState(""); const [shortenedUrl, setShortenedUrl] = useState(""); const [showInput, setShowInput] = useState(false); -- 2.45.2 From abbfbfbffb21c3fe65b04bf631b8fa458e8c237c Mon Sep 17 00:00:00 2001 From: Elia el Lazkani Date: Wed, 25 Dec 2024 15:21:20 +0100 Subject: [PATCH 2/5] chore(): Removes unneeded library imports --- shortenit/main.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/shortenit/main.py b/shortenit/main.py index 1963860..f9d90b1 100644 --- a/shortenit/main.py +++ b/shortenit/main.py @@ -1,10 +1,8 @@ #!/usr/bin/env python3 import argparse -import asyncio import logging import pathlib import sys -import time import typing from sqlalchemy import create_engine, exc -- 2.45.2 From 8dc4e4139024589ebf12cc310d71c5565012f657 Mon Sep 17 00:00:00 2001 From: Elia el Lazkani Date: Wed, 25 Dec 2024 15:29:32 +0100 Subject: [PATCH 3/5] chore(#10): Delegates the task of setting the url to the backend API * API now returns a full URL instead of a stub * Frontend now returns the value from the API as is * Configuration adds a scheme --- config/config.yaml | 1 + .../src/components/URLShortener/URLShortener.tsx | 5 ++--- shortenit/web.py | 14 +++++++++++++- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/config/config.yaml b/config/config.yaml index 042ccfd..03c8c9d 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -1,6 +1,7 @@ Server: host: 127.0.0.1 port: 8000 + scheme: http cors: False static_folder: frontend/build diff --git a/frontend/src/components/URLShortener/URLShortener.tsx b/frontend/src/components/URLShortener/URLShortener.tsx index 9f52852..98397d0 100644 --- a/frontend/src/components/URLShortener/URLShortener.tsx +++ b/frontend/src/components/URLShortener/URLShortener.tsx @@ -38,9 +38,8 @@ export default function URLShortener() { }) .then((response) => { if (response) { - const code: string = response.data.url; - const fullShortenedUrl: string = `http://127.0.0.1:8000/r/${code}`; - setShortenedUrl(fullShortenedUrl); + const shortUrl: string = response.data.url; + setShortenedUrl(shortUrl); setShowInput(true); } }); diff --git a/shortenit/web.py b/shortenit/web.py index 50aa7f7..c9fdcac 100644 --- a/shortenit/web.py +++ b/shortenit/web.py @@ -1,5 +1,6 @@ import logging from pathlib import Path +from urllib.parse import urlunparse import trafaret from flask import Flask, abort, redirect, request, send_from_directory @@ -62,6 +63,16 @@ class SiteHandler: def _get_server_config(self): return self.configuration.get("Server", None) + def _get_host(self): + host = self._get_server_config()["host"] + port = self._get_server_config()["port"] + scheme = self._get_server_config()["scheme"] + return scheme, host, port + + def _get_url(self, stub): + scheme, host, port = self._get_host() + return urlunparse((scheme, f"{host}:{port}", f"/r/{stub}", "", "", "")) + def shortenit(self): data = request.get_json() try: @@ -72,12 +83,13 @@ class SiteHandler: self.logger.error(e) abort(400) try: - short_url = self.shorten_url( + stub = self.shorten_url( self.configuration.get("Shortener", None), self.database, data["url"], data["timestamp"], ) + short_url = self._get_url(stub) except KeyError as e: self.logger.error(e) abort(400) -- 2.45.2 From 4c36f35492acbb03320d4ce8d81f617cd39e478c Mon Sep 17 00:00:00 2001 From: Elia el Lazkani Date: Wed, 25 Dec 2024 15:32:00 +0100 Subject: [PATCH 4/5] fix(#10): Removes the timestamp from the API endpoint The timestamp is generated by the database call, the value was mapped to TTL. It is currently removed from the API, the TTL can be added later when needed. --- frontend/src/components/URLShortener/URLShortener.tsx | 4 +--- shortenit/main.py | 2 +- shortenit/models/objects.py | 2 +- shortenit/web.py | 3 +-- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/frontend/src/components/URLShortener/URLShortener.tsx b/frontend/src/components/URLShortener/URLShortener.tsx index 98397d0..f956873 100644 --- a/frontend/src/components/URLShortener/URLShortener.tsx +++ b/frontend/src/components/URLShortener/URLShortener.tsx @@ -28,13 +28,11 @@ export default function URLShortener() { } try { - const timestamp = Math.floor(Date.now() / 1000); // Send the POST request to the backend await axios .post("http://127.0.0.1:8000/api/v1/shorten", { - url: url, - timestamp: timestamp, + url: url }) .then((response) => { if (response) { diff --git a/shortenit/main.py b/shortenit/main.py index f9d90b1..7b8bc2b 100644 --- a/shortenit/main.py +++ b/shortenit/main.py @@ -51,7 +51,7 @@ def main() -> typing.NoReturn: sys.exit(0) -def shorten_it(config: dict, session: Session, data: str, ttl: int): +def shorten_it(config: dict, session: Session, data: str, ttl: int = 0): shortener = Shortener(session, config) identifier = shortener.generate_uuid() if identifier: diff --git a/shortenit/models/objects.py b/shortenit/models/objects.py index e7fc16c..716c107 100644 --- a/shortenit/models/objects.py +++ b/shortenit/models/objects.py @@ -21,7 +21,7 @@ class Pointer(base.Base): __tablename__ = "pointers" id: Mapped[int] = mapped_column(primary_key=True, index=True, init=False) data: Mapped[str] = mapped_column(index=True) - ttl: Mapped[str] + ttl: Mapped[int] link_id: Mapped[int] = mapped_column(ForeignKey("links.id")) link: Mapped["Link"] = relationship(back_populates="pointers") timestamp: Mapped[datetime] = mapped_column(default=func.now()) diff --git a/shortenit/web.py b/shortenit/web.py index c9fdcac..f4920ab 100644 --- a/shortenit/web.py +++ b/shortenit/web.py @@ -57,7 +57,7 @@ class SiteHandler: self.shorten_url = shorten_url self.lenghten_url = lenghten_url self.shortenit_load_format = trafaret.Dict( - {trafaret.Key("url"): trafaret.URL, trafaret.Key("timestamp"): trafaret.Int} + {trafaret.Key("url"): trafaret.URL} ) def _get_server_config(self): @@ -87,7 +87,6 @@ class SiteHandler: self.configuration.get("Shortener", None), self.database, data["url"], - data["timestamp"], ) short_url = self._get_url(stub) except KeyError as e: -- 2.45.2 From 0238e4b67b5ce21aa9356c9da3b558d279268f5d Mon Sep 17 00:00:00 2001 From: Elia el Lazkani Date: Wed, 25 Dec 2024 15:33:49 +0100 Subject: [PATCH 5/5] enh(#10): Frontend is now configurable from config.json The host URL is now read from configuration. --- config/config.yaml | 4 ---- .../components/URLShortener/URLShortener.tsx | 7 +++++- frontend/src/config.json | 12 ++++++++++ frontend/src/config.tsx | 24 +++++++++++++++++++ 4 files changed, 42 insertions(+), 5 deletions(-) create mode 100644 frontend/src/config.json create mode 100644 frontend/src/config.tsx diff --git a/config/config.yaml b/config/config.yaml index 03c8c9d..e868f41 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -5,10 +5,6 @@ Server: cors: False static_folder: frontend/build -Web: - host: 127.0.0.1 - port: 8000 - Database: username: foo password: bar diff --git a/frontend/src/components/URLShortener/URLShortener.tsx b/frontend/src/components/URLShortener/URLShortener.tsx index f956873..7aa75e1 100644 --- a/frontend/src/components/URLShortener/URLShortener.tsx +++ b/frontend/src/components/URLShortener/URLShortener.tsx @@ -3,6 +3,7 @@ import "./URLShortener.css"; import axios from "axios"; import { ToastContainer, toast } from "react-toastify"; import "react-toastify/dist/ReactToastify.css"; +import Config from "../../config" export default function URLShortener() { const [url, setUrl] = useState(""); @@ -28,10 +29,14 @@ export default function URLShortener() { } try { + const config = Config() + const api_endpoint = "/api/v1/shorten"; + + const api_url = `${config.url}${api_endpoint}`; // Send the POST request to the backend await axios - .post("http://127.0.0.1:8000/api/v1/shorten", { + .post(api_url , { url: url }) .then((response) => { diff --git a/frontend/src/config.json b/frontend/src/config.json new file mode 100644 index 0000000..aba9fd4 --- /dev/null +++ b/frontend/src/config.json @@ -0,0 +1,12 @@ +{ + "frontend": { + "scheme": "http", + "host": "127.0.0.1", + "port": "8000" + }, + "api": { + "scheme": "http", + "host": "127.0.0.1", + "port": "8000" + } +} diff --git a/frontend/src/config.tsx b/frontend/src/config.tsx new file mode 100644 index 0000000..49984db --- /dev/null +++ b/frontend/src/config.tsx @@ -0,0 +1,24 @@ +import configuration from './config.json'; + +class APIConfig { + scheme: string; + host: string; + port: string; + url: string; + + constructor(scheme: string, host: string, port: string) { + this.scheme = scheme; + this.host = host; + this.port = port; + this.url = `${scheme}://${host}:${port}` + } +} + +export default function Config() { + const scheme = configuration.api.scheme; + const host = configuration.api.host; + const port = configuration.api.port; + + const apiConfig = new APIConfig(scheme, host, port); + return apiConfig +} -- 2.45.2