38
loading...
This website collects cookies to deliver better user experience
$ source env/bin/activate
pip install Flask
pip install Flask-SQLAlchemy
pip install python-dotenv
.flaskenv
to mention the directory of our appFLASK_APP=url_shortener
.env
to set admin username, password and database url as environment variables.ADMIN_USERNAME=admin
ADMIN_PASSWORD=password
DATABASE_URL=sqlite:///db.sqlite3
mkdir url_shortener
create_app()
function and have the settings file. from flask import Flask
from .extensions import db
from .routes import short
def create_app(config_file='settings.py'):
app = Flask(__name__)
app.config.from_pyfile(config_file)
db.init_app(app)
app.register_blueprint(short)
return app
.env
file.import os
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL')
SQLALCHEMY_TRACK_MODIFICATIONS = False
ADMIN_USERNAME = os.environ.get('ADMIN_USERNAME')
ADMIN_PASSWORD = os.environ.get('ADMIN_PASSWORD')
extensions.py
file. from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
model.py
file. import string
from datetime import datetime
from random import choices
from .extensions import db
class Link(db.Model):
id = db.Column(db.Integer, primary_key=True)
original_url = db.Column(db.String(512))
short_url = db.Column(db.String(3), unique=True)
visits = db.Column(db.Integer, default=0)
date_created = db.Column(db.DateTime, default=datetime.now)
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.short_url = self.generate_short_link()
def generate_short_link(self):
characters = string.digits + string.ascii_letters
short_url = ''.join(choices(characters, k=7))
link = self.query.filter_by(short_url=short_url).first()
if link:
return self.generate_short_link()
return short_url
Link
in which we will have the following columns: generate_short_link
where we will get a random 7 letters string from Upper case, Lower case or Numbers. For this we have used choices()
from random
library. We will check if the generated string exists in our database and if it exits we will run again to get unique string. routes.py
file. Main motto of this app is for personal use. So, we will be using basic authentication. We will be having check_auth()
function which will be comparing the username and password with the ones given as environment variables. authenticate()
will be saying that authorization is required. In requires_auth()
it will ask for authorization if its not authorized else it will check for authorisation with check_auth()
then it will return the function keyword arguments. from functools import wraps
from flask import request, Response, current_app
def check_auth(username, password):
#This function is called to check if a username password combination is valid.
return username == current_app.config['ADMIN_USERNAME'] \
and password == current_app.config['ADMIN_PASSWORD']
def authenticate():
#Sends a 401 response that enables basic auth
return Response(
'Could not verify your access level for that URL.\n'
'You have to login with proper credentials', 401,
{'WWW-Authenticate': 'Basic realm="Login Required"'})
def requires_auth(f):
@wraps(f)
def decorated(*args, **kwargs):
auth = request.authorization
if not auth or not check_auth(auth.username, auth.password):
return authenticate()
return f(*args, **kwargs)
return decorated
routes.py
Blueprint
- short
. Now we need to create some endpoints. /short_url
will be used to redirect the url. /
will be used for index. /add_link
will be used to add the url and will be using POST
method. /stats
will be used to display the statistics. errorhandler(404)
will be shown when the user goes out with a random link. html
files, which we will be trying to keep simple - have used Bulma to do it so. mkdir templates
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>URL Shortener</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.5/css/bulma.min.css">
<link href='https://fonts.googleapis.com/css?family=Tangerine' rel='stylesheet'>
<script defer src="https://use.fontawesome.com/releases/v5.3.1/js/all.js"></script>
<style>
.center {
padding: 30px;
border: 3px blue;
text-align: center;
}
h1 {
font-family: 'Tangerine', serif;
font-size: 50px;
text-align: center;
}
h2 {
font-size: 37px;
text-align: left;
}
</style>
</head>
<body>
<h1 style="color:black;" allign="center"><b>Seven URL Shortener</b></h1>
<div class="tabs is-centered" >
<ul>
<li class="is-active">
<a>
<span class="icon is-small"><i class="fas fa-home" aria-hidden="true"></i></span>
<span onclick="window.location='/'">Home</span>
</a>
</li>
<li>
<a>
<span class="icon is-small"><i class="far fa-file-alt" aria-hidden="true"></i></span>
<span onclick="window.location='/stats'">statistics</span>
</a>
</li>
</ul>
</div>
<div class="center">
<div>
<img src="https://github.com/rith-vik-7/trash/blob/main/short.jpg?raw=true" alt="short" width="700" height="433">
</div>
<section class="section">
<div class="container">
<form method="POST" action="{{ url_for('short.add_link') }}">
<div class="field">
<div class="control">
<input class="input" type="text" placeholder="Shorten your link" name="original_url">
</div>
</div>
<div class="control">
<button type="submit" style="float: right;" class="button is-info">Shorten</button>
</div>
</form>
</div>
</section>
</div>
</body>
<script>
document.addEventListener('keydown', function() {
if (event.keyCode == 123) {
alert("This function has been disabled to prevent you from stealing my code!");
return false;
} else if (event.ctrlKey && event.shiftKey && event.keyCode == 73) {
alert("This function has been disabled to prevent you from stealing my code!");
return false;
} else if (event.ctrlKey && event.keyCode == 85) {
alert("This function has been disabled to prevent you from stealing my code!");
return false;
}
}, false);
if (document.addEventListener) {
document.addEventListener('contextmenu', function(e) {
alert("This function has been disabled to prevent you from stealing my code!");
e.preventDefault();
}, false);
} else {
document.attachEvent('oncontextmenu', function() {
alert("This function has been disabled to prevent you from stealing my code!");
window.event.returnValue = false;
});
}
</script>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>URL Shortener</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.5/css/bulma.min.css">
<link href='https://fonts.googleapis.com/css?family=Tangerine' rel='stylesheet'>
<script defer src="https://use.fontawesome.com/releases/v5.3.1/js/all.js"></script>
<style>
.center {
padding: 30px;
border: 3px blue;
text-align: center;
}
h1 {
font-family: 'Tangerine', serif;
font-size: 50px;
text-align: center;
}
h2 {
font-size: 37px;
text-align: left;
}
</style>
</head>
<body>
<h1 style="color:black;" allign="center"><b>Seven URL Shortener</b></h1>
<div class="tabs is-centered">
<ul>
<li class="is-active">
<a>
<span class="icon is-small"><i class="fas fa-home" aria-hidden="true"></i></span>
<span onclick="window.location='/'">Home</span>
</a>
</li>
<li>
<a>
<span class="icon is-small"><i class="far fa-file-alt" aria-hidden="true"></i></span>
<span onclick="window.location='/stats'">statistics</span>
</a>
</li>
</ul>
</div>
<div class="center">
<div>
<img src="https://github.com/rith-vik-7/trash/blob/main/short.jpg?raw=true" alt="short" width="700" height="433">
</div>
<div class="container">
<div class="field">
<div class="control">
<input class="input" type="text" name="original_url" value="{{ original_url }}">
</div>
</div>
<div class="field">
<label class="label"><b>Seven</b> Shortened URL</label>
<div class="control">
<input class="input" type="text" name="original_url"
value="{{ url_for('short.redirect_to_url', short_url=new_link, _external=True) }}">
</div>
</div>
</div>
</section>
</div>
</body>
<script>
document.addEventListener('keydown', function() {
if (event.keyCode == 123) {
alert("This function has been disabled to prevent you from stealing my code!");
return false;
} else if (event.ctrlKey && event.shiftKey && event.keyCode == 73) {
alert("This function has been disabled to prevent you from stealing my code!");
return false;
} else if (event.ctrlKey && event.keyCode == 85) {
alert("This function has been disabled to prevent you from stealing my code!");
return false;
}
}, false);
if (document.addEventListener) {
document.addEventListener('contextmenu', function(e) {
alert("This function has been disabled to prevent you from stealing my code!");
e.preventDefault();
}, false);
} else {
document.attachEvent('oncontextmenu', function() {
alert("This function has been disabled to prevent you from stealing my code!");
window.event.returnValue = false;
});
}
</script>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>URL Shortener</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.5/css/bulma.min.css">
<link href='https://fonts.googleapis.com/css?family=Tangerine' rel='stylesheet'>
<script defer src="https://use.fontawesome.com/releases/v5.3.1/js/all.js"></script>
<style>
.center {
padding: 30px;
border: 3px blue;
text-align: center;
}
h1 {
font-family: 'Tangerine', serif;
font-size: 50px;
text-align: center;
}
h2 {
font-size: 37px;
text-align: left;
}
</style>
</head>
<body>
<h1 style="color:black;" allign="center"><b>Seven URL Shortener</b></h1>
<div class="tabs is-centered">
<ul>
<li>
<a>
<span class="icon is-small"><i class="fas fa-home" aria-hidden="true"></i></span>
<span onclick="window.location='/'">Home</span>
</a>
</li>
<li>
<a>
<span class="icon is-small"><i class="fas fa-link" aria-hidden="true"></i></span>
<span>Link</span>
</a>
</li>
<li class="is-active">
<a>
<span class="icon is-small"><i class="far fa-file-alt" aria-hidden="true"></i></span>
<span onclick="window.location='/stats'">statistics</span>
</a>
</li>
</ul>
</div>
<section class="section">
<div class="container">
<table class="table is-bordered is-striped is-narrow is-hoverable">
<thead>
<tr>
<th>Original URL</th>
<th>Short URL</th>
<th>Visits</th>
</tr>
</thead>
<tbody>
{% for link in links %}
<tr>
<td>{{ link.original_url }}</td>
<td>{{ url_for('short.redirect_to_url', short_url=link.short_url, _external=True) }}</td>
<td>{{ link.visits }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</section>
</body>
<script>
document.addEventListener('keydown', function() {
if (event.keyCode == 123) {
alert("This function has been disabled to prevent you from stealing my code!");
return false;
} else if (event.ctrlKey && event.shiftKey && event.keyCode == 73) {
alert("This function has been disabled to prevent you from stealing my code!");
return false;
} else if (event.ctrlKey && event.keyCode == 85) {
alert("This function has been disabled to prevent you from stealing my code!");
return false;
}
}, false);
if (document.addEventListener) {
document.addEventListener('contextmenu', function(e) {
alert("This function has been disabled to prevent you from stealing my code!");
e.preventDefault();
}, false);
} else {
document.attachEvent('oncontextmenu', function() {
alert("This function has been disabled to prevent you from stealing my code!");
window.event.returnValue = false;
});
}
</script>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>404 ERROR</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.5/css/bulma.min.css">
<script defer src="https://use.fontawesome.com/releases/v5.3.1/js/all.js"></script>
<body style="background-color:#192643;">
<section class="section">
<div class="container">
<img src="https://github.com/rith-vik-7/trash/blob/main/404.gif?raw=true" alt="Trulli" width="1000" height="900">
</div>
</section>
</body>
<script>
document.addEventListener('keydown', function() {
if (event.keyCode == 123) {
alert("This function has been disabled to prevent you from stealing my code!");
return false;
} else if (event.ctrlKey && event.shiftKey && event.keyCode == 73) {
alert("This function has been disabled to prevent you from stealing my code!");
return false;
} else if (event.ctrlKey && event.keyCode == 85) {
alert("This function has been disabled to prevent you from stealing my code!");
return false;
}
}, false);
if (document.addEventListener) {
document.addEventListener('contextmenu', function(e) {
alert("This function has been disabled to prevent you from stealing my code!");
e.preventDefault();
}, false);
} else {
document.attachEvent('oncontextmenu', function() {
alert("This function has been disabled to prevent you from stealing my code!");
window.event.returnValue = false;
});
}
</script>
</html>
add_link()
method to get the short url. Then, we will call render template that link is added and we will display the generated url by passing the generated short url and original url. short_url()
we will be using redirect()
function from flask to redirect short url to original url and get the counts of visits by using a counter which increments whenever the short url is called to redirect the original url. If the short url is not found in the database it will be redirected to 404 error.stats
we will redirect the visit counts along with original and short url to the rendered template. from flask import Blueprint, render_template, request, redirect
from .extensions import db
from .models import Link
from .auth import requires_auth
short = Blueprint('short', __name__)
@short.route('/<short_url>')
def redirect_to_url(short_url):
link = Link.query.filter_by(short_url=short_url).first_or_404()
link.visits = link.visits + 1
db.session.commit()
return redirect(link.original_url)
@short.route('/')
@requires_auth
def index():
return render_template('index.html')
@short.route('/add_link', methods=['POST'])
@requires_auth
def add_link():
original_url = request.form['original_url']
link = Link(original_url=original_url)
db.session.add(link)
db.session.commit()
return render_template('link_added.html',
new_link=link.short_url, original_url=link.original_url)
@short.route('/stats')
@requires_auth
def stats():
links = Link.query.all()
return render_template('stats.html', links=links)
@short.errorhandler(404)
def page_not_found(e):
return render_template('404.html'), 404
register_blueprint()
to __init__.py
url_shortener/settings.py
import os
SQLALCHEMY_DATABASE_URI = 'sqlite:///db.sqlite3' #os.environ.get('DATABASE_URL')
SQLALCHEMY_TRACK_MODIFICATIONS = False
ADMIN_USERNAME = os.environ.get('ADMIN_USERNAME')
ADMIN_PASSWORD = os.environ.get('ADMIN_PASSWORD')
python3
> from url shortener import create_ app
> from url shortener.extensions import db
> from url shortener.models import Link
> db.create_all (app=create_app())
db.sqlite3
we can change the SQLALCHEMY_DATABASE_URI
back as before. sqlite3 db.sqlite3
sqlite> .tables
link
sqlite> .exit
flask run
username: admin
password: password