Compare commits
75 Commits
51e9b87a3f
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 504d237405 | |||
| 6696bcc4e7 | |||
| 32a1458218 | |||
| 4697086f86 | |||
| c4b9e5f360 | |||
| 0a9934b889 | |||
| 8ad1650079 | |||
| 6e50013a84 | |||
| dba9a7690d | |||
| 319d237e5d | |||
| af6515e55f | |||
| 1b83098fd0 | |||
| ec11a3d4c4 | |||
| 024b829562 | |||
| d918540252 | |||
| 9022704e5c | |||
| 4046d25aa7 | |||
| aac2ec7ce2 | |||
| a714814ad0 | |||
| 47555303e2 | |||
| 9c83537d65 | |||
| b7d47b130d | |||
| baa8c1392d | |||
| b18012713e | |||
| b714a6c4e6 | |||
| 7188ad7c75 | |||
| 68314ba7af | |||
| f1e591ab5b | |||
| ee5d1b2758 | |||
| 7f2d0ec2f6 | |||
| 2b22eaf0e9 | |||
| 19d646aa40 | |||
| acd57b90a8 | |||
| d63d9cdb78 | |||
| 2ca97cba47 | |||
| 5ee126d0ec | |||
| 0d69fcc296 | |||
| 46c99f1ae0 | |||
| 1801e6d054 | |||
| ae17970d8c | |||
| 30fef37d45 | |||
| 76e90450f8 | |||
| 845a1c8494 | |||
| 4104ee47c4 | |||
| 597900d7b6 | |||
| 942a3adaf6 | |||
| 96960c17a1 | |||
| 6f7fc56e32 | |||
| 1cfa2668b2 | |||
| f524ed4e6a | |||
| 245f524c38 | |||
| 76f857ca0a | |||
| 6aeea9dedb | |||
| dd6ca2d75b | |||
| d9796b0b87 | |||
| 9958763f6f | |||
| a71f3f3681 | |||
| 9f8a9eebfe | |||
| a1fc7a4b27 | |||
| 0e8b558747 | |||
| b6d60e7210 | |||
| bf31f647e7 | |||
| 121cc91ad1 | |||
| ac2b23c459 | |||
| 10675cffbc | |||
| 32dee47628 | |||
| c08f81bd03 | |||
| 5063d78198 | |||
| a12366867d | |||
| 614dea44b4 | |||
| 305b269093 | |||
| 612ee5c740 | |||
| 64c2269c0a | |||
| f3ac9a8c1b | |||
| db414a0b03 |
86
client/bs_shutdown.py
Normal file
86
client/bs_shutdown.py
Normal file
@@ -0,0 +1,86 @@
|
||||
import urllib.request
|
||||
import json
|
||||
import socket
|
||||
from datetime import datetime
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
DEFAULT_SHUTDOWN = "21:00"
|
||||
|
||||
LAST_VALUE = 0
|
||||
|
||||
machine_name = socket.gethostname()
|
||||
url = "http://192.168.50.27:5000/lookup"
|
||||
payload = {
|
||||
"name": machine_name,
|
||||
}
|
||||
|
||||
def get_data():
|
||||
data = json.dumps(payload).encode("utf-8")
|
||||
|
||||
req = urllib.request.Request(
|
||||
url,
|
||||
headers={"Content-Type": "application/json"},
|
||||
data=data,
|
||||
method="POST"
|
||||
)
|
||||
|
||||
try:
|
||||
with urllib.request.urlopen(req, timeout=10) as response:
|
||||
data = response.read()
|
||||
json_data = json.loads(data)
|
||||
print(json_data)
|
||||
return json_data
|
||||
except:
|
||||
return None
|
||||
|
||||
def to_seconds(t):
|
||||
return t.hour * 3600 + t.minute * 60 + t.second
|
||||
|
||||
def set_shutdown(time, now):
|
||||
global LAST_VALUE
|
||||
|
||||
if (time - now) < 0 or time == LAST_VALUE:
|
||||
return
|
||||
LAST_VALUE = time
|
||||
print("[BS Shutdown] shutting down in " + str(time - now) + " seconds")
|
||||
# subprocess.run(["shutdown", "/s", "/t", (time - now), " "])
|
||||
|
||||
|
||||
def remove_shutdown():
|
||||
print("[BS Shutdown] Removed shutdown")
|
||||
# subprocess.run(["shutdown", "/a"])
|
||||
|
||||
def update():
|
||||
global LAST_VALUE
|
||||
|
||||
data = get_data()
|
||||
|
||||
if data is not None and data["noshutdown"] == 1:
|
||||
if (LAST_VALUE != 0):
|
||||
remove_shutdown() # In case
|
||||
LAST_VALUE = 0
|
||||
return
|
||||
|
||||
if data is None:
|
||||
time = to_seconds(datetime.strptime(DEFAULT_SHUTDOWN, "%H:%M").time())
|
||||
else:
|
||||
time = to_seconds(datetime.strptime(data["time"], "%H:%M").time())
|
||||
now = to_seconds(datetime.now().time())
|
||||
|
||||
if (time - now) < 0:
|
||||
return
|
||||
|
||||
if (time == LAST_VALUE):
|
||||
return
|
||||
|
||||
if (LAST_VALUE != 0):
|
||||
remove_shutdown()
|
||||
print("[BS Shutdown] New value")
|
||||
LAST_VALUE = time
|
||||
set_shutdown(time, now)
|
||||
|
||||
if __name__ == '__main__':
|
||||
while True:
|
||||
update()
|
||||
time.sleep(30)
|
||||
@@ -1,23 +1,125 @@
|
||||
from flask import Flask, render_template, request, redirect, url_for
|
||||
from flask import Flask, render_template, request, redirect, url_for, jsonify
|
||||
import sqlite3
|
||||
import re
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
items = []
|
||||
pattern = re.compile(r"^(?:[01]\d|2[0-3]):[0-5]\d$") # Regex "XX:XX"
|
||||
|
||||
DB_PATH = "data.db"
|
||||
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute("""
|
||||
CREATE TABLE IF NOT EXISTS items (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
time TEXT,
|
||||
noshutdown INTEGER DEFAULT 0
|
||||
)
|
||||
""")
|
||||
cursor.execute("""
|
||||
CREATE TABLE IF NOT EXISTS val (
|
||||
default_time TEXT NOT NULL DEFAULT '21:00'
|
||||
)
|
||||
""")
|
||||
cursor.execute("SELECT COUNT(*) FROM val")
|
||||
count = cursor.fetchone()[0]
|
||||
if count == 0:
|
||||
cursor.execute("INSERT INTO val (default_time) VALUES (?)", ('21:00',))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
def get_db_connection():
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
conn.row_factory = sqlite3.Row
|
||||
return conn
|
||||
|
||||
@app.route("/")
|
||||
def mainpage():
|
||||
return render_template('index.html', title='BG Shutdown', items=items)
|
||||
conn = get_db_connection()
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("SELECT name, time, noshutdown FROM items ORDER BY name")
|
||||
items = cursor.fetchall()
|
||||
cursor.execute("SELECT default_time FROM val")
|
||||
default_time_row = cursor.fetchone()
|
||||
default_time = default_time_row[0] if default_time_row else '21:00'
|
||||
conn.close()
|
||||
return render_template('index.html', title='BS Shutdown', items=items, default_time=default_time)
|
||||
|
||||
@app.route('/submit', methods =['POST'])
|
||||
def submit():
|
||||
value = request.form.get("query")
|
||||
time_value = request.form.get("time")
|
||||
print(value)
|
||||
items.append((value, time_value))
|
||||
noshutdown = 1 if request.form.get("noshutdown") == "on" else 0
|
||||
if not value:
|
||||
return redirect(url_for("mainpage"))
|
||||
if noshutdown == 0 and not time_value:
|
||||
return redirect(url_for("mainpage"))
|
||||
if noshutdown == 1:
|
||||
time_value = 'None'
|
||||
if time_value != 'None':
|
||||
if bool(pattern.match(time_value)) is not True:
|
||||
return redirect(url_for("mainpage"))
|
||||
conn = get_db_connection()
|
||||
cursor = conn.cursor()
|
||||
cursor.execute('SELECT 1 FROM items WHERE name = ?', (value,))
|
||||
item = cursor.fetchone()
|
||||
if item:
|
||||
cursor.execute("UPDATE items SET time = ?, noshutdown = ? WHERE name = ?", (time_value, noshutdown, value))
|
||||
else:
|
||||
cursor.execute("INSERT INTO items (name, time, noshutdown) VALUES (?, ?, ?)", (value, time_value, noshutdown))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return redirect(url_for("mainpage"))
|
||||
|
||||
@app.route("/submit-default", methods=["POST"])
|
||||
def submit_default():
|
||||
time_value = request.form.get("default-time")
|
||||
conn = get_db_connection()
|
||||
cursor = conn.cursor()
|
||||
if bool(pattern.match(time_value)) is not True:
|
||||
return redirect(url_for("mainpage"))
|
||||
cursor.execute("UPDATE val SET default_time = ?", (time_value,))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return redirect(url_for("mainpage"))
|
||||
|
||||
@app.route("/delete", methods=["POST"])
|
||||
def delete():
|
||||
value = request.form.get("item_name")
|
||||
time_value = request.form.get("item_time")
|
||||
if value in items:
|
||||
items.remove((value, time_value))
|
||||
print("Deleting:", value)
|
||||
return redirect(url_for("mainpage"))
|
||||
conn = get_db_connection()
|
||||
cursor = conn.cursor()
|
||||
cursor.execute('SELECT 1 FROM items WHERE name = ?', (value,))
|
||||
item = cursor.fetchone()
|
||||
if not item:
|
||||
conn.close()
|
||||
return redirect(url_for("mainpage"))
|
||||
cursor.execute(
|
||||
"DELETE FROM items WHERE name = ?",
|
||||
(value,)
|
||||
)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return redirect(url_for("mainpage"))
|
||||
|
||||
@app.route("/lookup", methods=["POST"])
|
||||
def lookup():
|
||||
data = request.get_json()
|
||||
if not data or "name" not in data:
|
||||
return jsonify({"error": "Not found"}), 404
|
||||
name = data["name"]
|
||||
conn = get_db_connection()
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(
|
||||
"SELECT name, time, noshutdown FROM items WHERE name = ?",
|
||||
(name,)
|
||||
)
|
||||
item = cursor.fetchone()
|
||||
conn.close()
|
||||
|
||||
if item:
|
||||
return jsonify({"name": item["name"], "noshutdown": item["noshutdown"], "time": item["time"]}), 200
|
||||
else:
|
||||
return jsonify({"error": "Not found"}), 404
|
||||
@@ -35,14 +35,17 @@
|
||||
<header>
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="{{ url_for('mainpage') }}">BG Shutdown</a>
|
||||
<a class="navbar-brand" href="{{ url_for('mainpage') }}">BS Shutdown</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-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 ms-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if title=='BG Shutdown' %}active{% endif %}" href="{{ url_for('mainpage') }}">Accueil</a>
|
||||
<a class="nav-link {% if title=='BS Shutdown' %}active{% endif %}" href="{{ url_for('mainpage') }}">Accueil</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if title=='BG Shutdown' %}active{% endif %}" href="{{ url_for('mainpage') }}">Groupes</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -50,7 +53,7 @@
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main class="container my-5">
|
||||
<main class="container my-5 flex-fill">
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
|
||||
|
||||
@@ -1,59 +1,108 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">
|
||||
|
||||
<div class="container py-4">
|
||||
|
||||
<!-- Formulaire réduit avec sélection d'heure -->
|
||||
<div class="card bg-dark bg-opacity-75 p-3 mb-4">
|
||||
<form method="post" action="/submit" class="row g-2 align-items-center justify-content-start">
|
||||
<div class="row g-2 align-items-center">
|
||||
|
||||
<!-- Champ texte -->
|
||||
<div class="col-md-4">
|
||||
<input
|
||||
type="text"
|
||||
name="query"
|
||||
class="form-control bg-dark text-white"
|
||||
placeholder="Enter text">
|
||||
</div>
|
||||
<div class="col-10">
|
||||
<form method="post" action="/submit" class="row g-2 align-items-center">
|
||||
<div class="col-md-2">
|
||||
<input
|
||||
type="text"
|
||||
name="query"
|
||||
class="form-control bg-dark text-white"
|
||||
placeholder="Nom de la machine">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<select name="time" class="form-select bg-dark text-white" id="time-select">
|
||||
{% for hour in range(0, 24) %}
|
||||
<option value="{{ '%02d:00'|format(hour) }}">{{ '%02d:00'|format(hour) }}</option>
|
||||
<option value="{{ '%02d:30'|format(hour) }}">{{ '%02d:30'|format(hour) }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<div class="form-check text-white">
|
||||
<input class="form-check-input" type="checkbox" name="noshutdown" id="noshutdown">
|
||||
<label class="form-check-label" for="noshutdown">Whitelist shutdown</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-1">
|
||||
<button type="submit" class="btn btn-sm btn-primary w-100">
|
||||
<i class="bi bi-plus-lg"> Save</i>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Sélecteur d'heure -->
|
||||
<div class="col-md-2">
|
||||
<select name="time" class="form-select bg-dark text-white">
|
||||
<div class="col-auto gap-1 ms-auto">
|
||||
<form method="post" action="/submit-default" class="d-flex align-items-center gap-1">
|
||||
<select name="default-time" class="form-select bg-dark text-white flex-grow-1" id="default-time-select">
|
||||
{% for hour in range(0, 24) %}
|
||||
<option value="{{ '%02d:00'|format(hour) }}">{{ '%02d:00'|format(hour) }}</option>
|
||||
<option value="{{ '%02d:30'|format(hour) }}">{{ '%02d:30'|format(hour) }}</option>
|
||||
{% set h1 = '%02d:00'|format(hour) %}
|
||||
{% set h2 = '%02d:30'|format(hour) %}
|
||||
|
||||
<option value="{{ h1 }}"
|
||||
{% if h1 == default_time %}selected{% endif %}>
|
||||
{{ h1 }}
|
||||
</option>
|
||||
|
||||
<option value="{{ h2 }}"
|
||||
{% if h2 == default_time %}selected{% endif %}>
|
||||
{{ h2 }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Bouton submit -->
|
||||
<div class="col-auto">
|
||||
<button type="submit" class="btn btn-secondary">
|
||||
Submit
|
||||
<button type="submit" class="btn btn-sm btn-primary w-100">
|
||||
<i class="bi bi-save"> Save</i>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tableau / Liste -->
|
||||
<div class="card bg-dark bg-opacity-75 p-3">
|
||||
<h5 class="text-white mb-3">Liste des éléments</h5>
|
||||
<div class="row fw-bold text-white mb-2">
|
||||
<div class="col-4">Nom</div>
|
||||
<div class="col-3">Whitelist</div>
|
||||
<div class="col-3">Time</div>
|
||||
<div class="col-2 text-end">Actions</div>
|
||||
</div>
|
||||
<div class="table-items">
|
||||
{% for item in items %}
|
||||
<div class="d-flex justify-content-between align-items-center py-2">
|
||||
<!-- Nom -->
|
||||
<span class="text-white">{{ item.name }}</span>
|
||||
<div class="row align-items-center py-2">
|
||||
<div class="col-4 text-white">
|
||||
{{ item.name }}
|
||||
</div>
|
||||
|
||||
<!-- Heure -->
|
||||
<span class="text-white">{{ item.time }}</span>
|
||||
<div class="col-3">
|
||||
{% if item.noshutdown == 1 %}
|
||||
<span class="text-success">OUI</span>
|
||||
{% else %}
|
||||
<span class="text-danger">NON</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Bouton supprimer -->
|
||||
<form method="post" action="/delete" class="m-0 p-0">
|
||||
<input type="hidden" name="item_name" value="{{ item.name }}">
|
||||
<input type="hidden" name="item_time" value="{{ item.time }}">
|
||||
<button type="submit" class="btn btn-sm btn-danger">×</button>
|
||||
</form>
|
||||
<div class="col-3 text-white">
|
||||
{% if item.noshutdown == 0 %}
|
||||
{{ item.time }}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="col-2 text-end">
|
||||
<form method="post" action="/delete" class="m-0">
|
||||
<input type="hidden" name="item_name" value="{{ item.name }}">
|
||||
<button type="submit" class="btn btn-sm btn-danger">
|
||||
<i class="bi bi-x-lg"></i>Supprimer
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% if not loop.last %}
|
||||
<hr class="border-secondary my-1">
|
||||
@@ -64,4 +113,15 @@
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const tickCheckbox = document.getElementById('noshutdown'); // script pr desactiver la selection de l'heure si whitelist
|
||||
const timeSelect = document.getElementById('time-select');
|
||||
|
||||
timeSelect.disabled = tickCheckbox.checked;
|
||||
|
||||
tickCheckbox.addEventListener('change', function() {
|
||||
timeSelect.disabled = this.checked;
|
||||
});
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user