Compare commits
11 Commits
a3b7ff3f9f
...
main
Author | SHA1 | Date | |
---|---|---|---|
10aeabdb83
|
|||
5604fac1b2
|
|||
89e802aa57
|
|||
06af95ce57
|
|||
ba69c2a97f
|
|||
ff088a6a24
|
|||
4d0869ddf7
|
|||
a872c70e93
|
|||
|
20db73836c | ||
05bc3112d6 | |||
|
ee1c5a43d5 |
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
__pycacahe__/*
|
||||
freeriders/__pycacahe__/*
|
||||
instance/
|
@@ -7,3 +7,4 @@ Web app for tracking current ticket numbers
|
||||
- keep all ticket numbers and timestamps in SQL table "tickets"
|
||||
- display last ticket number
|
||||
- don't allow tickets that are out of probable ticket number range
|
||||
- if last submited ticket is timestamped more then 90 minutes ago, try to predict the next number
|
||||
|
21
freeriders/functions.py
Normal file
21
freeriders/functions.py
Normal file
@@ -0,0 +1,21 @@
|
||||
import time
|
||||
import datetime
|
||||
|
||||
def datetounix(day, month, year, hour, minute, second):
|
||||
seconds = datetime.datetime(year, month, day, hour, minute, second).timestamp()
|
||||
return int(seconds)
|
||||
|
||||
def formatprefix2(number):
|
||||
return "{:02d}".format(number)
|
||||
|
||||
def formatprefix10(number):
|
||||
return "{:010d}".format(number)
|
||||
|
||||
def predict(timestamp):
|
||||
base_ticket = 7157662
|
||||
base_timestamp = 1695887564
|
||||
step = 0.688
|
||||
|
||||
ticket = base_ticket + (timestamp - base_timestamp) * step
|
||||
return int(ticket)
|
||||
|
@@ -1,14 +1,26 @@
|
||||
from flask import render_template, request, redirect
|
||||
from freeriders import app, db
|
||||
from freeriders.models import Ticket
|
||||
from freeriders.functions import formatprefix2,formatprefix10, predict
|
||||
from freeriders.models import Tickets
|
||||
from datetime import datetime
|
||||
import time
|
||||
|
||||
@app.route('/sms', methods=['GET'])
|
||||
def sms():
|
||||
if request.method == 'GET':
|
||||
timenow = int(time.time())
|
||||
|
||||
try:
|
||||
lastticket = Ticket.query.order_by(Ticket.timestamp.desc()).first()
|
||||
return render_template('sms.html', ticket = lastticket)
|
||||
lastticket = Tickets.query.order_by(Tickets.timestamp.desc()).first()
|
||||
|
||||
if lastticket.timestamp < timenow - (90 * 60):
|
||||
lastticket = formatprefix10(predict(timenow))
|
||||
else:
|
||||
lastticket = formatprefix10(lastticket.ticket)
|
||||
date = datetime.now()
|
||||
datenow = f'{formatprefix2(date.day)}.{formatprefix2(date.month)}.{date.year}'
|
||||
timenow = f'{formatprefix2(date.hour)}:{formatprefix2(date.minute)}:{formatprefix2(date.second)}'
|
||||
return render_template('sms.html', ticket = lastticket, date = datenow, time = timenow)
|
||||
except:
|
||||
return 'Error retriving last ticket'
|
||||
else:
|
||||
@@ -16,14 +28,22 @@ def sms():
|
||||
|
||||
@app.route('/submit', methods=['POST', 'GET'])
|
||||
def submit():
|
||||
PREDICTTIMERANGE = 60 * 60 * 24
|
||||
if request.method == 'GET':
|
||||
return render_template('submit.html')
|
||||
elif request.method == 'POST':
|
||||
timenow = int(time.time())
|
||||
ticket_input = request.form['ticket']
|
||||
|
||||
if ticket_input.isdigit() and len(ticket_input) == 10:
|
||||
ticket = Ticket(ticket = int(ticket_input), timestamp = timenow)
|
||||
if ticket_input.isdigit() and len(ticket_input) == 10 :
|
||||
if int(ticket_input) < predict(timenow + PREDICTTIMERANGE ) and int(ticket_input) > predict(timenow - PREDICTTIMERANGE ) :
|
||||
ticket = Tickets(ticket = int(ticket_input), timestamp = timenow)
|
||||
else:
|
||||
print(int(ticket_input))
|
||||
print(predict(timenow - PREDICTTIMERANGE))
|
||||
print(predict(timenow + PREDICTTIMERANGE))
|
||||
print(predict(timenow))
|
||||
return 'Ticket number is in unexpected range.'
|
||||
else:
|
||||
return 'Ticket format is wrong. Only 10 digits allowed.'
|
||||
|
||||
|
80
freeriders/static/style.css
Normal file
80
freeriders/static/style.css
Normal file
@@ -0,0 +1,80 @@
|
||||
:root {
|
||||
--border-radus: 1rem;
|
||||
--background: #F9F9F9;
|
||||
--header-background: #EEE;
|
||||
--header-height: 3rem;
|
||||
--input-bar-height: 3rem;
|
||||
}
|
||||
|
||||
body{
|
||||
background: var(--background);
|
||||
font-family: sans-serif;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-self: flex-start;
|
||||
gap: 1rem;
|
||||
margin: 0 auto;
|
||||
padding: 2rem 0.5rem;
|
||||
height: calc(100vh - var(--header-height) - var(--input-bar-height));
|
||||
overflow-y: scroll;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
header {
|
||||
background-color: var(--header-background);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding: 0 1rem;
|
||||
gap: 1rem;
|
||||
font-weight: bold;
|
||||
width: 100vw;
|
||||
height: var(--header-height);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
footer {
|
||||
width: 100vw;
|
||||
height: var(--input-bar-height);
|
||||
background-color: var(--background);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding: 0 1rem;
|
||||
box-sizing: border-box;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.request {
|
||||
background-color: #DFD;
|
||||
border-radius: var(--border-radus);
|
||||
padding: 0.5rem 1rem;
|
||||
align-self: flex-end;
|
||||
max-width: 80%;
|
||||
}
|
||||
|
||||
.ticket {
|
||||
background-color: #DDF;
|
||||
max-width: 80%;
|
||||
border-radius: var(--border-radus);
|
||||
padding: 0.5rem 1rem;
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
.date {
|
||||
align-self: center;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.textbox{
|
||||
background-color: var(--header-background);
|
||||
width: 80%;
|
||||
height: 1rem;
|
||||
padding: 0.2rem;
|
||||
border-radius: 2rem;
|
||||
}
|
@@ -1,14 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="/styles/style.css">
|
||||
<link rel="shortcut icon" href="/img/favicon.ico" type="image/x-icon">
|
||||
<title>Ticket tracking</title>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
35
freeriders/templates/sms.html
Normal file
35
freeriders/templates/sms.html
Normal file
@@ -0,0 +1,35 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Karta</title>
|
||||
<link rel="stylesheet" href="/static/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<div>x</div>
|
||||
<div>9011</div>
|
||||
<div class="rightAligner"></div>
|
||||
</header>
|
||||
<main>
|
||||
<section class='request'>
|
||||
A90
|
||||
</section>
|
||||
<section class='ticket'>
|
||||
U Beogradu, za broj telefona ste kupili
|
||||
VREMENSKU KARTU OD 90 MINUTA U ZONI A po
|
||||
ceni od 50 din + osnovna cena poruke,
|
||||
koja vazi do {{ date }}, {{ time }}.
|
||||
Karta broj: {{ ticket }}.
|
||||
Placanjem operateru izmirujete dugovanja
|
||||
za ovu kartu prema JKP Naplata prevozne
|
||||
usluge Beograd. Sacuvajte ovu poruku.
|
||||
</section>
|
||||
</main>
|
||||
<footer>
|
||||
<div class="textbox"></div>
|
||||
<div>x</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
18
freeriders/templates/submit.html
Normal file
18
freeriders/templates/submit.html
Normal file
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Submit</title>
|
||||
<link rel="stylesheet" href="/static/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<form action="/submit" method="POST">
|
||||
<label for="ticket">ticket</label>
|
||||
<input type="text" name="ticket" id="ticket" placeholder="1234567890" required>
|
||||
<button> Submit </button>
|
||||
</form>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
Reference in New Issue
Block a user