Commit b58f1dd2 authored by 132ikl's avatar 132ikl

Add web interface styling and configuration, fix existing long URL retrieval...

Add web interface styling and configuration, fix existing long URL retrieval and duplicate short URL checks
parent 513050e1
...@@ -26,4 +26,8 @@ allowed_chars: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_ ...@@ -26,4 +26,8 @@ allowed_chars: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_
# Amount of time in seconds to spend generating random short URLs until timeout # Amount of time in seconds to spend generating random short URLs until timeout
# Default: 5 # Default: 5
random_gen_timeout: 5 random_gen_timeout: 5
\ No newline at end of file
# Name shown on tab while on site and on page header
# Default: 'liteshort'
site_name: 'liteshort'
\ No newline at end of file
from flask import Flask, Response, request, current_app, g, send_from_directory from flask import Flask, request, current_app, g, render_template
import bcrypt import bcrypt
import random import random
import sqlite3 import sqlite3
...@@ -12,11 +12,11 @@ def load_config(): ...@@ -12,11 +12,11 @@ def load_config():
req_options = {'admin_username': 'admin', 'database_name': "urls", 'random_length': 4, req_options = {'admin_username': 'admin', 'database_name': "urls", 'random_length': 4,
'allowed_chars': 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_', 'allowed_chars': 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_',
'random_gen_timeout': 5 'random_gen_timeout': 5, 'site_name': 'liteshort'
} }
config_types = {'admin_username': str, 'database_name': str, 'random_length': int, config_types = {'admin_username': str, 'database_name': str, 'random_length': int,
'allowed_chars': str, 'random_gen_timeout': int} 'allowed_chars': str, 'random_gen_timeout': int, 'site_name': str}
for option in req_options.keys(): for option in req_options.keys():
if option not in new_config.keys(): # Make sure everything in req_options is set in config if option not in new_config.keys(): # Make sure everything in req_options is set in config
...@@ -45,19 +45,18 @@ def check_password(password, pass_config): ...@@ -45,19 +45,18 @@ def check_password(password, pass_config):
raise RuntimeError('This should never occur! Bailing...') raise RuntimeError('This should never occur! Bailing...')
def check_short_exist(database, short): def check_short_exist(short):
database.cursor().execute("SELECT long FROM urls WHERE short = ?", (short,)) query = query_db('SELECT long FROM urls WHERE short = ?', (short,))
result = database.cursor().fetchone() if query:
if database.cursor().fetchone(): return True
return result
return False return False
def check_long_exist(database, long): def check_long_exist(long):
database.cursor().execute("SELECT short FROM urls WHERE long = ?", (long,)) query = query_db('SELECT short FROM urls WHERE long = ?', (long,))
result = database.cursor().fetchone() for i in query:
if database.cursor().fetchone(): if i and (len(i['short']) <= current_app.config["random_length"]): # Checks if query if pre-existing URL is same as random length URL
return result return i['short']
return False return False
...@@ -77,6 +76,23 @@ def get_db(): ...@@ -77,6 +76,23 @@ def get_db():
return g.db return g.db
def query_db(query, args=(), one=False):
cur = get_db().execute(query, args)
rv = cur.fetchall()
cur.close()
return (rv[0] if rv else None) if one else rv
def response(rq, short, error_msg=None):
if 'json' in rq.form and rq.form['json']:
pass
else:
if short:
return render_template("main.html", result=(True, rq.base_url + short))
else:
return render_template("main.html", result=(False, error_msg))
config = load_config() config = load_config()
app = Flask(__name__) app = Flask(__name__)
...@@ -85,36 +101,36 @@ app.config.update(config) # Add loaded YAML config to Flask config ...@@ -85,36 +101,36 @@ app.config.update(config) # Add loaded YAML config to Flask config
@app.route('/') @app.route('/')
def main(): def main():
return send_from_directory('static', 'main.html') return render_template("main.html")
@app.route('/', methods=['POST']) @app.route('/', methods=['POST'])
def main_post(): def main_post():
if 'long' in request.form and request.form['long']: if 'long' in request.form and request.form['long']:
database = get_db()
if 'short' in request.form and request.form['short']: if 'short' in request.form and request.form['short']:
for char in request.form['short']: for char in request.form['short']:
if char not in current_app.config['allowed_chars']: if char not in current_app.config['allowed_chars']:
return Response('Character ' + char + ' not allowed in short URL.', status=200) return response(request, None, 'Character ' + char + ' not allowed in short URL.')
short = request.form['short'] short = request.form['short']
else: else:
timeout = time.time() + current_app.config['random_gen_timeout'] timeout = time.time() + current_app.config['random_gen_timeout']
while True: while True:
if time.time() >= timeout: if time.time() >= timeout:
return Response('Timeout while generating random short URL.', status=200) return response(request, None, 'Timeout while generating random short URL.')
short = generate_short() short = generate_short()
if not check_short_exist(database, short): if not check_short_exist(short):
break break
short_exists = check_short_exist(database, short) short_exists = check_short_exist(short)
long_exists = check_long_exist(database, request.form['long']) long_exists = check_long_exist(request.form['long'])
if long_exists and 'short' not in request.form: if long_exists and not ('short' in request.form and request.form['short']):
return request.base_url + long_exists return response(request, long_exists)
if short_exists: if short_exists:
return Response('Short URL already exists.', status=200) return response(request, None, "Short URL already exists.")
database = get_db()
database.cursor().execute("INSERT INTO urls (long,short) VALUES (?,?)", (request.form['long'], short)) database.cursor().execute("INSERT INTO urls (long,short) VALUES (?,?)", (request.form['long'], short))
database.commit() database.commit()
database.close() database.close()
return "Your shortened URL is available at " + request.base_url + short return response(request, short)
else: else:
return "Long URL required!" return "Long URL required!"
......
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>liteshort</title>
</head>
<body>
<form>
Long URL:
<br>
<input name="long" type="url">
<br>
Short URL:
<br>
<input name="short" type="text">
<br> <!-- TODO: Use CSS to do linebreaks -->
<input type="submit" value="Shorten" formmethod="post">
</form>
</body>
</html>
\ No newline at end of file
div.form {
margin-top: 5%;
text-align: center;
}
input {
margin: auto;
}
div.success {
display: inline-block;
font-family: Open Sans;
border-radius: 2vh;
padding: 2vh;
color: #62ad2c;
background-color: #E9FFD9;
border: 1px solid #62ad2c;
}
div.error {
display: inline-block;
font-family: Open Sans;
border-radius: 2vh;
padding: 2vh;
color: #a86464;
background-color: #FCE9E9;
border: 1px solid #a86464;
}
body {
text-align: center
}
div.success > a:link {
color: #62ad2c;
}
div.success > a:visited {
color: #507c52;
}
h2 {
font-weight: normal;
font-family: Open Sans;
}
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ config.site_name }}</title>
<link rel="stylesheet" href="https://unpkg.com/purecss@1.0.0/build/pure-min.css">
<link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet">
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div class="form">
<h2>{{ config.site_name }}</h2>
<form class="pure-form">
<input name="long" type="url" placeholder="Long URL">
<p>
<input name="short" type="text" placeholder="Custom link (optional)">
<p>
<button type="submit" class="pure-button pure-button-primary" formmethod="post">Shorten</button>
</form>
</div>
{% if result is defined and result[0] %}
<div class="success">
✓ Shortlink successfully generated! Available at <a href="{{ result[1] }}">{{ result[1] }}</a>
</div>
{% elif result is defined and not result[0] %}
<div class="error">
✖ Shortlink failed to generate! {{ result[1] }}
</div>
{% endif %}
</body>
</html>
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment