Compare commits

...

20 Commits

Author SHA1 Message Date
b8f43a6853 fix notification message 2024-11-09 18:22:22 +01:00
a3fbdf5859 Merge branch 'master' into ose 2024-11-09 16:41:35 +01:00
15ddca379f ose variable in config controls text input 2024-11-09 16:34:01 +01:00
88bec0c718 create ose 2024-06-18 10:25:25 +00:00
865c5433a9 Basic login functionality 2024-02-19 23:01:04 +01:00
83231a085d Add getUsernameFromCookie function 2024-02-19 22:10:17 +01:00
4c904551dc change word colour system 2024-02-10 23:51:36 +01:00
350445a58c fix margin of word input area 2024-02-10 23:32:02 +01:00
a206ba2cf0 fix cookie path 2024-02-01 16:37:41 +00:00
8f6b096d17 user cookie is set when sending word 2024-02-01 16:00:41 +01:00
dc3ee12e48 user and time can now be determined from archive 2024-01-28 18:14:28 +01:00
82a487d3dd handle span colour when there are fewer spans than users 2024-01-28 16:49:53 +01:00
69753dac66 fix admin login 2024-01-28 16:48:24 +01:00
40fc554954 color of send box is now working correctly for variable user number 2024-01-26 17:30:00 +01:00
94dc08ee8d put http headers at start of code 2024-01-26 17:21:24 +01:00
5613c1a82c add time since last word feature 2022-10-28 21:15:29 +00:00
Debian
5ab2f7b9b2 loadConfig with no cache 2022-10-06 20:08:58 +00:00
Debian
58b24e702c display current player 2022-10-06 19:54:17 +00:00
bbcb9830e3 trim right of new words and fix number no space bug 2022-03-25 14:45:54 +00:00
095f67973b fix broken admin site when no archives are present 2021-11-28 10:38:44 +00:00
4 changed files with 264 additions and 50 deletions

View File

