Compare commits
10 Commits
13368a0437
...
9dc9b7e1b5
Author | SHA1 | Date | |
---|---|---|---|
9dc9b7e1b5 | |||
8df6af5edf | |||
e3cce698a0 | |||
318468fe53 | |||
41fef3cb15 | |||
cc576e3c91 | |||
1455e45554 | |||
a442460338 | |||
f3b37d6ac2 | |||
c174f1dbc9 |
9
.bumpversion.toml
Normal file
9
.bumpversion.toml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
[bumpversion]
|
||||||
|
current_version = "0.1.0"
|
||||||
|
commit = true
|
||||||
|
tag = true
|
||||||
|
|
||||||
|
[[bumpversion::file]]
|
||||||
|
filename = "VERSION"
|
||||||
|
search = "{current_version}"
|
||||||
|
replace = "{new_version}"
|
2
app.py
2
app.py
@ -4,7 +4,7 @@ from flask_caching import Cache
|
|||||||
import requests.auth
|
import requests.auth
|
||||||
import os
|
import os
|
||||||
from lib.datetime import filter_accounts_next_30_days, filter_accounts_expired
|
from lib.datetime import filter_accounts_next_30_days, filter_accounts_expired
|
||||||
from lib.reqs import get_urls, get_user_accounts, add_user_account, delete_user_account, get_user_accounts_count, get_stream_names
|
from lib.reqs import get_urls, get_user_accounts, add_user_account, delete_user_account, get_stream_names
|
||||||
from flask import send_from_directory
|
from flask import send_from_directory
|
||||||
import requests
|
import requests
|
||||||
import base64
|
import base64
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
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"])
|
|
@ -1,37 +0,0 @@
|
|||||||
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
|
|
@ -3,6 +3,10 @@
|
|||||||
class Config:
|
class Config:
|
||||||
DEBUG = False
|
DEBUG = False
|
||||||
BASE_URL = '' # Set your base URL here
|
BASE_URL = '' # Set your base URL here
|
||||||
|
HOST = '0.0.0.0'
|
||||||
|
PORT = 5000
|
||||||
|
OCR_ENABLED = False
|
||||||
|
TEXT_INPUT_ENABLED = False
|
||||||
|
|
||||||
class DevelopmentConfig(Config):
|
class DevelopmentConfig(Config):
|
||||||
DEBUG = True
|
DEBUG = True
|
||||||
|
11
dockerfile
11
dockerfile
@ -1,5 +1,5 @@
|
|||||||
# Builder stage
|
# Builder stage
|
||||||
FROM python:3.11-slim-bookworm as builder
|
FROM python:3.11-slim-bookworm AS builder
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
@ -7,15 +7,10 @@ COPY requirements.txt .
|
|||||||
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt
|
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt
|
||||||
|
|
||||||
# Final stage
|
# Final stage
|
||||||
FROM python:3.11-slim-bookworm as final
|
FROM python:3.11-slim-bookworm AS final
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
libglib2.0-0 \
|
|
||||||
libsm6 \
|
|
||||||
libxrender1 \
|
|
||||||
libxext6 \
|
|
||||||
libgomp1 \
|
libgomp1 \
|
||||||
libgl1 \
|
|
||||||
&& apt-get clean \
|
&& apt-get clean \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
@ -43,5 +38,5 @@ USER appuser
|
|||||||
|
|
||||||
EXPOSE 5000
|
EXPOSE 5000
|
||||||
|
|
||||||
ENV FLASK_ENV production
|
ENV FLASK_ENV=production
|
||||||
CMD ["./run.sh"]
|
CMD ["./run.sh"]
|
||||||
|
19
lib/reqs.py
19
lib/reqs.py
@ -88,25 +88,6 @@ def add_user_account(base_url: str, auth: str, username: str, password: str, str
|
|||||||
return response.status_code == 200
|
return response.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
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']
|
|
||||||
|
|
||||||
|
|
||||||
def get_stream_names(base_url: str, auth: str) -> List[str]:
|
def get_stream_names(base_url: str, auth: str) -> List[str]:
|
||||||
"""Get a list of stream names from the API.
|
"""Get a list of stream names from the API.
|
||||||
|
|
||||||
|
BIN
requirements.txt
BIN
requirements.txt
Binary file not shown.
@ -1,13 +1,8 @@
|
|||||||
<!-- templates/add_account.html -->
|
{% extends "base.html" %}
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
{% block title %}Add Account - KTVManager{% endblock %}
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
{% block head_content %}
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Add Account - KTVManager</title>
|
|
||||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
|
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}" />
|
|
||||||
<link rel="manifest" href="{{ url_for('static', filename='site.webmanifest') }}?v={{ version }}" />
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/awesomplete/1.1.5/awesomplete.min.css" />
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/awesomplete/1.1.5/awesomplete.min.css" />
|
||||||
<style>
|
<style>
|
||||||
/* Hide the spinner by default */
|
/* Hide the spinner by default */
|
||||||
@ -16,29 +11,9 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
{% endblock %}
|
||||||
<body>
|
|
||||||
<!-- Navbar -->
|
|
||||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
|
||||||
<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>
|
|
||||||
<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>
|
|
||||||
|
|
||||||
|
{% block sub_nav %}
|
||||||
<!-- Sub-navigation for Accounts -->
|
<!-- Sub-navigation for Accounts -->
|
||||||
<div class="bg-light py-2">
|
<div class="bg-light py-2">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@ -52,57 +27,54 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
<!-- Main Content -->
|
{% block content %}
|
||||||
<main class="container mt-5">
|
<h1>Add Account</h1>
|
||||||
<h1>Add Account</h1>
|
<div>
|
||||||
<div>
|
<form action="/accounts/add" method="POST" onsubmit="showLoading()">
|
||||||
<form action="/accounts/add" method="POST" onsubmit="showLoading()">
|
<div class="form-group">
|
||||||
|
<label for="username">Username</label>
|
||||||
|
<input type="text" class="form-control" id="username" name="username" value="{{ username }}" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="password">Password</label>
|
||||||
|
<input type="text" class="form-control" id="password" name="password" value="{{ password }}" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="stream">Stream Name</label>
|
||||||
|
<input type="text" class="form-control" id="stream" name="stream" required>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary" id="submitButton">
|
||||||
|
<span class="spinner-border spinner-border-sm" id="loadingSpinner" role="status" aria-hidden="true"></span>
|
||||||
|
<span id="buttonText">Add Account</span>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
{% if ocr_enabled %}
|
||||||
|
<hr>
|
||||||
|
<h2>Load Details Via OCR</h2>
|
||||||
|
<form action="/OCRupload" method="POST" enctype="multipart/form-data" onsubmit="showLoadingOCR()">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="username">Username</label>
|
<label for="image">Select Image</label>
|
||||||
<input type="text" class="form-control" id="username" name="username" value="{{ username }}" required>
|
<input type="file" class="form-control-file" id="image" name="image" accept="image/*" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<button type="submit" class="btn btn-success" id="ocrButton">
|
||||||
<label for="password">Password</label>
|
<span class="spinner-border spinner-border-sm" id="ocrLoadingSpinner" role="status" aria-hidden="true"></span>
|
||||||
<input type="text" class="form-control" id="password" name="password" value="{{ password }}" required>
|
<span id="ocrButtonText">Load Details</span>
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="stream">Stream Name</label>
|
|
||||||
<input type="text" class="form-control" id="stream" name="stream" required>
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="btn btn-primary" id="submitButton">
|
|
||||||
<span class="spinner-border spinner-border-sm" id="loadingSpinner" role="status" aria-hidden="true"></span>
|
|
||||||
<span id="buttonText">Add Account</span>
|
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
{% if ocr_enabled %}
|
{% endif %}
|
||||||
<hr>
|
{% if text_input_enabled %}
|
||||||
<h2>Load Details Via OCR</h2>
|
<hr>
|
||||||
<form action="/OCRupload" method="POST" enctype="multipart/form-data" onsubmit="showLoadingOCR()">
|
<h2>Load Details Via Text</h2>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="image">Select Image</label>
|
<label for="accountDetails">Paste Account Details</label>
|
||||||
<input type="file" class="form-control-file" id="image" name="image" accept="image/*" required>
|
<textarea class="form-control" id="accountDetails" rows="4"></textarea>
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="btn btn-success" id="ocrButton">
|
{% endif %}
|
||||||
<span class="spinner-border spinner-border-sm" id="ocrLoadingSpinner" role="status" aria-hidden="true"></span>
|
{% endblock %}
|
||||||
<span id="ocrButtonText">Load Details</span>
|
|
||||||
</button>
|
{% block scripts %}
|
||||||
</form>
|
|
||||||
{% endif %}
|
|
||||||
{% if text_input_enabled %}
|
|
||||||
<hr>
|
|
||||||
<h2>Load Details Via Text</h2>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="accountDetails">Paste Account Details</label>
|
|
||||||
<textarea class="form-control" id="accountDetails" rows="4"></textarea>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
</main>
|
|
||||||
<footer class="bg-dark text-white text-center py-3 mt-5">
|
|
||||||
<p></p>
|
|
||||||
</footer>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/awesomplete/1.1.5/awesomplete.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/awesomplete/1.1.5/awesomplete.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
function showLoading() {
|
function showLoading() {
|
||||||
@ -175,5 +147,4 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
{% endblock %}
|
||||||
</html>
|
|
||||||
|
57
templates/base.html
Normal file
57
templates/base.html
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
<!-- templates/base.html -->
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>{% block title %}KTVManager{% endblock %}</title>
|
||||||
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
|
||||||
|
<link rel="icon" type="image/png" href="{{ url_for('static', filename='favicon-96x96.png') }}" sizes="96x96" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="{{ url_for('static', filename='favicon.svg') }}" />
|
||||||
|
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}" />
|
||||||
|
<link rel="apple-touch-icon" sizes="180x180" href="{{ url_for('static', filename='apple-touch-icon.png') }}" />
|
||||||
|
<meta name="apple-mobile-web-app-title" content="kTvManager" />
|
||||||
|
<link rel="manifest" href="{{ url_for('static', filename='site.webmanifest') }}?v={{ version }}" />
|
||||||
|
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}" />
|
||||||
|
{% block head_content %}{% endblock %}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<!-- Navbar -->
|
||||||
|
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||||
|
<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>
|
||||||
|
<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>
|
||||||
|
|
||||||
|
{% block sub_nav %}{% endblock %}
|
||||||
|
|
||||||
|
<!-- Main Content -->
|
||||||
|
<main class="container mt-5">
|
||||||
|
{% block content %}{% endblock %}
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer class="bg-dark text-white text-center py-3 mt-5">
|
||||||
|
<p>Version: {{ version }}</p>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
|
||||||
|
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
|
||||||
|
{% block scripts %}{% endblock %}
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -1,98 +1,61 @@
|
|||||||
<!DOCTYPE html>
|
{% extends "base.html" %}
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>KTVManager</title>
|
|
||||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
|
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}" />
|
|
||||||
<link rel="manifest" href="{{ url_for('static', filename='site.webmanifest') }}?v={{ version }}" />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<script>
|
|
||||||
if ('serviceWorker' in navigator) {
|
|
||||||
navigator.serviceWorker.register('{{ url_for("static", filename="service-worker.js") }}')
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<!-- Navbar -->
|
|
||||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
|
||||||
<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>
|
|
||||||
<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 -->
|
{% block title %}KTVManager{% endblock %}
|
||||||
<main class="container mt-5">
|
|
||||||
<h1>Welcome {{ username }}!</h1>
|
{% block content %}
|
||||||
<br>
|
<h1>Welcome {{ username }}!</h1>
|
||||||
<h2>You have {{ accounts }} active accounts</h2>
|
<br>
|
||||||
<br>
|
<h2>You have {{ accounts }} active accounts</h2>
|
||||||
|
<br>
|
||||||
{% if current_month_accounts %}
|
|
||||||
<h3>Accounts Expiring Within 30 Days</h3>
|
{% if current_month_accounts %}
|
||||||
<table class="table table-bordered table-striped">
|
<h3>Accounts Expiring Within 30 Days</h3>
|
||||||
<thead class="thead-dark">
|
<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>
|
<tr>
|
||||||
<th>Stream Name</th>
|
<td>{{ account.stream }}</td>
|
||||||
<th>Username</th>
|
<td>{{ account.username }}</td>
|
||||||
<th>Expiry Date</th>
|
<td>{{ account.expiaryDate_rendered }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
{% endfor %}
|
||||||
<tbody>
|
</tbody>
|
||||||
{% for account in current_month_accounts %}
|
</table>
|
||||||
<tr>
|
{% endif %}
|
||||||
<td>{{ account.stream }}</td>
|
{% if expired_accounts %}
|
||||||
<td>{{ account.username }}</td>
|
<h3>Expired Accounts</h3>
|
||||||
<td>{{ account.expiaryDate_rendered }}</td>
|
<table class="table table-bordered table-striped">
|
||||||
</tr>
|
<thead class="thead-dark">
|
||||||
{% endfor %}
|
<tr>
|
||||||
</tbody>
|
<th>Stream Name</th>
|
||||||
</table>
|
<th>Username</th>
|
||||||
{% endif %}
|
<th>Expiry Date</th>
|
||||||
{% if expired_accounts %}
|
</tr>
|
||||||
<h3>Expired Accounts</h3>
|
</thead>
|
||||||
<table class="table table-bordered table-striped">
|
<tbody>
|
||||||
<thead class="thead-dark">
|
{% for account in expired_accounts %}
|
||||||
<tr>
|
<tr>
|
||||||
<th>Stream Name</th>
|
<td>{{ account.stream }}</td>
|
||||||
<th>Username</th>
|
<td>{{ account.username }}</td>
|
||||||
<th>Expiry Date</th>
|
<td>{{ account.expiaryDate_rendered }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
{% endfor %}
|
||||||
<tbody>
|
</tbody>
|
||||||
{% for account in expired_accounts %}
|
</table>
|
||||||
<tr>
|
{% endif %}
|
||||||
<td>{{ account.stream }}</td>
|
{% endblock %}
|
||||||
<td>{{ account.username }}</td>
|
|
||||||
<td>{{ account.expiaryDate_rendered }}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
{% endif %}
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<!-- Footer -->
|
{% block scripts %}
|
||||||
<footer class="bg-dark text-white text-center py-3 mt-5">
|
<script>
|
||||||
<p>Version: {{ version }}</p>
|
if ('serviceWorker' in navigator) {
|
||||||
</footer>
|
navigator.serviceWorker.register('{{ url_for("static", filename="service-worker.js") }}')
|
||||||
|
}
|
||||||
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
|
</script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
|
{% endblock %}
|
||||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
@ -1,80 +1,36 @@
|
|||||||
<!-- templates/index.html -->
|
{% extends "base.html" %}
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>KTVManager</title>
|
|
||||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
|
|
||||||
<link rel="icon" type="image/png" href="{{ url_for('static', filename='favicon-96x96.png') }}" sizes="96x96" />
|
|
||||||
<link rel="icon" type="image/svg+xml" href="{{ url_for('static', filename='favicon.svg') }}" />
|
|
||||||
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}" />
|
|
||||||
<link rel="apple-touch-icon" sizes="180x180" href="{{ url_for('static', filename='apple-touch-icon.png') }}" />
|
|
||||||
<meta name="apple-mobile-web-app-title" content="kTvManager" />
|
|
||||||
<link rel="manifest" href="{{ url_for('static', filename='site.webmanifest') }}?v={{ version }}" />
|
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}" />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<!-- Navbar -->
|
{% block title %}KTVManager{% endblock %}
|
||||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
|
||||||
<a class="navbar-brand" href="/">KTVManager</a>
|
{% block content %}
|
||||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
<h1>Welcome to KTV Manager</h1>
|
||||||
<span class="navbar-toggler-icon"></span>
|
|
||||||
</button>
|
<!-- Login Form -->
|
||||||
<div class="collapse navbar-collapse" id="navbarNav">
|
<form action="/login" method="post" class="mt-3">
|
||||||
<ul class="navbar-nav ml-auto">
|
<div class="form-group">
|
||||||
<li class="nav-item">
|
<label for="username">Username:</label>
|
||||||
<a class="nav-link" href="/">Home</a>
|
<input type="text" class="form-control" id="username" name="username" required>
|
||||||
</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>
|
</div>
|
||||||
</nav>
|
<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>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
<!-- Main Content -->
|
{% block scripts %}
|
||||||
<main div class="container mt-5">
|
<script>
|
||||||
<h1>Welcome to KTV Manager</h1>
|
if ('serviceWorker' in navigator) {
|
||||||
|
navigator.serviceWorker.register('{{ url_for("static", filename="service-worker.js") }}')
|
||||||
<!-- Login Form -->
|
// .then(reg => {
|
||||||
<form action="/login" method="post" class="mt-3">
|
// console.log('Service worker:', reg);
|
||||||
<div class="form-group">
|
// .catch(err => {
|
||||||
<label for="username">Username:</label>
|
// console.log('Service worker:', err);
|
||||||
<input type="text" class="form-control" id="username" name="username" required>
|
// });
|
||||||
</div>
|
}
|
||||||
<div class="form-group">
|
</script>
|
||||||
<label for="password">Password:</label>
|
{% endblock %}
|
||||||
<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>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<footer class="bg-dark text-white text-center py-3 mt-5">
|
|
||||||
<p></p>
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
|
|
||||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
|
|
||||||
<script>
|
|
||||||
if ('serviceWorker' in navigator) {
|
|
||||||
navigator.serviceWorker.register('{{ url_for("static", filename="service-worker.js") }}')
|
|
||||||
// .then(reg => {
|
|
||||||
// console.log('Service worker:', reg);
|
|
||||||
// .catch(err => {
|
|
||||||
// console.log('Service worker:', err);
|
|
||||||
// });
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
@ -1,65 +1,23 @@
|
|||||||
<!-- templates/urls.html -->
|
{% extends "base.html" %}
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>KTVManager</title>
|
|
||||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
|
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}" />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<!-- Navbar (same as index.html) -->
|
{% block title %}URLs - KTVManager{% endblock %}
|
||||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
|
||||||
<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>
|
|
||||||
<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> <!-- Link to the URLs page -->
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="/urls">URLs</a> <!-- Link to the URLs page -->
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
<!-- Main Content -->
|
<h2>URLs</h2>
|
||||||
<main div class="container mt-5">
|
<table class="table table-striped">
|
||||||
<h2>URLs</h2>
|
<thead>
|
||||||
<table class="table table-striped">
|
<tr>
|
||||||
<thead>
|
<th>#</th>
|
||||||
<tr>
|
<th>URL</th>
|
||||||
<th>#</th>
|
</tr>
|
||||||
<th>URL</th>
|
</thead>
|
||||||
</tr>
|
<tbody>
|
||||||
</thead>
|
{% for url in urls %}
|
||||||
<tbody>
|
<tr>
|
||||||
{% for url in urls %}
|
<td>{{ loop.index }}</td>
|
||||||
<tr>
|
<td><a href="{{ url }}" target="_blank">{{ url }}</a></td>
|
||||||
<td>{{ loop.index }}</td>
|
</tr>
|
||||||
<td><a href="{{ url }}" target="_blank">{{ url }}</a></td>
|
{% endfor %}
|
||||||
</tr>
|
</tbody>
|
||||||
{% endfor %}
|
</table>
|
||||||
</tbody>
|
{% endblock %}
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<footer class="bg-dark text-white text-center py-3 mt-5">
|
|
||||||
<p></p>
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
|
|
||||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
@ -1,30 +1,13 @@
|
|||||||
<!DOCTYPE html>
|
{% extends "base.html" %}
|
||||||
<html lang="en">
|
|
||||||
<head>
|
{% block title %}Accounts - KTVManager{% endblock %}
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
{% block head_content %}
|
||||||
<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">
|
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.24/css/jquery.dataTables.min.css">
|
||||||
<link rel="stylesheet" href="https://cdn.datatables.net/responsive/2.2.9/css/responsive.dataTables.min.css">
|
<link rel="stylesheet" href="https://cdn.datatables.net/responsive/2.2.9/css/responsive.dataTables.min.css">
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}" />
|
{% endblock %}
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<!-- Navbar -->
|
|
||||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
|
||||||
<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>
|
|
||||||
<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>
|
|
||||||
|
|
||||||
|
{% block sub_nav %}
|
||||||
<!-- Sub-navigation for Accounts -->
|
<!-- Sub-navigation for Accounts -->
|
||||||
<div class="bg-light py-2">
|
<div class="bg-light py-2">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@ -38,56 +21,49 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
<!-- Main Content -->
|
{% block content %}
|
||||||
<main div class="container mt-5">
|
<h2>{{ username }}'s Accounts</h2>
|
||||||
<h2>{{ username }}'s Accounts</h2>
|
<div class="table-responsive">
|
||||||
<div class="table-responsive">
|
<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>
|
<th>Expiry Date</th>
|
||||||
<th>Expiry Date</th>
|
<th>Password</th>
|
||||||
<th>Password</th>
|
<th>Actions</th>
|
||||||
<th>Actions</th>
|
</tr>
|
||||||
</tr>
|
</thead>
|
||||||
</thead>
|
<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>
|
<td>{{ account.expiaryDate_rendered }}</td>
|
||||||
<td>{{ account.expiaryDate_rendered }}</td>
|
<td>{{ account.password }}</td>
|
||||||
<td>{{ account.password }}</td>
|
<td>
|
||||||
<td>
|
<form action="/accounts/delete" method="POST" style="display:inline;">
|
||||||
<form action="/accounts/delete" method="POST" style="display:inline;">
|
<input type="hidden" name="stream" value="{{ account.stream }}">
|
||||||
<input type="hidden" name="stream" value="{{ account.stream }}">
|
<input type="hidden" name="username" value="{{ account.username }}">
|
||||||
<input type="hidden" name="username" value="{{ account.username }}">
|
<button type="submit" class="btn btn-danger" onclick="return confirm('Are you sure you want to delete this account?');">
|
||||||
<button type="submit" class="btn btn-danger" onclick="return confirm('Are you sure you want to delete this account?');">
|
Delete
|
||||||
Delete
|
</button>
|
||||||
</button>
|
</form>
|
||||||
</form>
|
</td>
|
||||||
</td>
|
</tr>
|
||||||
</tr>
|
{% endfor %}
|
||||||
{% endfor %}
|
</tbody>
|
||||||
</tbody>
|
</table>
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</main>
|
{% endblock %}
|
||||||
|
|
||||||
<footer class="bg-dark text-white text-center py-3 mt-5">
|
{% block scripts %}
|
||||||
<p></p>
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
|
|
||||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
|
|
||||||
<script src="https://cdn.datatables.net/1.10.24/js/jquery.dataTables.min.js"></script>
|
<script src="https://cdn.datatables.net/1.10.24/js/jquery.dataTables.min.js"></script>
|
||||||
<script src="https://cdn.datatables.net/responsive/2.2.9/js/dataTables.responsive.min.js"></script>
|
<script src="https://cdn.datatables.net/responsive/2.2.9/js/dataTables.responsive.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
@ -114,7 +90,4 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user