Compare commits
	
		
			No commits in common. "9dc9b7e1b5e86d1b9a5dc982129d12fe4983ce08" and "13368a0437571a20419e5a97b0fe796ec01aa310" have entirely different histories.
		
	
	
		
			9dc9b7e1b5
			...
			13368a0437
		
	
		
@ -1,9 +0,0 @@
 | 
				
			|||||||
[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_stream_names
 | 
					from lib.reqs import get_urls, get_user_accounts, add_user_account, delete_user_account, get_user_accounts_count, get_stream_names
 | 
				
			||||||
from flask import send_from_directory
 | 
					from flask import send_from_directory
 | 
				
			||||||
import requests
 | 
					import requests
 | 
				
			||||||
import base64
 | 
					import base64
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										19
									
								
								backend/app.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								backend/app.py
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										37
									
								
								backend/lib/mysql.py
									
									
									
									
									
										Normal 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
 | 
				
			||||||
@ -3,10 +3,6 @@
 | 
				
			|||||||
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,10 +7,15 @@ 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/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -38,5 +43,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,6 +88,25 @@ 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,8 +1,13 @@
 | 
				
			|||||||
{% extends "base.html" %}
 | 
					<!-- templates/add_account.html -->
 | 
				
			||||||
 | 
					<!DOCTYPE html>
 | 
				
			||||||
{% block title %}Add Account - KTVManager{% endblock %}
 | 
					<html lang="en">
 | 
				
			||||||
 | 
					<head>
 | 
				
			||||||
{% block head_content %}
 | 
					    <meta charset="UTF-8">
 | 
				
			||||||
 | 
					    <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 */
 | 
				
			||||||
@ -11,9 +16,29 @@
 | 
				
			|||||||
            display: none;
 | 
					            display: none;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    </style>
 | 
					    </style>
 | 
				
			||||||
{% 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">
 | 
				
			||||||
@ -27,54 +52,57 @@
 | 
				
			|||||||
            </ul>
 | 
					            </ul>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
{% endblock %}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block content %}
 | 
					    <!-- Main Content -->
 | 
				
			||||||
    <h1>Add Account</h1>
 | 
					    <main class="container mt-5">
 | 
				
			||||||
    <div>
 | 
					        <h1>Add Account</h1>
 | 
				
			||||||
    <form action="/accounts/add" method="POST" onsubmit="showLoading()">
 | 
					        <div>
 | 
				
			||||||
        <div class="form-group">
 | 
					        <form action="/accounts/add" method="POST" onsubmit="showLoading()">
 | 
				
			||||||
            <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="image">Select Image</label>
 | 
					                <label for="username">Username</label>
 | 
				
			||||||
                <input type="file" class="form-control-file" id="image" name="image" accept="image/*" required>
 | 
					                <input type="text" class="form-control" id="username" name="username" value="{{ username }}" required>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
            <button type="submit" class="btn btn-success" id="ocrButton">
 | 
					            <div class="form-group">
 | 
				
			||||||
                <span class="spinner-border spinner-border-sm" id="ocrLoadingSpinner" role="status" aria-hidden="true"></span>
 | 
					                <label for="password">Password</label>
 | 
				
			||||||
                <span id="ocrButtonText">Load Details</span>
 | 
					                <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>
 | 
					            </button>
 | 
				
			||||||
        </form>
 | 
					        </form>
 | 
				
			||||||
    {% endif %}
 | 
					        {% if ocr_enabled %}
 | 
				
			||||||
    {% if text_input_enabled %}
 | 
					        <hr>
 | 
				
			||||||
    <hr>
 | 
					        <h2>Load Details Via OCR</h2>
 | 
				
			||||||
    <h2>Load Details Via Text</h2>
 | 
					            <form action="/OCRupload" method="POST" enctype="multipart/form-data" onsubmit="showLoadingOCR()">
 | 
				
			||||||
    <div class="form-group">
 | 
					                <div class="form-group">
 | 
				
			||||||
        <label for="accountDetails">Paste Account Details</label>
 | 
					                    <label for="image">Select Image</label>
 | 
				
			||||||
        <textarea class="form-control" id="accountDetails" rows="4"></textarea>
 | 
					                    <input type="file" class="form-control-file" id="image" name="image" accept="image/*" required>
 | 
				
			||||||
    </div>
 | 
					                </div>
 | 
				
			||||||
    {% endif %}
 | 
					                <button type="submit" class="btn btn-success" id="ocrButton">
 | 
				
			||||||
{% endblock %}
 | 
					                    <span class="spinner-border spinner-border-sm" id="ocrLoadingSpinner" role="status" aria-hidden="true"></span>
 | 
				
			||||||
 | 
					                    <span id="ocrButtonText">Load Details</span>
 | 
				
			||||||
{% block scripts %}
 | 
					                </button>
 | 
				
			||||||
 | 
					            </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() {
 | 
				
			||||||
@ -147,4 +175,5 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    </script>
 | 
					    </script>
 | 
				
			||||||
{% endblock %}
 | 
					</body>
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,57 +0,0 @@
 | 
				
			|||||||
<!-- 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,61 +1,98 @@
 | 
				
			|||||||
{% 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') }}" />
 | 
				
			||||||
 | 
					    <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>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block title %}KTVManager{% endblock %}
 | 
					    <!-- Main Content -->
 | 
				
			||||||
 | 
					    <main class="container mt-5">
 | 
				
			||||||
{% block content %}
 | 
					        <h1>Welcome {{ username }}!</h1>
 | 
				
			||||||
    <h1>Welcome {{ username }}!</h1>
 | 
					        <br>
 | 
				
			||||||
    <br>
 | 
					        <h2>You have {{ accounts }} active accounts</h2>
 | 
				
			||||||
    <h2>You have {{ accounts }} active accounts</h2>
 | 
					        <br>
 | 
				
			||||||
    <br>
 | 
					        
 | 
				
			||||||
    
 | 
					        {% if current_month_accounts %}
 | 
				
			||||||
    {% if current_month_accounts %}
 | 
					            <h3>Accounts Expiring Within 30 Days</h3>
 | 
				
			||||||
        <h3>Accounts Expiring Within 30 Days</h3>
 | 
					            <table class="table table-bordered table-striped">
 | 
				
			||||||
        <table class="table table-bordered table-striped">
 | 
					                <thead class="thead-dark">
 | 
				
			||||||
            <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>
 | 
				
			||||||
                        <td>{{ account.stream }}</td>
 | 
					                        <th>Stream Name</th>
 | 
				
			||||||
                        <td>{{ account.username }}</td>
 | 
					                        <th>Username</th>
 | 
				
			||||||
                        <td>{{ account.expiaryDate_rendered }}</td>
 | 
					                        <th>Expiry Date</th>
 | 
				
			||||||
                    </tr>
 | 
					                    </tr>
 | 
				
			||||||
                {% endfor %}
 | 
					                </thead>
 | 
				
			||||||
            </tbody>
 | 
					                <tbody>
 | 
				
			||||||
        </table>
 | 
					                    {% for account in current_month_accounts %}
 | 
				
			||||||
    {% endif %}
 | 
					                        <tr>
 | 
				
			||||||
    {% if expired_accounts %}
 | 
					                            <td>{{ account.stream }}</td>
 | 
				
			||||||
        <h3>Expired Accounts</h3>
 | 
					                            <td>{{ account.username }}</td>
 | 
				
			||||||
        <table class="table table-bordered table-striped">
 | 
					                            <td>{{ account.expiaryDate_rendered }}</td>
 | 
				
			||||||
            <thead class="thead-dark">
 | 
					                        </tr>
 | 
				
			||||||
                <tr>
 | 
					                    {% endfor %}
 | 
				
			||||||
                    <th>Stream Name</th>
 | 
					                </tbody>
 | 
				
			||||||
                    <th>Username</th>
 | 
					            </table>
 | 
				
			||||||
                    <th>Expiry Date</th>
 | 
					        {% endif %}
 | 
				
			||||||
                </tr>
 | 
					        {% if expired_accounts %}
 | 
				
			||||||
            </thead>
 | 
					            <h3>Expired Accounts</h3>
 | 
				
			||||||
            <tbody>
 | 
					            <table class="table table-bordered table-striped">
 | 
				
			||||||
                {% for account in expired_accounts %}
 | 
					                <thead class="thead-dark">
 | 
				
			||||||
                    <tr>
 | 
					                    <tr>
 | 
				
			||||||
                        <td>{{ account.stream }}</td>
 | 
					                        <th>Stream Name</th>
 | 
				
			||||||
                        <td>{{ account.username }}</td>
 | 
					                        <th>Username</th>
 | 
				
			||||||
                        <td>{{ account.expiaryDate_rendered }}</td>
 | 
					                        <th>Expiry Date</th>
 | 
				
			||||||
                    </tr>
 | 
					                    </tr>
 | 
				
			||||||
                {% endfor %}
 | 
					                </thead>
 | 
				
			||||||
            </tbody>
 | 
					                <tbody>
 | 
				
			||||||
        </table>
 | 
					                    {% for account in expired_accounts %}
 | 
				
			||||||
    {% endif %}
 | 
					                        <tr>
 | 
				
			||||||
{% endblock %}
 | 
					                            <td>{{ account.stream }}</td>
 | 
				
			||||||
 | 
					                            <td>{{ account.username }}</td>
 | 
				
			||||||
 | 
					                            <td>{{ account.expiaryDate_rendered }}</td>
 | 
				
			||||||
 | 
					                        </tr>
 | 
				
			||||||
 | 
					                    {% endfor %}
 | 
				
			||||||
 | 
					                </tbody>
 | 
				
			||||||
 | 
					            </table>
 | 
				
			||||||
 | 
					        {% endif %}
 | 
				
			||||||
 | 
					    </main>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block scripts %}
 | 
					    <!-- Footer -->
 | 
				
			||||||
<script>
 | 
					    <footer class="bg-dark text-white text-center py-3 mt-5">
 | 
				
			||||||
    if ('serviceWorker' in navigator) {
 | 
					        <p>Version: {{ version }}</p>
 | 
				
			||||||
        navigator.serviceWorker.register('{{ url_for("static", filename="service-worker.js") }}')
 | 
					    </footer>
 | 
				
			||||||
    }
 | 
					
 | 
				
			||||||
</script>
 | 
					    <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
 | 
				
			||||||
{% endblock %}
 | 
					    <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,36 +1,80 @@
 | 
				
			|||||||
{% extends "base.html" %}
 | 
					<!-- 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>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>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block title %}KTVManager{% endblock %}
 | 
					    <!-- Navbar -->
 | 
				
			||||||
 | 
					    <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
 | 
				
			||||||
{% block content %}
 | 
					        <a class="navbar-brand" href="/">KTVManager</a>
 | 
				
			||||||
    <h1>Welcome to KTV Manager</h1>
 | 
					        <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>
 | 
				
			||||||
    <!-- Login Form -->
 | 
					        </button>
 | 
				
			||||||
    <form action="/login" method="post" class="mt-3">
 | 
					        <div class="collapse navbar-collapse" id="navbarNav">
 | 
				
			||||||
        <div class="form-group">
 | 
					            <ul class="navbar-nav ml-auto">
 | 
				
			||||||
            <label for="username">Username:</label>
 | 
					                <li class="nav-item">
 | 
				
			||||||
            <input type="text" class="form-control" id="username" name="username" required>
 | 
					                    <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>
 | 
					        </div>
 | 
				
			||||||
        <div class="form-group">
 | 
					    </nav>
 | 
				
			||||||
            <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 %}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block scripts %}
 | 
					    <!-- Main Content -->
 | 
				
			||||||
