First Commit
This commit is contained in:
commit
12e5e43f5c
9 changed files with 638 additions and 0 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
__pycache__
|
||||
*.pyc
|
||||
database.db
|
6
Dockerfile
Normal file
6
Dockerfile
Normal file
|
@ -0,0 +1,6 @@
|
|||
FROM python:3.7.3
|
||||
|
||||
COPY ./ ./
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
CMD [ "python", "./server.py" ]
|
2
requirements.txt
Normal file
2
requirements.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
freenet-funk-api==0.1.4
|
||||
Flask==1.1.0
|
332
server.py
Normal file
332
server.py
Normal file
|
@ -0,0 +1,332 @@
|
|||
import sqlite3
|
||||
from flask import g
|
||||
from flask import Flask
|
||||
app = Flask(__name__)
|
||||
from functools import wraps
|
||||
from flask import request, Response
|
||||
from flask import render_template, redirect
|
||||
from funkapi import FunkAPI
|
||||
import json
|
||||
import time
|
||||
import datetime
|
||||
from dateutil.relativedelta import relativedelta
|
||||
import os
|
||||
|
||||
|
||||
DATABASE = os.getenv("FUNK_DATABASE", 'database.db')
|
||||
USERNAME = os.getenv("FUNK_USER", 'admin')
|
||||
PASSWORD = os.getenv("FUNK_PASS", 'geheim')
|
||||
ENABLED_AUTH = os.getenv("FUNK_AUTH", False)
|
||||
|
||||
#Helper
|
||||
def get_db():
|
||||
db = getattr(g, '_database', None)
|
||||
if db is None:
|
||||
db = g._database = sqlite3.connect(DATABASE)
|
||||
return db
|
||||
|
||||
def check_auth(username, password):
|
||||
"""This function is called to check if a username /
|
||||
password combination is valid.
|
||||
"""
|
||||
return username == USERNAME and password == 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):
|
||||
if not ENABLED_AUTH:
|
||||
return f(*args, **kwargs)
|
||||
auth = request.authorization
|
||||
if not auth or not check_auth(auth.username, auth.password):
|
||||
return authenticate()
|
||||
return f(*args, **kwargs)
|
||||
return decorated
|
||||
|
||||
# Functions
|
||||
def function_updateAccount(number):
|
||||
cur = get_db().cursor()
|
||||
cur.execute("SELECT mail, password FROM accounts WHERE `number` = '%s'" % (number))
|
||||
res = cur.fetchone()
|
||||
api = FunkAPI(res[0], res[1])
|
||||
|
||||
plan = api.getCurrentPlan()["productServiceInfo"]["marketingInfo"]["name"]
|
||||
usage = api.getData()["data"]["me"]["customerProducts"][0]["mobileNumbers"][0]["usage"]["usedDataPercentage"]
|
||||
|
||||
cur.execute("INSERT INTO updates VALUES (%s, %s, '%s', '%s')" % (
|
||||
number,
|
||||
int(time.time()),
|
||||
plan,
|
||||
usage
|
||||
))
|
||||
|
||||
get_db().commit()
|
||||
|
||||
def function_speacialDays(number):
|
||||
cur = get_db().cursor()
|
||||
cur.execute("SELECT day, month, year, plan FROM special WHERE number = %s ORDER BY year, month, day" % number)
|
||||
res = cur.fetchall()
|
||||
days = []
|
||||
for r in res:
|
||||
day = {}
|
||||
day["day"] = str(r[0])+"."+str(r[1])+"."+str(r[2])
|
||||
day["plan"] = r[3]
|
||||
days.append(day)
|
||||
return days
|
||||
|
||||
|
||||
|
||||
def function_getAccounts(includePassword = False):
|
||||
cur = get_db().cursor()
|
||||
cur.execute("SELECT number, mail, password, owner, defaultPlan FROM accounts")
|
||||
res = cur.fetchall()
|
||||
accounts = []
|
||||
for accountData in res:
|
||||
lastUpdate = cur.execute("SELECT updateTime, plan, dataUsed FROM updates WHERE number = '%s' ORDER BY updateTime DESC LIMIT 1" % (accountData[0])).fetchone()
|
||||
account = {}
|
||||
account["number"] = accountData[0]
|
||||
account["mail"] = accountData[1]
|
||||
if includePassword:
|
||||
account["password"] = accountData[2]
|
||||
account["owner"] = accountData[3]
|
||||
account["defaultPlan"] = accountData[4]
|
||||
account["currentPlan"] = lastUpdate[1]
|
||||
account["dataUsed"] = lastUpdate[2]
|
||||
account["lastUpdate"] = lastUpdate[0]
|
||||
accounts.append(account)
|
||||
|
||||
return accounts
|
||||
|
||||
def function_getAccount(number, includePassword = False):
|
||||
cur = get_db().cursor()
|
||||
cur.execute("SELECT number, mail, password, owner, defaultPlan FROM accounts WHERE number = %s" % (number))
|
||||
accountData = cur.fetchone()
|
||||
lastUpdate = cur.execute("SELECT updateTime, plan, dataUsed FROM updates WHERE number = '%s' ORDER BY updateTime DESC LIMIT 1" % (accountData[0])).fetchone()
|
||||
account = {}
|
||||
account["number"] = accountData[0]
|
||||
account["mail"] = accountData[1]
|
||||
if includePassword:
|
||||
account["password"] = accountData[2]
|
||||
account["owner"] = accountData[3]
|
||||
account["defaultPlan"] = accountData[4]
|
||||
account["currentPlan"] = lastUpdate[1]
|
||||
account["dataUsed"] = lastUpdate[2]
|
||||
account["lastUpdate"] = lastUpdate[0]
|
||||
return account
|
||||
|
||||
def function_getPlanForDay(number, year, month, day):
|
||||
cur = get_db().cursor()
|
||||
dayPlan = cur.execute("SELECT plan FROM special WHERE number = %s AND day = %s AND month = %s AND year = %s" % (number, day, month, year)).fetchone()
|
||||
if dayPlan:
|
||||
return dayPlan[0]
|
||||
else:
|
||||
defaultPlan = cur.execute("SELECT defaultPlan FROM accounts WHERE number = %s" % (number)).fetchone()
|
||||
return defaultPlan[0]
|
||||
|
||||
@app.route("/updateAll")
|
||||
@requires_auth
|
||||
def function_updateAccountsAtFunk():
|
||||
cur = get_db().cursor()
|
||||
today = datetime.datetime.now()
|
||||
done = cur.execute("SELECT count(*) FROM run_actions WHERE year = %s AND month = %s AND day = %s" % (today.year, today.month, today.day)).fetchone()
|
||||
|
||||
if done[0] == 0:
|
||||
numbers = cur.execute("SELECT number FROM accounts").fetchall()
|
||||
tomorrow = datetime.date.today() + datetime.timedelta(days=1)
|
||||
|
||||
for number in numbers:
|
||||
print("Update Account: "+str(number[0]))
|
||||
#function_updateAccount(number[0])
|
||||
account = function_getAccount(number[0], True)
|
||||
print(account)
|
||||
nextPlan = function_getPlanForDay(number[0], tomorrow.year, tomorrow.month, tomorrow.day)
|
||||
if account["currentPlan"] == nextPlan:
|
||||
print("Plan match, nothing to do")
|
||||
else:
|
||||
api = FunkAPI(account["mail"], account["password"])
|
||||
if nextPlan == "1 GB":
|
||||
api.order1GBPlan()
|
||||
elif nextPlan == "unlimited":
|
||||
api.orderUnlimitedPlan()
|
||||
elif nextPlan == "Break":
|
||||
api.startPause()
|
||||
else:
|
||||
print("SOMETHING GO WRONG")
|
||||
|
||||
cur.execute("INSERT INTO run_actions VALUES (%s, %s, %s) " % (today.year, today.month, today.day))
|
||||
get_db().commit()
|
||||
|
||||
return "OK";
|
||||
|
||||
|
||||
|
||||
else:
|
||||
return "Done for today"
|
||||
|
||||
|
||||
|
||||
|
||||
#Routes
|
||||
@app.route("/")
|
||||
@requires_auth
|
||||
def hello():
|
||||
return render_template("base.html")
|
||||
|
||||
@app.route('/setup', methods=['GET'])
|
||||
@requires_auth
|
||||
def setupDB():
|
||||
cur = get_db().cursor()
|
||||
cur.execute('''CREATE TABLE accounts (number integer, mail text, password text, owner text, defaultPlan text)''')
|
||||
cur.execute('''CREATE TABLE updates (number integer, updateTime integer, plan text, dataUsed integer)''')
|
||||
cur.execute('''CREATE TABLE special (number integer, day integer, month integer, year integer, plan text)''')
|
||||
cur.execute('''CREATE TABLE run_actions (year integer, month integer, day integer)''')
|
||||
get_db().commit()
|
||||
return "Accounts"
|
||||
|
||||
# GUI
|
||||
@app.route("/accounts")
|
||||
@requires_auth
|
||||
def gui_liste():
|
||||
return render_template("list.html", accounts=function_getAccounts(), currentTime=int(time.time()))
|
||||
|
||||
@app.route("/account/<number>")
|
||||
@requires_auth
|
||||
def gui_account(number):
|
||||
account = function_getAccount(number)
|
||||
special_days = function_speacialDays(number)
|
||||
|
||||
return render_template("account.html", account=account, special_days=special_days, currentTime=int(time.time()))
|
||||
|
||||
@app.route("/account/<number>/special", methods=['POST'])
|
||||
@requires_auth
|
||||
def special_days(number):
|
||||
start = datetime.datetime(int(request.form["from_year"]), int(request.form["from_month"]), int(request.form["from_day"]), 0, 0, 0)
|
||||
ende = datetime.datetime(int(request.form["to_year"]), int(request.form["to_month"]), int(request.form["to_day"]), 0, 0, 0)
|
||||
delta = ende - start
|
||||
|
||||
cur = get_db().cursor()
|
||||
for i in range(delta.days + 1):
|
||||
date = start + datetime.timedelta(days=i)
|
||||
if request.form["plan"] == "Default":
|
||||
cur.execute("DELETE FROM special WHERE number = %s AND year = %s AND month = %s AND day = %s" % (number, date.year, date.month, date.day))
|
||||
else:
|
||||
cur.execute("DELETE FROM special WHERE number = %s AND year = %s AND month = %s AND day = %s" % (number, date.year, date.month, date.day))
|
||||
cur.execute("INSERT INTO special VALUES (%s, %s, %s, %s, '%s')" % (number, date.day, date.month, date.year, request.form["plan"]))
|
||||
|
||||
get_db().commit();
|
||||
|
||||
return redirect("/account/"+str(number), code=302)
|
||||
|
||||
@app.route("/account/<number>/days")
|
||||
@requires_auth
|
||||
def list_days(number):
|
||||
start = datetime.datetime.now()
|
||||
ende = start + relativedelta(months=2)
|
||||
|
||||
delta = ende - start
|
||||
dayList = []
|
||||
|
||||
for i in range(delta.days + 1):
|
||||
day = {}
|
||||
date = start + datetime.timedelta(days=i)
|
||||
day["date"] = str(date.day)+"."+str(date.month)+"."+str(date.year)
|
||||
day["plan"] = function_getPlanForDay(number, date.year, date.month, date.day)
|
||||
dayList.append(day)
|
||||
|
||||
|
||||
return render_template("list_days.html", dayList=dayList)
|
||||
|
||||
@app.route("/account/add", methods=['GET'])
|
||||
@requires_auth
|
||||
def add_account_gui():
|
||||
return render_template("account_add.html")
|
||||
|
||||
@app.route("/account/add", methods=['POST'])
|
||||
@requires_auth
|
||||
def add_account_gui_save():
|
||||
r = addAccount()
|
||||
return redirect("/accounts", code=302)
|
||||
|
||||
|
||||
# API
|
||||
@app.route('/api/accounts', methods=['GET'])
|
||||
@requires_auth
|
||||
def listAccounts():
|
||||
resData = function_getAccounts()
|
||||
response = {"success": True, "data": resData}
|
||||
return json.dumps(response)
|
||||
|
||||
@app.route('/api/account/<number>/update', methods=['GET'])
|
||||
@requires_auth
|
||||
def updateAccount(number):
|
||||
function_updateAccount(number)
|
||||
response = {"success": True}
|
||||
return json.dumps(response)
|
||||
|
||||
@app.route('/api/account/<number>/changeDafault', methods=['POST'])
|
||||
@requires_auth
|
||||
def changeDefault(number):
|
||||
cur = get_db().cursor()
|
||||
default = request.form["plan"]
|
||||
cur.execute("UPDATE accounts SET `defaultPlan` = '%s' WHERE `number` = %s" % (default, number))
|
||||
get_db().commit();
|
||||
response = {"success": True}
|
||||
return json.dumps(response)
|
||||
|
||||
@app.route('/api/accounts', methods=['POST'])
|
||||
@requires_auth
|
||||
def addAccount():
|
||||
cur = get_db().cursor()
|
||||
mail = request.form["mail"]
|
||||
password = request.form["password"]
|
||||
response = {}
|
||||
response["success"] = False
|
||||
response["msg"] = ""
|
||||
|
||||
try:
|
||||
api = FunkAPI(mail, password)
|
||||
personalData = api.getPersonalInfo()
|
||||
except Exception:
|
||||
response["msg"] = "Autherized failed, wrong mail/password?"
|
||||
return json.dumps(response)
|
||||
|
||||
plan = api.getCurrentPlan()["productServiceInfo"]["marketingInfo"]["name"]
|
||||
name = personalData["firstName"]+" "+personalData["lastName"]
|
||||
|
||||
# getUsage
|
||||
data = api.getData()
|
||||
number = data["data"]["me"]["customerProducts"][0]["mobileNumbers"][0]["number"]
|
||||
|
||||
|
||||
#number integer, mail text, password text, owner text, defaultPlan text
|
||||
cur.execute("INSERT INTO accounts VALUES ('%s', '%s', '%s', '%s', '%s')" % (
|
||||
number,
|
||||
mail,
|
||||
password,
|
||||
name,
|
||||
plan
|
||||
))
|
||||
|
||||
get_db().commit()
|
||||
function_updateAccount(number)
|
||||
|
||||
response["success"] = True
|
||||
response["data"] = {"name": name}
|
||||
|
||||
return json.dumps(response)
|
||||
#SQLITE
|
||||
|
||||
@app.teardown_appcontext
|
||||
def close_connection(exception):
|
||||
db = getattr(g, '_database', None)
|
||||
if db is not None:
|
||||
db.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=True,host='0.0.0.0')
|
205
templates/account.html
Normal file
205
templates/account.html
Normal file
|
@ -0,0 +1,205 @@
|
|||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<h3>Accounts {{ account["mail"] }}</h3>
|
||||
<span id="info"></span>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th>Owner</th>
|
||||
<td>{{ account["owner"] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Mail</th>
|
||||
<td>{{ account["mail"] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Number</th>
|
||||
<td>{{ account["number"] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Current Plan</th>
|
||||
<td>{{ account["currentPlan"] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Default Plan</th>
|
||||
<td>{{ account["defaultPlan"] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Updatet min ago</th>
|
||||
<td>
|
||||
{{ ((currentTime - account["lastUpdate"]) /60)|round(1) }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Data Usage</th>
|
||||
<td>{{ account["dataUsed"] }}%</td>
|
||||
</tr>
|
||||
</table>
|
||||
<a href="#" class="btn btn-warning btn-sm updateNow">Update now</a>
|
||||
<hr>
|
||||
<h4>Update Default Plan</h4>
|
||||
<p>The Default Plan will be set if no other Rule is enabled for the Day.</p>
|
||||
<select class="form-control" id="defaultPlan">
|
||||
<option value="1 GB" {% if account["defaultPlan"] == '1 GB' %}selected{% endif %}>1 GB</option>
|
||||
<option value="unlimited" {% if account["defaultPlan"] == 'unlimited' %}selected{% endif %}>Unlimit</option>
|
||||
<option value="Break" {% if account["defaultPlan"] == 'Break' %}selected{% endif %}>Break</option>
|
||||
</select><br>
|
||||
<input type="button" class="btn btn-warning" value="Save" id="changeDefaultPlan">
|
||||
|
||||
<hr>
|
||||
<h4>Special Days</h4>
|
||||
<p>Add some Special Days</p>
|
||||
<b>From</b>
|
||||
<form method="post" action="/account/{{ account['number'] }}/special">
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<select name="from_day" class="form-control">
|
||||
<option>01</option>
|
||||
<option>02</option>
|
||||
<option>03</option>
|
||||
<option>04</option>
|
||||
<option>05</option>
|
||||
<option>06</option>
|
||||
<option>07</option>
|
||||
<option>08</option>
|
||||
<option>09</option>
|
||||
<option>11</option>
|
||||
<option>12</option>
|
||||
<option>13</option>
|
||||
<option>14</option>
|
||||
<option>15</option>
|
||||
<option>16</option>
|
||||
<option>17</option>
|
||||
<option>18</option>
|
||||
<option>19</option>
|
||||
<option>21</option>
|
||||
<option>22</option>
|
||||
<option>23</option>
|
||||
<option>24</option>
|
||||
<option>25</option>
|
||||
<option>26</option>
|
||||
<option>27</option>
|
||||
<option>28</option>
|
||||
<option>29</option>
|
||||
<option>30</option>
|
||||
<option>31</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<select name="from_month" class="form-control">
|
||||
<option value="1">Januar</option>
|
||||
<option value="2">Feburar</option>
|
||||
<option value="3">März</option>
|
||||
<option value="4">April</option>
|
||||
<option value="5">Mai</option>
|
||||
<option value="6">Juni</option>
|
||||
<option value="7">Juli</option>
|
||||
<option value="8">August</option>
|
||||
<option value="9">September</option>
|
||||
<option value="10">Okbotber</option>
|
||||
<option value="11">November</option>
|
||||
<option value="12">Dezember</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<select name="from_year" class="form-control">
|
||||
<option>2019</option>
|
||||
<option>2020</option>
|
||||
<option>2021</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<b>To</b>
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<select name="to_day" class="form-control">
|
||||
<option>01</option>
|
||||
<option>02</option>
|
||||
<option>03</option>
|
||||
<option>04</option>
|
||||
<option>05</option>
|
||||
<option>06</option>
|
||||
<option>07</option>
|
||||
<option>08</option>
|
||||
<option>09</option>
|
||||
<option>11</option>
|
||||
<option>12</option>
|
||||
<option>13</option>
|
||||
<option>14</option>
|
||||
<option>15</option>
|
||||
<option>16</option>
|
||||
<option>17</option>
|
||||
<option>18</option>
|
||||
<option>19</option>
|
||||
<option>21</option>
|
||||
<option>22</option>
|
||||
<option>23</option>
|
||||
<option>24</option>
|
||||
<option>25</option>
|
||||
<option>26</option>
|
||||
<option>27</option>
|
||||
<option>28</option>
|
||||
<option>29</option>
|
||||
<option>30</option>
|
||||
<option>31</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<select name="to_month" class="form-control">
|
||||
<option value="1">Januar</option>
|
||||
<option value="2">Feburar</option>
|
||||
<option value="3">März</option>
|
||||
<option value="4">April</option>
|
||||
<option value="5">Mai</option>
|
||||
<option value="6">Juni</option>
|
||||
<option value="7">Juli</option>
|
||||
<option value="8">August</option>
|
||||
<option value="9">September</option>
|
||||
<option value="10">Okbotber</option>
|
||||
<option value="11">November</option>
|
||||
<option value="12">Dezember</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<select name="to_year" class="form-control">
|
||||
<option>2019</option>
|
||||
<option>2020</option>
|
||||
<option>2021</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<b>Plan</b>
|
||||
<select name="plan" class="form-control">
|
||||
<option value="1 GB">1 GB</option>
|
||||
<option value="Unlimit">Unlimit</option>
|
||||
<option value="Break">Break</option>
|
||||
<option value="Default">Default (Delet all specal days in this Period)</option>
|
||||
</select><br>
|
||||
<input type="submit" class="btn btn-success" value="Save">
|
||||
</form>
|
||||
<hr>
|
||||
<h4>Next Special Days</h4>
|
||||
<table class="table">
|
||||
{% for day in special_days %}
|
||||
<tr>
|
||||
<td> {{ day["day"] }}</td>
|
||||
<td> {{ day["plan"] }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
<a href="/account/{{account["number"]}}/days" class="btn btn-sm btn-success">See next 2 Month</a>
|
||||
<script>
|
||||
$(".updateNow").click(function() {
|
||||
$("#info").html("Update Account");
|
||||
$.get("/api/account/{{account['number']}}/update", function() {
|
||||
$("#info").html("Update Account done");
|
||||
location.reload();
|
||||
});
|
||||
});
|
||||
$("#changeDefaultPlan").click(function () {
|
||||
$("#info").html("Update Default Plan");
|
||||
$.post("/api/account/{{account['number']}}/changeDafault", {"plan": $("#defaultPlan").val()}, function() {
|
||||
location.reload();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
11
templates/account_add.html
Normal file
11
templates/account_add.html
Normal file
|
@ -0,0 +1,11 @@
|
|||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<h3>Add Account</h3>
|
||||
<form method="post" action="">
|
||||
<label>E-Mail</label>
|
||||
<input name="mail" class="form-control">
|
||||
<label>Password</label>
|
||||
<input name="password" class="form-control" type="password"><br>
|
||||
<input type="submit" class="btn btn-success" value="Add Account">
|
||||
</form>
|
||||
{% endblock %}
|
35
templates/base.html
Normal file
35
templates/base.html
Normal file
|
@ -0,0 +1,35 @@
|
|||
<head>
|
||||
<title>FUNK Manager</title>
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
|
||||
|
||||
<script src="https://code.jquery.com/jquery-3.3.1.min.js" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container" style="margin-top: 30px;">
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
||||
<a class="navbar-brand" href="/">Funk Manager</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/accounts">Accounts</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/account/add">New Account</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="row" style="margin-top:20px;">
|
||||
<div class="col-md-12">
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
28
templates/list.html
Normal file
28
templates/list.html
Normal file
|
@ -0,0 +1,28 @@
|
|||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<h3>FUNK Accounts</h3>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th>Number</th>
|
||||
<th>Data Usage</th>
|
||||
<th>Current Plan</th>
|
||||
<th>Default Plan</th>
|
||||
<th>Last Update</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
{% for account in accounts %}
|
||||
<tr>
|
||||
<td> +{{ account["number"] }}</td>
|
||||
<td>
|
||||
<div class="progress">
|
||||
<div class="progress-bar" role="progressbar" style="width: {{ account["dataUsed"] }}%;" aria-valuenow="{{ account["dataUsed"] }}" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
</td>
|
||||
<td> {{ account["currentPlan"] }}</td>
|
||||
<td> {{ account["defaultPlan"] }}</td>
|
||||
<td> {{ ((currentTime - account["lastUpdate"]) /60)|round(1) }} min</td>
|
||||
<td> <a href="/account/{{ account["number"] }}" class="btn btn-sm btn-warning">Edit</a> </td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endblock %}
|
16
templates/list_days.html
Normal file
16
templates/list_days.html
Normal file
|
@ -0,0 +1,16 @@
|
|||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<h3>Days</h3>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th>Day</th>
|
||||
<th>Plan</th>
|
||||
</tr>
|
||||
{% for day in dayList %}
|
||||
<tr>
|
||||
<td>{{ day["date"] }}</td>
|
||||
<td>{{ day["plan"] }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endblock %}
|
Loading…
Reference in a new issue