clean up and started adding python backend

This commit is contained in:
Karl Hudgell 2024-11-05 15:54:21 +00:00
parent f5369c05ac
commit d718b89035
6 changed files with 128 additions and 42 deletions

8
app.py
View File

@ -4,17 +4,17 @@ from flask_caching import Cache
import requests.auth import requests.auth
import os import os
from lib.datetime import filter_accounts_current_month from lib.datetime import filter_accounts_current_month
from lib.reqs import get_urls, get_user_accounts, add_user_account, delete_user_account from lib.reqs import get_urls, get_user_accounts, add_user_account, delete_user_account, get_user_accounts_count
from flask import send_from_directory from flask import send_from_directory
import requests import requests
import base64 import base64
from flask import Flask from flask import Flask
from config import DevelopmentConfig # or ProductionConfig from config import DevelopmentConfig
app = Flask(__name__) app = Flask(__name__)
app.config.from_object( app.config.from_object(
DevelopmentConfig DevelopmentConfig
) # Use DevelopmentConfig or ProductionConfig as needed )
cache = Cache(app, config={"CACHE_TYPE": "SimpleCache"}) cache = Cache(app, config={"CACHE_TYPE": "SimpleCache"})
@ -44,7 +44,7 @@ def home():
return render_template( return render_template(
"home.html", "home.html",
username=session["username"], username=session["username"],
accounts=get_user_accounts(base_url, session["auth_credentials"]), accounts=get_user_accounts_count(base_url, session["auth_credentials"]),
current_month_accounts=current_month_accounts, current_month_accounts=current_month_accounts,
) )

19
backend/app.py Normal file
View File

@ -0,0 +1,19 @@
from flask import Flask, jsonify
from config import DevelopmentConfig
from lib.mysql import execute_query
app = Flask(__name__)
app.config.from_object(DevelopmentConfig)
@app.route('/getUserAccounts', methods=['GET'])
def get_user_accounts():
# Use the execute_query function to get user accounts
data = execute_query("SELECT COUNT(*) AS account_count FROM userAccounts WHERE userID = %s;", (1,))
if data is None:
return jsonify({"error": "Database query failed"}), 500
return jsonify(data), 200
# Run the app
if __name__ == '__main__':
app.run(debug=app.config["DEBUG"], port=app.config["PORT"])

37
backend/lib/mysql.py Normal file
View File

@ -0,0 +1,37 @@
import mysql.connector
from flask import current_app
def execute_query(query, params=None, fetch_one=False):
"""Execute a SQL query and optionally fetch results."""
try:
# Get database configuration from the current app context
db_config = {
"host": current_app.config['DBHOST'],
"user": current_app.config['DBUSER'],
"password": current_app.config['DBPASS'],
"database": current_app.config['DATABASE'],
}
# Establish database connection
connection = mysql.connector.connect(**db_config)
cursor = connection.cursor(dictionary=True)
# Execute the query with optional parameters
cursor.execute(query, params)
# Fetch results if it's a SELECT query
if query.strip().upper().startswith("SELECT"):
result = cursor.fetchone() if fetch_one else cursor.fetchall()
else:
# Commit changes for INSERT, UPDATE, DELETE
connection.commit()
result = cursor.rowcount # Number of affected rows
# Close the database connection
cursor.close()
connection.close()
return result
except mysql.connector.Error as err:
print("Error: ", err)
return None

View File

@ -1,11 +1,20 @@
import requests import requests
import json import json
from datetime import datetime from datetime import datetime
from typing import List, Dict, Any
def get_urls(base_url, auth: str) -> list: def get_urls(base_url: str, auth: str) -> List[Dict[str, Any]]:
"""Retrieve user account streams from the specified base URL.
Args:
base_url (str): The base URL of the API.
auth (str): The authorization token for accessing the API.
Returns:
List[Dict[str, Any]]: A list of user account streams.
"""
url = f"{base_url}/getUserAccounts/streams" url = f"{base_url}/getUserAccounts/streams"
payload = {} payload = {}
headers = {"Authorization": f"Basic {auth}"} headers = {"Authorization": f"Basic {auth}"}
@ -13,67 +22,86 @@ def get_urls(base_url, auth: str) -> list:
return json.loads(response.text) return json.loads(response.text)
def get_user_accounts(base_url, auth: str) -> list: def get_user_accounts(base_url: str, auth: str) -> List[Dict[str, Any]]:
url = f"{base_url}/getUserAccounts" """Retrieve user accounts from the specified base URL.
Args:
base_url (str): The base URL of the API.
auth (str): The authorization token for accessing the API.
Returns:
List[Dict[str, Any]]: A list of user accounts with their expiration dates rendered.
"""
url = f"{base_url}/getUserAccounts"
payload = {} payload = {}
headers = {"Authorization": f"Basic {auth}"} headers = {"Authorization": f"Basic {auth}"}
response = requests.request("GET", url, headers=headers, data=payload) response = requests.request("GET", url, headers=headers, data=payload)
res_json = json.loads(response.text) res_json = json.loads(response.text)
for account in res_json: for account in res_json:
account["expiaryDate_rendered"] = datetime.utcfromtimestamp( account["expiaryDate_rendered"] = datetime.utcfromtimestamp(
account["expiaryDate"] account["expiaryDate"]
).strftime("%d/%m/%Y") ).strftime("%d/%m/%Y")
return res_json return res_json
def delete_user_account(base_url: str, auth: str, stream:str, username:str) -> bool: def delete_user_account(base_url: str, auth: str, stream: str, username: str) -> bool:
"""_summary_ """Delete a user account from the specified base URL.
Args: Args:
base_url (str): _description_ base_url (str): The base URL of the API.
auth (str): _description_ auth (str): The authorization token for accessing the API.
stream (str): _description_ stream (str): The name of the stream associated with the user account.
username (str): _description_ username (str): The username of the account to delete.
Returns: Returns:
bool: _description_ bool: True if the account was deleted successfully, False otherwise.
""" """
url = f"{base_url}/deleteAccount" url = f"{base_url}/deleteAccount"
payload = {"stream": stream, "user": username} payload = {"stream": stream, "user": username}
headers = {"Authorization": f"Basic {auth}"} headers = {"Authorization": f"Basic {auth}"}
response = requests.request("POST", url, headers=headers, data=payload) response = requests.request("POST", url, headers=headers, data=payload)
if "Deleted" in response.text: return "Deleted" in response.text
return True
else:
return False
def add_user_account(base_url: str, auth: str, username: str, password: str, stream: str) -> bool:
def add_user_account(base_url: str, auth: str, username:str, password:str, stream:str,) -> bool: """Add a user account to the specified base URL.
"""_summary_
Args: Args:
base_url (str): _description_ base_url (str): The base URL of the API.
auth (str): _description_ auth (str): The authorization token for accessing the API.
stream (str): _description_ username (str): The username of the account to add.
username (str): _description_ password (str): The password of the account to add.
stream (str): The name of the stream associated with the user account.
Returns: Returns:
bool: _description_ bool: True if the account was added successfully, False otherwise.
""" """
url = f"{base_url}/addAccount" url = f"{base_url}/addAccount"
payload = {"username": username, "password": password, "stream": stream} payload = {"username": username, "password": password, "stream": stream}
headers = {"Authorization": f"Basic {auth}"} headers = {"Authorization": f"Basic {auth}"}
response = requests.request("POST", url, headers=headers, data=payload) response = requests.request("POST", url, headers=headers, data=payload)
if "Added successfully" in response.text: return "Added successfully" in response.text
return True
else:
return False def get_user_accounts_count(base_url: str, auth: str) -> int:
"""Get the count of user accounts from the specified base URL.
Args:
base_url (str): The base URL of the API.
auth (str): The authorization token for accessing the API.
Returns:
int: The count of user accounts.
"""
url = f"{base_url}/getUserAccounts/count"
payload = {}
headers = {"Authorization": f"Basic {auth}"}
response = requests.request("GET", url, headers=headers, data=payload)
res_json = json.loads(response.text)
return res_json['count']

View File

@ -34,7 +34,7 @@
<div class="container mt-5"> <div class="container mt-5">
<h1>Welcome {{ username }}!</h1> <h1>Welcome {{ username }}!</h1>
<br> <br>
<h2>You have {{ accounts|length }} active accounts</h2> <h2>You have {{ accounts }} active accounts</h2>
<br> <br>
{% if current_month_accounts %} {% if current_month_accounts %}

View File

@ -45,7 +45,7 @@
<table class="table table-striped" id="accountsTable"> <table class="table table-striped" id="accountsTable">
<thead> <thead>
<tr> <tr>
<th>#</th> <!-- <th>#</th> -->
<th>Username</th> <th>Username</th>
<th>Stream</th> <th>Stream</th>
<th>Stream URL</th> <th>Stream URL</th>
@ -57,7 +57,7 @@
<tbody> <tbody>
{% for account in user_accounts %} {% for account in user_accounts %}
<tr> <tr>
<td>{{ loop.index }}</td> <!-- <td>{{ loop.index }}</td> -->
<td>{{ account.username }}</td> <td>{{ account.username }}</td>
<td>{{ account.stream }}</td> <td>{{ account.stream }}</td>
<td><a href="{{ account.streamURL }}" target="_blank">{{ account.streamURL }}</a></td> <td><a href="{{ account.streamURL }}" target="_blank">{{ account.streamURL }}</a></td>
@ -100,17 +100,19 @@
return data; // return as is if the format is unexpected return data; // return as is if the format is unexpected
}; };
// Initialize DataTable with custom sorting // Initialize DataTable with custom sorting and default ordering by Expiry Date
$('#accountsTable').DataTable({ $('#accountsTable').DataTable({
"searching": true, "searching": true,
"ordering": true, "ordering": true,
"responsive": true, "responsive": true,
"order": [[3, 'asc']], // Default order by Expiry Date column in ascending order
"columnDefs": [ "columnDefs": [
{ "type": "date-eu", "targets": 4 } // Use custom date-eu type for the date column { "type": "date-eu", "targets": 3 } // Use custom date-eu type for the date column
] ]
}); });
}); });
</script> </script>
</body> </body>
</html> </html>