Google reCaptcha

This commit is contained in:
Roman committed 2020-06-26 23:32:45 +02:00
1 parent 9442a120ab
commit cd6c28c9b3
16 files changed
+552 -115

No files matched your search

+115
View File
@@ -0,0 +1,115 @@
<?php
namespace Api {
class ContactAPI extends Request {
}
}
namespace Api\Contact {
use Api\ContactAPI;
use Api\Parameter\Parameter;
use Api\Parameter\StringType;
use Api\VerifyCaptcha;
use Objects\User;
class Request extends ContactAPI {
private int $notificationId;
private int $contactRequestId;
public function __construct(User $user, bool $externalCall = false) {
$parameters = array(
'fromName' => new StringType('fromName', 32),
'fromEmail' => new Parameter('fromEmail', Parameter::TYPE_EMAIL),
'message' => new StringType('message', 512),
);
$settings = $user->getConfiguration()->getSettings();
if ($settings->isRecaptchaEnabled()) {
$parameters["captcha"] = new StringType("captcha");
}
parent::__construct($user, $externalCall, $parameters);
}
public function execute($values = array()) {
if (!parent::execute($values)) {
return false;
}
$settings = $this->user->getConfiguration()->getSettings();
if ($settings->isRecaptchaEnabled()) {
$captcha = $this->getParam("captcha");
$req = new VerifyCaptcha($this->user);
if (!$req->execute(array("captcha" => $captcha, "action" => "contact"))) {
return $this->createError($req->getLastError());
}
}
if (!$this->insertContactRequest()) {
return false;
}
$this->createNotification();
if (!$this->success) {
return $this->createError("The contact request was saved, but the server was unable to create a notification.");
}
return $this->success;
}
private function insertContactRequest() {
$sql = $this->user->getSQL();
$name = $this->getParam("fromName");
$email = $this->getParam("fromEmail");
$message = $this->getParam("message");
$res = $sql->insert("ContactRequest", array("from_name", "from_email", "message"))
->addRow($name, $email, $message)
->returning("uid")
->execute();
$this->success = ($res !== FALSE);
$this->lastError = $sql->getLastError();
if ($this->success) {
$this->contactRequestId = $sql->getLastInsertId();
}
return $this->success;
}
private function createNotification() {
$sql = $this->user->getSQL();
$name = $this->getParam("fromName");
$email = $this->getParam("fromEmail");
$message = $this->getParam("message");
$res = $sql->insert("Notification", array("title", "message", "type"))
->addRow("New Contact Request from: $name", "$name ($email) wrote:\n$message", "message")
->returning("uid")
->execute();
$this->success = ($res !== FALSE);
$this->lastError = $sql->getLastError();
if ($this->success) {
$this->notificationId = $sql->getLastInsertId();
$res = $sql->insert("GroupNotification", array("group_id", "notification_id"))
->addRow(USER_GROUP_ADMIN, $this->notificationId)
->addRow(USER_GROUP_SUPPORT, $this->notificationId)
->execute();
$this->success = ($res !== FALSE);
$this->lastError = $sql->getLastError();
}
return $this->success;
}
}
}
+67 -28
View File
@@ -1,11 +1,9 @@
<?php
namespace Api {
class NotificationsAPI extends Request {
}
}
namespace Api\Notifications {
@@ -14,6 +12,9 @@ namespace Api\Notifications {
use Api\Parameter\Parameter;
use Api\Parameter\StringType;
use Driver\SQL\Condition\Compare;
use Driver\SQL\Condition\CondIn;
use Driver\SQL\Query\Select;
use Objects\User;
class Create extends NotificationsAPI {
@@ -144,67 +145,67 @@ namespace Api\Notifications {
class Fetch extends NotificationsAPI {
private array $notifications;
private array $notificationids;
public function __construct($user, $externalCall = false) {
parent::__construct($user, $externalCall, array());
parent::__construct($user, $externalCall, array(
'new' => new Parameter('new', Parameter::TYPE_BOOLEAN, true, true)
));
$this->loginRequired = true;
}
private function fetchUserNotifications() {
$onlyNew = $this->getParam('new');
$userId = $this->user->getId();
$sql = $this->user->getSQL();
$res = $sql->select($sql->distinct("Notification.uid"), "created_at", "title", "message")
$query = $sql->select($sql->distinct("Notification.uid"), "created_at", "title", "message", "type")
->from("Notification")
->innerJoin("UserNotification", "UserNotification.notification_id", "Notification.uid")
->where(new Compare("UserNotification.user_id", $userId))
->where(new Compare("UserNotification.seen", false))
->orderBy("created_at")->descending()
->execute();
->orderBy("created_at")->descending();
$this->success = ($res !== FALSE);
$this->lastError = $sql->getLastError();
if ($this->success) {
foreach($res as $row) {
$id = $row["uid"];
if (!isset($this->notifications[$id])) {
$this->notifications[$id] = array(
"uid" => $id,
"title" => $row["title"],
"message" => $row["message"],
"created_at" => $row["created_at"],
);
}
}
if ($onlyNew) {
$query->where(new Compare("UserNotification.seen", false));
}
return $this->success;
return $this->fetchNotifications($query);
}
private function fetchGroupNotifications() {
$onlyNew = $this->getParam('new');
$userId = $this->user->getId();
$sql = $this->user->getSQL();
$res = $sql->select($sql->distinct("Notification.uid"), "created_at", "title", "message")
$query = $sql->select($sql->distinct("Notification.uid"), "created_at", "title", "message", "type")
->from("Notification")
->innerJoin("GroupNotification", "GroupNotification.notification_id", "Notification.uid")
->innerJoin("UserGroup", "GroupNotification.group_id", "UserGroup.group_id")
->where(new Compare("UserGroup.user_id", $userId))
->where(new Compare("GroupNotification.seen", false))
->orderBy("created_at")->descending()
->execute();
->orderBy("created_at")->descending();
if ($onlyNew) {
$query->where(new Compare("GroupNotification.seen", false));
}
return $this->fetchNotifications($query);
}
private function fetchNotifications(Select $query) {
$sql = $this->user->getSQL();
$res = $query->execute();
$this->success = ($res !== FALSE);
$this->lastError = $sql->getLastError();
if ($this->success) {
foreach($res as $row) {
$id = $row["uid"];
if (!isset($this->notifications[$id])) {
if (!in_array($id, $this->notificationids)) {
$this->notificationids[] = $id;
$this->notifications[] = array(
"uid" => $id,
"title" => $row["title"],
"message" => $row["message"],
"created_at" => $row["created_at"],
"type" => $row["type"]
);
}
}
@@ -219,6 +220,7 @@ namespace Api\Notifications {
}
$this->notifications = array();
$this->notificationids = array();
if ($this->fetchUserNotifications() && $this->fetchGroupNotifications()) {
$this->result["notifications"] = $this->notifications;
}
@@ -227,4 +229,41 @@ namespace Api\Notifications {
}
}
class Seen extends NotificationsAPI {
public function __construct(User $user, bool $externalCall = false) {
parent::__construct($user, $externalCall, array());
$this->loginRequired = true;
}
public function execute($values = array()) {
if (!parent::execute($values)) {
return false;
}
$sql = $this->user->getSQL();
$res = $sql->update("UserNotification")
->set("seen", true)
->where(new Compare("user_id", $this->user->getId()))
->execute();
$this->success = ($res !== FALSE);
$this->lastError = $sql->getLastError();
if ($this->success) {
$res = $sql->update("GroupNotification")
->set("seen", true)
->where(new CondIn("group_id",
$sql->select("group_id")
->from("UserGroup")
->where(new Compare("user_id", $this->user->getId()))))
->execute();
$this->success = ($res !== FALSE);
$this->lastError = $sql->getLastError();
}
return $this->success;
}
}
}
+4 -2
View File
@@ -48,15 +48,17 @@ class Request {
}
public function parseParams($values) {
foreach($this->params as $name => $param) {
$value = $values[$name] ?? NULL;
if(!$param->optional && (is_null($value) || empty($value))) {
$isEmpty = (is_string($value) || is_array($value)) && empty($value);
if(!$param->optional && (is_null($value) || $isEmpty)) {
$this->lastError = 'Missing parameter: ' . $name;
return false;
}
if(!is_null($value) && !empty($value)) {
if(!is_null($value) && !$isEmpty) {
if(!$param->parseParam($value)) {
$value = print_r($value, true);
$this->lastError = "Invalid Type for parameter: $name '$value' (Required: " . $param->getTypeName() . ")";
+20 -3
View File
@@ -120,6 +120,7 @@ namespace Api\User {
use Api\Parameter\StringType;
use Api\SendMail;
use Api\UserAPI;
use Api\VerifyCaptcha;
use DateTime;
use Driver\SQL\Condition\Compare;
use Driver\SQL\Condition\CondIn;
@@ -531,13 +532,20 @@ namespace Api\User {
private ?int $userId;
private string $token;
public function __construct($user, $externalCall = false) {
parent::__construct($user, $externalCall, array(
public function __construct(User $user, bool $externalCall = false) {
$parameters = array(
"username" => new StringType("username", 32),
'email' => new Parameter('email', Parameter::TYPE_EMAIL),
"password" => new StringType("password"),
"confirmPassword" => new StringType("confirmPassword"),
));
);
$settings = $user->getConfiguration()->getSettings();
if ($settings->isRecaptchaEnabled()) {
$parameters["captcha"] = new StringType("captcha");
}
parent::__construct($user, $externalCall, $parameters);
}
private function insertToken() {
@@ -582,6 +590,15 @@ namespace Api\User {
return $this->createError("User Registration is not enabled.");
}
$settings = $this->user->getConfiguration()->getSettings();
if ($settings->isRecaptchaEnabled()) {
$captcha = $this->getParam("captcha");
$req = new VerifyCaptcha($this->user);
if (!$req->execute(array("captcha" => $captcha, "action" => "register"))) {
return $this->createError($req->getLastError());
}
}
$username = $this->getParam("username");
$email = $this->getParam('email');
if (!$this->userExists($username, $email)) {
+67
View File
@@ -0,0 +1,67 @@
<?php
namespace Api;
use Api\Parameter\StringType;
use Objects\User;
class VerifyCaptcha extends Request {
public function __construct(User $user, bool $externalCall = false) {
parent::__construct($user, $externalCall, array(
"captcha" => new StringType("captcha"),
"action" => new StringType("action"),
));
$this->isPublic = false;
}
public function execute($values = array()) {
if(!parent::execute($values)) {
return false;
}
$settings = $this->user->getConfiguration()->getSettings();
if (!$settings->isRecaptchaEnabled()) {
return $this->createError("Google reCaptcha is not enabled.");
}
$url = "https://www.google.com/recaptcha/api/siteverify";
$secret = $settings->getRecaptchaSecretKey();
$captcha = $this->getParam("captcha");
$action = $this->getParam("action");
$params = array(
"secret" => $secret,
"response" => $captcha
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = @json_decode(curl_exec($ch), true);
curl_close ($ch);
$this->success = false;
$this->lastError = "Could not verify captcha: No response from google received.";
if($response) {
$this->success = $response["success"];
if(!$this->success) {
$this->lastError = "Could not verify captcha: " . implode(";", $response["error-codes"]);
} else {
$score = $response["score"];
if($action !== $response["action"]) {
$this->createError("Could not verify captcha: Action does not match");
}
else if($score < 0.7) {
$this->createError("Could not verify captcha: Google ReCaptcha Score < 0.7 (Your score: $score), you are likely a bot");
}
}
}
return $this->success;
}
}
+13 -4
View File
@@ -88,6 +88,7 @@ class CreateDatabase {
$queries[] = $sql->createTable("Notification")
->addSerial("uid")
->addEnum("type", array("default","message","warning"), false, "default")
->addDateTime("created_at", false, $sql->currentTimestamp())
->addString("title", 32)
->addString("message", 256)
@@ -96,7 +97,7 @@ class CreateDatabase {
$queries[] = $sql->createTable("UserNotification")
->addInt("user_id")
->addInt("notification_id")
->addBool("seen")
->addBool("seen", false)
->foreignKey("user_id", "User", "uid")
->foreignKey("notification_id", "Notification", "uid")
->unique("user_id", "notification_id");
@@ -104,7 +105,7 @@ class CreateDatabase {
$queries[] = $sql->createTable("GroupNotification")
->addInt("group_id")
->addInt("notification_id")
->addBool("seen")
->addBool("seen", false)
->foreignKey("group_id", "Group", "uid")
->foreignKey("notification_id", "Notification", "uid")
->unique("group_id", "notification_id");
@@ -144,8 +145,8 @@ class CreateDatabase {
$queries[] = $sql->createTable("Settings")
->addString("name", 32)
->addString("value", 1024, true)
->addBool("private", false)
->addBool("readonly", false)
->addBool("private", false) // these values are not returned from '/api/settings/get', but can be changed
->addBool("readonly", false) // these values are neither returned, nor can be changed from outside
->primaryKey("name");
$settingsQuery = $sql->insert("Settings", array("name", "value", "private", "readonly"))
@@ -162,6 +163,14 @@ class CreateDatabase {
(Settings::loadDefaults())->addRows($settingsQuery);
$queries[] = $settingsQuery;
$queries[] = $sql->createTable("ContactRequest")
->addSerial("uid")
->addString("from_name", 32)
->addString("from_email", 64)
->addString("message", 512)
->addDateTime("created_at", false, $sql->currentTimestamp())
->primaryKey("uid");
return $queries;
}
+25 -1
View File
@@ -16,6 +16,9 @@ class Settings {
private string $jwtSecret;
private bool $installationComplete;
private bool $registrationAllowed;
private bool $recaptchaEnabled;
private string $recaptchaPublicKey;
private string $recaptchaPrivateKey;
public function getJwtSecret(): string {
return $this->jwtSecret;
@@ -36,6 +39,9 @@ class Settings {
$settings->jwtSecret = $jwt;
$settings->installationComplete = false;
$settings->registrationAllowed = false;
$settings->recaptchaPublicKey = "";
$settings->recaptchaPrivateKey = "";
$settings->recaptchaEnabled = false;
return $settings;
}
@@ -49,6 +55,9 @@ class Settings {
$this->registrationAllowed = $result["user_registration_enabled"] ?? $this->registrationAllowed;
$this->installationComplete = $result["installation_completed"] ?? $this->installationComplete;
$this->jwtSecret = $result["jwt_secret"] ?? $this->jwtSecret;
$this->recaptchaEnabled = $result["recaptcha_enabled"] ?? $this->recaptchaEnabled;
$this->recaptchaPublicKey = $result["recaptcha_public_key"] ?? $this->recaptchaPublicKey;
$this->recaptchaPrivateKey = $result["recaptcha_private_key"] ?? $this->recaptchaPrivateKey;
if (!isset($result["jwt_secret"])) {
$req = new \Api\Settings\Set($user);
@@ -66,7 +75,10 @@ class Settings {
->addRow("base_url", $this->baseUrl, false, false)
->addRow("user_registration_enabled", $this->registrationAllowed ? "1" : "0", false, false)
->addRow("installation_completed", $this->installationComplete ? "1" : "0", true, true)
->addRow("jwt_secret", $this->jwtSecret, true, true);
->addRow("jwt_secret", $this->jwtSecret, true, true)
->addRow("recaptcha_enabled", $this->recaptchaEnabled ? "1" : "0", false, false)
->addRow("recaptcha_public_key", $this->recaptchaPublicKey, false, false)
->addRow("recaptcha_private_key", $this->recaptchaPrivateKey, true, false);
}
public function getSiteName() {
@@ -76,4 +88,16 @@ class Settings {
public function getBaseUrl() {
return $this->baseUrl;
}
public function isRecaptchaEnabled() {
return $this->recaptchaEnabled;
}
public function getRecaptchaSiteKey() {
return $this->recaptchaPublicKey;
}
public function getRecaptchaSecretKey() {
return $this->recaptchaPrivateKey;
}
}
+4 -4
View File
@@ -5,13 +5,13 @@ namespace Driver\SQL\Condition;
class CondIn extends Condition {
private string $column;
private array $values;
private $expression;
public function __construct(string $column, array $values) {
public function __construct(string $column, $expression) {
$this->column = $column;
$this->values = $values;
$this->expression = $expression;
}
public function getColumn() { return $this->column; }
public function getValues() { return $this->values; }
public function getExpression() { return $this->expression; }
}
+67 -51
View File
@@ -10,7 +10,6 @@ use Driver\SQL\Condition\Condition;
use Driver\SQL\Condition\CondKeyword;
use Driver\SQL\Condition\CondNot;
use Driver\SQL\Condition\CondOr;
use Driver\SQL\Condition\CondRegex;
use Driver\SQL\Constraint\Constraint;
use \Driver\SQL\Constraint\Unique;
use \Driver\SQL\Constraint\PrimaryKey;
@@ -18,6 +17,7 @@ use \Driver\SQL\Constraint\ForeignKey;
use Driver\SQL\Query\CreateTable;
use Driver\SQL\Query\Delete;
use Driver\SQL\Query\Insert;
use Driver\SQL\Query\Query;
use Driver\SQL\Query\Select;
use Driver\SQL\Query\Truncate;
use Driver\SQL\Query\Update;
@@ -50,27 +50,27 @@ abstract class SQL {
}
public function createTable($tableName) {
return new Query\CreateTable($this, $tableName);
return new CreateTable($this, $tableName);
}
public function insert($tableName, $columns=array()) {
return new Query\Insert($this, $tableName, $columns);
return new Insert($this, $tableName, $columns);
}
public function select(...$columNames) {
return new Query\Select($this, $columNames);
return new Select($this, $columNames);
}
public function truncate($table) {
return new Query\Truncate($this, $table);
return new Truncate($this, $table);
}
public function delete($table) {
return new Query\Delete($this, $table);
return new Delete($this, $table);
}
public function update($table) {
return new Query\Update($this, $table);
return new Update($this, $table);
}
// ####################
@@ -86,6 +86,53 @@ abstract class SQL {
public abstract function disconnect();
// Querybuilder
protected function buildQuery(Query $query, array &$params) {
if ($query instanceof Select) {
$select = $query;
$columns = $this->columnName($select->getColumns());
$tables = $select->getTables();
if (!$tables) {
return $this->execute("SELECT $columns", $params, true);
}
$tables = $this->tableName($tables);
$where = $this->getWhereClause($select->getConditions(), $params);
$joinStr = "";
$joins = $select->getJoins();
if (!empty($joins)) {
foreach($joins as $join) {
$type = $join->getType();
$joinTable = $this->tableName($join->getTable());
$columnA = $this->columnName($join->getColumnA());
$columnB = $this->columnName($join->getColumnB());
$joinStr .= " $type JOIN $joinTable ON $columnA=$columnB";
}
}
$groupBy = "";
$groupColumns = $select->getGroupBy();
if (!empty($groupColumns)) {
$groupBy = " GROUP BY " . $this->columnName($groupColumns);
}
$orderBy = "";
$orderColumns = $select->getOrderBy();
if (!empty($orderColumns)) {
$orderBy = " ORDER BY " . $this->columnName($orderColumns);
$orderBy .= ($select->isOrderedAscending() ? " ASC" : " DESC");
}
$limit = ($select->getLimit() > 0 ? (" LIMIT " . $select->getLimit()) : "");
$offset = ($select->getOffset() > 0 ? (" OFFSET " . $select->getOffset()) : "");
return "SELECT $columns FROM $tables$joinStr$where$groupBy$orderBy$limit$offset";
} else {
$this->lastError = "buildQuery() not implemented for type: " . get_class($query);
return FALSE;
}
}
public function executeCreateTable(CreateTable $createTable) {
$tableName = $this->tableName($createTable->getTableName());
$ifNotExists = $createTable->ifNotExists() ? " IF NOT EXISTS": "";
@@ -161,46 +208,8 @@ abstract class SQL {
}
public function executeSelect(Select $select) {
$columns = $this->columnName($select->getColumns());
$tables = $select->getTables();
$params = array();
if (!$tables) {
return $this->execute("SELECT $columns", $params, true);
}
$tables = $this->tableName($tables);
$where = $this->getWhereClause($select->getConditions(), $params);
$joinStr = "";
$joins = $select->getJoins();
if (!empty($joins)) {
foreach($joins as $join) {
$type = $join->getType();
$joinTable = $this->tableName($join->getTable());
$columnA = $this->columnName($join->getColumnA());
$columnB = $this->columnName($join->getColumnB());
$joinStr .= " $type JOIN $joinTable ON $columnA=$columnB";
}
}
$groupBy = "";
$groupColumns = $select->getGroupBy();
if (!empty($groupColumns)) {
$groupBy = " GROUP BY " . $this->columnName($groupColumns);
}
$orderBy = "";
$orderColumns = $select->getOrderBy();
if (!empty($orderColumns)) {
$orderBy = " ORDER BY " . $this->columnName($orderColumns);
$orderBy .= ($select->isOrderedAscending() ? " ASC" : " DESC");
}
$limit = ($select->getLimit() > 0 ? (" LIMIT " . $select->getLimit()) : "");
$offset = ($select->getOffset() > 0 ? (" OFFSET " . $select->getOffset()) : "");
$query = "SELECT $columns FROM $tables$joinStr$where$groupBy$orderBy$limit$offset";
$query = $this->buildQuery($select, $params);
if($select->dump) { var_dump($query); var_dump($params); }
return $this->execute($query, $params, true);
}
@@ -342,14 +351,21 @@ abstract class SQL {
}
} else if($condition instanceof CondIn) {
$value = $condition->getValues();
$expression = $condition->getExpression();
if (is_array($expression)) {
$values = array();
foreach ($expression as $value) {
$values[] = $this->addValue($value, $params);
}
$values = array();
foreach ($condition->getValues() as $value) {
$values[] = $this->addValue($value, $params);
$values = implode(",", $values);
} else if($expression instanceof Select) {
$values = $this->buildQuery($expression, $params);
} else {
$this->lastError = "Unsupported in-expression value: " . get_class($condition);
return false;
}
$values = implode(",", $values);
return $this->columnName($condition->getColumn()) . " IN ($values)";
} else if($condition instanceof CondKeyword) {
$left = $condition->getLeftExp();
+1 -1
View File
@@ -54,7 +54,7 @@ if(isset($_GET["api"]) && is_string($_GET["api"])) {
try {
$file = getClassPath($parentClass);
if(!file_exists($file)) {
if(!file_exists($file) || !class_exists($parentClass) || !class_exists($apiClass)) {
header("404 Not Found");
$response = createError("Not found");
} else {
+5 -5
View File
@@ -11226,7 +11226,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) *
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"default\", function() { return API; });\n/* harmony import */ var babel_polyfill__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babel-polyfill */ \"./node_modules/babel-polyfill/lib/index.js\");\n/* harmony import */ var babel_polyfill__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babel_polyfill__WEBPACK_IMPORTED_MODULE_0__);\nfunction asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }\n\nfunction _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, \"next\", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, \"throw\", err); } _next(undefined); }); }; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\n\n\nvar API = /*#__PURE__*/function () {\n function API() {\n _classCallCheck(this, API);\n\n this.loggedIn = false;\n this.user = {};\n }\n\n _createClass(API, [{\n key: \"csrfToken\",\n value: function csrfToken() {\n return this.loggedIn ? this.user.session.csrf_token : null;\n }\n }, {\n key: \"apiCall\",\n value: function () {\n var _apiCall = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(method, params) {\n var response, res;\n return regeneratorRuntime.wrap(function _callee$(_context) {\n while (1) {\n switch (_context.prev = _context.next) {\n case 0:\n params = params || {};\n params.csrf_token = this.csrfToken();\n _context.next = 4;\n return fetch(\"/api/\" + method, {\n method: 'post',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify(params)\n });\n\n case 4:\n response = _context.sent;\n _context.next = 7;\n return response.json();\n\n case 7:\n res = _context.sent;\n\n if (!res.success && res.msg === \"You are not logged in.\") {\n document.location.reload();\n }\n\n return _context.abrupt(\"return\", res);\n\n case 10:\n case \"end\":\n return _context.stop();\n }\n }\n }, _callee, this);\n }));\n\n function apiCall(_x, _x2) {\n return _apiCall.apply(this, arguments);\n }\n\n return apiCall;\n }()\n }, {\n key: \"fetchUser\",\n value: function () {\n var _fetchUser = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2() {\n var response, data;\n return regeneratorRuntime.wrap(function _callee2$(_context2) {\n while (1) {\n switch (_context2.prev = _context2.next) {\n case 0:\n _context2.next = 2;\n return fetch(\"/api/user/info\");\n\n case 2:\n response = _context2.sent;\n _context2.next = 5;\n return response.json();\n\n case 5:\n data = _context2.sent;\n this.user = data[\"user\"];\n this.loggedIn = data[\"loggedIn\"];\n return _context2.abrupt(\"return\", data && data.success && data.loggedIn);\n\n case 9:\n case \"end\":\n return _context2.stop();\n }\n }\n }, _callee2, this);\n }));\n\n function fetchUser() {\n return _fetchUser.apply(this, arguments);\n }\n\n return fetchUser;\n }()\n }, {\n key: \"editUser\",\n value: function () {\n var _editUser = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3(id, username, email, password, groups) {\n returnLine truncated
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"default\", function() { return API; });\n/* harmony import */ var babel_polyfill__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babel-polyfill */ \"./node_modules/babel-polyfill/lib/index.js\");\n/* harmony import */ var babel_polyfill__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babel_polyfill__WEBPACK_IMPORTED_MODULE_0__);\nfunction asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }\n\nfunction _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, \"next\", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, \"throw\", err); } _next(undefined); }); }; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\n\n\nvar API = /*#__PURE__*/function () {\n function API() {\n _classCallCheck(this, API);\n\n this.loggedIn = false;\n this.user = {};\n }\n\n _createClass(API, [{\n key: \"csrfToken\",\n value: function csrfToken() {\n return this.loggedIn ? this.user.session.csrf_token : null;\n }\n }, {\n key: \"apiCall\",\n value: function () {\n var _apiCall = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(method, params) {\n var response, res;\n return regeneratorRuntime.wrap(function _callee$(_context) {\n while (1) {\n switch (_context.prev = _context.next) {\n case 0:\n params = params || {};\n params.csrf_token = this.csrfToken();\n _context.next = 4;\n return fetch(\"/api/\" + method, {\n method: 'post',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify(params)\n });\n\n case 4:\n response = _context.sent;\n _context.next = 7;\n return response.json();\n\n case 7:\n res = _context.sent;\n\n if (!res.success && res.msg === \"You are not logged in.\") {\n document.location.reload();\n }\n\n return _context.abrupt(\"return\", res);\n\n case 10:\n case \"end\":\n return _context.stop();\n }\n }\n }, _callee, this);\n }));\n\n function apiCall(_x, _x2) {\n return _apiCall.apply(this, arguments);\n }\n\n return apiCall;\n }()\n }, {\n key: \"fetchUser\",\n value: function () {\n var _fetchUser = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2() {\n var response, data;\n return regeneratorRuntime.wrap(function _callee2$(_context2) {\n while (1) {\n switch (_context2.prev = _context2.next) {\n case 0:\n _context2.next = 2;\n return fetch(\"/api/user/info\");\n\n case 2:\n response = _context2.sent;\n _context2.next = 5;\n return response.json();\n\n case 5:\n data = _context2.sent;\n this.user = data[\"user\"];\n this.loggedIn = data[\"loggedIn\"];\n return _context2.abrupt(\"return\", data && data.success && data.loggedIn);\n\n case 9:\n case \"end\":\n return _context2.stop();\n }\n }\n }, _callee2, this);\n }));\n\n function fetchUser() {\n return _fetchUser.apply(this, arguments);\n }\n\n return fetchUser;\n }()\n }, {\n key: \"editUser\",\n value: function () {\n var _editUser = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3(id, username, email, password, groups) {\n returnLine truncated
/***/ }),
@@ -11343,7 +11343,7 @@ eval("\nvar content = __webpack_require__(/*! !../../node_modules/css-loader/dis
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-dom */ \"./node_modules/react-dom/index.js\");\n/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_dom__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _include_adminlte_min_css__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./include/adminlte.min.css */ \"./src/include/adminlte.min.css\");\n/* harmony import */ var _include_adminlte_min_css__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_include_adminlte_min_css__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var _include_index_css__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./include/index.css */ \"./src/include/index.css\");\n/* harmony import */ var _include_index_css__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_include_index_css__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var _api_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./api.js */ \"./src/api.js\");\n/* harmony import */ var _header_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./header.js */ \"./src/header.js\");\n/* harmony import */ var _sidebar_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./sidebar.js */ \"./src/sidebar.js\");\n/* harmony import */ var _views_users_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./views/users.js */ \"./src/views/users.js\");\n/* harmony import */ var _views_overview_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./views/overview.js */ \"./src/views/overview.js\");\n/* harmony import */ var _views_adduser__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./views/adduser */ \"./src/views/adduser.js\");\n/* harmony import */ var _elements_icon__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./elements/icon */ \"./src/elements/icon.js\");\n/* harmony import */ var _elements_dialog__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./elements/dialog */ \"./src/elements/dialog.js\");\n/* harmony import */ var react_router_dom__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! react-router-dom */ \"./node_modules/react-router-dom/esm/react-router-dom.js\");\n/* harmony import */ var _404__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./404 */ \"./src/404.js\");\n/* harmony import */ var _views_logs__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./views/logs */ \"./src/views/logs.js\");\n/* harmony import */ var _views_pages__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ./views/pages */ \"./src/views/pages.js\");\n/* harmony import */ var _views_help__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ./views/help */ \"./src/views/help.js\");\n/* harmony import */ var _footer__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ./footer */ \"./src/footer.js\");\n/* harmony import */ var _views_edituser__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ./views/edituser */ \"./src/views/edituser.js\");\n/* harmony import */ var _views_addgroup__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ./views/addgroup */ \"./src/views/addgroup.js\");\n/* harmony import */ var _views_settings__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ./views/settings */ \"./src/views/settings.js\");\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); Line truncated
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-dom */ \"./node_modules/react-dom/index.js\");\n/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_dom__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _include_adminlte_min_css__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./include/adminlte.min.css */ \"./src/include/adminlte.min.css\");\n/* harmony import */ var _include_adminlte_min_css__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_include_adminlte_min_css__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var _include_index_css__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./include/index.css */ \"./src/include/index.css\");\n/* harmony import */ var _include_index_css__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_include_index_css__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var _api_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./api.js */ \"./src/api.js\");\n/* harmony import */ var _header_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./header.js */ \"./src/header.js\");\n/* harmony import */ var _sidebar_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./sidebar.js */ \"./src/sidebar.js\");\n/* harmony import */ var _views_users_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./views/users.js */ \"./src/views/users.js\");\n/* harmony import */ var _views_overview_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./views/overview.js */ \"./src/views/overview.js\");\n/* harmony import */ var _views_adduser__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./views/adduser */ \"./src/views/adduser.js\");\n/* harmony import */ var _elements_icon__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./elements/icon */ \"./src/elements/icon.js\");\n/* harmony import */ var _elements_dialog__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./elements/dialog */ \"./src/elements/dialog.js\");\n/* harmony import */ var react_router_dom__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! react-router-dom */ \"./node_modules/react-router-dom/esm/react-router-dom.js\");\n/* harmony import */ var _404__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./404 */ \"./src/404.js\");\n/* harmony import */ var _views_logs__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./views/logs */ \"./src/views/logs.js\");\n/* harmony import */ var _views_pages__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ./views/pages */ \"./src/views/pages.js\");\n/* harmony import */ var _views_help__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ./views/help */ \"./src/views/help.js\");\n/* harmony import */ var _footer__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ./footer */ \"./src/footer.js\");\n/* harmony import */ var _views_edituser__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ./views/edituser */ \"./src/views/edituser.js\");\n/* harmony import */ var _views_addgroup__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ./views/addgroup */ \"./src/views/addgroup.js\");\n/* harmony import */ var _views_settings__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ./views/settings */ \"./src/views/settings.js\");\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); Line truncated
/***/ }),
@@ -11403,7 +11403,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) *
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"default\", function() { return HelpPage; });\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var react_router_dom__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-router-dom */ \"./node_modules/react-router-dom/esm/react-router-dom.js\");\n/* harmony import */ var _elements_icon__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../elements/icon */ \"./src/elements/icon.js\");\n/* harmony import */ var react_collapse__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! react-collapse */ \"./node_modules/react-collapse/lib/index.js\");\n/* harmony import */ var react_collapse__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(react_collapse__WEBPACK_IMPORTED_MODULE_3__);\nfunction _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }\n\nfunction _nonIterableRest() { throw new TypeError(\"Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\"); }\n\nfunction _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === \"string\") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === \"Object\" && o.constructor) n = o.constructor.name; if (n === \"Map\" || n === \"Set\") return Array.from(o); if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }\n\nfunction _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }\n\nfunction _iterableToArrayLimit(arr, i) { if (typeof Symbol === \"undefined\" || !(Symbol.iterator in Object(arr))) return; var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i[\"return\"] != null) _i[\"return\"](); } finally { if (_d) throw _e; } } return _arr; }\n\nfunction _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }\n\n\n\n\n\nfunction HelpPage() {\n var _useState = Object(react__WEBPACK_IMPORTED_MODULE_0__[\"useState\"])(false),\n _useState2 = _slicedToArray(_useState, 2),\n firstStepsCollapsed = _useState2[0],\n collapseFirstSteps = _useState2[1];\n\n var _useState3 = Object(react__WEBPACK_IMPORTED_MODULE_0__[\"useState\"])(false),\n _useState4 = _slicedToArray(_useState3, 2),\n faqCollapsed = _useState4[0],\n collapseFaq = _useState4[1];\n\n var _useState5 = Object(react__WEBPACK_IMPORTED_MODULE_0__[\"useState\"])(false),\n _useState6 = _slicedToArray(_useState5, 2),\n aboutCollapsed = _useState6[0],\n collapseAbout = _useState6[1];\n\n return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(react__WEBPACK_IMPORTED_MODULE_0___default.a.Fragment, null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(\"section\", {\n className: \"content-header\"\n }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(\"div\", {\n className: \"container-fluid\"\n }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(\"div\", {\n className: \"row mb-2\"\n }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(\"div\", {\n className: \"col-sm-6\"\n }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(\"h1\", null, \"WebBase Help & Information\")), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(\"div\", {\n className: \"col-sm-6\"\n }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(\"ol\", {\n className: \"breadcrumb float-sm-right\"\n }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(\"li\", {\n className: \"breadcrumb-item\"\n }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(react_router_dom__WEBPACK_IMPORTED_MODULE_1__[\"Link\"], {\n to: \"/admin/dashboard\"\n }, \"Home\")), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(\"li\", {\n className: \"breadcrumb-item active\"\n }, \"Help\")))))), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(\"section\", {\n className: \"content\"\n }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(\"div\", {\n classNameLine truncated
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"default\", function() { return HelpPage; });\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var react_router_dom__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-router-dom */ \"./node_modules/react-router-dom/esm/react-router-dom.js\");\n/* harmony import */ var _elements_icon__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../elements/icon */ \"./src/elements/icon.js\");\n/* harmony import */ var react_collapse__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! react-collapse */ \"./node_modules/react-collapse/lib/index.js\");\n/* harmony import */ var react_collapse__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(react_collapse__WEBPACK_IMPORTED_MODULE_3__);\nfunction _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }\n\nfunction _nonIterableRest() { throw new TypeError(\"Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\"); }\n\nfunction _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === \"string\") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === \"Object\" && o.constructor) n = o.constructor.name; if (n === \"Map\" || n === \"Set\") return Array.from(o); if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }\n\nfunction _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }\n\nfunction _iterableToArrayLimit(arr, i) { if (typeof Symbol === \"undefined\" || !(Symbol.iterator in Object(arr))) return; var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i[\"return\"] != null) _i[\"return\"](); } finally { if (_d) throw _e; } } return _arr; }\n\nfunction _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }\n\n\n\n\n\nfunction HelpPage() {\n var _useState = Object(react__WEBPACK_IMPORTED_MODULE_0__[\"useState\"])(false),\n _useState2 = _slicedToArray(_useState, 2),\n firstStepsCollapsed = _useState2[0],\n collapseFirstSteps = _useState2[1];\n\n var _useState3 = Object(react__WEBPACK_IMPORTED_MODULE_0__[\"useState\"])(false),\n _useState4 = _slicedToArray(_useState3, 2),\n faqCollapsed = _useState4[0],\n collapseFaq = _useState4[1];\n\n var _useState5 = Object(react__WEBPACK_IMPORTED_MODULE_0__[\"useState\"])(false),\n _useState6 = _slicedToArray(_useState5, 2),\n aboutCollapsed = _useState6[0],\n collapseAbout = _useState6[1];\n\n return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(react__WEBPACK_IMPORTED_MODULE_0___default.a.Fragment, null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(\"section\", {\n className: \"content-header\"\n }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(\"div\", {\n className: \"container-fluid\"\n }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(\"div\", {\n className: \"row mb-2\"\n }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(\"div\", {\n className: \"col-sm-6\"\n }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(\"h1\", null, \"WebBase Help & Information\")), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(\"div\", {\n className: \"col-sm-6\"\n }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(\"ol\", {\n className: \"breadcrumb float-sm-right\"\n }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(\"li\", {\n className: \"breadcrumb-item\"\n }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(react_router_dom__WEBPACK_IMPORTED_MODULE_1__[\"Link\"], {\n to: \"/admin/dashboard\"\n }, \"Home\")), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(\"li\", {\n className: \"breadcrumb-item active\"\n }, \"Help\")))))), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(\"section\", {\n className: \"content\"\n }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(\"div\", {\n classNameLine truncated
/***/ }),
@@ -11415,7 +11415,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) *
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"default\", function() { return Logs; });\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var react_router_dom__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-router-dom */ \"./node_modules/react-router-dom/esm/react-router-dom.js\");\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\nfunction _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _isNativeReflectConstruct() { if (typeof Reflect === \"undefined\" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === \"function\") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\n\n\n\nvar Logs = /*#__PURE__*/function (_React$Component) {\n _inherits(Logs, _React$Component);\n\n var _super = _createSuper(Logs);\n\n function Logs(props) {\n _classCallCheck(this, Logs);\n\n return _super.call(this, props);\n }\n\n _createClass(Logs, [{\n key: \"render\",\n value: function render() {\n return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__[\"createElement\"](react__WEBPACK_IMPORTED_MODULE_0__[\"Fragment\"], null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__[\"createElement\"](\"div\", {\n className: \"content-header\"\n }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__[\"createElement\"](\"div\", {\n className: \"container-fluid\"\n }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__[\"createElement\"](\"div\", {\n className: \"row mb-2\"\n }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__[\"createElement\"](\"div\", {\n className: \"col-sm-6\"\n }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__[\"createElement\"](\"h1\", {\n className: \"m-0 text-dark\"\n }, \"Logs & Notifications\")), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__[\"createElement\"](\"div\", {\n className: \"col-sm-6\"\n }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__[\"createElement\"](\"ol\", {\n className: \"breadcrumb float-sm-right\"\n }, /*#__PURE__*/react_Line truncated
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"default\", function() { return Logs; });\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var react_router_dom__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-router-dom */ \"./node_modules/react-router-dom/esm/react-router-dom.js\");\n/* harmony import */ var _elements_icon__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../elements/icon */ \"./src/elements/icon.js\");\n/* harmony import */ var moment__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! moment */ \"./node_modules/moment/moment.js\");\n/* harmony import */ var moment__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(moment__WEBPACK_IMPORTED_MODULE_3__);\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === \"undefined\" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === \"number\") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError(\"Invalid attempt to iterate non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\"); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }\n\nfunction _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === \"string\") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === \"Object\" && o.constructor) n = o.constructor.name; if (n === \"Map\" || n === \"Set\") return Array.from(o); if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }\n\nfunction _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }\n\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expreLine truncated
/***/ }),
@@ -11451,7 +11451,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) *
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"default\", function() { return Settings; });\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var react_router_dom__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-router-dom */ \"./node_modules/react-router-dom/esm/react-router-dom.js\");\n/* harmony import */ var _elements_alert__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../elements/alert */ \"./src/elements/alert.js\");\n/* harmony import */ var react_collapse_lib_Collapse__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! react-collapse/lib/Collapse */ \"./node_modules/react-collapse/lib/Collapse.js\");\n/* harmony import */ var react_collapse_lib_Collapse__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(react_collapse_lib_Collapse__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var _elements_icon__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../elements/icon */ \"./src/elements/icon.js\");\n/* harmony import */ var draft_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! draft-js */ \"./node_modules/draft-js/lib/Draft.js\");\n/* harmony import */ var draft_js__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(draft_js__WEBPACK_IMPORTED_MODULE_5__);\n/* harmony import */ var react_draft_wysiwyg__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! react-draft-wysiwyg */ \"./node_modules/react-draft-wysiwyg/dist/react-draft-wysiwyg.js\");\n/* harmony import */ var react_draft_wysiwyg__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(react_draft_wysiwyg__WEBPACK_IMPORTED_MODULE_6__);\n/* harmony import */ var draftjs_to_html__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! draftjs-to-html */ \"./node_modules/draftjs-to-html/lib/draftjs-to-html.js\");\n/* harmony import */ var draftjs_to_html__WEBPACK_IMPORTED_MODULE_7___default = /*#__PURE__*/__webpack_require__.n(draftjs_to_html__WEBPACK_IMPORTED_MODULE_7__);\n/* harmony import */ var html_to_draftjs__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! html-to-draftjs */ \"./node_modules/html-to-draftjs/dist/html-to-draftjs.js\");\n/* harmony import */ var html_to_draftjs__WEBPACK_IMPORTED_MODULE_8___default = /*#__PURE__*/__webpack_require__.n(html_to_draftjs__WEBPACK_IMPORTED_MODULE_8__);\n/* harmony import */ var sanitize_html__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! sanitize-html */ \"./node_modules/sanitize-html/dist/sanitize-html.js\");\n/* harmony import */ var sanitize_html__WEBPACK_IMPORTED_MODULE_9___default = /*#__PURE__*/__webpack_require__.n(sanitize_html__WEBPACK_IMPORTED_MODULE_9__);\n/* harmony import */ var react_draft_wysiwyg_dist_react_draft_wysiwyg_css__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! react-draft-wysiwyg/dist/react-draft-wysiwyg.css */ \"./node_modules/react-draft-wysiwyg/dist/react-draft-wysiwyg.css\");\n/* harmony import */ var react_draft_wysiwyg_dist_react_draft_wysiwyg_css__WEBPACK_IMPORTED_MODULE_10___default = /*#__PURE__*/__webpack_require__.n(react_draft_wysiwyg_dist_react_draft_wysiwyg_css__WEBPACK_IMPORTED_MODULE_10__);\n/* harmony import */ var react_tooltip__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! react-tooltip */ \"./node_modules/react-tooltip/dist/index.es.js\");\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === \"undefined\" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === \"number\") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError(\"Invalid attempt to iterate non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\"); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } }Line truncated
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"default\", function() { return Settings; });\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var react_router_dom__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-router-dom */ \"./node_modules/react-router-dom/esm/react-router-dom.js\");\n/* harmony import */ var _elements_alert__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../elements/alert */ \"./src/elements/alert.js\");\n/* harmony import */ var react_collapse_lib_Collapse__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! react-collapse/lib/Collapse */ \"./node_modules/react-collapse/lib/Collapse.js\");\n/* harmony import */ var react_collapse_lib_Collapse__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(react_collapse_lib_Collapse__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var _elements_icon__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../elements/icon */ \"./src/elements/icon.js\");\n/* harmony import */ var draft_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! draft-js */ \"./node_modules/draft-js/lib/Draft.js\");\n/* harmony import */ var draft_js__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(draft_js__WEBPACK_IMPORTED_MODULE_5__);\n/* harmony import */ var react_draft_wysiwyg__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! react-draft-wysiwyg */ \"./node_modules/react-draft-wysiwyg/dist/react-draft-wysiwyg.js\");\n/* harmony import */ var react_draft_wysiwyg__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(react_draft_wysiwyg__WEBPACK_IMPORTED_MODULE_6__);\n/* harmony import */ var draftjs_to_html__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! draftjs-to-html */ \"./node_modules/draftjs-to-html/lib/draftjs-to-html.js\");\n/* harmony import */ var draftjs_to_html__WEBPACK_IMPORTED_MODULE_7___default = /*#__PURE__*/__webpack_require__.n(draftjs_to_html__WEBPACK_IMPORTED_MODULE_7__);\n/* harmony import */ var html_to_draftjs__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! html-to-draftjs */ \"./node_modules/html-to-draftjs/dist/html-to-draftjs.js\");\n/* harmony import */ var html_to_draftjs__WEBPACK_IMPORTED_MODULE_8___default = /*#__PURE__*/__webpack_require__.n(html_to_draftjs__WEBPACK_IMPORTED_MODULE_8__);\n/* harmony import */ var sanitize_html__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! sanitize-html */ \"./node_modules/sanitize-html/dist/sanitize-html.js\");\n/* harmony import */ var sanitize_html__WEBPACK_IMPORTED_MODULE_9___default = /*#__PURE__*/__webpack_require__.n(sanitize_html__WEBPACK_IMPORTED_MODULE_9__);\n/* harmony import */ var react_draft_wysiwyg_dist_react_draft_wysiwyg_css__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! react-draft-wysiwyg/dist/react-draft-wysiwyg.css */ \"./node_modules/react-draft-wysiwyg/dist/react-draft-wysiwyg.css\");\n/* harmony import */ var react_draft_wysiwyg_dist_react_draft_wysiwyg_css__WEBPACK_IMPORTED_MODULE_10___default = /*#__PURE__*/__webpack_require__.n(react_draft_wysiwyg_dist_react_draft_wysiwyg_css__WEBPACK_IMPORTED_MODULE_10__);\n/* harmony import */ var react_tooltip__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! react-tooltip */ \"./node_modules/react-tooltip/dist/index.es.js\");\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === \"undefined\" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === \"number\") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError(\"Invalid attempt to iterate non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\"); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } }Line truncated
/***/ }),
+6 -3
View File
@@ -43,8 +43,12 @@ export default class API {
return this.apiCall("user/logout");
}
async getNotifications() {
return this.apiCall("notifications/fetch");
async getNotifications(onlyNew = true) {
return this.apiCall("notifications/fetch", { new: onlyNew });
}
async markNotificationsSeen() {
return this.apiCall("notifications/seen");
}
async getUser(id) {
@@ -101,6 +105,5 @@ export default class API {
async sendTestMail(receiver) {
return this.apiCall("sendTestMail", { receiver: receiver });
}
};
+3 -2
View File
@@ -28,7 +28,7 @@ class AdminDashboard extends React.Component {
this.state = {
loaded: false,
dialog: { onClose: () => this.hideDialog() },
notifications: { }
notifications: [ ]
};
}
@@ -75,6 +75,7 @@ class AdminDashboard extends React.Component {
this.controlObj = {
showDialog: this.showDialog.bind(this),
fetchNotifications: this.fetchNotifications.bind(this),
api: this.api
};
@@ -92,7 +93,7 @@ class AdminDashboard extends React.Component {
return <EditUser {...newProps} />
}}/>
<Route path={"/admin/group/add"}><CreateGroup {...this.controlObj} /></Route>
<Route path={"/admin/logs"}><Logs {...this.controlObj} /></Route>
<Route path={"/admin/logs"}><Logs {...this.controlObj} notifications={this.state.notifications} /></Route>
<Route path={"/admin/settings"}><Settings {...this.controlObj} /></Route>
<Route path={"/admin/pages"}><PageOverview {...this.controlObj} /></Route>
<Route path={"/admin/help"}><HelpPage {...this.controlObj} /></Route>
+2 -2
View File
@@ -32,8 +32,8 @@ export default function HelpPage() {
<div className="col-12 col-md-8 col-lg-4">
<p>
WebBase is a php framework to simplify user management, pages and routing.
It can easily be modified and extended by writing document classes or
access the database with the available abstracted scheme. It also includes
It can easily be modified and extended by writing document classes and the database
can be accessed through the available abstracted scheme. It also includes
a REST API with access control, parameter type checking and more.
</p>
</div>
+98 -6
View File
@@ -1,13 +1,100 @@
import * as React from "react";
import {Link} from "react-router-dom";
import Icon from "../elements/icon";
import moment from 'moment';
export default class Logs extends React.Component {
constructor(props) {
super(props);
this.state = {
alerts: [],
notifications: []
};
this.parent = {
api : props.api,
fetchNotifications: props.fetchNotifications,
}
}
removeError(i) {
if (i >= 0 && i < this.state.alerts.length) {
let alerts = this.state.alerts.slice();
alerts.splice(i, 1);
this.setState({...this.state, alerts: alerts});
}
}
componentDidMount() {
this.parent.api.getNotifications(false).then((res) => {
if (!res.success) {
let alerts = this.state.alerts.slice();
alerts.push({ message: res.msg, title: "Error fetching Notifications" });
this.setState({ ...this.state, alerts: alerts });
} else {
this.setState({ ...this.state, notifications: res.notifications });
}
this.parent.api.markNotificationsSeen().then((res) => {
if (!res.success) {
let alerts = this.state.alerts.slice();
alerts.push({ message: res.msg, title: "Error fetching Notifications" });
this.setState({ ...this.state, alerts: alerts });
}
this.parent.fetchNotifications();
});
});
}
render() {
const colors = ["red", "green", "blue", "purple", "maroon"];
let dates = { };
for (let notification of this.state.notifications) {
let day = moment(notification["created_at"]).format('ll');
if (!dates.hasOwnProperty(day)) {
dates[day] = [];
}
let icon = "bell";
if (notification.type === "message") {
icon = "envelope";
} else if(notification.type === "warning") {
icon = "exclamation-triangle";
}
dates[day].push({ ...notification, icon: icon, timestamp: notification["created_at"] });
}
let elements = [];
for (let date in dates) {
let color = colors[Math.floor(Math.random() * colors.length)];
elements.push(
<div className={"time-label"} key={"time-label-" + date}>
<span className={"bg-" + color}>{date}</span>
</div>
);
for (let event of dates[date]) {
let timeString = moment(event.timestamp).fromNow();
elements.push(
<div>
<Icon icon={event.icon} className={"bg-" + color}/>
<div className="timeline-item">
<span className="time"><Icon icon={"clock"}/> {timeString}</span>
<h3 className="timeline-header">{event.title}</h3>
<div className="timeline-body">{event.message}</div>
</div>
</div>
);
}
}
return <>
<div className="content-header">
<div className="container-fluid">
@@ -25,13 +112,18 @@ export default class Logs extends React.Component {
</div>
</div>
<div className={"content"}>
<div className={"content-fluid"}>
<div className={"container-fluid"}>
<div className={"row"}>
<div className={"col-lg-6"}>
</div>
<div className={"col-lg-6"}>
<div className={"col-lg-8 col-12"}>
<div className="timeline">
<div className={"time-label"}>
<span className={"bg-blue"}>Today</span>
</div>
{elements}
<div>
<Icon icon={"clock"} className={"bg-gray"}/>
</div>
</div>
</div>
</div>
</div>
+55 -3
View File
@@ -45,6 +45,13 @@ export default class Settings extends React.Component {
isEditing: null,
keys: ["message_confirm_email", "message_accept_invite", "message_reset_password"]
},
recaptcha: {
alerts: [],
isOpen: true,
isSaving: false,
isResetting: false,
keys: ["recaptcha_enabled", "recaptcha_public_key", "recaptcha_private_key"]
},
uncategorised: {
alerts: [],
isOpen: true,
@@ -60,8 +67,9 @@ export default class Settings extends React.Component {
};
this.hiddenKeys = [
"mail_password",
"jwt_secret"
"recaptcha_private_key",
"mail_password",
"jwt_secret"
];
}
@@ -164,7 +172,7 @@ export default class Settings extends React.Component {
<div className={"card-header"} style={{cursor: "pointer"}}
onClick={() => this.toggleCollapse(category)}>
<h4 className={"card-title"}>
<Icon className={"mr-2"} icon={icon}/>
<Icon className={"mr-2"} icon={icon} type={icon==="google"?"fab":"fas"} />
{title}
</h4>
<div className={"card-tools"}>
@@ -402,6 +410,49 @@ export default class Settings extends React.Component {
return formGroups;
}
getRecaptchaForm() {
return <>
<div className={"form-group mt-2"}>
<div className={"form-check"}>
<input type={"checkbox"} className={"form-check-input"}
name={"recaptcha_enabled"} id={"recaptcha_enabled"}
checked={(this.state.settings["recaptcha_enabled"] ?? "0") === "1"}
onChange={this.onChangeValue.bind(this)}/>
<label className={"form-check-label"} htmlFor={"recaptcha_enabled"}>
Enable Google's reCaptcha
</label>
</div>
</div>
<hr className={"m-2"}/>
<label htmlFor={"recaptcha_public_key"} className={"mt-2"}>reCaptcha Site Key</label>
<div className={"input-group"}>
<div className={"input-group-prepend"}>
<span className={"input-group-text"}>
<Icon icon={"unlock"}/>
</span>
</div>
<input type={"text"} className={"form-control"}
value={this.state.settings["recaptcha_public_key"] ?? ""}
placeholder={"Enter site key"} name={"recaptcha_public_key"}
id={"recaptcha_public_key"} onChange={this.onChangeValue.bind(this)}
disabled={(this.state.settings["recaptcha_enabled"] ?? "0") !== "1"}/>
</div>
<label htmlFor={"recaptcha_private_key"} className={"mt-2"}>reCaptcha Secret Key</label>
<div className={"input-group mb-3"}>
<div className={"input-group-prepend"}>
<span className={"input-group-text"}>
<Icon icon={"lock"}/>
</span>
</div>
<input type={"password"} className={"form-control"}
value={this.state.settings["recaptcha_private_key"] ?? ""}
placeholder={"(unchanged)"} name={"recaptcha_private_key"}
id={"mail_password"} onChange={this.onChangeValue.bind(this)}
disabled={(this.state.settings["recaptcha_enabled"] ?? "0") !== "1"}/>
</div>
</>
}
getUncategorizedForm() {
let tr = [];
@@ -463,6 +514,7 @@ export default class Settings extends React.Component {
"general": {color: "primary", icon: "cogs", title: "General Settings", content: this.createGeneralForm()},
"mail": {color: "warning", icon: "envelope", title: "Mail Settings", content: this.createMailForm()},
"messages": {color: "info", icon: "copy", title: "Message Templates", content: this.getMessagesForm()},
"recaptcha": {color: "danger", icon: "google", title: "Google reCaptcha", content: this.getRecaptchaForm()},
"uncategorised": {color: "secondary", icon: "stream", title: "Uncategorised", content: this.getUncategorizedForm()},
};