Merge remote-tracking branch 'origin/main' into feature-page
This commit is contained in:
commit
4947b55fe8
12 changed files with 182 additions and 200 deletions
13
README.md
13
README.md
|
@ -4,11 +4,18 @@ Shortenit is a tool to shorten urls.
|
||||||
|
|
||||||
**NOTE**: This is a very early draft project. Contributions are welcome.
|
**NOTE**: This is a very early draft project. Contributions are welcome.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
To install `shortenit` and all of its dependencies for development, run the following script.
|
||||||
|
|
||||||
|
``` shell
|
||||||
|
$ scripts/install.sh
|
||||||
|
```
|
||||||
|
|
||||||
## Running
|
## Running
|
||||||
|
|
||||||
To run `shortenit`, edit the configuration file found in [config/config.yaml](config/config.yaml) then run the following commands.
|
To run `shortenit` for development, edit the configuration file found in [config/config.yaml](config/config.yaml) then run the following script.
|
||||||
|
|
||||||
```text
|
```text
|
||||||
$ pip install -e .
|
$ scripts/run.sh
|
||||||
$ shortenit
|
|
||||||
```
|
```
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
Server:
|
Server:
|
||||||
host: 127.0.0.1
|
host: 127.0.0.1
|
||||||
port: 8000
|
port: 8000
|
||||||
|
scheme: http
|
||||||
Web:
|
cors: False
|
||||||
host: 127.0.0.1
|
static_folder: frontend/build
|
||||||
port: 8000
|
|
||||||
|
|
||||||
Database:
|
Database:
|
||||||
username: foo
|
username: foo
|
||||||
|
|
25
docs/conf.py
25
docs/conf.py
|
@ -6,29 +6,28 @@
|
||||||
# -- Project information -----------------------------------------------------
|
# -- Project information -----------------------------------------------------
|
||||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
|
||||||
|
|
||||||
project = 'shortenit'
|
project = "shortenit"
|
||||||
copyright = '2024, Elia el Lazkani'
|
copyright = "2024, Elia el Lazkani"
|
||||||
author = 'Elia el Lazkani'
|
author = "Elia el Lazkani"
|
||||||
release = '0.0.0'
|
release = "0.0.0"
|
||||||
|
|
||||||
# -- General configuration ---------------------------------------------------
|
# -- General configuration ---------------------------------------------------
|
||||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
||||||
|
|
||||||
extensions = [
|
extensions = [
|
||||||
'sphinx.ext.autodoc',
|
"sphinx.ext.autodoc",
|
||||||
'sphinx.ext.todo',
|
"sphinx.ext.todo",
|
||||||
'sphinx.ext.coverage',
|
"sphinx.ext.coverage",
|
||||||
'sphinx.ext.viewcode',
|
"sphinx.ext.viewcode",
|
||||||
'sphinx_autodoc_typehints',
|
"sphinx_autodoc_typehints",
|
||||||
]
|
]
|
||||||
|
|
||||||
templates_path = ['_templates']
|
templates_path = ["_templates"]
|
||||||
exclude_patterns = []
|
exclude_patterns = []
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# -- Options for HTML output -------------------------------------------------
|
# -- Options for HTML output -------------------------------------------------
|
||||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
|
||||||
|
|
||||||
html_theme = 'alabaster'
|
html_theme = "alabaster"
|
||||||
html_static_path = ['_static']
|
html_static_path = ["_static"]
|
||||||
|
|
|
@ -3,9 +3,9 @@ import "./URLShortener.css";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { ToastContainer, toast } from "react-toastify";
|
import { ToastContainer, toast } from "react-toastify";
|
||||||
import "react-toastify/dist/ReactToastify.css";
|
import "react-toastify/dist/ReactToastify.css";
|
||||||
import QRCodeGenerator from "../qrCode/qrCodeGenerator";
|
import Config from "../../config"
|
||||||
|
|
||||||
export default function () {
|
export default function URLShortener() {
|
||||||
const [url, setUrl] = useState<string>("");
|
const [url, setUrl] = useState<string>("");
|
||||||
const [shortenedUrl, setShortenedUrl] = useState<string>("");
|
const [shortenedUrl, setShortenedUrl] = useState<string>("");
|
||||||
const [showInput, setShowInput] = useState<boolean>(false);
|
const [showInput, setShowInput] = useState<boolean>(false);
|
||||||
|
@ -29,19 +29,20 @@ export default function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const timestamp = Math.floor(Date.now() / 1000);
|
const config = Config()
|
||||||
|
const api_endpoint = "/api/v1/shorten";
|
||||||
|
|
||||||
|
const api_url = `${config.url}${api_endpoint}`;
|
||||||
|
|
||||||
// Send the POST request to the backend
|
// Send the POST request to the backend
|
||||||
await axios
|
await axios
|
||||||
.post("http://127.0.0.1:8000/shortenit", {
|
.post(api_url , {
|
||||||
url: url,
|
url: url
|
||||||
timestamp: timestamp,
|
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (response) {
|
if (response) {
|
||||||
const code: string = response.data.url;
|
const shortUrl: string = response.data.url;
|
||||||
const fullShortenedUrl: string = `http://127.0.0.1:8000/${code}`;
|
setShortenedUrl(shortUrl);
|
||||||
setShortenedUrl(fullShortenedUrl);
|
|
||||||
setShowInput(true);
|
setShowInput(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -75,40 +76,39 @@ export default function () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<>
|
<div className="URLShortener-component">
|
||||||
<div className="URLShortener-component">
|
<div className="left-side">
|
||||||
<div className="left-side">
|
<h1>Paste the URL</h1>
|
||||||
<h1>Paste the URL</h1>
|
<form className="url-input" onSubmit={ShortenIt}>
|
||||||
<form className="url-input" onSubmit={ShortenIt}>
|
<input
|
||||||
<input
|
type="text"
|
||||||
type="text"
|
placeholder="www.example.com"
|
||||||
placeholder="www.example.com"
|
aria-label="URL input field"
|
||||||
aria-label="URL input field"
|
value={url}
|
||||||
value={url}
|
onChange={(e) => setUrl(e.target.value)}
|
||||||
onChange={(e) => setUrl(e.target.value)}
|
/>
|
||||||
/>
|
<button type="submit">Shorten It</button>
|
||||||
<button type="submit">Shorten It</button>
|
</form>
|
||||||
</form>
|
|
||||||
{shortenedUrl && (
|
{shortenedUrl && showInput && (
|
||||||
<div className="url-input shortened">
|
<div className="url-input shortened">
|
||||||
<input type="text" readOnly value={shortenedUrl} />
|
<input type="text" readOnly value={shortenedUrl} />
|
||||||
<button onClick={copyURL}>Copy</button>
|
<button onClick={copyURL}>Copy</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="right-side">
|
||||||
|
<div className="right-side-title">
|
||||||
|
<h1>Shorten It</h1>
|
||||||
</div>
|
</div>
|
||||||
<div className="right-side">
|
<div className="right-side-content">
|
||||||
<div className="right-side-title">
|
<p>
|
||||||
<h1>Shorten It</h1>
|
Shortenit is a free and open-source URL shortening service designed
|
||||||
</div>
|
for simplicity and efficiency.
|
||||||
<div className="right-side-content">
|
</p>
|
||||||
<p>
|
|
||||||
Shortenit is a free and open-source URL shortening service
|
|
||||||
designed for simplicity and efficiency.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ToastContainer />
|
<ToastContainer />
|
||||||
</>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
12
frontend/src/config.json
Normal file
12
frontend/src/config.json
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"frontend": {
|
||||||
|
"scheme": "http",
|
||||||
|
"host": "127.0.0.1",
|
||||||
|
"port": "8000"
|
||||||
|
},
|
||||||
|
"api": {
|
||||||
|
"scheme": "http",
|
||||||
|
"host": "127.0.0.1",
|
||||||
|
"port": "8000"
|
||||||
|
}
|
||||||
|
}
|
24
frontend/src/config.tsx
Normal file
24
frontend/src/config.tsx
Normal file
|
@ -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
|
||||||
|
}
|
7
scripts/install.sh
Executable file
7
scripts/install.sh
Executable file
|
@ -0,0 +1,7 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
cd frontend
|
||||||
|
npm install
|
||||||
|
|
||||||
|
cd ..
|
||||||
|
poetry install
|
6
scripts/run.sh
Executable file
6
scripts/run.sh
Executable file
|
@ -0,0 +1,6 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
cd frontend
|
||||||
|
npm run build
|
||||||
|
cd ..
|
||||||
|
poetry run shortenit "$@"
|
|
@ -1,10 +1,8 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import argparse
|
import argparse
|
||||||
import asyncio
|
|
||||||
import logging
|
import logging
|
||||||
import pathlib
|
import pathlib
|
||||||
import sys
|
import sys
|
||||||
import time
|
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
from sqlalchemy import create_engine, exc
|
from sqlalchemy import create_engine, exc
|
||||||
|
@ -53,9 +51,8 @@ def main() -> typing.NoReturn:
|
||||||
sys.exit(0)
|
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_config = config.get("Shortener", None)
|
shortener = Shortener(session, config)
|
||||||
shortener = Shortener(session, shortener_config)
|
|
||||||
identifier = shortener.generate_uuid()
|
identifier = shortener.generate_uuid()
|
||||||
if identifier:
|
if identifier:
|
||||||
try:
|
try:
|
||||||
|
@ -65,9 +62,9 @@ def shorten_it(config: dict, session: Session, data: str, ttl: int):
|
||||||
_link = Link(data=data, pointers=[])
|
_link = Link(data=data, pointers=[])
|
||||||
|
|
||||||
_pointer = Pointer(data=identifier, link_id=_link.id, link=_link, ttl=ttl)
|
_pointer = Pointer(data=identifier, link_id=_link.id, link=_link, ttl=ttl)
|
||||||
|
session.add(_pointer)
|
||||||
_link.pointers.append(_pointer)
|
_link.pointers.append(_pointer)
|
||||||
session.add(_link)
|
session.add(_link)
|
||||||
session.add(_pointer)
|
|
||||||
session.commit()
|
session.commit()
|
||||||
return _pointer.data
|
return _pointer.data
|
||||||
return None
|
return None
|
||||||
|
|
|
@ -21,7 +21,7 @@ class Pointer(base.Base):
|
||||||
__tablename__ = "pointers"
|
__tablename__ = "pointers"
|
||||||
id: Mapped[int] = mapped_column(primary_key=True, index=True, init=False)
|
id: Mapped[int] = mapped_column(primary_key=True, index=True, init=False)
|
||||||
data: Mapped[str] = mapped_column(index=True)
|
data: Mapped[str] = mapped_column(index=True)
|
||||||
ttl: Mapped[str]
|
ttl: Mapped[int]
|
||||||
link_id: Mapped[int] = mapped_column(ForeignKey("links.id"))
|
link_id: Mapped[int] = mapped_column(ForeignKey("links.id"))
|
||||||
link: Mapped["Link"] = relationship(back_populates="pointers")
|
link: Mapped["Link"] = relationship(back_populates="pointers")
|
||||||
timestamp: Mapped[datetime] = mapped_column(default=func.now())
|
timestamp: Mapped[datetime] = mapped_column(default=func.now())
|
||||||
|
|
|
@ -1,121 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
|
||||||
<meta name="description" content="The personal URL Shortener">
|
|
||||||
<meta name="author" content="">
|
|
||||||
|
|
||||||
<title>ShortenIt</title>
|
|
||||||
|
|
||||||
<!-- Bootstrap core CSS -->
|
|
||||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
|
|
||||||
|
|
||||||
<script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
|
|
||||||
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
|
|
||||||
|
|
||||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
|
|
||||||
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.4/clipboard.min.js"></script>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
|
|
||||||
var href = window.location.href;
|
|
||||||
|
|
||||||
$(function() {
|
|
||||||
$('#submitButton').click(function() {
|
|
||||||
$.ajax({
|
|
||||||
type: "POST",
|
|
||||||
url: "/shortenit",
|
|
||||||
data: JSON.stringify({'url' : $('#url-input').val(),
|
|
||||||
'timestamp': Date.now()}),
|
|
||||||
success: returnSuccess,
|
|
||||||
error: returnFailure,
|
|
||||||
dataType: 'json',
|
|
||||||
contentType: "application/json",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function returnSuccess(data, textStatus, jqXHR) {
|
|
||||||
var url = href.concat(data.url);
|
|
||||||
console.log(href)
|
|
||||||
if(data.url) {
|
|
||||||
document.getElementById("url-result").value = url;
|
|
||||||
} else {
|
|
||||||
document.getElementById("url-result").value = "The URL was too short and somehow got lost on the way, please try generating a new one.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function returnFailure(data, textStatus, jqXHR) {
|
|
||||||
document.getElementById("url-result").value = "Please enter a valid URL!";
|
|
||||||
}
|
|
||||||
|
|
||||||
window.onload=function() {
|
|
||||||
console.log(ClipboardJS.isSupported())
|
|
||||||
var clipboard = new ClipboardJS('.btn', {
|
|
||||||
container: document.getElementById('copy-button')
|
|
||||||
});
|
|
||||||
|
|
||||||
clipboard.on('success', function(e) {
|
|
||||||
console.info('Action:', e.action);
|
|
||||||
console.info('Text:', e.text);
|
|
||||||
console.info('Trigger:', e.trigger);
|
|
||||||
});
|
|
||||||
|
|
||||||
clipboard.on('error', function(e) {
|
|
||||||
console.error('Action:', e.action);
|
|
||||||
console.error('Trigger:', e.trigger);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<!-- Page Content -->
|
|
||||||
<div class="container">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-lg-12 text-center">
|
|
||||||
<h1 class="mt-5">Shorten It!</h1>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-lg-12 form-group">
|
|
||||||
<div class="form-row">
|
|
||||||
<div class="col-9">
|
|
||||||
<input type="text" class="form-control" name="url" id="url-input" placeholder="https://www.duckduckgo.com" />
|
|
||||||
</div>
|
|
||||||
<div class="col-3">
|
|
||||||
<button id="submitButton" type="button" class="btn btn-outline-primary">Shorten URL</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- <a href="#" id="url-result">Enter URL</a> -->
|
|
||||||
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-lg-12 form-group">
|
|
||||||
<div class="form-row">
|
|
||||||
<div class="col-9">
|
|
||||||
<input type="text" id="url-result" class="form-control" readonly>
|
|
||||||
</div>
|
|
||||||
<div class="col-3">
|
|
||||||
<div>
|
|
||||||
<button class="btn btn-outline-primary" data-clipboard-target="#url-result" data-clipboard-action="copy">Copy</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Bootstrap core JavaScript -->
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
|
@ -1,10 +1,12 @@
|
||||||
import logging
|
import logging
|
||||||
import os
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from flask_cors import CORS
|
from urllib.parse import urlunparse
|
||||||
|
|
||||||
import trafaret
|
import trafaret
|
||||||
from flask import Flask, abort, redirect, render_template, request
|
from flask import Flask, abort, redirect, request, send_from_directory
|
||||||
|
from flask_cors import CORS
|
||||||
|
|
||||||
|
from .common import check_file
|
||||||
|
|
||||||
|
|
||||||
class Web:
|
class Web:
|
||||||
|
@ -21,17 +23,29 @@ class Web:
|
||||||
self.app.run(host=self.host, port=self.port, debug=self.debug)
|
self.app.run(host=self.host, port=self.port, debug=self.debug)
|
||||||
|
|
||||||
def init(self):
|
def init(self):
|
||||||
|
server_config = self.handler.configuration.get("Server", None)
|
||||||
self.app = Flask(__name__)
|
self.app = Flask(__name__)
|
||||||
self.setup_routes()
|
self.setup_routes()
|
||||||
CORS(self.app)
|
if server_config and server_config.get("cors", False):
|
||||||
|
self.logger.debug("Enabling CORS...")
|
||||||
|
CORS(self.app)
|
||||||
|
|
||||||
def setup_routes(self):
|
def setup_routes(self):
|
||||||
self.app.add_url_rule("/", "/", self.handler.index, methods=["GET"])
|
|
||||||
self.app.add_url_rule(
|
self.app.add_url_rule(
|
||||||
"/shortenit", "/shortenit", self.handler.shortenit, methods=["POST"]
|
"/", "/", self.handler.index, methods=["GET"], defaults={"path": ""}
|
||||||
|
)
|
||||||
|
self.app.add_url_rule("/<path:path>", "/", self.handler.index, methods=["GET"])
|
||||||
|
self.app.add_url_rule(
|
||||||
|
"/static/css/<path:path>", "css", self.handler.css, methods=["GET"]
|
||||||
)
|
)
|
||||||
self.app.add_url_rule(
|
self.app.add_url_rule(
|
||||||
"/<identifier>", "/identifier", self.handler.short_redirect, methods=["GET"]
|
"/static/js/<path:path>", "js", self.handler.js, methods=["GET"]
|
||||||
|
)
|
||||||
|
self.app.add_url_rule(
|
||||||
|
"/api/v1/shorten", "shorten", self.handler.shortenit, methods=["POST"]
|
||||||
|
)
|
||||||
|
self.app.add_url_rule(
|
||||||
|
"/r/<identifier>", "redirect", self.handler.short_redirect, methods=["GET"]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -43,9 +57,22 @@ class SiteHandler:
|
||||||
self.shorten_url = shorten_url
|
self.shorten_url = shorten_url
|
||||||
self.lenghten_url = lenghten_url
|
self.lenghten_url = lenghten_url
|
||||||
self.shortenit_load_format = trafaret.Dict(
|
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):
|
||||||
|
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):
|
def shortenit(self):
|
||||||
data = request.get_json()
|
data = request.get_json()
|
||||||
try:
|
try:
|
||||||
|
@ -56,9 +83,12 @@ class SiteHandler:
|
||||||
self.logger.error(e)
|
self.logger.error(e)
|
||||||
abort(400)
|
abort(400)
|
||||||
try:
|
try:
|
||||||
short_url = self.shorten_url(
|
stub = self.shorten_url(
|
||||||
self.configuration, self.database, data["url"], data["timestamp"]
|
self.configuration.get("Shortener", None),
|
||||||
|
self.database,
|
||||||
|
data["url"],
|
||||||
)
|
)
|
||||||
|
short_url = self._get_url(stub)
|
||||||
except KeyError as e:
|
except KeyError as e:
|
||||||
self.logger.error(e)
|
self.logger.error(e)
|
||||||
abort(400)
|
abort(400)
|
||||||
|
@ -73,7 +103,29 @@ class SiteHandler:
|
||||||
abort(404)
|
abort(404)
|
||||||
return redirect(url)
|
return redirect(url)
|
||||||
|
|
||||||
def index(self):
|
def index(self, path):
|
||||||
return render_template("index.html")
|
if path != "":
|
||||||
|
return self._fetch_from_directory(path)
|
||||||
|
else:
|
||||||
|
return self._fetch_from_directory("index.html")
|
||||||
|
|
||||||
|
def css(self, path):
|
||||||
|
path = "static/css/" + path
|
||||||
|
return self._fetch_from_directory(path)
|
||||||
|
|
||||||
|
def js(self, path):
|
||||||
|
path = "static/js/" + path
|
||||||
|
return self._fetch_from_directory(path)
|
||||||
|
|
||||||
|
def _fetch_from_directory(self, path):
|
||||||
|
try:
|
||||||
|
project_root = Path(__file__).parent.parent
|
||||||
|
static_folder = (
|
||||||
|
f"{project_root}/" + self._get_server_config()["static_folder"]
|
||||||
|
)
|
||||||
|
if check_file(static_folder + "/" + path):
|
||||||
|
return send_from_directory(static_folder, path)
|
||||||
|
else:
|
||||||
|
abort(404)
|
||||||
|
except:
|
||||||
|
abort(500)
|
||||||
|
|
Loading…
Reference in a new issue