diff options
author | Thedro Neely <thedroneely@gmail.com> | 2018-08-30 04:40:53 -0400 |
---|---|---|
committer | Thedro Neely <thedroneely@gmail.com> | 2018-08-30 04:40:53 -0400 |
commit | 2659205908bd5cab508f4ff817123673e078ab74 (patch) | |
tree | e455f36b124e9b98f7005e6d4310b71881734623 /bootstrap/comments/admin | |
download | edwinmattiacci.com-2659205908bd5cab508f4ff817123673e078ab74.tar.gz edwinmattiacci.com-2659205908bd5cab508f4ff817123673e078ab74.tar.bz2 edwinmattiacci.com-2659205908bd5cab508f4ff817123673e078ab74.zip |
Initialize Repo: First Commit
Diffstat (limited to 'bootstrap/comments/admin')
32 files changed, 1939 insertions, 0 deletions
diff --git a/bootstrap/comments/admin/admin.css b/bootstrap/comments/admin/admin.css new file mode 100644 index 0000000..f2be72b --- /dev/null +++ b/bootstrap/comments/admin/admin.css @@ -0,0 +1,102 @@ +body, html { + width: 100%; + min-width: 100%; + height: 100%; + min-height: 100%; +} + +body { + padding: 0px 0px 0px 230px; +} + +#sidebar { + position: absolute; + top: 0px; + left: 0px; + width: 230px; + height: 100%; + border-right: #CCCCCC; + border-right: 1px solid #CCCCCC; + background-color: #F5F5F5; + overflow: auto; +} + +#navigation { + border-top: 1px solid #CCCCCC; + border-bottom: 1px solid #CCCCCC; +} + +#logo, +#navigation div, +#navigation a { + position: relative; + display: block; + width: 100%; + vertical-align: top; + overflow: hidden; +} + +#navigation div { + border: none; + border-bottom: 1px solid #CCCCCC; +} + +#navigation div:last-child { + border-bottom: none; +} + +#logo, +#navigation a { + padding: 15px; + margin: 0px; + border: none; +} + +#navigation a, +#navigation:hover a.active { + border: none; + border-right: 4px solid transparent; + color: #222222; +} + +#navigation a.active { + color: #266394; + border-right: 4px solid #3485C7; + background-color: #EEEEEE; + font-weight: bold; +} + +#navigation:hover a.active { + background-color: transparent; +} + +#navigation a:hover, +#navigation a.active:hover { + color: #266394; + border-color: #3485C7; + background-color: #EEEEEE; +} + +div#logo, +div#logo a { + height: 234px; +} + +div#logo a, +#navigation:hover div#logo a { + border: none; + border-bottom: 4px solid transparent; +} + +div#logo a:hover, +div#logo a.active { + border: none; + border-bottom: 4px solid #5E94FF; +} + +#content { + width: 100%; + height: 100%; + vertical-align: top; + background-color: #FFFFFF; +} diff --git a/bootstrap/comments/admin/admin.html b/bootstrap/comments/admin/admin.html new file mode 100644 index 0000000..155d743 --- /dev/null +++ b/bootstrap/comments/admin/admin.html @@ -0,0 +1,56 @@ +<!DOCTYPE html> + +<html lang="en" dir="ltr"> + <head> + <title>HashOver - {hashover:title}</title> + + <link type="text/css" href="../themes/default/general.css" rel="stylesheet"> + <link type="text/css" href="../themes/default/special.css" rel="stylesheet"> + <link type="text/css" href="admin.css" rel="stylesheet"> + + <script type="text/javascript" src="admin.js"></script> + + <meta http-equiv="Content-type" content="text/html; charset=utf-8"> + <meta http-equiv="Content-Language" content="EN"> + + <link type="image/x-icon" href="../images/favicon.png" rel="shortcut icon"> + <link type="image/x-icon" href="../images/favicon.png" rel="icon"> + <link href="https://www.gnu.org/licenses/agpl" rel="copyright"> + </head> + + <body> + <div id="sidebar"> + <div id="logo"> + <img src="../images/hashover-logo.png" alt="HashOver" width="100%"> + </div> + + <div id="navigation"> + <div> + <a class="view-link" href="views/moderation/" target="content">{hashover:moderation}</a> + </div> + + <div> + <a class="view-link" href="views/blocklist/" target="content">{hashover:block-ip-addresses}</a> + </div> + + <div> + <a class="view-link" href="views/url-queries/" target="content">{hashover:filter-url-queries}</a> + </div> + + <div> + <a class="view-link" href="views/updates/" target="content">{hashover:check-for-updates}</a> + </div> + + <div> + <a class="view-link" href="views/documentation/" target="content">{hashover:documentation}</a> + </div> + + <div> + <a class="view-link" href="views/settings/" target="content">{hashover:settings}</a> + </div> + </div> + </div> + + <iframe id="content" name="content" src="views/moderation/" frameborder="0"></iframe> + </body> +</html> diff --git a/bootstrap/comments/admin/admin.js b/bootstrap/comments/admin/admin.js new file mode 100644 index 0000000..046735b --- /dev/null +++ b/bootstrap/comments/admin/admin.js @@ -0,0 +1,41 @@ +// Wait for the page HTML to be parsed +document.addEventListener ('DOMContentLoaded', function () { + // Get view links + var viewLinks = document.getElementsByClassName ('view-link'); + + // Get content frame + var content = document.getElementById ('content'); + + // Execute a given function for each view link + function eachViewLink (callback) + { + for (var i = 0, il = viewLinks.length; i < il; i++) { + callback (viewLinks[i]); + } + } + + // Remove active class from all view links + function clearViewTabs () + { + eachViewLink (function (link) { + link.className = 'view-link'; + }); + } + + // Automatically select the proper view tab on page load + content.onload = function () + { + // Remove active class from all view links + clearViewTabs (); + + // Select active proper tab for currently loaded view + eachViewLink (function (link) { + var regex = new RegExp (link.getAttribute ('href')); + var frameUrl = content.contentDocument.location.href; + + if (regex.test (decodeURIComponent (frameUrl))) { + link.className += ' active'; + } + }); + }; +}, false); diff --git a/bootstrap/comments/admin/index.php b/bootstrap/comments/admin/index.php new file mode 100644 index 0000000..d7a29bc --- /dev/null +++ b/bootstrap/comments/admin/index.php @@ -0,0 +1,58 @@ +<?php namespace HashOver; + +// Copyright (C) 2018 Jacob Barkdull +// This file is part of HashOver. +// +// HashOver is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// HashOver is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with HashOver. If not, see <http://www.gnu.org/licenses/>. + + +// Do some standard HashOver setup work +require (realpath ('../backend/standard-setup.php')); + +// Autoload class files +spl_autoload_register (function ($uri) { + $uri = str_replace ('\\', '/', strtolower ($uri)); + $class_name = basename ($uri); + + if (!@include (realpath ('../backend/classes/' . $class_name . '.php'))) { + echo '"' . $class_name . '.php" file could not be included!'; + exit; + } +}); + +try { + // Instantiate HashOver class + $hashover = new \HashOver (); + $hashover->initiate (); + $hashover->finalize (); + + // Template data + $template = array ( + 'title' => $hashover->locale->text['admin'], + 'moderation' => $hashover->locale->text['moderation'], + 'block-ip-addresses' => $hashover->locale->text['block-ip-addresses'], + 'filter-url-queries' => $hashover->locale->text['filter-url-queries'], + 'check-for-updates' => $hashover->locale->text['check-for-updates'], + 'documentation' => $hashover->locale->text['documentation'], + 'settings' => $hashover->locale->text['settings'] + ); + + // Load and parse HTML template + echo $hashover->templater->parseTemplate ('admin.html', $template); + +} catch (\Exception $error) { + $misc = new Misc ('php'); + $message = $error->getMessage (); + $misc->displayError ($message); +} diff --git a/bootstrap/comments/admin/views/blocklist/blocklist.html b/bootstrap/comments/admin/views/blocklist/blocklist.html new file mode 100644 index 0000000..86dd089 --- /dev/null +++ b/bootstrap/comments/admin/views/blocklist/blocklist.html @@ -0,0 +1,44 @@ +<!DOCTYPE html> + +<html lang="en" dir="ltr"> + <head> + <title>HashOver - {hashover:title}</title> + + <link type="text/css" href="../../../themes/default/general.css" rel="stylesheet"> + <link type="text/css" href="../../../themes/default/special.css" rel="stylesheet"> + + <script type="text/javascript" src="../shared/update-elements.js"></script> + <script type="text/javascript" src="blocklist.js"></script> + + <meta http-equiv="Content-type" content="text/html; charset=utf-8"> + <meta http-equiv="Content-Language" content="EN"> + + <link type="image/x-icon" href="../../../images/favicon.png" rel="shortcut icon"> + <link type="image/x-icon" href="../../../images/favicon.png" rel="icon"> + <link href="https://www.gnu.org/licenses/agpl" rel="copyright"> + </head> + + <body> + <h1 class="underlined"> + <span id="title">{hashover:title}</span> + + {hashover:logout} + </h1> + + <div class="p-spaced muted-text"> + {hashover:sub-title} + {hashover:message} + </div> + + <form method="post"> + <p id="ip-list"> + {hashover:inputs} + </p> + + <p> + <input id="save-button" type="submit" value="{hashover:save-button}"> + <input id="new-button" type="button" value="+"> + </p> + </form> + </body> +</html> diff --git a/bootstrap/comments/admin/views/blocklist/blocklist.js b/bootstrap/comments/admin/views/blocklist/blocklist.js new file mode 100644 index 0000000..4b04dbf --- /dev/null +++ b/bootstrap/comments/admin/views/blocklist/blocklist.js @@ -0,0 +1,30 @@ +// Wait for the page HTML to be parsed +document.addEventListener ('DOMContentLoaded', function () { + // Get the "New Address" and "Save" buttons + var newButton = document.getElementById ('new-button'); + var ipList = document.getElementById ('ip-list'); + var saveButton = document.getElementById ('save-button'); + + newButton.onclick = function () + { + // Create input and indentation + var addresses = document.getElementsByClassName ('addresses'); + var indentation = document.createTextNode ('\n\t\t\t\t'); + + // Clone the first address field + var input = addresses[0].cloneNode (true); + + // Remove its value + input.value = ''; + + // Append indentation and input to IP address list + ipList.appendChild (indentation); + ipList.appendChild (input); + }; + + // Disable the "Save" button when clicked + saveButton.onclick = function () + { + this.disabled = true; + }; +}, false); diff --git a/bootstrap/comments/admin/views/blocklist/index.php b/bootstrap/comments/admin/views/blocklist/index.php new file mode 100644 index 0000000..8d27633 --- /dev/null +++ b/bootstrap/comments/admin/views/blocklist/index.php @@ -0,0 +1,104 @@ +<?php namespace HashOver; + +// Copyright (C) 2018 Jacob Barkdull +// This file is part of HashOver. +// +// HashOver is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// HashOver is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with HashOver. If not, see <http://www.gnu.org/licenses/>. + + +try { + // View setup + require (realpath ('../view-setup.php')); + + // Default blocklist array + $blocklist = array (); + + // Blocklist JSON file location + $blocklist_file = $hashover->setup->getAbsolutePath ('config/blocklist.json'); + + // Check if the form has been submitted + if (!empty ($_POST['addresses']) and is_array ($_POST['addresses'])) { + // If so, run through submitted addresses + foreach ($_POST['addresses'] as $address) { + // Add each non-empty address value to the blocklist array + if (!empty ($address)) { + $blocklist[] = $address; + } + } + + // Save the JSON data to the blocklist file + if ($hashover->setup->verifyAdmin ($hashover->login->password) + and $data_files->saveJSON ($blocklist_file, $blocklist)) + { + // Redirect with success indicator + header ('Location: index.php?status=success'); + } else { + // Redirect with failure indicator + header ('Location: index.php?status=failure'); + } + + // Exit after redirect + exit; + } + + // Otherwise, load and parse blocklist file + $json = $data_files->readJSON ($blocklist_file); + + // Check for JSON parse error + if (is_array ($json)) { + $blocklist = $json; + } + + // IP Address inputs + $inputs = new HTMLTag ('span'); + + // Create IP address inputs + for ($i = 0, $il = max (3, count ($blocklist)); $i < $il; $i++) { + // Use IP address from file or blank + $address = !empty ($blocklist[$i]) ? $blocklist[$i] : ''; + + // Create input tag + $input = new HTMLTag ('input', array ( + 'class' => 'addresses', + 'type' => 'text', + 'name' => 'addresses[]', + 'value' => $address, + 'size' => '15', + 'maxlength' => '15', + 'placeholder' => '127.0.0.1', + 'title' => $hashover->locale->text['blocklist-ip-tip'] + ), false, true); + + // Add input to inputs container + $inputs->appendChild ($input); + } + + // Template data + $template = array ( + 'title' => $hashover->locale->text['blocklist-title'], + 'logout' => $logout->asHTML ("\t\t\t"), + 'sub-title' => $hashover->locale->text['blocklist-sub'], + 'message' => $form_message, + 'inputs' => $inputs->getInnerHTML ("\t\t\t\t"), + 'save-button' => $hashover->locale->text['save'] + ); + + // Load and parse HTML template + echo $hashover->templater->parseTemplate ('blocklist.html', $template); + +} catch (\Exception $error) { + $misc = new Misc ('php'); + $message = $error->getMessage (); + $misc->displayError ($message); +} diff --git a/bootstrap/comments/admin/views/documentation/documentation.html b/bootstrap/comments/admin/views/documentation/documentation.html new file mode 100644 index 0000000..be82e62 --- /dev/null +++ b/bootstrap/comments/admin/views/documentation/documentation.html @@ -0,0 +1,27 @@ +<!DOCTYPE html> + +<html lang="en" dir="ltr"> + <head> + <title>HashOver - {hashover:title}</title> + + <link type="text/css" href="../../../themes/default/general.css" rel="stylesheet"> + <link type="text/css" href="../../../themes/default/special.css" rel="stylesheet"> + + <meta http-equiv="Content-type" content="text/html; charset=utf-8"> + <meta http-equiv="Content-Language" content="EN"> + + <link type="image/x-icon" href="../../../images/favicon.png" rel="shortcut icon"> + <link type="image/x-icon" href="../../../images/favicon.png" rel="icon"> + <link href="https://www.gnu.org/licenses/agpl" rel="copyright"> + </head> + + <body> + <h1 class="underlined"> + {hashover:title} + + {hashover:logout} + </h1> + + <p class="muted-text">{hashover:sub-title}</p> + </body> +</html> diff --git a/bootstrap/comments/admin/views/documentation/index.php b/bootstrap/comments/admin/views/documentation/index.php new file mode 100644 index 0000000..74a62be --- /dev/null +++ b/bootstrap/comments/admin/views/documentation/index.php @@ -0,0 +1,38 @@ +<?php namespace HashOver; + +// Copyright (C) 2018 Jacob Barkdull +// This file is part of HashOver. +// +// HashOver is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// HashOver is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with HashOver. If not, see <http://www.gnu.org/licenses/>. + + +try { + // View setup + require (realpath ('../view-setup.php')); + + // Template data + $template = array ( + 'title' => $hashover->locale->text['documentation'], + 'logout' => $logout->asHTML ("\t\t\t"), + 'sub-title' => $hashover->locale->text['coming-soon'] + ); + + // Load and parse HTML template + echo $hashover->templater->parseTemplate ('documentation.html', $template); + +} catch (\Exception $error) { + $misc = new Misc ('php'); + $message = $error->getMessage (); + $misc->displayError ($message); +} diff --git a/bootstrap/comments/admin/views/example/example.html b/bootstrap/comments/admin/views/example/example.html new file mode 100644 index 0000000..1e4464c --- /dev/null +++ b/bootstrap/comments/admin/views/example/example.html @@ -0,0 +1,30 @@ +<!DOCTYPE html> + +<html lang="en" dir="ltr"> + <head> + <title>HashOver - {hashover:title}</title> + + <link type="text/css" href="../../../themes/default/general.css" rel="stylesheet"> + <link type="text/css" href="../../../themes/default/special.css" rel="stylesheet"> + <link type="text/css" href="example.css" rel="stylesheet"> + + <script type="text/javascript" src="example.js"></script> + + <meta http-equiv="Content-type" content="text/html; charset=utf-8"> + <meta http-equiv="Content-Language" content="EN"> + + <link type="image/x-icon" href="../../../images/favicon.png" rel="shortcut icon"> + <link type="image/x-icon" href="../../../images/favicon.png" rel="icon"> + <link href="https://www.gnu.org/licenses/agpl" rel="copyright"> + </head> + + <body> + <h1 class="underlined"> + {hashover:title} + + {hashover:logout} + </h1> + + <p class="muted-text">{hashover:sub-title}</p> + </body> +</html> diff --git a/bootstrap/comments/admin/views/example/index.php b/bootstrap/comments/admin/views/example/index.php new file mode 100644 index 0000000..7848daf --- /dev/null +++ b/bootstrap/comments/admin/views/example/index.php @@ -0,0 +1,38 @@ +<?php namespace HashOver; + +// Copyright (C) 2018 Jacob Barkdull +// This file is part of HashOver. +// +// HashOver is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// HashOver is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with HashOver. If not, see <http://www.gnu.org/licenses/>. + + +try { + // View setup + require (realpath ('../view-setup.php')); + + // Template data + $template = array ( + 'title' => $hashover->locale->text['example'], + 'logout' => $logout->asHTML ("\t\t\t"), + 'sub-title' => $hashover->locale->text['example'] + ); + + // Load and parse HTML template + echo $hashover->templater->parseTemplate ('example.html', $template); + +} catch (\Exception $error) { + $misc = new Misc ('php'); + $message = $error->getMessage (); + $misc->displayError ($message); +} diff --git a/bootstrap/comments/admin/views/login/index.php b/bootstrap/comments/admin/views/login/index.php new file mode 100644 index 0000000..1913ece --- /dev/null +++ b/bootstrap/comments/admin/views/login/index.php @@ -0,0 +1,92 @@ +<?php namespace HashOver; + +// Copyright (C) 2018 Jacob Barkdull +// This file is part of HashOver. +// +// HashOver is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// HashOver is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with HashOver. If not, see <http://www.gnu.org/licenses/>. + + +// Redirects the user back to where they came from +function redirect ($url = '') +{ + // Check if we're redirecting to a specific URL + if (!empty ($url)) { + // If so, use it + header ('Location: ' . $url); + } else { + // If not, check if there is a redirect specified + if (!empty ($_GET['redirect'])) { + // If so, use it + header ('Location: ' . $_GET['redirect']); + } else { + // If not, redirect to moderation + header ('Location: ../moderation/'); + } + } + + // Exit after redirect + exit; +} + +try { + // View setup + require (realpath ('../view-setup.php')); + + // Check if the user submitted login information + if (!empty ($_POST['name']) and !empty ($_POST['password'])) { + // If so, attempt to log them in + $hashover->login->setLogin (); + + // Check if the user is not admin + if ($hashover->setup->adminLogin ($hashover->login->loginHash) === false) { + // If so, logout + $hashover->login->clearLogin (); + + // Sleep 5 seconds + sleep (5); + } + + // And redirect user to desired view + redirect (); + } + + // Check if we're logging out + if (isset ($_GET['logout'])) { + // If so, attempt to log the user out + $hashover->login->clearLogin (); + + // And redirect user to main admin page + redirect ($hashover->setup->getHttpPath ('admin')); + } + + // Template data + $template = array ( + 'title' => $hashover->locale->text['login'], + 'logout' => $logout->asHTML ("\t\t\t"), + 'sub-title' => $hashover->locale->text['admin-required'], + 'name' => $hashover->locale->text['name'], + 'password' => $hashover->locale->text['password'], + 'email' => $hashover->locale->optionalize ('email'), + 'website' => $hashover->locale->optionalize ('website'), + 'login' => $hashover->locale->text['login'] + ); + + // Load and parse HTML template + echo $hashover->templater->parseTemplate ('login.html', $template); + +} catch (\Exception $error) { + $misc = new Misc ('php'); + $message = $error->getMessage (); + $misc->displayError ($message); +} diff --git a/bootstrap/comments/admin/views/login/login.css b/bootstrap/comments/admin/views/login/login.css new file mode 100644 index 0000000..37e0547 --- /dev/null +++ b/bootstrap/comments/admin/views/login/login.css @@ -0,0 +1,27 @@ +body { + background-image: url('../../../images/white-noise.png'); +} + +#login { + position: absolute; + left: 50%; + top: 50%; + padding: 15px; + margin: -133px 0px 0px -150px; + width: 300px; + border: 2px solid #CCCCCC; + background-color: #FFFFFF; + overflow: hidden; +} + +#login input { + width: 100%; +} + +input[name="name"], input[name="password"] { + font-weight: bold; +} + +#login.red { + border-color: #FF0000; +} diff --git a/bootstrap/comments/admin/views/login/login.html b/bootstrap/comments/admin/views/login/login.html new file mode 100644 index 0000000..47dbd29 --- /dev/null +++ b/bootstrap/comments/admin/views/login/login.html @@ -0,0 +1,37 @@ +<!DOCTYPE html> + +<html lang="en" dir="ltr"> + <head> + <title>HashOver - {hashover:title}</title> + + <link type="text/css" href="../../../themes/default/general.css" rel="stylesheet"> + <link type="text/css" href="../../../themes/default/special.css" rel="stylesheet"> + <link type="text/css" href="login.css" rel="stylesheet"> + + <script type="text/javascript" src="login.js"></script> + + <meta http-equiv="Content-type" content="text/html; charset=utf-8"> + <meta http-equiv="Content-Language" content="EN"> + + <link type="image/x-icon" href="../../../images/favicon.png" rel="shortcut icon"> + <link type="image/x-icon" href="../../../images/favicon.png" rel="icon"> + <link href="https://www.gnu.org/licenses/agpl" rel="copyright"> + </head> + + <body> + <div id="login" class="red animate-all"> + <h1 class="underlined">{hashover:title}</h1> + + <form method="post"> + <div><input type="text" name="name" placeholder="{hashover:name}"></div> + <div><input type="password" name="password" placeholder="{hashover:password}"></div> + <div><input type="text" name="email" placeholder="{hashover:email}"></div> + <div><input type="text" name="website" placeholder="{hashover:website}"></div> + + <p> + <input type="submit" value="{hashover:login}"> + </p> + </form> + </div> + </body> +</html> diff --git a/bootstrap/comments/admin/views/login/login.js b/bootstrap/comments/admin/views/login/login.js new file mode 100644 index 0000000..a94955c --- /dev/null +++ b/bootstrap/comments/admin/views/login/login.js @@ -0,0 +1,10 @@ +// Wait for the page HTML to be parsed +document.addEventListener ('DOMContentLoaded', function () { + // Get login dialog + var login = document.getElementById ('login'); + + // Remove red border class + setTimeout (function () { + login.className = login.className.replace (/red ?/, ''); + }, 1000); +}, false); diff --git a/bootstrap/comments/admin/views/moderation/index.php b/bootstrap/comments/admin/views/moderation/index.php new file mode 100644 index 0000000..2252389 --- /dev/null +++ b/bootstrap/comments/admin/views/moderation/index.php @@ -0,0 +1,88 @@ +<?php namespace HashOver; + +// Copyright (C) 2018 Jacob Barkdull +// This file is part of HashOver. +// +// HashOver is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// HashOver is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with HashOver. If not, see <http://www.gnu.org/licenses/>. + + +try { + // View setup + require (realpath ('../view-setup.php')); + + // Create comment thread table + $table = new HTMLTag ('table', array ( + 'id' => 'threads', + 'class' => 'striped-rows-odd', + 'cellspacing' => '0', + 'cellpadding' => '4' + )); + + // Get comment threads + $threads = $hashover->thread->queryThreads (); + + // Run through comment threads + foreach ($threads as $thread) { + // Create table row and cell + $tr = new HTMLTag ('tr'); + $td = new HTMLTag ('td'); + + // Read and parse JSON metadata file + $data = $hashover->thread->data->readMeta ('page-info', $thread); + + // Check if metadata was read successfully + if ($data === false or empty ($data['url']) or empty ($data['title'])) { + continue; + } + + // Create thread hyperlink + $thread_link = new HTMLTag ('a', array ( + 'href' => 'threads.php?' . implode ('&', array ( + 'thread=' . urlencode ($thread), + 'title=' . urlencode ($data['title']), + 'url=' . urlencode ($data['url']) + )), + + 'innerHTML' => $data['title'] + )); + + // Append thread hyperlink to cell + $td->appendChild ($thread_link); + + // Append page URL to row + $td->appendChild (new HTMLTag ('p', new HTMLTag ('small', $data['url']))); + + // Append cell to row + $tr->appendChild ($td); + + // Append row to table + $table->appendChild ($tr); + } + + // Template data + $template = array ( + 'title' => $hashover->locale->text['moderation'], + 'logout' => $logout->asHTML ("\t\t\t"), + 'sub-title' => $hashover->locale->text['moderation-sub'], + 'threads' => $table->asHTML ("\t\t") + ); + + // Load and parse HTML template + echo $hashover->templater->parseTemplate ('moderation.html', $template); + +} catch (\Exception $error) { + $misc = new Misc ('php'); + $message = $error->getMessage (); + $misc->displayError ($message); +} diff --git a/bootstrap/comments/admin/views/moderation/moderation.css b/bootstrap/comments/admin/views/moderation/moderation.css new file mode 100644 index 0000000..ec6c389 --- /dev/null +++ b/bootstrap/comments/admin/views/moderation/moderation.css @@ -0,0 +1,3 @@ +#threads small { + color: #5AB3FA; +} diff --git a/bootstrap/comments/admin/views/moderation/moderation.html b/bootstrap/comments/admin/views/moderation/moderation.html new file mode 100644 index 0000000..a9d9df7 --- /dev/null +++ b/bootstrap/comments/admin/views/moderation/moderation.html @@ -0,0 +1,30 @@ +<!DOCTYPE html> + +<html lang="en" dir="ltr"> + <head> + <title>HashOver - {hashover:title}</title> + + <link type="text/css" href="../../../themes/default/general.css" rel="stylesheet"> + <link type="text/css" href="../../../themes/default/special.css" rel="stylesheet"> + <link type="text/css" href="moderation.css" rel="stylesheet"> + + <meta http-equiv="Content-type" content="text/html; charset=utf-8"> + <meta http-equiv="Content-Language" content="EN"> + + <link type="image/x-icon" href="../../../images/favicon.png" rel="shortcut icon"> + <link type="image/x-icon" href="../../../images/favicon.png" rel="icon"> + <link href="https://www.gnu.org/licenses/agpl" rel="copyright"> + </head> + + <body> + <h1 class="underlined"> + {hashover:title} + + {hashover:logout} + </h1> + + <p class="muted-text">{hashover:sub-title}</p> + + {hashover:threads} + </body> +</html> diff --git a/bootstrap/comments/admin/views/moderation/threads.css b/bootstrap/comments/admin/views/moderation/threads.css new file mode 100644 index 0000000..48258da --- /dev/null +++ b/bootstrap/comments/admin/views/moderation/threads.css @@ -0,0 +1,27 @@ +.special a, +.special a:link { + display: inline-block; + border-bottom: 0.1em solid transparent; + margin-bottom: -0.1em; +} + +.special a:hover { + border-bottom-color: #266394; +} + +#loading { + display: block ! important; + position: absolute; + top: 50%; + left: 0px; + width: 100%; + margin-top: -15px; +} + +#loading img { + vertical-align: top; +} + +.hashover > div { + display: none; +} diff --git a/bootstrap/comments/admin/views/moderation/threads.html b/bootstrap/comments/admin/views/moderation/threads.html new file mode 100644 index 0000000..68c57a5 --- /dev/null +++ b/bootstrap/comments/admin/views/moderation/threads.html @@ -0,0 +1,34 @@ +<!DOCTYPE html> + +<html lang="en" dir="ltr"> + <head> + <title>HashOver - {hashover:title}</title> + + <link type="text/css" href="../../../themes/default/general.css" rel="stylesheet"> + <link type="text/css" href="threads.css" rel="stylesheet"> + + <meta http-equiv="Content-type" content="text/html; charset=utf-8"> + <meta http-equiv="Content-Language" content="EN"> + + <link type="image/x-icon" href="../../../images/favicon.png" rel="shortcut icon"> + <link type="image/x-icon" href="../../../images/favicon.png" rel="icon"> + <link href="https://www.gnu.org/licenses/agpl" rel="copyright"> + </head> + + <body> + <h1 class="underlined special"> + ← <a href="../moderation/">{hashover:title}</a> + + {hashover:logout} + </h1> + + <div id="hashover"> + <center id="loading"> + <img src="../../../images/loading-ltr.gif" alt="Loading..." width="90" height="30"> + </center> + </div> + + <script type="text/javascript" src="../../../comments.php?nodefault"></script> + <script type="text/javascript" src="threads.js"></script> + </body> +</html> diff --git a/bootstrap/comments/admin/views/moderation/threads.js b/bootstrap/comments/admin/views/moderation/threads.js new file mode 100644 index 0000000..851cad3 --- /dev/null +++ b/bootstrap/comments/admin/views/moderation/threads.js @@ -0,0 +1,21 @@ +var fullQueries = window.location.search.substr (1); +var queries = fullQueries.split ('&'); +var options = {}; + +// Parse URL queries as HashOver options +for (var i = 0, il = queries.length; i < il; i++) { + var queryParts = queries[i].split ('='); + var queryName = queryParts[0]; + var queryValue = queryParts[1]; + + if (queryName && queryValue) { + queryValue = queryValue.replace (/\+/g, '%20'); + queryValue = decodeURIComponent (queryValue); + + // Set option + options[queryName] = queryValue; + } +} + +// Instantiate HashOver +var hashover = new HashOver (options); diff --git a/bootstrap/comments/admin/views/moderation/threads.php b/bootstrap/comments/admin/views/moderation/threads.php new file mode 100644 index 0000000..b22c692 --- /dev/null +++ b/bootstrap/comments/admin/views/moderation/threads.php @@ -0,0 +1,33 @@ +<?php namespace HashOver; + +// Copyright (C) 2018 Jacob Barkdull +// This file is part of HashOver. +// +// HashOver is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// HashOver is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with HashOver. If not, see <http://www.gnu.org/licenses/>. + + +try { + // View setup + require (realpath ('../view-setup.php')); + + // Load and parse HTML template + echo $hashover->templater->parseTemplate ('threads.html', array ( + 'title' => $hashover->locale->text['back'], + 'logout' => $logout->asHTML ("\t\t\t") + )); +} catch (\Exception $error) { + $misc = new Misc ('php'); + $message = $error->getMessage (); + $misc->displayError ($message); +} diff --git a/bootstrap/comments/admin/views/settings/index.php b/bootstrap/comments/admin/views/settings/index.php new file mode 100644 index 0000000..37a72b3 --- /dev/null +++ b/bootstrap/comments/admin/views/settings/index.php @@ -0,0 +1,515 @@ +<?php namespace HashOver; + +// Copyright (C) 2018 Jacob Barkdull +// This file is part of HashOver. +// +// HashOver is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// HashOver is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with HashOver. If not, see <http://www.gnu.org/licenses/>. + + +// Generates an array of various settings information +function ui_array (Setup $setup) +{ + // Theme names + $themes = array (); + + // Themes directory + $themes_directory = $setup->getAbsolutePath ('themes'); + + // Get each theme directory name + foreach (glob ($themes_directory . '/*', GLOB_ONLYDIR) as $directory) { + $theme = basename ($directory); + $themes[$theme] = $theme; + } + + // Return array of settings allowed to be changed + return array ( + 'language' => array ( + 'type' => 'select', + 'value' => $setup->language, + + 'options' => array ( + 'auto' => 'auto', + 'en' => 'English', + 'da' => 'Danish', + 'el' => 'Greek', + 'de' => 'German', + 'es' => 'Spanish', + 'fa' => 'Persian', + 'fr' => 'French', + 'jp' => 'Japanese', + 'ko' => 'Korean', + 'lt' => 'Lithuanian', + 'nl' => 'Dutch', + 'pl' => 'Polish', + 'pt-br' => 'Brazilian Portuguese', + 'ro' => 'Romanian', + 'tr' => 'Turkish', + 'zh-cn' => 'Simplified Chinese' + ) + ), + 'theme' => array ( + 'type' => 'select', + 'value' => $setup->theme, + 'options' => $themes + ), + 'uses-moderation' => array ( + 'type' => 'checkbox', + 'value' => $setup->usesModeration + ), + 'pends-user-edits' => array ( + 'type' => 'checkbox', + 'value' => $setup->pendsUserEdits + ), + 'data-format' => array ( + 'type' => 'select', + 'value' => $setup->dataFormat, + + 'options' => array ( + 'xml' => 'XML', + 'json' => 'JSON', + 'sql' => 'SQL' + ) + ), + 'default-name' => array ( + 'type' => 'text', + 'value' => $setup->defaultName + ), + 'allows-images' => array ( + 'type' => 'checkbox', + 'value' => $setup->allowsImages + ), + 'allows-login' => array ( + 'type' => 'checkbox', + 'value' => $setup->allowsLogin + ), + 'allows-likes' => array ( + 'type' => 'checkbox', + 'value' => $setup->allowsLikes + ), + 'allows-dislikes' => array ( + 'type' => 'checkbox', + 'value' => $setup->allowsDislikes + ), + 'uses-ajax' => array ( + 'type' => 'checkbox', + 'value' => $setup->usesAjax + ), + 'collapses-interface' => array ( + 'type' => 'checkbox', + 'value' => $setup->collapsesInterface + ), + 'collapses-comments' => array ( + 'type' => 'checkbox', + 'value' => $setup->collapsesComments + ), + 'collapse-limit' => array ( + 'type' => 'number', + 'value' => $setup->collapseLimit + ), + 'reply-mode' => array ( + 'type' => 'select', + 'value' => $setup->replyMode, + + 'options' => array ( + 'thread' => 'Threaded', + 'stream' => 'Stream' + ) + ), + 'stream-depth' => array ( + 'type' => 'number', + 'value' => $setup->streamDepth + ), + 'popularity-threshold' => array ( + 'type' => 'number', + 'value' => $setup->popularityThreshold + ), + 'popularity-limit' => array ( + 'type' => 'number', + 'value' => $setup->popularityLimit + ), + 'uses-markdown' => array ( + 'type' => 'checkbox', + 'value' => $setup->usesMarkdown + ), + 'server-timezone' => array ( + 'type' => 'text', + 'value' => $setup->serverTimezone + ), + 'uses-user-timezone' => array ( + 'type' => 'checkbox', + 'value' => $setup->usesUserTimezone + ), + 'uses-short-dates' => array ( + 'type' => 'checkbox', + 'value' => $setup->usesShortDates + ), + 'time-format' => array ( + 'documentation' => 'http://php.net/manual/en/function.date.php', + 'type' => 'text', + 'value' => $setup->timeFormat + ), + 'date-format' => array ( + 'documentation' => 'http://php.net/manual/en/function.date.php', + 'type' => 'text', + 'value' => $setup->dateFormat + ), + 'displays-title' => array ( + 'type' => 'checkbox', + 'value' => $setup->displaysTitle + ), + 'form-position' => array ( + 'type' => 'select', + 'value' => $setup->formPosition, + + 'options' => array ( + 'top' => 'Top', + 'bottom' => 'Bottom' + ) + ), + 'uses-auto-login' => array ( + 'type' => 'checkbox', + 'value' => $setup->usesAutoLogin + ), + 'shows-reply-count' => array ( + 'type' => 'checkbox', + 'value' => $setup->showsReplyCount + ), + 'count-includes-deleted' => array ( + 'type' => 'checkbox', + 'value' => $setup->countIncludesDeleted + ), + 'icon-mode' => array ( + 'type' => 'select', + 'value' => $setup->iconMode, + + 'options' => array ( + 'image' => 'Image', + 'count' => 'Count', + 'none' => 'None' + ) + ), + 'icon-size' => array ( + 'type' => 'number', + 'value' => $setup->iconSize + ), + 'image-format' => array ( + 'type' => 'select', + 'value' => $setup->imageFormat, + + 'options' => array ( + 'png' => 'PNG', + 'svg' => 'SVG' + ) + ), + 'uses-labels' => array ( + 'type' => 'checkbox', + 'value' => $setup->usesLabels + ), + 'uses-cancel-buttons' => array ( + 'type' => 'checkbox', + 'value' => $setup->usesCancelButtons + ), + 'appends-css' => array ( + 'type' => 'checkbox', + 'value' => $setup->appendsCss + ), + 'appends-rss' => array ( + 'type' => 'checkbox', + 'value' => $setup->appendsRss + ), + 'login-method' => array ( + 'type' => 'select', + 'value' => $setup->loginMethod, + 'options' => array ('defaultLogin' => 'Default Login') + ), + 'sets-cookies' => array ( + 'type' => 'checkbox', + 'value' => $setup->setsCookies + ), + 'secure-cookies' => array ( + 'type' => 'checkbox', + 'value' => $setup->secureCookies + ), + 'stores-ip-address' => array ( + 'type' => 'checkbox', + 'value' => $setup->storesIpAddress + ), + 'subscribes-user' => array ( + 'type' => 'checkbox', + 'value' => $setup->subscribesUser + ), + 'allows-user-replies' => array ( + 'type' => 'checkbox', + 'value' => $setup->allowsUserReplies + ), + 'noreply-email' => array ( + 'type' => 'text', + 'value' => $setup->noreplyEmail + ), + 'spam-batabase' => array ( + 'type' => 'select', + 'value' => $setup->spamDatabase, + + 'options' => array ( + 'remote' => 'StopForumSpam.com', + 'local' => 'Local CSV file' + ) + ), + 'spam-check-modes' => array ( + 'type' => 'select', + 'value' => $setup->spamCheckModes, + + 'options' => array ( + 'json' => 'JSON', + 'php' => 'PHP', + 'both' => 'Both' + ) + ), + 'gravatar-force' => array ( + 'type' => 'checkbox', + 'value' => $setup->gravatarForce + ), + 'gravatar-default' => array ( + 'type' => 'select', + 'value' => $setup->gravatarDefault, + + 'options' => array ( + 'custom' => 'Custom', + 'identicon' => 'Identicon', + 'monsterid' => 'Monsterid', + 'wavatar' => 'Wavatar', + 'retro' => 'Retro' + ) + ), + 'minifies-javascript' => array ( + 'type' => 'checkbox', + 'value' => $setup->minifiesJavascript + ), + 'minify-level' => array ( + 'type' => 'select', + 'cast' => 'number', + 'value' => $setup->minifyLevel, + + 'options' => array ( + 1 => 'Basic (removes code comments)', + 2 => 'Low (removes whitespace + Basic)', + 3 => 'Medium (removes newlines + Low)', + 4 => 'High (removes extra bits + Medium)' + ) + ), + 'allow-local-metadata' => array ( + 'type' => 'checkbox', + 'value' => $setup->allowLocalMetadata + ) + ); +} + +try { + // View setup + require (realpath ('../view-setup.php')); + + // Get array of UI elements to create + $ui = ui_array ($hashover->setup); + + // Check if the form has been submitted + if (isset ($_POST['save'])) { + // Settings JSON file path + $settings_file = $hashover->setup->getAbsolutePath ('config/settings.json'); + + // Read JSON settings file + $json = $data_files->readJSON ($settings_file); + + // Existing JSON settings or an empty array + $settings = ($json !== false) ? $json : array (); + + // Run through configurable settings + foreach ($ui as $name => $setting) { + // Use specified type or optional cast + $type = !empty ($setting['cast']) ? 'cast' : 'type'; + + switch ($setting[$type]) { + // Set value to boolean based on POST data + case 'checkbox': { + $settings[$name] = isset ($_POST[$name]); + break; + } + + // Cast number values to integers + case 'number': { + $settings[$name] = (int)($_POST[$name]); + break; + } + + // All other values are strings + default: { + $settings[$name] = (string)($_POST[$name]); + break; + } + } + } + + // Save the settings to the JSON settings file + if ($hashover->setup->verifyAdmin ($hashover->login->password) + and $data_files->saveJSON ($settings_file, $settings)) + { + // Redirect with success indicator + header ('Location: index.php?status=success'); + } else { + // Redirect with failure indicator + header ('Location: index.php?status=failure'); + } + + // Exit after redirect + exit; + } + + // Otherwise, create settings table + $table = new HTMLTag ('table', array ( + 'id' => 'settings', + 'class' => 'p-spaced', + 'cellspacing' => '0', + 'cellpadding' => '4' + )); + + // Create settings table + foreach ($ui as $name => $setting) { + // Create table row + $tr = new HTMLTag ('tr'); + + // Create setting description cell + $description = new HTMLTag ('td'); + + // Create description label + $label = new HTMLTag ('label', array ( + 'for' => $name, + 'innerHTML' => $hashover->locale->text['setting-' . $name] + ), false); + + // Check for documentation URL + if (!empty ($setting['documentation'])) { + // Create documentation link + $docs = new HTMLTag ('a', array ( + 'href' => $setting['documentation'], + 'target' => '_blank', + 'innerHTML' => mb_strtolower ($hashover->locale->text['documentation']) + ), false); + + // Append documentation in parentheses + $label->appendInnerHTML ('(' . $docs->asHTML () . ')'); + } + + // Append label to description cell + $description->appendChild ($label); + + // Append description cell to settings table row + $tr->appendChild ($description); + + // Create setting value cell + $field = new HTMLTag ('td'); + + switch ($setting['type']) { + case 'checkbox': { + // Create checkbox for enabling/disabling the setting + $element = new HTMLTag ('input', array ( + 'id' => $name, + 'type' => 'checkbox', + 'name' => $name + ), false, true); + + // Set check based on current setting + if ($setting['value'] !== false) { + $element->createAttribute ('checked', 'true'); + } + + break; + } + + // Create text/number box for entering the setting value + case 'number' : case 'text': { + $element = new HTMLTag ('input', array ( + 'id' => $name, + 'type' => $setting['type'], + 'name' => $name, + 'value' => $setting['value'], + 'size' => ($setting['type'] === 'text') ? '25' : '10' + ), false, true); + + break; + } + + // Create dropdown menu for selecting the setting value + case 'select': { + // Create wrapper element for dropdown menu + $element = new HTMLTag ('span', array ( + 'class' => 'select-wrapper' + )); + + // Create dropdown menu + $select = new HTMLTag ('select', array ( + 'id' => $name, + 'name' => $name, + 'size' => 1 + )); + + foreach ($setting['options'] as $value => $text) { + // Create setting option + $option = new HTMLTag ('option', array ( + 'value' => $value, + 'innerHTML' => $text + ), false); + + // Select proper option + if ($value === $setting['value']) { + $option->createAttribute ('selected', 'true'); + } + + // Append option to menu + $select->appendChild ($option); + } + + // Append dropdown menu to wrapper element + $element->appendChild ($select); + + break; + } + } + + // Append the setting value element to the setting value cell + $field->appendChild ($element); + + // Append the setting value cell to the settings table row + $tr->appendChild ($field); + + // Add row to settings table + $table->appendChild ($tr); + } + + // Template data + $template = array ( + 'title' => $hashover->locale->text['settings'], + 'logout' => $logout->asHTML ("\t\t\t"), + 'sub-title' => $hashover->locale->text['settings-sub'], + 'message' => $form_message, + 'settings' => $table->asHTML ("\t\t\t"), + 'save-button' => $hashover->locale->text['save'] + ); + + // Load and parse HTML template + echo $hashover->templater->parseTemplate ('settings.html', $template); + +} catch (\Exception $error) { + $misc = new Misc ('php'); + $message = $error->getMessage (); + $misc->displayError ($message); +} diff --git a/bootstrap/comments/admin/views/settings/settings.css b/bootstrap/comments/admin/views/settings/settings.css new file mode 100644 index 0000000..1e1f1da --- /dev/null +++ b/bootstrap/comments/admin/views/settings/settings.css @@ -0,0 +1,15 @@ +#settings { + width: 100%; +} + +#settings tr:nth-child(odd) { + background-color: #F5F5F5; +} + +input, textarea, select, .select-wrapper { + margin: 0px; +} + +table tr { + height: 35px; +} diff --git a/bootstrap/comments/admin/views/settings/settings.html b/bootstrap/comments/admin/views/settings/settings.html new file mode 100644 index 0000000..bf4330a --- /dev/null +++ b/bootstrap/comments/admin/views/settings/settings.html @@ -0,0 +1,41 @@ +<!DOCTYPE html> + +<html lang="en" dir="ltr"> + <head> + <title>HashOver - {hashover:title}</title> + + <link type="text/css" href="../../../themes/default/general.css" rel="stylesheet"> + <link type="text/css" href="../../../themes/default/special.css" rel="stylesheet"> + <link type="text/css" href="settings.css" rel="stylesheet"> + + <script type="text/javascript" src="../shared/update-elements.js"></script> + + <meta http-equiv="Content-type" content="text/html; charset=utf-8"> + <meta http-equiv="Content-Language" content="EN"> + + <link type="image/x-icon" href="../../../images/favicon.png" rel="shortcut icon"> + <link type="image/x-icon" href="../../../images/favicon.png" rel="icon"> + <link href="https://www.gnu.org/licenses/agpl" rel="copyright"> + </head> + + <body> + <h1 class="underlined"> + <span id="title">{hashover:title}</span> + + {hashover:logout} + </h1> + + <div class="p-spaced muted-text"> + {hashover:sub-title} + {hashover:message} + </div> + + <form method="post"> + {hashover:settings} + + <p> + <input id="save-button" type="submit" name="save" value="{hashover:save-button}"> + </p> + </form> + </body> +</html> diff --git a/bootstrap/comments/admin/views/shared/update-elements.js b/bootstrap/comments/admin/views/shared/update-elements.js new file mode 100644 index 0000000..a6d2d74 --- /dev/null +++ b/bootstrap/comments/admin/views/shared/update-elements.js @@ -0,0 +1,12 @@ +// Wait for the page HTML to be parsed +document.addEventListener ('DOMContentLoaded', function () { + // Get message element + var message = document.getElementById ('message'); + + // Hide message after 5 seconds + if (message !== null) { + setTimeout (function () { + message.className = message.className.replace ('success', 'hide'); + }, 1000 * 5); + } +}, false); diff --git a/bootstrap/comments/admin/views/updates/index.php b/bootstrap/comments/admin/views/updates/index.php new file mode 100644 index 0000000..660abf1 --- /dev/null +++ b/bootstrap/comments/admin/views/updates/index.php @@ -0,0 +1,38 @@ +<?php namespace HashOver; + +// Copyright (C) 2018 Jacob Barkdull +// This file is part of HashOver. +// +// HashOver is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// HashOver is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with HashOver. If not, see <http://www.gnu.org/licenses/>. + + +try { + // View setup + require (realpath ('../view-setup.php')); + + // Template data + $template = array ( + 'title' => $hashover->locale->text['check-for-updates'], + 'logout' => $logout->asHTML ("\t\t\t"), + 'sub-title' => $hashover->locale->text['coming-soon'] + ); + + // Load and parse HTML template + echo $hashover->templater->parseTemplate ('updates.html', $template); + +} catch (\Exception $error) { + $misc = new Misc ('php'); + $message = $error->getMessage (); + $misc->displayError ($message); +} diff --git a/bootstrap/comments/admin/views/updates/updates.html b/bootstrap/comments/admin/views/updates/updates.html new file mode 100644 index 0000000..be82e62 --- /dev/null +++ b/bootstrap/comments/admin/views/updates/updates.html @@ -0,0 +1,27 @@ +<!DOCTYPE html> + +<html lang="en" dir="ltr"> + <head> + <title>HashOver - {hashover:title}</title> + + <link type="text/css" href="../../../themes/default/general.css" rel="stylesheet"> + <link type="text/css" href="../../../themes/default/special.css" rel="stylesheet"> + + <meta http-equiv="Content-type" content="text/html; charset=utf-8"> + <meta http-equiv="Content-Language" content="EN"> + + <link type="image/x-icon" href="../../../images/favicon.png" rel="shortcut icon"> + <link type="image/x-icon" href="../../../images/favicon.png" rel="icon"> + <link href="https://www.gnu.org/licenses/agpl" rel="copyright"> + </head> + + <body> + <h1 class="underlined"> + {hashover:title} + + {hashover:logout} + </h1> + + <p class="muted-text">{hashover:sub-title}</p> + </body> +</html> diff --git a/bootstrap/comments/admin/views/url-queries/index.php b/bootstrap/comments/admin/views/url-queries/index.php new file mode 100644 index 0000000..461f62a --- /dev/null +++ b/bootstrap/comments/admin/views/url-queries/index.php @@ -0,0 +1,134 @@ +<?php namespace HashOver; + +// Copyright (C) 2018 Jacob Barkdull +// This file is part of HashOver. +// +// HashOver is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// HashOver is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with HashOver. If not, see <http://www.gnu.org/licenses/>. + + +try { + // View setup + require (realpath ('../view-setup.php')); + + // Default URL Query Pair array + $ignored_queries = array (); + + // Ignored URL queries JSON file location + $ignored_queries_file = $hashover->setup->getAbsolutePath ('config/ignored-queries.json'); + + // Check if the form has been submitted + if (!empty ($_POST['names']) and is_array ($_POST['names']) + and !empty ($_POST['values']) and is_array ($_POST['values'])) + { + // If so, run through submitted queries + for ($i = 0, $il = count ($_POST['names']); $i < $il; $i++) { + // Add each non-empty query to the pair array + if (!empty ($_POST['names'][$i])) { + // Start the query pair with the query name + $query_pair = $_POST['names'][$i]; + + // Check if the query has a value + if (!empty ($_POST['values'][$i])) { + // If so, add it to the pair + $query_pair .= '=' . $_POST['values'][$i]; + } + + // Add the query pair to the URL Query Pair array + $ignored_queries[] = $query_pair; + } + } + + // Save the JSON data to the URL Query Pairs file + if ($hashover->setup->verifyAdmin ($hashover->login->password) + and $data_files->saveJSON ($ignored_queries_file, $ignored_queries)) + { + // Redirect with success indicator + header ('Location: index.php?status=success'); + } else { + // Redirect with failure indicator + header ('Location: index.php?status=failure'); + } + + // Exit after redirect + exit; + } + + // Otherwise, load and parse URL Query Pairs file + $json = $data_files->readJSON ($ignored_queries_file); + + // Check for JSON parse error + if (is_array ($json)) { + $ignored_queries = $json; + } + + // URL Query Pair inputs + $inputs = new HTMLTag ('span'); + + // Create URL Query Pair inputs + for ($i = 0, $il = max (3, count ($ignored_queries)); $i < $il; $i++) { + // Use URL query pairs from file or blank + $query = !empty ($ignored_queries[$i]) ? $ignored_queries[$i] : ''; + + // Split query pair into name and value + $query_parts = explode ('=', $query); + $query_name = $query_parts[0]; + $query_value = !empty ($query_parts[1]) ? $query_parts[1] : ''; + + // Create input tag + $input = new HTMLTag ('div', array ( + 'children' => array ( + new HTMLTag ('input', array ( + 'class' => 'name', + 'type' => 'text', + 'name' => 'names[]', + 'value' => $query_name, + 'size' => '15', + 'placeholder' => $hashover->locale->text['name'], + 'title' => $hashover->locale->text['url-queries-name-tip'] + ), false, true), + + new HTMLTag ('input', array ( + 'class' => 'value', + 'type' => 'text', + 'name' => 'values[]', + 'value' => $query_value, + 'size' => '25', + 'placeholder' => $hashover->locale->text['value'], + 'title' => $hashover->locale->text['url-queries-value-tip'] + ), false, true) + ) + )); + + // Add input to inputs container + $inputs->appendChild ($input); + } + + // Template data + $template = array ( + 'title' => $hashover->locale->text['url-queries-title'], + 'logout' => $logout->asHTML ("\t\t\t"), + 'sub-title' => $hashover->locale->text['url-queries-sub'], + 'message' => $form_message, + 'inputs' => $inputs->getInnerHTML ("\t\t\t\t"), + 'save-button' => $hashover->locale->text['save'] + ); + + // Load and parse HTML template + echo $hashover->templater->parseTemplate ('url-queries.html', $template); + +} catch (\Exception $error) { + $misc = new Misc ('php'); + $message = $error->getMessage (); + $misc->displayError ($message); +} diff --git a/bootstrap/comments/admin/views/url-queries/url-queries.html b/bootstrap/comments/admin/views/url-queries/url-queries.html new file mode 100644 index 0000000..fe350ce --- /dev/null +++ b/bootstrap/comments/admin/views/url-queries/url-queries.html @@ -0,0 +1,44 @@ +<!DOCTYPE html> + +<html lang="en" dir="ltr"> + <head> + <title>HashOver - {hashover:title}</title> + + <link type="text/css" href="../../../themes/default/general.css" rel="stylesheet"> + <link type="text/css" href="../../../themes/default/special.css" rel="stylesheet"> + + <script type="text/javascript" src="../shared/update-elements.js"></script> + <script type="text/javascript" src="url-queries.js"></script> + + <meta http-equiv="Content-type" content="text/html; charset=utf-8"> + <meta http-equiv="Content-Language" content="EN"> + + <link type="image/x-icon" href="../../../images/favicon.png" rel="shortcut icon"> + <link type="image/x-icon" href="../../../images/favicon.png" rel="icon"> + <link href="https://www.gnu.org/licenses/agpl" rel="copyright"> + </head> + + <body> + <h1 class="underlined"> + <span id="title">{hashover:title}</span> + + {hashover:logout} + </h1> + + <div class="p-spaced muted-text"> + {hashover:sub-title} + {hashover:message} + </div> + + <form method="post"> + <div id="queries-list" class="p-spaced"> + {hashover:inputs} + </div> + + <p> + <input id="save-button" type="submit" value="{hashover:save-button}"> + <input id="new-button" type="button" value="+"> + </p> + </form> + </body> +</html> diff --git a/bootstrap/comments/admin/views/url-queries/url-queries.js b/bootstrap/comments/admin/views/url-queries/url-queries.js new file mode 100644 index 0000000..6267691 --- /dev/null +++ b/bootstrap/comments/admin/views/url-queries/url-queries.js @@ -0,0 +1,36 @@ +// Wait for the page HTML to be parsed +document.addEventListener ('DOMContentLoaded', function () { + // Get the "New Query Pair" and "Save" buttons + var newButton = document.getElementById ('new-button'); + var queriesList = document.getElementById ('queries-list'); + var saveButton = document.getElementById ('save-button'); + + newButton.onclick = function () + { + // Create inputs and indentation + var div = document.createElement ('div'); + var names = document.getElementsByClassName ('name'); + var values = document.getElementsByClassName ('value'); + var indentation = document.createTextNode ('\n\t\t\t\t\t'); + + // Clone the first name and value fields + var nameInput = names[0].cloneNode (true); + var valueInput = values[0].cloneNode (true); + + // Remove their values + nameInput.value = ''; + valueInput.value = ''; + + // Append indentation and input to URL Query Pair list + div.appendChild (nameInput); + div.appendChild (indentation); + div.appendChild (valueInput); + queriesList.appendChild (div); + }; + + // Disable the "Save" button when clicked + saveButton.onclick = function () + { + this.disabled = true; + }; +}, false); diff --git a/bootstrap/comments/admin/views/view-setup.php b/bootstrap/comments/admin/views/view-setup.php new file mode 100644 index 0000000..adcf93d --- /dev/null +++ b/bootstrap/comments/admin/views/view-setup.php @@ -0,0 +1,107 @@ +<?php namespace HashOver; + +// Copyright (C) 2018 Jacob Barkdull +// This file is part of HashOver. +// +// HashOver is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// HashOver is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with HashOver. If not, see <http://www.gnu.org/licenses/>. + + +// Do some standard HashOver setup work +require (realpath ('../../../backend/standard-setup.php')); + +// Autoload class files +spl_autoload_register (function ($uri) { + $uri = str_replace ('\\', '/', strtolower ($uri)); + $class_name = basename ($uri); + + if (!@include (realpath ('../../../backend/classes/' . $class_name . '.php'))) { + echo '"' . $class_name . '.php" file could not be included!'; + exit; + } +}); + +// Instantiate HashOver class +$hashover = new \HashOver (); +$hashover->initiate (); +$hashover->finalize (); + +// Instantiate FileWriter class +$data_files = new DataFiles ($hashover->setup); + +// Exit if the user isn't logged in as admin +if ($hashover->login->userIsAdmin !== true) { + $uri = $_SERVER['REQUEST_URI']; + $uri_parts = explode ('?', $uri); + + if (basename ($uri_parts[0]) !== 'login') { + header ('Location: ../login/?redirect=' . urlencode ($uri)); + exit; + } +} + +// Create logout hyperlink +$logout = new HTMLTag ('span', array ( + 'class' => 'right', + + 'children' => array ( + new HTMLTag ('a', array ( + 'href' => '../login/?logout=true', + 'target' => '_parent', + 'innerHTML' => $hashover->locale->text['logout'] + )) + ) +)); + +// Check if the form has been submitted +if (!empty ($_GET['status'])) { + // Check if the form submission was successful + if ($_GET['status'] === 'success') { + // If so, create message element for success message + $message = new HTMLTag ('div', array ( + 'id' => 'message', + 'class' => 'success', + + 'children' => array ( + new HTMLTag ('p', array ( + 'innerHTML' => $hashover->locale->text['successful-save'] + ), false) + ) + )); + } else { + // If so, create message element for error message + $message = new HTMLTag ('div', array ( + 'id' => 'message', + 'class' => 'error', + + 'children' => array ( + // Main error message + new HTMLTag ('p', array ( + 'innerHTML' => $hashover->locale->text['failed-to-save'] + ), false), + + // File permissions explanation + new HTMLTag ('p', array ( + 'innerHTML' => $hashover->locale->permissionsInfo ('config') + ), false) + ) + )); + } + + // Set message as HTML + $form_message = $message->asHTML ("\t\t"); + +} else { + // If not, set the message as an empty string + $form_message = ''; +} |