adds status and server time indicators. fixes checkboxes

This commit is contained in:
2025-02-10 18:22:06 +01:00
parent 2b6aebdab4
commit 0340dea4f8
6 changed files with 96 additions and 36 deletions

View File

@@ -1,3 +1,4 @@
import os
from flask import Flask from flask import Flask
from flask_bootstrap import Bootstrap5 from flask_bootstrap import Bootstrap5
from datetime import datetime from datetime import datetime
@@ -12,6 +13,8 @@ from app.logging_config import init_logger
def create_app(): def create_app():
app = Flask(__name__) app = Flask(__name__)
os.environ['TZ'] = 'UTC'
config = load_config() config = load_config()
app.config['SECRET_KEY'] = config['DEFAULT']['SECRET_KEY'] app.config['SECRET_KEY'] = config['DEFAULT']['SECRET_KEY']

View File

@@ -1,6 +1,75 @@
class Common {
constructor() {
this.activityIndicator = document.getElementById('activity_indicator');
this.endTimeElement = document.getElementById('end_time');
this.serverTimeElement = document.getElementById('server_time');
this.init();
}
init() {
this.updateServerTime();
setInterval(() => this.updateServerTime(), 60000); // Update every minute
this.checkScrapingStatus();
}
async fetchEndTime() {
try {
const response = await fetch('/scraping_get_end_time');
const data = await response.json();
if (data.end_time) {
const endTime = new Date(data.end_time);
const localEndTime = endTime.toLocaleString();
this.endTimeElement.textContent = `End Time: ${endTime} TCT`;
}
} catch (error) {
this.endTimeElement.textContent = 'Error fetching end time';
console.error('Error fetching end time:', error);
}
}
async updateServerTime() {
try {
const response = await fetch('/server_time');
const data = await response.json();
this.serverTimeElement.textContent = `Server Time (UTC): ${data.server_time}`;
} catch (error) {
console.error('Error fetching server time:', error);
}
}
async checkScrapingStatus() {
try {
const response = await fetch('/scraping_status');
const data = await response.json();
if (data.scraping_active) {
this.activityIndicator.classList.remove('text-bg-danger');
this.activityIndicator.classList.add('text-bg-success');
this.activityIndicator.textContent = 'Active';
this.endTimeElement.classList.remove('d-none');
this.endTimeElement.textContent = data.end_time;
await this.fetchEndTime();
} else {
this.activityIndicator.classList.remove('text-bg-success');
this.activityIndicator.classList.add('text-bg-danger');
this.activityIndicator.textContent = 'Inactive';
this.endTimeElement.textContent = '';
this.endTimeElement.classList.add('d-none');
}
} catch (error) {
console.error('Error checking scraping status:', error);
}
}
}
document.addEventListener('DOMContentLoaded', () => {
new Common();
});
function checkAllCheckboxes(tableId, checkAllCheckboxId) { function checkAllCheckboxes(tableId, checkAllCheckboxId) {
const table = document.getElementById(tableId); const table = document.getElementById(tableId);
const checkboxes = table.querySelectorAll('input[type="checkbox"]'); const checkboxes = table.querySelectorAll('input[type="checkbox"]:not(:disabled)');
const checkAllCheckbox = document.getElementById(checkAllCheckboxId); const checkAllCheckbox = document.getElementById(checkAllCheckboxId);
checkboxes.forEach(checkbox => checkbox.checked = checkAllCheckbox.checked); checkboxes.forEach(checkbox => checkbox.checked = checkAllCheckbox.checked);

View File

@@ -9,52 +9,26 @@ class ScraperApp {
} }
init() { init() {
this.checkScrapingStatus(); this.checkScrapingStatusIndex();
this.addEventListeners(); this.addEventListeners();
} }
async checkScrapingStatus() { async checkScrapingStatusIndex() {
try { try {
const response = await fetch('/scraping_status'); const response = await fetch('/scraping_status');
const data = await response.json(); const data = await response.json();
if (data.scraping_active) { if (data.scraping_active) {
this.startButton.disabled = true; this.startButton.disabled = true;
this.stopButton.disabled = false; this.stopButton.disabled = false;
this.activityIndicator.classList.remove('text-bg-danger');
this.activityIndicator.classList.add('text-bg-success');
this.activityIndicator.textContent = 'Active';
this.endTimeElement.classList.remove('d-none');
this.endTimeElement.textContent = data.end_time;
await this.fetchEndTime();
} else { } else {
this.startButton.disabled = false; this.startButton.disabled = false;
this.stopButton.disabled = true; this.stopButton.disabled = true;
this.activityIndicator.classList.remove('text-bg-success');
this.activityIndicator.classList.add('text-bg-danger');
this.activityIndicator.textContent = 'Inactive';
this.endTimeElement.textContent = '';
this.endTimeElement.classList.add('d-none');
} }
} catch (error) { } catch (error) {
console.error('Error checking scraping status:', error); console.error('Error checking scraping status:', error);
} }
} }
async fetchEndTime() {
try {
const response = await fetch('/scraping_get_end_time');
const data = await response.json();
if (data.end_time) {
this.endTimeElement.textContent = `Track until: ${data.end_time}`;
}
} catch (error) {
this.endTimeElement.textContent = 'Error fetching end time';
console.error('Error fetching end time:', error);
}
}
async startScraping(event) { async startScraping(event) {
event.preventDefault(); // Prevent the default form submission event.preventDefault(); // Prevent the default form submission
const formData = new FormData(this.form); const formData = new FormData(this.form);
@@ -65,7 +39,7 @@ class ScraperApp {
}); });
const data = await response.json(); const data = await response.json();
if (data.status === "Scraping started") { if (data.status === "Scraping started") {
this.checkScrapingStatus(); this.checkScrapingStatusIndex();
} }
} catch (error) { } catch (error) {
console.error('Error starting scraping:', error); console.error('Error starting scraping:', error);
@@ -79,7 +53,7 @@ class ScraperApp {
}); });
const data = await response.json(); const data = await response.json();
if (data.status === "Scraping stopped") { if (data.status === "Scraping stopped") {
this.checkScrapingStatus(); this.checkScrapingStatusIndex();
} }
} catch (error) { } catch (error) {
console.error('Error stopping scraping:', error); console.error('Error stopping scraping:', error);
@@ -93,4 +67,6 @@ class ScraperApp {
} }
// Initialize the application when DOM is fully loaded // Initialize the application when DOM is fully loaded
document.addEventListener('DOMContentLoaded', () => new ScraperApp()); document.addEventListener('DOMContentLoaded', () => {
new ScraperApp();
});

