initial working version

This commit is contained in:
Karl Hudgell 2024-11-02 20:04:56 +00:00
parent 061959cf6f
commit 44a7cd0b82
13 changed files with 245 additions and 10 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
venv/
config.py

17
.vscode/launch.json vendored Normal file
View File

@ -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"]
}
]
}

Binary file not shown.

73
app.py Normal file
View File

@ -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'])

11
config.py.sample Normal file
View File

@ -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

Binary file not shown.

Binary file not shown.

25
lib/datetime.py Normal file
View File

@ -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

26
lib/reqs.py Normal file
View File

@ -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

66
templates/home.html Normal file
View File

@ -0,0 +1,66 @@
<!-- templates/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>KTV Manager</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
</head>
<body>
<!-- Navbar -->
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<a class="navbar-brand" href="#">KTV Manager</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<a class="nav-link" href="/">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/accounts">Accounts</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/urls">URLs</a>
</li>
</ul>
</div>
</nav>
<!-- Main Content -->
<div class="container mt-5">
<h1>Welcome to KTV Manager {{ username }}</h1>
<span>You have {{accounts|length}} accounts</span>
<h3>Accounts Expiring This Month</h3>
<table class="table table-bordered table-striped">
<thead class="thead-dark">
<tr>
<th>Stream Name</th>
<th>Username</th>
<th>Expiry Date</th>
</tr>
</thead>
<tbody>
{% for account in current_month_accounts %}
<tr>
<td>{{ account.stream }}</td>
<td>{{ account.username }}</td>
<td>{{ account.expiaryDate_rendered }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<footer class="bg-dark text-white text-center py-3 mt-5">
<p>&copy; 2024 KTV Manager | All rights reserved</p>
</footer>
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.0.7/dist/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
</body>
</html>

View File

@ -21,10 +21,10 @@
<a class="nav-link" href="/">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/accounts">Accounts</a> <!-- Link to the URLs page -->
<a class="nav-link" href="/accounts">Accounts</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/urls">URLs</a> <!-- Link to the URLs page -->
<a class="nav-link" href="/urls">URLs</a>
</li>
</ul>
</div>
@ -33,7 +33,22 @@
<!-- Main Content -->
<div class="container mt-5">
<h1>Welcome to KTV Manager</h1>
<!-- <p>This website is built using Flask and Bootstrap. Its designed to look great on any screen size!</p> -->
<!-- Login Form -->
<form action="/login" method="post" class="mt-3">
<div class="form-group">
<label for="username">Username:</label>
<input type="text" class="form-control" id="username" name="username" required>
</div>
<div class="form-group">
<label for="password">Password:</label>
<input type="password" class="form-control" id="password" name="password" required>
</div>
<button type="submit" class="btn btn-primary">Login</button>
{% if error %}
<div class="alert alert-danger mt-3">{{ error }}</div>
{% endif %}
</form>
</div>
<footer class="bg-dark text-white text-center py-3 mt-5">

View File

@ -4,7 +4,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>URLs List</title>
<title>KTVManager</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
</head>
<body>
@ -53,7 +53,7 @@
</div>
<footer class="bg-dark text-white text-center py-3 mt-5">
<p>&copy; 2024 My Site | All rights reserved</p>
<p>&copy; 2024 KTVManager | All rights reserved</p>
</footer>
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>

View File

@ -4,7 +4,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>User Accounts</title>
<title>KTVManager</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.24/css/jquery.dataTables.min.css">
<style>
@ -19,7 +19,7 @@
<!-- Navbar (same as index.html) -->
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<a class="navbar-brand" href="#">KTV Manager</a>
<a class="navbar-brand" href="#">KTVManager</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
@ -40,7 +40,7 @@
<!-- Main Content -->
<div class="container mt-5">
<h2>User Accounts</h2>
<h2>{{ username }}'s Accounts</h2>
<table class="table table-striped" id="accountsTable">
<thead>
<tr>
@ -59,7 +59,7 @@
<td>{{ account.username }}</td>
<td>{{ account.stream }}</td>
<td><a href="{{ account.streamURL }}" target="_blank">{{ account.streamURL }}</a></td>
<td>{{ account.expiaryDate }}</td> <!-- Ensure this is in d/m/Y format -->
<td>{{ account.expiaryDate_rendered }}</td>
<td class="password-cell" data-password="{{ account.password }}">
<span class="password-blur">********</span>
</td>
@ -70,7 +70,7 @@
</div>
<footer class="bg-dark text-white text-center py-3 mt-5">
<p>&copy; 2024 My Site | All rights reserved</p>
<p>&copy; 2024 KTVManager | All rights reserved</p>
</footer>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>