<script>
 | 
					    <main div class="container mt-5">
 | 
				
			||||||
    if ('serviceWorker' in navigator) {
 | 
					        <h1>Welcome to KTV Manager</h1>
 | 
				
			||||||
        navigator.serviceWorker.register('{{ url_for("static", filename="service-worker.js") }}')
 | 
					
 | 
				
			||||||
        // .then(reg => {
 | 
					        <!-- Login Form -->
 | 
				
			||||||
        // 		console.log('Service worker:', reg);
 | 
					        <form action="/login" method="post" class="mt-3">
 | 
				
			||||||
        // .catch(err => {
 | 
					            <div class="form-group">
 | 
				
			||||||
        // 	console.log('Service worker:', err);
 | 
					                <label for="username">Username:</label>
 | 
				
			||||||
        // });
 | 
					                <input type="text" class="form-control" id="username" name="username" required>
 | 
				
			||||||
    }
 | 
					            </div>
 | 
				
			||||||
</script>
 | 
					            <div class="form-group">
 | 
				
			||||||
{% endblock %}
 | 
					                <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>
 | 
				
			||||||
 | 
					    </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,23 +1,65 @@
 | 
				
			|||||||
{% extends "base.html" %}
 | 
					<!-- templates/urls.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>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block title %}URLs - KTVManager{% endblock %}
 | 
					    <!-- Navbar (same as index.html) -->
 | 
				
			||||||
 | 
					    <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 %}
 | 
					
 | 
				
			||||||
    <h2>URLs</h2>
 | 
					    <!-- Main Content -->
 | 
				
			||||||
    <table class="table table-striped">
 | 
					    <main div class="container mt-5">
 | 
				
			||||||
        <thead>
 | 
					        <h2>URLs</h2>
 | 
				
			||||||
            <tr>
 | 
					        <table class="table table-striped">
 | 
				
			||||||
                <th>#</th>
 | 
					            <thead>
 | 
				
			||||||
                <th>URL</th>
 | 
					                <tr>
 | 
				
			||||||
            </tr>
 | 
					                    <th>#</th>
 | 
				
			||||||
        </thead>
 | 
					                    <th>URL</th>
 | 
				
			||||||
        <tbody>
 | 
					                </tr>
 | 
				
			||||||
            {% for url in urls %}
 | 
					            </thead>
 | 
				
			||||||
            <tr>
 | 
					            <tbody>
 | 
				
			||||||
                <td>{{ loop.index }}</td>
 | 
					                {% for url in urls %}
 | 
				
			||||||
                <td><a href="{{ url }}" target="_blank">{{ url }}</a></td>
 | 
					                <tr>
 | 
				
			||||||
            </tr>
 | 
					                    <td>{{ loop.index }}</td>
 | 
				
			||||||
            {% endfor %}
 | 
					                    <td><a href="{{ url }}" target="_blank">{{ url }}</a></td>
 | 
				
			||||||
        </tbody>
 | 
					                </tr>
 | 
				
			||||||
    </table>
 | 
					                {% endfor %}
 | 
				
			||||||
{% endblock %}
 | 
					            </tbody>
 | 
				
			||||||
 | 
					        </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,13 +1,30 @@
 | 
				
			|||||||
{% extends "base.html" %}
 | 
					<!DOCTYPE html>
 | 
				
			||||||
 | 
					<html lang="en">
 | 
				
			||||||
{% block title %}Accounts - KTVManager{% endblock %}
 | 
					<head>
 | 
				
			||||||
 | 
					    <meta charset="UTF-8">
 | 
				
			||||||
{% block head_content %}
 | 
					    <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="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">
 | 
				
			||||||
{% endblock %}
 | 
					    <link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}" />    
 | 
				
			||||||
 | 
					</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">
 | 
				
			||||||