@ -1,3 +1,22 @@
<?php
if (null !== $_POST['set_pwd']) {
$pwd = $_POST['set_pwd'];
file_put_contents('data/admin_pwd', password_hash($pwd, PASSWORD_DEFAULT));
setcookie('owe_admin', base64_encode($pwd), ['httponly' => true]);
header('location: admin.php');
} elseif (null !== $_POST['pwd']) {
$pwd = $_POST['pwd'];
if (password_verify($pwd, file_get_contents('data/admin_pwd'))) {
setcookie('owe_admin', base64_encode($pwd), ['httponly' => true]);
header('location: admin.php');
print("DER KEKS MÜSSTE GESETZT SEIN");
} else {
print("Nope, falsch");
}
}
?>
<!DOCTYPE html> <!DOCTYPE html>
<?php <?php
@ -47,13 +66,6 @@ $config_data = json_decode($raw_json_config, false);
<?php <?php
if (null !== $_POST['set_pwd']) {
$pwd = $_POST['set_pwd'];
file_put_contents('data/admin_pwd', password_hash($pwd, PASSWORD_DEFAULT));
setcookie('owe_admin', base64_encode($pwd), ['httponly' => true]);
header('location: admin.php');
}
endif; endif;
if ($login): if ($login):
@ -96,17 +108,8 @@ $config_data = json_decode($raw_json_config, false);
</form> </form>
<?php <?php
if (null !== $_POST['pwd']) { endif;
$pwd = $_POST['pwd']; ?>
if (password_verify($pwd, file_get_contents('data/admin_pwd'))) {
setcookie('owe_admin', base64_encode($pwd), ['httponly' => true]);
header('location: admin.php');
} else {
print("Nope, falsch");
}
}
endif; ?>
</p> </p>
<script> <script>
@ -178,7 +181,12 @@ $config_data = json_decode($raw_json_config, false);
} }
function defaultNewArchive() { function defaultNewArchive() {
lastlink = document.getElementById("archive_links").lastElementChild.getAttribute("href"); try {
lastlink = document.getElementById("archive_links").lastElementChild.getAttribute("href");
} catch(err) {
// last link not found, perhaps there is no archive yet
lastlink = "sentences-archive-8-aug-00.txt";
}
var re = /(\d+)-(\w\w\w)-(\d+)\.txt/; var re = /(\d+)-(\w\w\w)-(\d+)\.txt/;
res = re.exec(lastlink); res = re.exec(lastlink);

View File

@ -1,21 +1,21 @@
<?php
header("Cache-Control: no-cache, no-store, must-revalidate");
?>
<!DOCTYPE html> <!DOCTYPE html>
<?php <?php
function get_color_from_ip($ip) { function get_color_from_userdata($data) {
$ip_elem = explode(".", $ip);
$css = "background-color: hsl("; $css = "background-color: hsl(";
$number = abs(crc32($ip)); $number = abs(crc32($data));
$css .= ($number % 360).", "; $css .= ($number % 360).", ";
$css .= (50 + (($number >> 3) % 51))."%, "; $css .= (50 + (($number >> 3) % 51))."%, ";
$css .= (50 + (($number >> 5) % 51))."%);"; $css .= (50 + (($number >> 5) % 31))."%);"; // maximal 80%, es soll nicht einfach weiß sein
return $css; return $css;
} }
//header("refresh: 28");
header("Cache-Control: no-cache, no-store, must-revalidate");
if (!is_dir("data")) { if (!is_dir("data")) {
// initialize everything // initialize everything
mkdir("data", 0755); mkdir("data", 0755);
@ -37,16 +37,23 @@ if (array_key_exists("submitted", $_REQUEST)) {
} }
$sentences = fopen("./data/sentences.txt", "a") or die("unable to open sentences file"); $sentences = fopen("./data/sentences.txt", "a") or die("unable to open sentences file");
$content = "<span style='"; $content = "<span data-user='";
$content .= $_REQUEST["user"];
$content .= "' data-time='";
$content .= time();
$content .= "' style='";
if ($botrequest) { if ($botrequest) {
$content .= "background-color: darksalmon; color: white;'>"; $content .= "background-color: darksalmon; color: white;'>";
} else { } else {
$content .= get_color_from_ip($_SERVER['REMOTE_ADDR'])."'>"; // Farbe hängt ab von Benutzer und ändert sich nach gewisser Zeit.
$content .= get_color_from_userdata($_REQUEST["user"].strval(intdiv(time(),60*60*24*7)))."'>";
} }
$ends_of_sentence = ['.', '!', '?']; $ends_of_sentence = ['.', '!', '?'];
if (preg_match("/\p{L}/", $word[0])) { // check if first character is letter (including ä, ê, ß stuff)
$word = rtrim($word);
if (preg_match("/[\p{L}0-9]/", $word[0])) { // check if first character is letter (including ä, ê, ß stuff)
$content .= " "; $content .= " ";
} }
$content .= htmlentities($word); $content .= htmlentities($word);
@ -120,9 +127,16 @@ $config_data = json_decode($raw_json_config, false);
</div> </div>
<button onclick="onReloadClicked()" id="but-reload">aktualisieren</button> <button onclick="onReloadClicked()" id="but-reload">aktualisieren</button>
<br> <br>
<div id="login_area">
</div>
<div class="word_input_area"> <div class="word_input_area">
<?php if ($config_data->ose) : ?>
<textarea name="submitted" id="wordinput" placeholder="Nächster Satz" autocomplete="off"></textarea> <button id="sendbut" class="send_button" onclick="sendWord()">
<?php else: ?>
<input type="text" name="submitted" id="wordinput" placeholder="Nächstes Wort" autocomplete="off"> <button id="sendbut" class="send_button" onclick="sendWord()"> <input type="text" name="submitted" id="wordinput" placeholder="Nächstes Wort" autocomplete="off"> <button id="sendbut" class="send_button" onclick="sendWord()">
<?php <?php
endif;
print(isset($config_data->send_logo) ? ("<img src='data/".$config_data->send_logo."' width='64'>") : "<i class='far fa-paper-plane'></i>"); print(isset($config_data->send_logo) ? ("<img src='data/".$config_data->send_logo."' width='64'>") : "<i class='far fa-paper-plane'></i>");
?> ?>
</button> </button>

230
owe.js
View File

@ -2,7 +2,7 @@ var previousTextLength;
var config_data; var config_data;
var unread_words = 0; var unread_words = 0;
function loadSentences(alertIfNew = false, increaseUnread = true) { async function loadSentences(alertIfNew = false, increaseUnread = true) {
fetch("./data/sentences.txt", {headers: {"Cache-Control": "no-cache, no-store"}}) fetch("./data/sentences.txt", {headers: {"Cache-Control": "no-cache, no-store"}})
.then((response) => { .then((response) => {
return response.text().then((text) => { return response.text().then((text) => {
@ -31,16 +31,21 @@ function loadSentences(alertIfNew = false, increaseUnread = true) {
// color // color
var spans = document.querySelector(".sentences").getElementsByTagName("span"); var spans = document.querySelector(".sentences").getElementsByTagName("span");
// we expect this to be from the user who's turn it is now (3 users)
var histurnspan = spans[spans.length - 3]; if (spans.length >= config_data.users.length) {
//console.log(histurnspan.getAttribute("style")); var histurnspan = spans[spans.length - config_data.users.length];
document.getElementById("wordinput").setAttribute("style", histurnspan.getAttribute("style")); //console.log(histurnspan.getAttribute("style"));
document.getElementById("wordinput").setAttribute("style", histurnspan.getAttribute("style"));
} else {
console.error('Not enough spans available for users.');
}
initializeLoginArea();
}); });
}); });
} }
function loadConfig() { async function loadConfig() {
fetch("./data/config.json").then((response) => { fetch("./data/config.json", {headers: {"Cache-Control": "no-cache, no-store"}}).then((response) => {
return response.text().then((text) => { return response.text().then((text) => {
config_data = JSON.parse(text); config_data = JSON.parse(text);
setInterval(loadSentences, 5000, ((typeof config_data.notifications !== "undefined") ? config_data.notifications : true)); setInterval(loadSentences, 5000, ((typeof config_data.notifications !== "undefined") ? config_data.notifications : true));
@ -50,6 +55,29 @@ function loadConfig() {
}); });
} }
function getUsernameFromCookie() {
// Split the document.cookie string into individual cookie key-value pairs
var cookies = document.cookie.split(';').map(cookie => cookie.trim());
// Loop through the cookies to find the 'owe_user' cookie
for (var i = 0; i < cookies.length; i++) {
var cookie = cookies[i];
if (cookie.startsWith('owe_user=')) {
// Extract the username from the 'owe_user' cookie
return decodeURIComponent(cookie.substring('owe_user='.length));
}
}
// Return null if the 'owe_user' cookie is not set
return null;
}
function deleteUsernameCookie() {
// Set the 'owe_user' cookie to expire by setting its expiration date to a time in the past
document.cookie = 'owe_user=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=.;';
}
function onReloadClicked() { function onReloadClicked() {
loadSentences(); loadSentences();
document.querySelector("#but-reload").style.visibility = "hidden"; document.querySelector("#but-reload").style.visibility = "hidden";
@ -58,23 +86,37 @@ function onReloadClicked() {
}, 100); }, 100);
} }
function sendWord() { async function sendWord() {
var data = new FormData(); try {
data.append('submitted', encodeURI(document.getElementById("wordinput").value)); var data = new FormData();
const Http = new XMLHttpRequest(); var wordInput = document.getElementById("wordinput");
Http.open('POST', '.'); data.append('submitted', encodeURI(wordInput.value));
Http.onreadystatechange=(e)=>{
document.getElementById("wordinput").value = ""; // Use await to get the next player asynchronously
loadSentences(false, false); var nextPlayer = await getNextPlayer();
resetUnread(); data.append('user', nextPlayer);
}
Http.send(data); const Http = new XMLHttpRequest();
Http.open('POST', '.');
Http.onreadystatechange = (e) => {
wordInput.value = "";
loadSentences(false, false);
resetUnread();
};
// Set the 'owe_user' cookie with the value obtained from getNextPlayer
document.cookie = `owe_user=${encodeURIComponent(nextPlayer)}; path=.`;
Http.send(data);
} catch (error) {
console.error("Error in sendWord:", error);
}
} }
function displayNotification(word) { function displayNotification(word) {
if (Notification.permission == 'granted') { if (Notification.permission == 'granted') {
navigator.serviceWorker.getRegistration().then(function(reg) { navigator.serviceWorker.getRegistration().then(function(reg) {
reg.showNotification("Neues Wort auf " + (config_data.title ? config_data.title : "OWE"), reg.showNotification("Neuer Beitrag auf " + (config_data.title ? config_data.title : "OWE"),
{ body: word, icon: (config_data.logo? config_data.logo.image_path : "OWE_Logo.png"), requireInteraction: true }); { body: word, icon: (config_data.logo? config_data.logo.image_path : "OWE_Logo.png"), requireInteraction: true });
}); });
} }
@ -101,6 +143,154 @@ function resetUnread() {
document.getElementsByTagName("title")[0].innerText = (config_data.title ? config_data.title : "One Word Each"); document.getElementsByTagName("title")[0].innerText = (config_data.title ? config_data.title : "One Word Each");
} }
function getNextPlayer() {
var sentencesDiv = document.querySelector(".sentences");
var spans = sentencesDiv.getElementsByTagName("span");
if (spans.length > 0) {
var lastSpan = spans[spans.length - 1];
var lastPlayer = lastSpan.dataset.user;
var idxNext = (config_data.users.indexOf(lastPlayer) + 1) % config_data.users.length;
return config_data.users[idxNext];
} else {
// If there are no spans, determine the next user from the archive file
var archiveFileUrl = getArchiveFileUrl(); // Replace with the actual function that returns the archive file URL
return getLastUserFromArchive(archiveFileUrl)
.then(lastUser => {
if (lastUser) {
// Calculate the next user's index based on the list of users
var idxNext = (config_data.users.indexOf(lastUser) + 1) % config_data.users.length;
return config_data.users[idxNext];
} else {
// Handle the case when the archive file is empty or contains no spans
console.error("Archive file is empty or contains no spans.");
return null;
}
})
.catch(error => {
console.error("Error fetching archive file:", error);
return null;
});
}
}
function getLastUserFromArchive(archiveFileUrl) {
// Fetch the last span from the archive file and extract the username
return getLastSpanFromArchive(archiveFileUrl)
.then(lastArchiveSpan => {
if (lastArchiveSpan) {
return lastArchiveSpan.dataset.user;
} else {
// Handle the case when the archive file is empty or contains no spans
console.error("Archive file is empty or contains no spans.");
return null;
}
})
.catch(error => {
console.error("Error fetching archive file:", error);
return null;
});
}
function getLastSpanFromArchive(archiveFileUrl) {
// Make an asynchronous request to fetch the content of the archive file
return fetch(archiveFileUrl)
.then(response => response.text())
.then(htmlContent => {
// Parse the HTML content to get the last span
var parser = new DOMParser();
var doc = parser.parseFromString(htmlContent, 'text/html');
var archiveSpans = doc.querySelectorAll("span");
if (archiveSpans.length > 0) {
return archiveSpans[archiveSpans.length - 1];
} else {
// Return null if the archive file is empty or contains no spans
return null;
}
});
}
// bullshit implementation:
function getArchiveFileUrl() {
return "./data/sentences-archive-25-nov-23-26-jan-24.txt";
}
async function getTimeSinceLast() {
var sentencesDiv = document.querySelector(".sentences");
var spans = sentencesDiv.getElementsByTagName("span");
if (spans.length > 0) {
var lastSpan = spans[spans.length - 1];
var lastTime = lastSpan.dataset.time;
return Date.now() / 1e3 - lastTime; // in seconds
} else {
// If there are no spans, determine the last time from the archive file
var archiveFileUrl = getArchiveFileUrl(); // Replace with the actual function that returns the archive file URL
return getLastTimeFromArchive(archiveFileUrl);
}
}
async function getLastTimeFromArchive(archiveFileUrl) {
try {
// Fetch the last span from the archive file
var lastSpan = await getLastSpanFromArchive(archiveFileUrl);
if (lastSpan) {
var lastTime = lastSpan.dataset.time;
return Date.now() / 1e3 - lastTime; // in seconds
} else {
// Handle the case when the archive file is empty or contains no spans
console.error("Archive file is empty or contains no spans.");
return null;
}
} catch (error) {
console.error("Error fetching archive file:", error);
return null;
}
}
function logoutUser() {
deleteUsernameCookie();
initializeLoginArea(); // Reload everything in the login area
}
async function initializeLoginArea() {
var loginArea = document.getElementById('login_area');
var sendButton = document.getElementById('sendbut');
sendButton.style.display = "unset"
var wordInput = document.getElementById('wordinput');
wordInput.disabled = false;
// Use async/await to wait for the result of getNextPlayer
try {
var loggedInPlayer = getUsernameFromCookie();
var nextPlayer = await getNextPlayer();
var relative_time = await getTimeSinceLast();
// Clear the login area
loginArea.innerHTML = "";
if (loggedInPlayer != null) {
loginArea.innerHTML += "Du bist angemeldet als " + loggedInPlayer + "."
loginArea.innerHTML += " <button onclick='logoutUser()'>abmelden</button><br>\n";
if (loggedInPlayer != nextPlayer) {
sendButton.style.display = "none";
wordInput.disabled = true;
}
}
loginArea.innerHTML += nextPlayer + " ist dran!<br>\n";
var days = Math.floor(relative_time / (3600 * 24));
var hours = Math.floor(relative_time / 3600) % 24;
var minutes = Math.floor(relative_time / 60) % 60;
loginArea.innerHTML += "Schon seit " + days + " Tagen, " + hours + " Stunden und " + minutes + " Minuten!";
} catch (error) {
// Handle any errors that may occur in the getNextPlayer function
console.error("Error in initializeLoginArea:", error);
}
}
window.onfocus = resetUnread; window.onfocus = resetUnread;
//setTimeout(loadSentences, 500); //setTimeout(loadSentences, 500);
@ -118,7 +308,7 @@ input.addEventListener("keyup", function(event) {
// Trigger the button element with a click // Trigger the button element with a click
document.getElementById("sendbut").click(); document.getElementById("sendbut").click();
} }
}); });
var isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent); var isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);

View File

@ -97,7 +97,7 @@ a {
background-color: white; background-color: white;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
width: auto; width: inherit;
} }
#sidebar_button { #sidebar_button {
@ -115,6 +115,8 @@ input, .send_button {
.word_input_area { .word_input_area {
border: 2px solid white; border: 2px solid white;
display: inline-flex; display: inline-flex;
margin: 30px 0px;
width: 100%;
} }
table { table {