View File

@@ -1,4 +1,3 @@
<!-- app/templates/includes/navigation.html -->
<nav class="navbar navbar-nav navbar-expand-md bg-primary"> <nav class="navbar navbar-nav navbar-expand-md bg-primary">
<div class="container-fluid"> <div class="container-fluid">
<a class="navbar-brand" href="/">Torn User Activity Scraper</a> <a class="navbar-brand" href="/">Torn User Activity Scraper</a>
@@ -14,4 +13,11 @@
</label> </label>
</div> </div>
</div> </div>
</nav> </nav>
<div id="status_container" class="container-fluid d-flex justify-content-center">
<div class="d-flex m-2" id="navbarNav">
<div id="activity_indicator" class="badge text-bg-danger fw-bold m-1">Inactive</div>
<div id="server_time" class="badge text-bg-secondary m-1"></div>
<div id="end_time" class="badge text-bg-info d-none m-1"></div>
</div>
</div>

View File

@@ -7,8 +7,6 @@
<h2>Scraper</h2> <h2>Scraper</h2>
</div> </div>
<div class="col text-end"> <div class="col text-end">
<span id="end_time" class="badge text-bg-info d-none"></span>
<span id="activity_indicator" class="badge text-bg-danger fw-bold">Inactive</span>
</div> </div>
</div> </div>
<form id="scrapingForm" method="POST" action="{{ url_for('start_scraping') }}"> <form id="scrapingForm" method="POST" action="{{ url_for('start_scraping') }}">

View File

@@ -9,6 +9,8 @@ from app.api import scraper as scraper
from app.analysis import load_data, load_analysis_modules from app.analysis import load_data, load_analysis_modules
from datetime import datetime
views_bp = Blueprint("views", __name__) views_bp = Blueprint("views", __name__)
def register_views(app): def register_views(app):
@@ -115,4 +117,10 @@ def register_views(app):
context["results"] = results context["results"] = results
return render_template("analyze.html", **context) return render_template("analyze.html", **context)
@views_bp.route('/server_time')
def server_time():
current_time = datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')
return {'server_time': current_time}
app.register_blueprint(views_bp) app.register_blueprint(views_bp)