diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 0000000..e73bd06 --- /dev/null +++ b/.jshintrc @@ -0,0 +1,3 @@ +{ + "esversion": 10 +} \ No newline at end of file diff --git a/assets/script.js b/assets/script.js index 8207ebf..6948d7a 100644 --- a/assets/script.js +++ b/assets/script.js @@ -1,17 +1,25 @@ let UserInfo = {}; let PageIntervals = []; +let config = + { + articleRefresh: 300000, + messageFadeIn: 300, + messageDisappear: 200 + }; -function isLoggedIn(){ - return UserInfo.Email && UserInfo.Email.length > 0; +function isLoggedIn() { + "use strict"; + return UserInfo.Email && 0 < UserInfo.Email.length; } async function handleResponse(data, successMessage, failureMessage) { + "use strict"; const statusMessageContainer = document.getElementById("statusMessageContainer"); const statusMessage = document.createElement("div"); statusMessage.classList.add("status-message"); - if (data.Status === 'Success') { + if ('Success' === data.Status) { statusMessage.innerText = successMessage; statusMessage.classList.add("success"); } else { @@ -26,44 +34,43 @@ async function handleResponse(data, successMessage, failureMessage) { statusMessage.style.opacity = "0"; setTimeout(() => { statusMessage.remove(); - }, 500); - }, 2000); + }, config.messageFadeIn); + }, config.messageDisappear); } async function showDashboardGreeting() { + "use strict"; document.getElementById("welcomeMsg").innerText = `Ahoj, ${UserInfo.FirstName}.`; } -async function doAction(url, requestData, successMessage, failureMessage, silent = false) { - try { - const params = new URLSearchParams(); +async function doAction(url, requestData, successMessage, failureMessage, silent) { + "use strict"; + const params = new URLSearchParams(); - for (const key in requestData) { - params.append(key, requestData[key]); - } - - const response = await fetch(url, { - method: 'POST', - body: params, - }); - - if (!response.ok) { - console.error(`HTTP error! Status: ${response.status}`); - } - - const data = await response.json(); - - if (!silent) { - await handleResponse(data, successMessage, failureMessage); - } - - return data; - } catch (error) { - console.error('Error:', error); + for (const key in requestData) { + params.append(key, requestData[key]); } + + const response = await fetch(url, { + method: 'POST', + body: params, + }); + + if (!response.ok) { + console.error(`HTTP error! Status: ${response.status}`); + } + + const data = await response.json(); + + if (!silent) { + await handleResponse(data, successMessage, failureMessage); + } + + return data; } async function handlePageResponse(data) { + "use strict"; const navbar = document.getElementById("navbar_container"); const pageArea = document.getElementById("page_container"); @@ -83,6 +90,7 @@ async function handlePageResponse(data) { } async function displayList(data, elementId, deleteFunction) { + "use strict"; const tableContainer = document.getElementById(elementId); tableContainer.innerHTML = ""; // Clear previous content @@ -96,7 +104,7 @@ async function displayList(data, elementId, deleteFunction) { headerRow.appendChild(th); } - if (typeof deleteFunction === "function") { + if ("function" === typeof deleteFunction) { const th = document.createElement("th"); th.appendChild(document.createTextNode("Delete")); headerRow.appendChild(th); @@ -109,7 +117,7 @@ async function displayList(data, elementId, deleteFunction) { td.appendChild(document.createTextNode(line[key])); dataRow.appendChild(td); } - if (typeof deleteFunction === "function") { + if ("function" === typeof deleteFunction) { const td = document.createElement("td"); const deleteButton = document.createElement('button'); deleteButton.textContent = "Delete"; @@ -122,28 +130,24 @@ async function displayList(data, elementId, deleteFunction) { tableContainer.appendChild(table); } -async function doPageAction(requestData, wantsReturn = false) { - try { - const response = await fetch('/page', { - method: 'POST', - body: new URLSearchParams(requestData), - }); +async function doPageAction(requestData) { + "use strict"; + const response = await fetch('/page', { + method: 'POST', + body: new URLSearchParams(requestData), + }); - if (!response.ok) { - console.error(`HTTP error! Status: ${response.status}`); - } - - const data = await response.json(); - await handlePageResponse(data); - if (wantsReturn) { - return data; - } - } catch (error) { - console.error('Error:', error); + if (!response.ok) { + console.error(`HTTP error! Status: ${response.status}`); } + + const data = await response.json(); + await handlePageResponse(data); + return data; } async function initAjaxNavigationEvents() { + "use strict"; const allLinks = document.querySelectorAll('.navsite_link, .navpage_link'); const pageLinks = document.querySelectorAll('.navpage_link'); @@ -163,27 +167,30 @@ async function initAjaxNavigationEvents() { } }); }); - const toggleButton = document.getElementById("toggle_button") - const navLinks = document.getElementById("navsite_list") + const toggleButton = document.getElementById("toggle_button"); + const navLinks = document.getElementById("navsite_list"); toggleButton.addEventListener('click', () => { - navLinks.classList.toggle("active") - }) + navLinks.classList.toggle("active"); + }); } async function initAjax() { + "use strict"; await initAjaxNavigationEvents(); await onPageLoad(); } -async function togglearticlecreate(){ +async function togglearticlecreate() { + "use strict"; let articleContainerElement = document.getElementById("articlecreatecontainer"); articleContainerElement.classList.toggle("hidden"); } -async function renderarticles(){ +async function renderarticles() { + "use strict"; let template = document.querySelector('template[data-template-name="article"]').innerHTML; let articles = await doAction( "/newsarticle", @@ -197,12 +204,13 @@ async function renderarticles(){ let articleout = ""; for (const article of articles.Articles) { - articleout += template.replace("__TEMPLATE_ARTICLE_TITLE__", article.Title).replace("__TEMPLATE_ARTICLE_AUTHOR__", article.WrittenByName).replace("__TEMPLATE_ARTICLE_DATE__", article.WrittenAt).replace("__TEMPLATE_ARTICLE_BODY__", article.Body) + articleout += template.replace("__TEMPLATE_ARTICLE_TITLE__", article.Title).replace("__TEMPLATE_ARTICLE_AUTHOR__", article.WrittenByName).replace("__TEMPLATE_ARTICLE_DATE__", article.WrittenAt).replace("__TEMPLATE_ARTICLE_BODY__", article.Body); } document.getElementById("articleslist").innerHTML = articleout; } -async function submitarticle(){ +async function submitarticle() { + "use strict"; let articleTitleElement = document.getElementById("articletitleinput"); let articleBodyElement = document.getElementById("articlebodyinput"); await doAction( @@ -219,35 +227,36 @@ async function submitarticle(){ await togglearticlecreate(); } -async function articleInit(){ +async function articleInit() { + "use strict"; let articleContainerElement = document.getElementById("articlecreatecontainer"); let articleCreateOpenElement = document.getElementById("articlecreateopen"); articleContainerElement.addEventListener("keyup", function (ev) { - if(ev.key === "Escape"){ + if ("Escape" === ev.key) { togglearticlecreate(); } - }) - PageIntervals.push(setInterval(renderarticles, 300000)); + }); + PageIntervals.push(setInterval(renderarticles, config.articleRefresh)); document.getElementById("articleprivilegeinput").setAttribute("max", UserInfo.Privileges); - if(UserInfo.Privileges < 2){ + if (2 > UserInfo.Privileges) { articleContainerElement.style.display = "none"; articleCreateOpenElement.style.display = "none"; - } - else{ + } else { articleCreateOpenElement.style.display = "inline-block"; } } async function onPageLoad() { + "use strict"; await restoreUserInfo(); let currentSite = localStorage.getItem("currentSite"); let currentPage = localStorage.getItem("currentPage"); - for(let interval of PageIntervals) { + for (let interval of PageIntervals) { clearInterval(interval); } - if (currentSite === "home" && currentPage === "settings") { + if ("home" === currentSite && "settings" === currentPage) { if (document.getElementById("user-settings")) { await populateUserInfoFields(UserInfo); } @@ -256,21 +265,22 @@ async function onPageLoad() { await listUsers(true); } } - if (currentSite === "account" && currentPage === "index" && isLoggedIn()) { + if ("account" === currentSite && "index" === currentPage && isLoggedIn()) { await showDashboardGreeting(); } - if (currentSite === "news" && currentPage === "index") { + if ("news" === currentSite && "index" === currentPage) { await articleInit(); } } async function navigateTo(site, page) { + "use strict"; const data = { action: "getPage", site: site, page: page, }; - doPageAction(data, true).then(() => { + doPageAction(data).then(() => { localStorage.setItem("currentSite", site); localStorage.setItem("currentPage", page); onPageLoad(); @@ -278,6 +288,7 @@ async function navigateTo(site, page) { } async function softReload() { + "use strict"; let currentSite = localStorage.getItem("currentSite"); let currentPage = localStorage.getItem("currentPage"); await navigateTo(currentSite, currentPage); @@ -285,6 +296,7 @@ async function softReload() { } async function refreshNavbar() { + "use strict"; const data = { action: "getNavigation", }; @@ -294,11 +306,12 @@ async function refreshNavbar() { } async function logout() { + "use strict"; const data = { action: "logout", }; - doAction('/account', data, "Logout Successful!", "Logout failed.") + doAction('/account', data, "Logout Successful!", "Logout failed.", false) .then(async () => { await refreshNavbar(); await navigateTo(localStorage.getItem("defaultSite"), localStorage.getItem("defaultPage")); @@ -312,6 +325,7 @@ async function logout() { } async function login() { + "use strict"; const email = document.getElementById("login_email").value; const password = document.getElementById("login_password").value; await doLogin(email, password); @@ -321,17 +335,19 @@ async function login() { } async function doLogin(email, password) { + "use strict"; const data = { action: "login", email: email, password: password, }; - await doAction('/account', data, "Login Successful!", "Login failed. Please check your credentials."); + await doAction('/account', data, "Login Successful!", "Login failed. Please check your credentials.", false); umami.track("login"); } async function register() { + "use strict"; const firstName = document.getElementById("register_firstName").value; const lastName = document.getElementById("register_lastName").value; const email = document.getElementById("register_email").value; @@ -351,13 +367,15 @@ async function register() { } async function doRegister(requestData) { - await doAction('/account', requestData, "Registration Successful!", "Registration failed."); + "use strict"; + await doAction('/account', requestData, "Registration Successful!", "Registration failed.", false); umami.track("register"); } //User settings start async function changePassword() { + "use strict"; const oldPassword = document.getElementById("changeOldPassword").value; const newPassword = document.getElementById("changeNewPassword").value; @@ -371,11 +389,13 @@ async function changePassword() { } async function doChangePassword(requestData, successMessage, failureMessage) { - await doAction('/account', requestData, successMessage, failureMessage); + "use strict"; + await doAction('/account', requestData, successMessage, failureMessage, false); umami.track("passwordChange"); } async function updateUserProfile() { + "use strict"; const firstName = document.getElementById("updateFirstName").value; const lastName = document.getElementById("updateLastName").value; const nickname = document.getElementById("updateNickname").value; @@ -389,11 +409,12 @@ async function updateUserProfile() { minecraft_nick: minecraftNick, }; - await doAction('/account', data, "Profile update Successful!", "Profile update failed."); + await doAction('/account', data, "Profile update Successful!", "Profile update failed.", false); umami.track("updateUserProfile"); } async function updateEmail() { + "use strict"; const newEmail = document.getElementById("updateNewEmail").value; const data = { @@ -401,11 +422,12 @@ async function updateEmail() { email: newEmail, }; - await doAction('/account', data, "Email update Successful!", "Email update failed."); + await doAction('/account', data, "Email update Successful!", "Email update failed.", false); umami.track("updateEmail"); } async function populateUserInfoFields(userData) { + "use strict"; document.getElementById("updateFirstName").value = userData.FirstName || ""; document.getElementById("updateLastName").value = userData.LastName || ""; document.getElementById("updateNickname").value = userData.Nickname || ""; @@ -414,6 +436,7 @@ async function populateUserInfoFields(userData) { } async function restoreUserInfo() { + "use strict"; for (let i = 0; i < localStorage.length; i++) { let key = localStorage.key(i); if (key.startsWith("UserInfo_")) { @@ -424,12 +447,13 @@ async function restoreUserInfo() { } async function getUserInfo() { + "use strict"; const data = { action: "get_user_info", }; const result = await doAction('/account', data, "User info retrieved Successfully!", "User info retrieval failed.", true); - if (result && result.Status === "Success") { + if (result && "Success" === result.Status) { Object.keys(result.UserInfo).forEach(index => { let value = result.UserInfo[index]; localStorage.setItem("UserInfo_" + index, value); @@ -444,6 +468,7 @@ async function getUserInfo() { //Admin settings start async function addActivationCodes() { + "use strict"; const count = document.getElementById("activationCodeCount").value; const data = { @@ -451,26 +476,28 @@ async function addActivationCodes() { count: count, }; - doAction('/account', data, "Activation codes added Successfully!", "Activation codes addition failed.").then((result) => { + doAction('/account', data, "Activation codes added Successfully!", "Activation codes addition failed.", false).then((result) => { displayList(result.ActivationCodes, "codeListTable", deleteActivationCode); umami.track("addActivationCodes"); }); } -async function listUsers(silent = false) { +async function listUsers(silent) { + "use strict"; const data = { action: "list_users", }; doAction('/account', data, "User list retrieved Successfully!", "User list retrieval failed.", silent).then((result) => { - if (result && result.Status === "Success") { + if (result && "Success" === result.Status) { displayList(result.Users, "userListTable", deleteUser); } }); } -async function listActivationCodes(silent = false) { +async function listActivationCodes(silent) { + "use strict"; const data = { action: "list_activation_codes", }; @@ -481,31 +508,33 @@ async function listActivationCodes(silent = false) { } async function deleteUser(userId) { + "use strict"; const data = { action: "delete_user", user_id: userId, }; - await doAction('/account', data, "User deleted Successfully!", "User deletion failed."); - await listUsers(); + await doAction('/account', data, "User deleted Successfully!", "User deletion failed.", false); + await listUsers(false); umami.track("deleteUser"); } async function deleteActivationCode(activationCode) { + "use strict"; const data = { action: "delete_activation_code", activation_code: activationCode, }; - await doAction('/account', data, "Activation code deleted Successfully!", "Activation code deletion failed."); - await listActivationCodes(); + await doAction('/account', data, "Activation code deleted Successfully!", "Activation code deletion failed.", false); + await listActivationCodes(false); umami.track("deleteActivationCode"); } //Admin settings end -if (document.readyState !== "loading") { - setTimeout(initAjax, 0); -} else { +if ("loading" === document.readyState) { document.addEventListener("DOMContentLoaded", initAjax); +} else { + setTimeout(initAjax, 0); } \ No newline at end of file diff --git a/assets/style.css b/assets/style.css index ccf7758..d784e47 100644 --- a/assets/style.css +++ b/assets/style.css @@ -17,6 +17,7 @@ --third-bg: #383838; } + body { display: grid; width: 100%; @@ -37,6 +38,13 @@ body { padding: 0; } +body > nav, +body > footer { + background-color: rgba(0, 0, 0, 0.6); + padding: 1.2rem; + text-align: center; +} + body > nav { display: flex; flex-direction: row; @@ -48,13 +56,14 @@ body > nav { margin-bottom: 20px; } + body > footer { grid-area: foot; box-shadow: 0 -20px 28px 0 rgba(0, 0, 0, 0.6); margin-top: 20px; } -body > page { +body > main { grid-area: main; height: 100%; } @@ -70,11 +79,23 @@ header hr { width: 30%; } +li { + list-style: none; +} + header ul li { list-style: circle; width: fit-content; } +ul { + display: flex; + flex-direction: row; + gap: 2.5rem; + list-style: none; + padding-left: 0; +} + header ul { display: flex; flex-direction: column; @@ -105,22 +126,12 @@ li a:hover::after { width: 85%; } -li { - list-style: none; -} li.navpage_item { padding-left: 20px; padding-right: 20px; } -nav, -footer { - background-color: rgba(0, 0, 0, 0.6); - padding: 1.2rem; - text-align: center; -} - table>tbody, table>tbody>tr, table>tbody>tr>th, @@ -130,6 +141,15 @@ table>tbody>tr>td { text-align: center; } +button { + border-radius: 25px; + border: 2px solid var(--primary); + background: var(--third-bg); + color: var(--primary-text); + width: 175px; + transition-duration: 0.3s; +} + table>tbody>tr>td>button { border: unset; border-radius: unset; @@ -142,14 +162,6 @@ table { border-collapse: collapse; } -ul { - display: flex; - flex-direction: row; - gap: 2.5rem; - list-style: none; - padding-left: 0; -} - ul.navpage_list { gap: 10px; border: 4px solid var(--primary-hover) !important; @@ -266,6 +278,7 @@ ul.navpage_list { width: inherit; } + /*noinspection CssUnusedSymbol*/ #navsite_list.active { display: flex; -moz-box-shadow: 0 20px 28px 0 rgba(0, 0, 0, 0.6); @@ -292,6 +305,7 @@ ul.navpage_list { flex-direction: column; } +/*noinspection CssUnusedSymbol*/ .status-message { background-color: #dff0d8; /* Success background color */ @@ -305,6 +319,7 @@ ul.navpage_list { transition: opacity 0.5s ease-in-out; } +/*noinspection CssUnusedSymbol*/ .status-message.failure { background-color: #f2dede; /* Failure background color */ @@ -353,15 +368,6 @@ textarea{ border-radius: 10px; } -button { - border-radius: 25px; - border: 2px solid var(--primary); - background: var(--third-bg); - color: var(--primary-text); - width: 175px; - transition-duration: 0.3s; -} - button:hover { background: var(--primary); transition-duration: 0.3s; @@ -380,10 +386,8 @@ header.ye-span:hover + body{ background-size: 10% !important; } -body:has(.ye-span:hover) { - background: url('/assets/images/ye.jpg') repeat !important; - background-size: 10% !important; -} + + #articlecreate { position: fixed; @@ -425,6 +429,7 @@ div#articleslist > article > div.articleinfo > *{ width: fit-content; } +/*noinspection CssUnusedSymbol*/ div#articleslist > article > div.articleinfo{ display: flex; flex-direction: row; @@ -432,8 +437,4 @@ div#articleslist > article > div.articleinfo{ div#articleslist>article{ border: 4px solid var(--primary); -} - -a.navsite_link.active:after{ - } \ No newline at end of file diff --git a/lib/upload.php b/lib/upload.php index 0e361a0..df125a4 100644 --- a/lib/upload.php +++ b/lib/upload.php @@ -57,16 +57,28 @@ function saveUploadedFileInDatabase($filePath, $fileType):bool function doImageUpload($inFile, $outFile): bool { // Create Imagick object - $imagick = new Imagick($inFile); + try { + $imagick = new Imagick($inFile); + } catch (ImagickException $e) { + } // Set the desired format for reencoding (WebP) - $imagick->setImageFormat('webp'); + try { + $imagick->setImageFormat('webp'); + } catch (ImagickException $e) { + } // Remove non-essential metadata - $imagick->stripImage(); + try { + $imagick->stripImage(); + } catch (ImagickException $e) { + } // Write the reencoded image to the output file - $imagick->writeImage($outFile); + try { + $imagick->writeImage($outFile); + } catch (ImagickException $e) { + } // Destroy the Imagick object to free up resources $imagick->destroy(); @@ -138,19 +150,16 @@ function parseIncomingFiles(): array foreach ($incomingFiles as $incomingFile) { if ($incomingFile["error"] == 0 && is_file($incomingFile["tmp_name"])) { $type = explode("/", $incomingFile["type"]); - switch ($type) { - case "image": - $imgFname = pathinfo($incomingFile["name"], PATHINFO_FILENAME); - $uploadPath = getUploadPath("image", $imgFname); - if(!empty($uploadPath)) { - if (!doImageUpload($incomingFile["tmp_name"], $uploadPath)) { - $success = false; - } - } - else{ + if ($type == "image") { + $imgFname = pathinfo($incomingFile["name"], PATHINFO_FILENAME); + $uploadPath = getUploadPath("image", $imgFname); + if (!empty($uploadPath)) { + if (!doImageUpload($incomingFile["tmp_name"], $uploadPath)) { $success = false; } - break; + } else { + $success = false; + } } } } diff --git a/templates/403.html b/templates/403.html index e208ec7..ee1b469 100644 --- a/templates/403.html +++ b/templates/403.html @@ -2,5 +2,6 @@