funk-manager/server.py

332 lines
11 KiB
Python
Raw Normal View History

2019-07-06 09:34:24 +00:00
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')