Added click tracking

This commit is contained in:
xemeds
2020-08-22 15:36:09 +03:00
parent 1ef3c1b154
commit e65f43e401
9 changed files with 140 additions and 10 deletions
+38 -4
View File
@@ -5,7 +5,7 @@ from tiny0.config import WEBSITE_DOMAIN
from tiny0 import db
from tiny0.models import URL
# Validates a URL
# Validates a url
def validate_URL(form, field):
# Make sure the url is not too short or long
if len(field.data) < 4 or len(field.data) > 2000:
@@ -64,11 +64,45 @@ def validate_token(form, field):
# Raise a ValidationError
raise ValidationError("Token already exists")
# Validates a short url
def validate_short_URL(form, field):
# Make sure the short url is not too short or long
if len(field.data) < (len(WEBSITE_DOMAIN) + 7) or len(field.data) > (len(WEBSITE_DOMAIN) + 25):
return
# If the start of the short url is not valid
if (not(field.data.lower().startswith(WEBSITE_DOMAIN + "/"))
and not(field.data.lower().startswith("http://" + WEBSITE_DOMAIN + "/"))
and not(field.data.lower().startswith("https://" + WEBSITE_DOMAIN + "/"))):
# Raise a ValidationError
raise ValidationError("Invalid short URL")
# Get the token of the short url
if field.data.lower().startswith(WEBSITE_DOMAIN + "/"):
token = field.data[len(WEBSITE_DOMAIN) + 1:]
elif field.data.lower().startswith("http://" + WEBSITE_DOMAIN + "/"):
token = field.data[len(WEBSITE_DOMAIN) + 8:]
elif field.data.lower().startswith("https://" + WEBSITE_DOMAIN + "/"):
token = field.data[len(WEBSITE_DOMAIN) + 9:]
# If the token of the short url does not exist in the database
if not db.session.query(db.session.query(URL).filter_by(token=token).exists()).scalar():
# Raise a ValidationError
raise ValidationError("That short URL does not exists")
# After all the validation is done set the forms url value as the token
field.data = token
class URLForm(FlaskForm):
url = StringField(validators=[DataRequired(),
Length(min=4, max=2000, message="Invalid URL length"),
validate_URL])
url = StringField(validators=[DataRequired(), Length(min=4, max=2000, message="Invalid URL length"), validate_URL])
token = StringField(validators=[Optional(), Length(min=6, max=16, message="Invalid token length"), validate_token])
submit = SubmitField("Shorten")
class TrackerForm(FlaskForm):
url = StringField(validators=[DataRequired(), Length(min=len(WEBSITE_DOMAIN) + 7, max=len(WEBSITE_DOMAIN) + 25, message="Invalid short URL"), validate_short_URL])
submit = SubmitField("Track")
+2 -1
View File
@@ -4,6 +4,7 @@ class URL(db.Model):
id = db.Column(db.Integer, primary_key=True)
token = db.Column(db.String(16), index=True, unique=True, nullable=False)
url = db.Column(db.String(2000), nullable=False)
clicks = db.Column(db.Integer, nullable=False, default=0)
def __repr__(self):
return f"'{self.id}' '{self.token}' '{self.url}'"
return f"'{self.id}' '{self.token}' '{self.url} '{self.clicks}'"
+25 -2
View File
@@ -1,6 +1,6 @@
from flask import render_template, redirect, url_for
from tiny0 import app, db
from tiny0.forms import URLForm
from tiny0.forms import URLForm, TrackerForm
from tiny0.models import URL
from tiny0.token import gen_valid_token
from tiny0.config import WEBSITE_DOMAIN
@@ -35,7 +35,7 @@ def index():
# Return the url page with the shortened url
return render_template("url.html", url=WEBSITE_DOMAIN + "/" + token)
# If the form was invalid or not submitted
# Else if the form was invalid or not submitted
else:
# Return the index page with the form
return render_template("index.html", form=form)
@@ -53,9 +53,32 @@ def short_url(token):
# Else if the query response contained data
else:
# Addd one to the clicks of the shortened url
query.clicks += 1
db.session.commit()
# Redirect to the url of the token
return redirect(query.url)
# Click Tracker route
@app.route("/tracker", methods=['GET', 'POST'])
def tracker():
# Create a instance of the form
form = TrackerForm()
# If the form was valid
if form.validate_on_submit():
# Get the clicks of the given token
clicks = URL.query.filter_by(token=form.url.data).first().clicks
# Return the clicks page with the clicks of that token
return render_template("clicks.html", clicks=clicks)
# Else if the form was invalid or not submitted
else:
# Return the tracker page with the form
return render_template("tracker.html", form=form)
# Donate route
@app.route("/donate")
def donate():
+37
View File
@@ -110,6 +110,43 @@ body {
margin-bottom: 2vh;
}
.click-tracker {
text-align: center;
margin-top: 5vh;
}
.click-tracker a:link {
color: #bb86fc;
text-decoration: none;
font-size: 25px;
font-weight: bold;
}
.click-tracker a:visited {
color: #bb86fc;
}
.click-tracker a:hover {
color: #7b59a5;
}
.clicks-list {
text-align: center;
margin: 30vh 0 0 0;
}
.clicks-number {
color: #bb86fc;
font-size: 125px;
font-weight: bold;
}
.clicks-text {
color: #bb86fc;
font-size: 25px;
font-weight: bold;
}
.error-message {
text-align: center;
color: #ffffff;
+11
View File
@@ -0,0 +1,11 @@
{% extends "layout.html" %}
{% block body %}
<ul class="clicks-list">
<li><p class="clicks-number">{{ clicks }}</p></li>
<li><p class="clicks-text">Click(s)</p></li>
</ul>
<div class="click-tracker">
<a href="{{ url_for('tracker') }}">Track Another</a>
</div>
{% endblock %}
+4 -1
View File
@@ -2,7 +2,7 @@
{% block body %}
<form method="POST" action="" class="url-form">
{% if form.url.errors or form.token.errors %}
{% if form.errors %}
<ul class="form-error-message">
{% for error in form.url.errors %}
<li>{{ error }}</li>
@@ -24,4 +24,7 @@
<li>{{ form.submit(class="button") }}</li>
</ul>
</form>
<div class="click-tracker">
<a href="{{ url_for('tracker') }}">Click Tracker</a>
</div>
{% endblock %}
+2 -2
View File
@@ -14,7 +14,7 @@
<div id="page-container">
<div id="content-wrap">
{% if form %}
{% if not form.url.errors and not form.token.errors %}
{% if not form.errors %}
<body onload="typeTitle()">
<div class="headers">
<a class="title" id="title" href="{{ url_for('index') }}"></a>
@@ -38,7 +38,7 @@
{% block body %}{% endblock %}
{% if form %}
{% if not form.url.errors and not form.token.errors %}
{% if not form.errors %}
<script>
var i = 0;
var title_text = "tiny0";
+18
View File
@@ -0,0 +1,18 @@
{% extends "layout.html" %}
{% block body %}
<form method="POST" action="" class="url-form">
{% if form.errors %}
<ul class="form-error-message">
{% for error in form.url.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
{{ form.hidden_tag() }}
<ul class='input-list'>
<li>{{ form.url(placeholder="Enter the short URL here", autofocus=true, class="url") }}</li>
<li>{{ form.submit(class="button") }}</li>
</ul>
</form>
{% endblock %}
+3
View File
@@ -7,4 +7,7 @@
<li><button onclick="copyURL()" class="button">Copy</button></li>
</ul>
</div>
<div class="click-tracker">
<a href="{{ url_for('tracker') }}">Click Tracker</a>
</div>
{% endblock %}