mirror of
https://git.ikl.sh/132ikl/liteshort.git
synced 2023-08-10 21:13:04 +03:00
Add web interface styling and configuration, fix existing long URL retrieval and duplicate short URL checks
This commit is contained in:
parent
513050e131
commit
b58f1dd273
@ -27,3 +27,7 @@ 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
|
||||||
|
|
||||||
|
# Name shown on tab while on site and on page header
|
||||||
|
# Default: 'liteshort'
|
||||||
|
site_name: 'liteshort'
|
64
liteshort.py
64
liteshort.py
@ -1,4 +1,4 @@
|
|||||||
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():
|
|||||||
|
|
||||||
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):
|
|||||||
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():
|
|||||||
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
|
|||||||
|
|
||||||
@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!"
|
||||||
|
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
<!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>
|
|
46
static/styles.css
Normal file
46
static/styles.css
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
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;
|
||||||
|
}
|
32
templates/main.html
Normal file
32
templates/main.html
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<!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>
|
Loading…
Reference in New Issue
Block a user