@ -21,49 +38,56 @@
 | 
				
			|||||||
            </ul>
 | 
					            </ul>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
{% endblock %}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block content %}
 | 
					    <!-- Main Content -->
 | 
				
			||||||
    <h2>{{ username }}'s Accounts</h2>
 | 
					    <main div class="container mt-5">
 | 
				
			||||||
    <div class="table-responsive">
 | 
					        <h2>{{ username }}'s Accounts</h2>
 | 
				
			||||||
        <table class="table table-striped" id="accountsTable">
 | 
					        <div class="table-responsive">
 | 
				
			||||||
            <thead>
 | 
					            <table class="table table-striped" id="accountsTable">
 | 
				
			||||||
                <tr>
 | 
					                <thead>
 | 
				
			||||||
                    <!-- <th>#</th> -->
 | 
					                    <tr>
 | 
				
			||||||
                    <th>Username</th>
 | 
					                        <!-- <th>#</th> -->
 | 
				
			||||||
                    <th>Stream</th>
 | 
					                        <th>Username</th>
 | 
				
			||||||
                    <th>Stream URL</th>
 | 
					                        <th>Stream</th>
 | 
				
			||||||
                    <th>Expiry Date</th>
 | 
					                        <th>Stream URL</th>
 | 
				
			||||||
                    <th>Password</th>
 | 
					                        <th>Expiry Date</th>
 | 
				
			||||||
                    <th>Actions</th>
 | 
					                        <th>Password</th>
 | 
				
			||||||
                </tr>
 | 
					                        <th>Actions</th>
 | 
				
			||||||
            </thead>
 | 
					                    </tr>
 | 
				
			||||||
            <tbody>
 | 
					                </thead>
 | 
				
			||||||
                {% for account in user_accounts %}
 | 
					                <tbody>
 | 
				
			||||||
                <tr>
 | 
					                    {% for account in user_accounts %}
 | 
				
			||||||
                    <!-- <td>{{ loop.index }}</td> -->
 | 
					                    <tr>
 | 
				
			||||||
                    <td>{{ account.username }}</td>
 | 
					                        <!-- <td>{{ loop.index }}</td> -->
 | 
				
			||||||
                    <td>{{ account.stream }}</td>
 | 
					                        <td>{{ account.username }}</td>
 | 
				
			||||||
                    <td><a href="{{ account.streamURL }}" target="_blank">{{ account.streamURL }}</a></td>
 | 
					                        <td>{{ account.stream }}</td>
 | 
				
			||||||
                    <td>{{ account.expiaryDate_rendered }}</td>
 | 
					                        <td><a href="{{ account.streamURL }}" target="_blank">{{ account.streamURL }}</a></td>
 | 
				
			||||||
                    <td>{{ account.password }}</td>
 | 
					                        <td>{{ account.expiaryDate_rendered }}</td>
 | 
				
			||||||
                    <td>
 | 
					                        <td>{{ account.password }}</td>
 | 
				
			||||||
                        <form action="/accounts/delete" method="POST" style="display:inline;">
 | 
					                        <td>
 | 
				
			||||||
                            <input type="hidden" name="stream" value="{{ account.stream }}">
 | 
					                            <form action="/accounts/delete" method="POST" style="display:inline;">
 | 
				
			||||||
                            <input type="hidden" name="username" value="{{ account.username }}">
 | 
					                                <input type="hidden" name="stream" value="{{ account.stream }}">
 | 
				
			||||||
                            <button type="submit" class="btn btn-danger" onclick="return confirm('Are you sure you want to delete this account?');">
 | 
					                                <input type="hidden" name="username" value="{{ account.username }}">
 | 
				
			||||||
                                Delete
 | 
					                                <button type="submit" class="btn btn-danger" onclick="return confirm('Are you sure you want to delete this account?');">
 | 
				
			||||||
                            </button>
 | 
					                                    Delete
 | 
				
			||||||
                        </form>
 | 
					                                </button>
 | 
				
			||||||
                    </td>
 | 
					                            </form>
 | 
				
			||||||
                </tr>
 | 
					                        </td>
 | 
				
			||||||
                {% endfor %}
 | 
					                    </tr>
 | 
				
			||||||
            </tbody>
 | 
					                    {% endfor %}
 | 
				
			||||||
        </table>
 | 
					                </tbody>
 | 
				
			||||||
 | 
					            </table>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
{% endblock %}
 | 
					    </main>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block scripts %}
 | 
					    <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.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>
 | 
				
			||||||
@ -90,4 +114,7 @@
 | 
				
			|||||||
            });
 | 
					            });
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    </script>
 | 
					    </script>
 | 
				
			||||||
{% endblock %}
 | 
					    
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					</body>
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user