361 lines
13 KiB
PHP
361 lines
13 KiB
PHP
<?php
|
|
|
|
require '../../lib/glob.php';
|
|
require '../../lib/muoribene.php';
|
|
require '../../lib/sessionstart.php';
|
|
require '../../lib/myconn.php';
|
|
require '../../lib/getadmacc.php';
|
|
if ($account['Level'] == 'guest')
|
|
muoribene('Sorry, you are not authorized.', true);
|
|
require '../../lib/menu.php';
|
|
$menu['menu']['selected'] = true;
|
|
$menu['menu']['submenu']['notifs']['selected'] = true;
|
|
buildmenu($menu);
|
|
|
|
$dbg = '';
|
|
|
|
// praticamente una macro
|
|
function hspech($str)
|
|
{
|
|
return (htmlspecialchars($str, ENT_QUOTES | ENT_HTML5, 'UTF-8'));
|
|
}
|
|
|
|
function are_valid_ids($ids)
|
|
{
|
|
if (count($ids) <= 0) return false;
|
|
foreach ($ids as $id) {
|
|
if (!(preg_match('/^[0-9]+$/', $id) === 1)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && $_SERVER["CONTENT_TYPE"] === "application/json") {
|
|
$response = array(
|
|
"done" => true,
|
|
"error" => ""
|
|
);
|
|
$body = json_decode(file_get_contents('php://input'), true);
|
|
if (array_key_exists('act', $body) &&
|
|
array_key_exists('ids', $body) &&
|
|
are_valid_ids($body["ids"])) {
|
|
switch ($body['act']) {
|
|
case "massread":
|
|
mysqli_query($link, 'UPDATE Notifications SET Seen=1 WHERE ID in (' . implode(", ", $body["ids"]) . ')')
|
|
or muoribene(mysqli_error($link), true);
|
|
break;
|
|
case "massdelete":
|
|
mysqli_query($link, 'UPDATE Notifications SET Deleted=1 WHERE ID in (' . implode(", ", $body["ids"]) . ')')
|
|
or muoribene(mysqli_error($link), true);
|
|
break;
|
|
default:
|
|
http_response_code(400);
|
|
$response["done"] = false;
|
|
$response["error"] = "Unknown act.";
|
|
}
|
|
} else {
|
|
http_response_code(400);
|
|
$response["done"] = false;
|
|
$response["error"] = "Bad request.";
|
|
}
|
|
echo(json_encode($response));
|
|
mysqli_close($link);
|
|
exit(0);
|
|
}
|
|
|
|
|
|
$dbg .= $dlang . '<br>' . N;
|
|
$dbg .= '<pre>' . print_r($_GET, 1) . '</pre>';
|
|
|
|
require '../../lib/notifs.php';
|
|
$notifs = notifs($link);
|
|
|
|
$filtordon = false;
|
|
if ($filtordon) {
|
|
$filtordimgoff = 'imgs/cerca_act_off.svg';
|
|
$filtordimgon = 'imgs/cerca_act_on.svg';
|
|
} else {
|
|
$filtordimgoff = 'imgs/cerca_off.svg';
|
|
$filtordimgon = 'imgs/cerca_on.svg';
|
|
}
|
|
?>
|
|
<!DOCTYPE HTML>
|
|
<html lang="en">
|
|
<head>
|
|
<title>Mustard - Notifs</title>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
|
<meta name="description" content="Admin pages for Mastodon Help">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
|
<link rel="icon" type="image/png" href="imgs/icona-32.png" sizes="32x32">
|
|
<link rel="icon" type="image/png" href="imgs/icona-192.png" sizes="192x192">
|
|
<link rel="icon" type="image/png" href="imgs/icona-512.png" sizes="512x512">
|
|
<link rel="apple-touch-icon-precomposed" href="imgs/icona-180.png">
|
|
<script language="JavaScript" src="js/menu.js?v=<?php echo($cjrand); ?>"></script>
|
|
<script language="JavaScript" src="js/confirma.js?v=<?php echo($cjrand); ?>"></script>
|
|
<link rel="stylesheet" type="text/css" href="css/theme.css?v=<?php echo($cjrand); ?>">
|
|
<link rel="stylesheet" type="text/css" href="css/notifs.css?v=<?php echo($cjrand); ?>">
|
|
<script language="JavaScript">
|
|
<!--
|
|
<?php require 'js/notifs.js.php'; ?>
|
|
|
|
function reverseSelection() {
|
|
let checkboxes = getAliveCheckboxes()
|
|
checkboxes.forEach(function (box) {
|
|
box.checked = !box.checked;
|
|
})
|
|
let n_selected = getSelectedNotifs().length;
|
|
if (n_selected > 0) {
|
|
setBtnsVisibility("visible");
|
|
} else if (n_selected === 0) {
|
|
setBtnsVisibility("hidden");
|
|
document.getElementById("global-selector").checked = false;
|
|
}
|
|
if (n_selected === checkboxes.length) {
|
|
document.getElementById("global-selector").checked = true;
|
|
}
|
|
}
|
|
|
|
function setBtnsVisibility(state) {
|
|
let controls = document.querySelector("#notifs-list-controls");
|
|
controls.querySelector("#read-btn").style.visibility = state;
|
|
controls.querySelector("#delete-btn").style.visibility = state;
|
|
}
|
|
|
|
function toggleState(check) {
|
|
if (check.checked) {
|
|
setBtnsVisibility("visible");
|
|
} else {
|
|
setBtnsVisibility("hidden")
|
|
}
|
|
let checkboxes = getAliveCheckboxes()
|
|
checkboxes.forEach(function (box) {
|
|
box.checked = check.checked;
|
|
});
|
|
}
|
|
|
|
function notifSelect(check) {
|
|
let checkboxes = getAliveCheckboxes()
|
|
if (check.checked) {
|
|
setBtnsVisibility("visible");
|
|
} else if (checkboxes.every(box => !box.checked)) {
|
|
setBtnsVisibility("hidden");
|
|
}
|
|
}
|
|
|
|
function showFilterPanel() {
|
|
let plancia = document.querySelector("#plancia");
|
|
if (plancia.style.display !== "block") {
|
|
if (plancia.childElementCount <= 3) {
|
|
addAfter(plancia.firstElementChild);
|
|
}
|
|
plancia.style.display = "block";
|
|
}
|
|
}
|
|
|
|
function getFilters() {
|
|
return Array.from(document.querySelectorAll("#plancia .notifs-criterion"));
|
|
}
|
|
|
|
function newFilter() {
|
|
return "<div class='notifs-criterion'>" +
|
|
" <label for='start-date'>Da</label>" +
|
|
" <input id='start-date' name='start-date' type='date'>" +
|
|
" <label for='stop-date'>A</label>" +
|
|
" <input id='stop-date' name='stop-date' type='date'>" +
|
|
" <select id='severity'>" +
|
|
" <option value='-1'>Indifferente</option>" +
|
|
" <option value='1'>Normal</option>" +
|
|
" <option value='2'>Warning</option>" +
|
|
" <option value='3'>Error</option>" +
|
|
" </select>" +
|
|
" <select id='operation'>" +
|
|
" <option value='0'>E</option>" +
|
|
" <option value='1'>O</option>" +
|
|
" </select>" +
|
|
" <img class='plus' src='imgs/plus.svg' title='Aggiungi un criterio sotto questo'" +
|
|
" onclick='addAfter(this.parentElement)'>" +
|
|
" <img class='minus' src='imgs/minus.svg' title='Rimuovi questo criterio'" +
|
|
" onclick='removeFilter(this.parentElement)'>" +
|
|
"</div>";
|
|
}
|
|
|
|
function addAfter(elem) {
|
|
let filters = getFilters();
|
|
if (filters.length < 7) {
|
|
elem.insertAdjacentHTML('afterend', newFilter());
|
|
filters = getFilters();
|
|
if (filters.length > 1) {
|
|
let select = elem.querySelector("#operation");
|
|
if (select.disabled) {
|
|
select.disabled = false;
|
|
}
|
|
}
|
|
filters[filters.length - 1].querySelector("#operation").disabled = true;
|
|
}
|
|
}
|
|
|
|
function removeFilter(elem) {
|
|
let filters = getFilters();
|
|
if (filters.length > 1) {
|
|
elem.remove();
|
|
filters = getFilters();
|
|
filters[filters.length - 1].querySelector("#operation").disabled = true;
|
|
}
|
|
}
|
|
|
|
function clearFilters() {
|
|
let filtered = document.querySelectorAll(".filtered");
|
|
filtered.forEach(f => f.classList.remove("filtered"))
|
|
getFilters().forEach(f => f.remove());
|
|
document.querySelector("#plancia").style.display = "none";
|
|
}
|
|
|
|
function makeDateFilter(criterion) {
|
|
let start = criterion.querySelector("#start-date").value;
|
|
let stop = criterion.querySelector("#stop-date").value;
|
|
start = (start === '') ? new Date(0) : new Date(start);
|
|
stop = (stop === '') ? new Date() : new Date(stop);
|
|
return date => (date <= stop) && (date >= start);
|
|
}
|
|
|
|
function makeSeverityFilter(criterion) {
|
|
let select = criterion.querySelector("#severity");
|
|
let severity = select.options[select.selectedIndex].value;
|
|
if (severity === "-1") {
|
|
return x => true;
|
|
}
|
|
return x => x === severity;
|
|
}
|
|
|
|
function makeFilterFunction(criterion) {
|
|
let dateFilter = makeDateFilter(criterion);
|
|
let severityFilter = makeSeverityFilter(criterion);
|
|
return notif => {
|
|
let microtime = new Date(parseFloat(notif.dataset.microtime) * 1000);
|
|
let severity = notif.dataset.severity;
|
|
return dateFilter(microtime) && severityFilter(severity);
|
|
}
|
|
}
|
|
|
|
function applyFilters() {
|
|
let filters = getFilters();
|
|
let notifs = getAliveNotifs();
|
|
let filterFunctions = filters.map(makeFilterFunction);
|
|
let fun = x => filterFunctions[0](x);
|
|
|
|
for (let i = 0; i < filters.length - 1; i++) {
|
|
// Questo hack serve per evitare che la chiamata
|
|
// al filtro sia interpretata come ricorsione.
|
|
let filter = fun;
|
|
if (filters[i].querySelector("#operation").value === "0") {
|
|
fun = x => (filter(x) && filterFunctions[i + 1](x));
|
|
} else {
|
|
fun = x => (filter(x) || filterFunctions[i + 1](x));
|
|
}
|
|
}
|
|
|
|
notifs.forEach(notif => {
|
|
if (!fun(notif)) {
|
|
notif.classList.add("filtered");
|
|
}
|
|
});
|
|
document.querySelector("#plancia").style.display = "none";
|
|
}
|
|
|
|
// -->
|
|
</script>
|
|
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/fork-awesome@1.1.7/css/fork-awesome.min.css"
|
|
integrity="sha256-gsmEoJAws/Kd3CjuOQzLie5Q3yshhvmo7YNtBG7aaEY=" crossorigin="anonymous">
|
|
</head>
|
|
<body>
|
|
|
|
<nav>
|
|
<div id="hmenu">
|
|
<ul>
|
|
<?php echo($menuout); ?>
|
|
</ul>
|
|
<div class="mtit">Notifiche</div>
|
|
<div id="rightdiv">
|
|
<img src="<?php echo($filtordimgoff); ?>" id="lente" class="rlinks" title="Mostra il pannello di filtraggio"
|
|
onclick="showFilterPanel();">
|
|
<?php echo('<img src="' . $notifs['imgoff'] . '" id="bell" class="rlinks" title="Show notifications" onclick="shidenotifs();">' . N); ?>
|
|
<img src="imgs/esci.svg" class="rlinks" title="Logout" onclick="document.location.href='logout.php';">
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
|
|
<?php echo($notifs['div']); ?>
|
|
|
|
<div id="notifs-grid">
|
|
<div id="notifs-list">
|
|
<?php
|
|
$sev_classes = array(
|
|
1 => "sev-normal",
|
|
2 => "sev-warning",
|
|
3 => "sev-error"
|
|
);
|
|
$seen_class = array(
|
|
0 => "unseen",
|
|
1 => "seen"
|
|
);
|
|
$deleted = array(
|
|
0 => "",
|
|
1 => "deleted"
|
|
);
|
|
foreach ($notifs['notifs'] as $n) {
|
|
echo("<div id=\"notif-" . $n["ID"] . "\" class=\"" . "notif " . $deleted[$n["Deleted"]] . " " . $sev_classes[$n["Severity"]] . " " . $seen_class[$n["Seen"]] .
|
|
"\" data-microtime='" . $n['Microtime'] . "' " .
|
|
"data-severity='" . $n['Severity'] . "'>" .
|
|
"<input type=\"checkbox\" class=\"seen-checkbox\" onclick='notifSelect(this)'>" .
|
|
"<button type='button' onclick='markread(this.parentElement)'><i class=\"fa fa-envelope-open-o\" aria-hidden=\"true\"></i></button>" .
|
|
"<button type='button' onclick='markdeleted(this.parentElement)'><i class=\"fa fa-trash-o\" aria-hidden=\"true\"></i></button>" .
|
|
"<p id='notif-text'>" . gmdate('d/m/Y H:i:s', round($n['Microtime'])) . ": " . $n["Notification"] . "</p>" .
|
|
"</div>\n");
|
|
}
|
|
?>
|
|
</div>
|
|
|
|
<div id="popup">
|
|
<div id="inpopup">
|
|
<div id="popupcont">
|
|
...
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="footer">
|
|
<div id="notifs-list-controls">
|
|
<input id="global-selector" type="checkbox" onclick="toggleState(this)">
|
|
<button id='reverse-btn' type='button' class="control-btn" onclick="reverseSelection()">
|
|
Inverti selezione
|
|
</button>
|
|
<button id='read-btn' type='button' class="control-btn" onclick="readSelected()">
|
|
<i class="fa fa-envelope-open-o" aria-hidden="true"></i>
|
|
</button>
|
|
<button id='delete-btn' type='button' class="control-btn" onclick="deleteSelected()">
|
|
<i class="fa fa-trash-o" aria-hidden="true"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="plancia">
|
|
<button id='clear-filters-btn' type='button'
|
|
onclick="confirma('Attenzione!','<p>Confermi di voler rimuovere tutti i criteri di filtraggio?</p>','No','Si','','clearFilters();')">
|
|
Rimuovi tutti i criteri di filtraggio
|
|
</button>
|
|
<div id="criterion-list"></div>
|
|
<button id='apply-filters-btn' type='button' onclick="applyFilters()">
|
|
Applica
|
|
</button>
|
|
</div>
|
|
|
|
</body>
|
|
</html>
|
|
|
|
<?php
|
|
mysqli_close($link);
|
|
exit(0);
|
|
?>
|