Skip to content

Instantly share code, notes, and snippets.

@roniemartinez roniemartinez/application.py Secret
Created Jan 13, 2019

Embed
What would you like to do?
Atom: A Simple URL shortener
#!/usr/bin/env python
# __author__ = "Ronie Martinez"
# __copyright__ = "Copyright 2018-2019, Ronie Martinez"
# __credits__ = ["Ronie Martinez"]
# __maintainer__ = "Ronie Martinez"
# __email__ = "ronie.martinez@easyaspy.org"
import binascii
import os
from urllib.parse import urlparse
from flask import Flask, request, url_for, render_template, redirect
from flask_wtf import FlaskForm
from hashids import Hashids
from sqlalchemy import Column, String, TIMESTAMP, text, create_engine
from sqlalchemy.dialects.mysql import BIGINT
from sqlalchemy.orm import sessionmaker
from wtforms import StringField, SubmitField
from wtforms.validators import URL, Length
from models import Base
class Atom(Base):
__tablename__ = 'atoms'
id = Column(BIGINT(unsigned=True), primary_key=True)
url = Column(String(2_000))
added = Column(TIMESTAMP, nullable=False, server_default=text('CURRENT_TIMESTAMP'))
class AtomForm(FlaskForm):
url = StringField('URL', validators=[URL(require_tld=True, message="Invalid URL"),
Length(max=2000, message="Maximum URL length is 2000")])
atomize = SubmitField('Atomize')
application = Flask(__name__)
application.config['SERVER_NAME'] = '<server_name.>'
application.config['WTF_CSRF_ENABLED '] = True
application.config['SECRET_KEY'] = binascii.hexlify(os.urandom(20))
with application.app_context():
engine = create_engine(f'mysql+cymysql://{os.getenv("DB_USER")}:{os.getenv("DB_PASSWORD")}@{os.getenv("DB_HOST")}:'
f'{os.getenv("DB_PORT")}/{os.getenv("DB_NAME")}', pool_recycle=7200, pool_pre_ping=True)
session_maker = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base.metadata.create_all(bind=engine)
@application.route('/', methods=['GET', 'POST'])
def index():
global session_maker
form = AtomForm()
atomized = None
if request.method == 'POST' and form.validate_on_submit():
if urlparse(form.url.data).netloc == urlparse(url_for('index', _external=True)).netloc:
form.errors['url'] = ['URLs from Atom (this site) are not allowed']
else:
database_session = session_maker()
try:
a = Atom(url=form.url.data)
database_session.add(a)
database_session.commit()
hash_id = Hashids(salt=os.getenv('ATOM_SALT')).encode(a.id)
atomized = url_for('get_url', hash_id=hash_id, _external=True, _scheme='https')
finally:
database_session.close()
form.url.data = ''
return render_template('atom.html', form=form, atomized=atomized)
@application.route('/<hash_id>')
def get_url(hash_id):
global session_maker
database_session = session_maker()
try:
atom_id = Hashids(salt=os.getenv('ATOM_SALT')).decode(hash_id)[0]
row = database_session.query(Atom).filter_by(id=atom_id).first() # type: Atom
if row:
return redirect(row.url)
raise LookupError
except (IndexError, LookupError):
return redirect(url_for('index'))
finally:
database_session.close()
{% if atomized %}
<input id="atomized" class="form-control" value="{{ atomized }}" readonly>
{% endif %}
<form method="POST" action="{{ url_for('index') }}" autocomplete="off">
{{ form.csrf_token }}
<div class="form-group has-feedback {{ 'has-error' if 'url' in form.errors else '' }}">
{{ form.url(class_='form-control' + (' is-invalid' if 'url' in form.errors else ''), placeholder='Enter URL') }}
<span class="glyphicon glyphicon-globe form-control-feedback"></span>
{% if 'url' in form.errors %}
<div>
<small class="text-danger">{{ form.errors['url'][0] }}</small>
</div>
{% endif %}
</div>
<div class="form-group has-feedback">
{{ form.atomize(class_='btn btn-primary btn-block btn-flat') }}
</div>
</form>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.