From 44a7cd0b82348b99beaee5ce3e8df0481004b7eb Mon Sep 17 00:00:00 2001 From: Karl Hudgell Date: Sat, 2 Nov 2024 20:04:56 +0000 Subject: [PATCH] initial working version --- .gitignore | 2 + .vscode/launch.json | 17 ++++++ __pycache__/config.cpython-310.pyc | Bin 0 -> 727 bytes app.py | 73 +++++++++++++++++++++++ config.py.sample | 11 ++++ lib/__pycache__/datetime.cpython-310.pyc | Bin 0 -> 883 bytes lib/__pycache__/reqs.cpython-310.pyc | Bin 988 -> 979 bytes lib/datetime.py | 25 ++++++++ lib/reqs.py | 26 ++++++++ templates/home.html | 66 ++++++++++++++++++++ templates/index.html | 21 ++++++- templates/urls.html | 4 +- templates/user_accounts.html | 10 ++-- 13 files changed, 245 insertions(+), 10 deletions(-) create mode 100644 .gitignore create mode 100644 .vscode/launch.json create mode 100644 __pycache__/config.cpython-310.pyc create mode 100644 app.py create mode 100644 config.py.sample create mode 100644 lib/__pycache__/datetime.cpython-310.pyc create mode 100644 lib/datetime.py create mode 100644 lib/reqs.py create mode 100644 templates/home.html diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4dda9a4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +venv/ +config.py diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..669e8d6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,17 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Python Debugger: Current File", + "type": "debugpy", + "request": "launch", + "program": "${file}", + "console": "integratedTerminal", + "justMyCode": false, + "args": ["--host=0.0.0.0"] + } + ] +} \ No newline at end of file diff --git a/__pycache__/config.cpython-310.pyc b/__pycache__/config.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..66f5ef20cf213cfa3dbeb490b2dc82a404ce3368 GIT binary patch literal 727 zcmZ`%!H&}~5Oor#iI(kB1V;{>ka{3n3a1L8W!tbth3=|Nk+33JQEf`qBrZ-;1lQ%j zukaQ8hp&9X-uA>yA`mNeZTV@Q$IhF1j%v3L2n=03Uj4EN`HkfNL4lmWD*6CtL=a(p zhjnQ)WVUdCIg(sD%mPk@3*4=_En0KZ^_Fn&#sHP(i;p0Xgjs?xTUg8yHlxB}uAr3y~kLwllHs!A0>py>e{qR#+ZU@K5l>f*Jjo>I=794|i7LhTkn_(~lK#!i!{IE9_$2&b+);SCI5Ym~t9i&5v$uv` zoX;Xd$LI6tC((DH>>935hJ$!fNL|E}M5n>H5-XXe@klMJOy*?~k5wjzO2~K;y?>YF z$x3RzcoQ${hJx)^jb1pgibDXOP^+1~RcCIs?y3XFZ(0XdJLcXfuZt!^eSHLgf5R1?^$ApgJGWM$+mHp-&V>e3m*raJji|OEu}9d4?Y+X- l4oc~}2*{>gr?#N3px)Vc(fBW#_k4*)7A=4yyW>5ee*k`IjlKW? literal 0 HcmV?d00001 diff --git a/app.py b/app.py new file mode 100644 index 0000000..1118f0c --- /dev/null +++ b/app.py @@ -0,0 +1,73 @@ +# app.py +from flask import Flask, render_template, request, redirect, url_for, session, flash +import requests.auth +from lib.datetime import filter_accounts_current_month +from lib.reqs import (get_urls, get_user_accounts) +import requests +import base64 +from flask import Flask +from config import DevelopmentConfig # or ProductionConfig + +app = Flask(__name__) +app.config.from_object(DevelopmentConfig) # Use DevelopmentConfig or ProductionConfig as needed + +@app.route('/') +def home(): + # If the user is logged in, redirect to a protected page like /accounts + if session.get('logged_in'): + base_url = app.config['BASE_URL'] # Access base_url from the config + all_accounts = get_user_accounts(base_url, session['auth_credentials']) + current_month_accounts = filter_accounts_current_month(all_accounts) + return render_template('home.html', username=session['username'], accounts=get_user_accounts(base_url, session['auth_credentials']), current_month_accounts=current_month_accounts) + return render_template('index.html') + +@app.route('/login', methods=['POST']) +def login(): + username = request.form['username'] + password = request.form['password'] + + # Encode the username and password in Base64 + credentials = f"{username}:{password}" + encoded_credentials = base64.b64encode(credentials.encode()).decode() + + base_url = app.config['BASE_URL'] # Access base_url from the config + login_url = f"{base_url}/Login" # Construct the full URL + + # Send GET request to the external login API with Basic Auth + response = requests.get( + login_url, + auth=requests.auth.HTTPBasicAuth(username, password) + ) + + # Check if login was successful + if response.status_code == 200 and response.json().get("auth") == "Success": + # Set session variable to indicate the user is logged in + session['logged_in'] = True + session['username'] = username + session['auth_credentials'] = encoded_credentials + return redirect(url_for('home')) # Redirect to the Accounts page + else: + # Show error on the login page + error = "Invalid username or password. Please try again." + return render_template('index.html', error=error) + +@app.route('/urls', methods=['GET']) +def urls(): + # Check if the user is logged in + if not session.get('logged_in'): + return redirect(url_for('home')) + # Placeholder content for Accounts page + base_url = app.config['BASE_URL'] # Access base_url from the config + return render_template('urls.html', urls=get_urls(base_url, session['auth_credentials'])) + +@app.route('/accounts', methods=['GET']) +def user_accounts(): + # Check if the user is logged in + if not session.get('logged_in'): + return redirect(url_for('home')) + # Placeholder content for Accounts page + base_url = app.config['BASE_URL'] # Access base_url from the config + return render_template('user_accounts.html', username=session['username'], user_accounts=get_user_accounts(base_url, session['auth_credentials'])) + +if __name__ == '__main__': + app.run(debug=app.config['DEBUG'], host=app.config['HOST'], port=app.config['PORT']) diff --git a/config.py.sample b/config.py.sample new file mode 100644 index 0000000..fc4419e --- /dev/null +++ b/config.py.sample @@ -0,0 +1,11 @@ +# config.py + +class Config: + DEBUG = False + BASE_URL = '' # Set your base URL here + +class DevelopmentConfig(Config): + DEBUG = True + +class ProductionConfig(Config): + BASE_URL = '' # Production base URL diff --git a/lib/__pycache__/datetime.cpython-310.pyc b/lib/__pycache__/datetime.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..32a83d9ff89ac3a8c4fa774693444eb466ba27bf GIT binary patch literal 883 zcmaJ<&2G~`5T4z&jhm)WXaudGH-uyfMQ}w?gwzNXRrCVoU>RA)-UO4i9dzJbpY`z?6R3}1prN;io#*J;KP-;q2|xC}MV1_G~RVjeA) zjXVAg3`L!w(r`{LU_vyE$!Chf5;A3zIih_kAI>cad4P;68_R3gUz>aMVA>kfbNd3O zdlPboBoo-d z3>fr@+&m+FkTl1#P-E7#G* zzrD)4a`3lS=f8FEca}b3n%`to6-K%kNv;_NyZ_~G=1<*6<JMu~G} t+43%$4n1q0jNKKH>Ps`Pm0|vsX~Y~=|GBNKNQQ#9%{(b%tOEw5e*hed=2=$`SlXw4|tT!o$x1!Y5EV89kO;@TVi&rlmB*#+N zeGlKl+v>xZRMFlYnBQc=$K;!Q@^|jtcwP~iI2vzXH($NyGi^3)CWNoR#Xw;ywJpnaY~farx~207VAvbvmirnq1YltIb`uVr9b zcOTs~6*F!Nok>Nfc(2~|!-v}_kdN&k4tp{jicp3^f8c`+S5}M{Ni3Evsul%{n%*I+ yCEp(BSkWh>dHlDd3+q5ZHjJRfWy$J13%hkrMzPH4ATq^%#a#70W^v#f+57_jj8^ji delta 487 zcmcc2eutempO=@50SHvw)Y8=^@^;iSf_PBC3Z&V9*cph6O@KrSV=ZGQLoHJZQwnnp z!)%7ROqqz3yi<)rB4rs|buTNxV|80x2|mV_3k7C9y-=TH2b#K<~1i&2$Pc=80ssCpJg z7A8JMAtoNiB2l0Nl98Rq4itbpFN!SZ)w0&Gx-i7@)v}eaE?}!+OJS2_Sjf15J%xQC zBZ#ME!%!$w!wU2ThhLR0USCYEVX~flmdVzVy@(m;mLdTVAqXNkL4**Hh~g+pEsoDB z&d-ZtPXv0lG_Ryc7$gZML?(MM%L^eq%)uzd$ii48F}adi!3yO0A_=%!BwawUTO2mI a`6;D2sdk{?DF#I-2LlHq52FyX7#9FdOk%PC diff --git a/lib/datetime.py b/lib/datetime.py new file mode 100644 index 0000000..f2de689 --- /dev/null +++ b/lib/datetime.py @@ -0,0 +1,25 @@ +from datetime import datetime +from flask import render_template + +def filter_accounts_current_month(accounts): + # Get the start and end of the current month + now = datetime.now() + start_of_month = datetime(now.year, now.month, 1) + if now.month == 12: + # If current month is December, next month is January of the next year + start_of_next_month = datetime(now.year + 1, 1, 1) + else: + # Otherwise, next month is just the next month of the same year + start_of_next_month = datetime(now.year, now.month + 1, 1) + + # Convert start and end of the month to epoch timestamps + start_of_month_timestamp = int(start_of_month.timestamp()) + start_of_next_month_timestamp = int(start_of_next_month.timestamp()) + + # Filter accounts with expiryDate in the current month + accounts_in_current_month = [ + account for account in accounts + if start_of_month_timestamp <= account['expiaryDate'] < start_of_next_month_timestamp + ] + + return accounts_in_current_month diff --git a/lib/reqs.py b/lib/reqs.py new file mode 100644 index 0000000..093baf5 --- /dev/null +++ b/lib/reqs.py @@ -0,0 +1,26 @@ +import requests +import json +from datetime import datetime + + +def get_urls(base_url, auth: str) -> list: + url = f"{base_url}/getUserAccounts/streams" + + payload = {} + headers = {"Authorization": f"Basic {auth}"} + + response = requests.request("GET", url, headers=headers, data=payload) + return json.loads(response.text) + + +def get_user_accounts(base_url, auth: str) -> list: + url = f"{base_url}/getUserAccounts" + + payload = {} + headers = {"Authorization": f"Basic {auth}"} + + response = requests.request("GET", url, headers=headers, data=payload) + res_json = json.loads(response.text) + for account in res_json: + account['expiaryDate_rendered'] = datetime.utcfromtimestamp(account['expiaryDate']).strftime('%d/%m/%Y') + return res_json diff --git a/templates/home.html b/templates/home.html new file mode 100644 index 0000000..0bb2afc --- /dev/null +++ b/templates/home.html @@ -0,0 +1,66 @@ + + + + + + + KTV Manager + + + + + + + + +
+

Welcome to KTV Manager {{ username }}

+ You have {{accounts|length}} accounts +

Accounts Expiring This Month

+ + + + + + + + + + {% for account in current_month_accounts %} + + + + + + {% endfor %} + +
Stream NameUsernameExpiry Date
{{ account.stream }}{{ account.username }}{{ account.expiaryDate_rendered }}
+
+ +
+

© 2024 KTV Manager | All rights reserved

+
+ + + + + + diff --git a/templates/index.html b/templates/index.html index 75cede2..0953cb9 100644 --- a/templates/index.html +++ b/templates/index.html @@ -21,10 +21,10 @@ Home @@ -33,7 +33,22 @@

Welcome to KTV Manager

- + + +
+
+ + +
+
+ + +
+ + {% if error %} +
{{ error }}
+ {% endif %} +