Mail Templates + Frontend

This commit is contained in:
Roman committed 2020-06-26 18:24:44 +02:00
1 parent f5a8f2c777
commit 33dd990b71
7 files changed
+190 -133

No files matched your search

+71 -25
View File
@@ -98,6 +98,18 @@ namespace Api {
return ($this->success && !empty($res) ? $res : array());
}
protected function getMessageTemplate($key) {
$req = new \Api\Settings\Get($this->user);
$this->success = $req->execute(array("key" => $key));
$this->lastError = $req->getLastError();
if ($this->success) {
return $req->getResult()["settings"][$key] ?? "{{link}}";
}
return $this->success;
}
}
}
@@ -386,19 +398,39 @@ namespace Api\User {
//send validation mail
if ($this->success) {
$request = new SendMail($this->user);
$link = "http://localhost/acceptInvitation?token=$token";
$this->success = $request->execute(array(
"from" => "webmaster@romanh.de",
$settings = $this->user->getConfiguration()->getSettings();
$baseUrl = htmlspecialchars($settings->getBaseUrl());
$siteName = htmlspecialchars($settings->getSiteName());
$body = $this->getMessageTemplate("message_accept_invite");
if ($this->success) {
$replacements = array(
"link" => "$baseUrl/acceptInvite?token=$token",
"site_name" => $siteName,
"base_url" => $baseUrl,
"username" => htmlspecialchars($username)
);
foreach($replacements as $key => $value) {
$body = str_replace("{{{$key}}}", $value, $body);
}
$request = new SendMail($this->user);
$this->success = $request->execute(array(
"to" => $email,
"subject" => "Account Invitation for web-base@localhost",
"body" =>
"Hello,<br>
you were invited to create an account on web-base@localhost. Click on the following link to confirm the registration, it is 48h valid from now.
If the invitation was not intended, you can simply ignore this email.<br><br><a href=\"$link\">$link</a>"
)
);
$this->lastError = $request->getLastError();
"subject" => "[$siteName] Account Invitation",
"body" => $body
));
$this->lastError = $request->getLastError();
}
if (!$this->success) {
$this->lastError = "The invitation was created but the confirmation email could not be sent. " .
"Please contact the server administration. Reason: " . $this->lastError;
}
}
return $this->success;
}
@@ -573,22 +605,36 @@ If the invitation was not intended, you can simply ignore this email.<br><br><a
return false;
}
$request = new SendMail($this->user);
$link = "http://localhost/confirmEmail?token=$this->token";
$this->success = $request->execute(array(
"from" => "webmaster@romanh.de",
"to" => $email,
"subject" => "E-Mail Confirmation for web-base@localhost",
"body" =>
"Hello,<br>
you recently registered an account on web-base@localhost. Click on the following link to confirm the registration, it is 48h valid from now.
If the registration was not intended, you can simply ignore this email.<br><br><a href=\"$link\">$link</a>"
)
);
$settings = $this->user->getConfiguration()->getSettings();
$baseUrl = htmlspecialchars($settings->getBaseUrl());
$siteName = htmlspecialchars($settings->getSiteName());
$body = $this->getMessageTemplate("message_confirm_email");
if ($this->success) {
$replacements = array(
"link" => "$baseUrl/confirmEmail?token=$this->token",
"site_name" => $siteName,
"base_url" => $baseUrl,
"username" => htmlspecialchars($username)
);
foreach($replacements as $key => $value) {
$body = str_replace("{{{$key}}}", $value, $body);
}
$request = new SendMail($this->user);
$this->success = $request->execute(array(
"to" => $email,
"subject" => "[$siteName] E-Mail Confirmation",
"body" => $body
));
$this->lastError = $request->getLastError();
}
if (!$this->success) {
$this->lastError = "Your account was registered but the confirmation email could not be sent. " .
"Please contact the server administration. Reason: " . $request->getLastError();
"Please contact the server administration. Reason: " . $this->lastError;
}
return $this->success;
+20 -26
View File
@@ -165,37 +165,31 @@ class CreateDatabase {
}
private static function MessageConfirmEmail() : string {
return str_replace("\n", "", intendCode(
"Hello {{username}},<br>
You recently created an account on {{site_name}}. Please click on the following link to
confirm your email address and complete your registration. If you haven't registered an
account, you can simply ignore this email. The link is valid for the next 48 hours:<br><br>
<a href=\"{{link}}\">{{confirm_link}}</a><br><br>
Best Regards<br>
{{site_name}} Administration", false
));
return "Hello {{username}},<br>" .
"You recently created an account on {{site_name}}. Please click on the following link to " .
"confirm your email address and complete your registration. If you haven't registered an " .
"account, you can simply ignore this email. The link is valid for the next 48 hours:<br><br> " .
"<a href=\"{{link}}\">{{link}}</a><br><br> " .
"Best Regards<br> " .
"{{site_name}} Administration";
}
private static function MessageAcceptInvite() : string {
return str_replace("\n", "", intendCode(
"Hello {{username}},<br>
You were invited to create an account on {{site_name}}. Please click on the following link to
confirm your email address and complete your registration by choosing a new password.
If you want to decline the invitation, you can simply ignore this email. The link is valid for the next 48 hours:<br><br>
<a href=\"{{link}}\">{{link}}</a><br><br>
Best Regards<br>
{{site_name}} Administration", false
));
return "Hello {{username}},<br>" .
"You were invited to create an account on {{site_name}}. Please click on the following link to " .
"confirm your email address and complete your registration by choosing a new password. " .
"If you want to decline the invitation, you can simply ignore this email. The link is valid for the next 48 hours:<br><br>" .
"<a href=\"{{link}}\">{{link}}</a><br><br>" .
"Best Regards<br>" .
"{{site_name}} Administration";
}
private static function MessageResetPassword() : string {
return str_replace("\n", "", intendCode(
"Hello {{username}},<br>
you requested a password reset on {{sitename}}. Please click on the following link to
choose a new password. If this request was not intended, you can simply ignore the email. The Link is valid for one hour:<br><br>
<a href=\"{{link}}\">{{link}}</a><br><br>
Best Regards<br>
{{site_name}} Administration", false
));
return "Hello {{username}},<br>" .
"you requested a password reset on {{sitename}}. Please click on the following link to " .
"choose a new password. If this request was not intended, you can simply ignore the email. The Link is valid for one hour:<br><br>" .
"<a href=\"{{link}}\">{{link}}</a><br><br>" .
"Best Regards<br>" .
"{{site_name}} Administration";
}
}
+8
View File
@@ -68,4 +68,12 @@ class Settings {
->addRow("installation_completed", $this->installationComplete ? "1" : "0", true)
->addRow("jwt_secret", $this->jwtSecret, true);
}
public function getSiteName() {
return $this->siteName;
}
public function getBaseUrl() {
return $this->baseUrl;
}
}
+13 -1
View File
@@ -11033,6 +11033,18 @@ eval("__webpack_require__.r(__webpack_exports__);\nfunction isAbsolute(pathname)
/***/ }),
/***/ "./node_modules/sanitize-html/dist/sanitize-html.js":
/*!**********************************************************!*\
!*** ./node_modules/sanitize-html/dist/sanitize-html.js ***!
\**********************************************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
eval("/* WEBPACK VAR INJECTION */(function(global) {var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var require;var require;function _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;}}};}function _toConsumableArray(arr){return _arrayWithoutHoles(arr)||_iterableToArray(arr)||_unsupportedIterableToArray(arr)||_nonIterableSpread();}function _nonIterableSpread(){throw new TypeError(\"Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\");}function _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);}function _iterableToArray(iter){if(typeof Symbol!==\"undefined\"&&Symbol.iterator in Object(iter))return Array.from(iter);}function _arrayWithoutHoles(arr){if(Array.isArray(arr))return _arrayLikeToArray(arr);}function _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;}function _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);}(function(f){if(( false?undefined:_typeof(exports))===\"object\"&&typeof module!==\"undefined\"){module.exports=f();}else if(true){!(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = (f),\n\t\t\t\t__WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ?\n\t\t\t\t(__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__),\n\t\t\t\t__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));}else{ var g; }})(function(){var define,module,exports;return function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c=\"function\"==typeof require&&require;if(!f&&c)return require(i,!0);if(u)return u(i,!0);var a=new Error(\"Cannot find module '\"+i+\"'\");throw a.code=\"MODULE_NOT_FOUND\",a;}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r);},p,p.exports,r,e,n,t);}return n[i].exports;}for(var u=\"function\"==typeof require&&require,i=0;i<t.length;i++){o(t[i]);}return o;}return r;}()({1:[function(require,module,exports){'use strict';exports.byteLength=byteLength;exports.toByteArray=toByteArray;exports.fromByteArray=fromByteArray;var lookup=[];var revLookup=[];var Arr=typeof Uint8Array!=='undefined'?Uint8Array:Array;var code='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';for(var i=0,len=code.length;i<len;++i){lookup[i]=code[i];revLookup[code.charCodeAt(i)]=i;}// Support decoding URL-safe base64 strings, as Node.js does.\n// See: https://en.wikipedia.org/wiki/Base64#URL_applications\nrevLookup['-'.charCodeAt(0)]=62;revLookup['_'.charCodeAt(0)]=63;function getLens(b64){var len=b64.length;if(len%4>0){throw new Error('Invalid string. Length must be a multiple of 4');}// Trim off extra bytes after placeholder bytes are found\n// See: https://github.com/beatgammit/base64-js/issues/42\nvar validLen=b64.indexOf('=');if(validLen===-1)validLen=len;var placeHoldersLen=validLen===len?0:4-validLen%4;return[validLen,placeHoldersLen];}// base64 is 4/3 + up to two characters of the original data\nfunction byteLength(b64){var lens=getLens(b64);var validLen=lens[0];var placeHoldersLen=lens[1];return(validLen+placeHoldersLen)*3/4-placeHoldersLen;}function _byteLength(b64,validLen,placeHoldersLen){return(validLen+placeHoldersLen)*3/4-placeHoldersLen;}function toByteArray(b64){var tmp;var lens=getLens(b64);var validLen=lens[0];var placeHoldersLen=lens[1];var arr=new Arr(_byteLength(b64,validLen,placeHoldersLen)); Line truncated
/***/ }),
/***/ "./node_modules/scheduler/cjs/scheduler-tracing.development.js":
/*!*********************************************************************!*\
!*** ./node_modules/scheduler/cjs/scheduler-tracing.development.js ***!
@@ -11439,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 react_draft_wysiwyg_dist_react_draft_wysiwyg_css__WEBPACK_IMPORTED_MODULE_9__ = __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_9___default = /*#__PURE__*/__webpack_require__.n(react_draft_wysiwyg_dist_react_draft_wysiwyg_css__WEBPACK_IMPORTED_MODULE_9__);\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 ||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
/***/ }),
+54
View File
@@ -11830,6 +11830,55 @@
"walker": "~1.0.5"
}
},
"sanitize-html": {
"version": "1.27.0",
"resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-1.27.0.tgz",
"integrity": "sha512-U1btucGeYVpg0GoK43jPpe/bDCV4cBOGuxzv5NBd0bOjyZdMKY0n98S/vNlO1wVwre0VCj8H3hbzE7gD2+RjKA==",
"requires": {
"chalk": "^2.4.1",
"htmlparser2": "^4.1.0",
"lodash": "^4.17.15",
"postcss": "^7.0.27",
"srcset": "^2.0.1",
"xtend": "^4.0.1"
},
"dependencies": {
"domelementtype": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz",
"integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ=="
},
"domhandler": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.0.0.tgz",
"integrity": "sha512-eKLdI5v9m67kbXQbJSNn1zjh0SDzvzWVWtX+qEI3eMjZw8daH9k8rlj1FZY9memPwjiskQFbe7vHVVJIAqoEhw==",
"requires": {
"domelementtype": "^2.0.1"
}
},
"domutils": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.1.0.tgz",
"integrity": "sha512-CD9M0Dm1iaHfQ1R/TI+z3/JWp/pgub0j4jIQKH89ARR4ATAV2nbaOQS5XxU9maJP5jHaPdDDQSEHuE2UmpUTKg==",
"requires": {
"dom-serializer": "^0.2.1",
"domelementtype": "^2.0.1",
"domhandler": "^3.0.0"
}
},
"htmlparser2": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz",
"integrity": "sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==",
"requires": {
"domelementtype": "^2.0.1",
"domhandler": "^3.0.0",
"domutils": "^2.0.0",
"entities": "^2.0.0"
}
}
}
},
"sanitize.css": {
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-10.0.0.tgz",
@@ -12450,6 +12499,11 @@
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
},
"srcset": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/srcset/-/srcset-2.0.1.tgz",
"integrity": "sha512-00kZI87TdRKwt+P8jj8UZxbfp7mK2ufxcIMWvhAOZNJTRROimpHeruWrGvCZneiuVDLqdyHefVp748ECTnyUBQ=="
},
"sshpk": {
"version": "1.16.1",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
+2 -1
View File
@@ -17,7 +17,8 @@
"react-router-dom": "^5.2.0",
"react-scripts": "^3.4.1",
"react-select": "^3.1.0",
"react-tooltip": "^4.2.7"
"react-tooltip": "^4.2.7",
"sanitize-html": "^1.27.0"
},
"scripts": {
"build": "webpack --mode development && mv dist/main.js ../js/admin.min.js"
+22 -80
View File
@@ -3,11 +3,13 @@ import {Link} from "react-router-dom";
import Alert from "../elements/alert";
import {Collapse} from "react-collapse/lib/Collapse";
import Icon from "../elements/icon";
import { EditorState, ContentState, convertFromHTML, convertToRaw } from 'draft-js'
import { EditorState, ContentState, convertToRaw } from 'draft-js'
import { Editor } from 'react-draft-wysiwyg'
import draftToHtml from 'draftjs-to-html';
import htmlToDraft from 'html-to-draftjs';
import sanitizeHtml from 'sanitize-html'
import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css';
import ReactTooltip from "react-tooltip";
export default class Settings extends React.Component {
@@ -302,11 +304,16 @@ export default class Settings extends React.Component {
<div className={"form-group"} key={"group-" + key}>
<label htmlFor={key}>
{ title }
<ReactTooltip id={"tooltip-" + key} />
<Icon icon={"times"} className={"ml-2 text-danger"} style={{cursor: "pointer"}}
onClick={() => this.closeEditor(false)}
onClick={() => this.closeEditor(false)} data-type={"error"}
data-tip={"Discard Changes"} data-place={"top"} data-effect={"solid"}
data-for={"tooltip-" + key}
/>
<Icon icon={"check"} className={"ml-1 text-success"} style={{cursor: "pointer"}}
onClick={() => this.closeEditor(true)}
<Icon icon={"check"} className={"ml-2 text-success"} style={{cursor: "pointer"}}
onClick={() => this.closeEditor(true)} data-type={"success"}
data-tip={"Save Changes"} data-place={"top"} data-effect={"solid"}
data-for={"tooltip-" + key}
/>
</label>
{ editor }
@@ -315,15 +322,16 @@ export default class Settings extends React.Component {
} else {
formGroups.push(
<div className={"form-group"} key={"group-" + key}>
<ReactTooltip id={"tooltip-" + key} />
<label htmlFor={key}>
{ title }
<Icon icon={"pencil-alt"} className={"ml-2"} style={{cursor: "pointer"}}
onClick={() => this.openEditor(key)}
onClick={() => this.openEditor(key)} data-type={"info"}
data-tip={"Edit Template"} data-place={"top"} data-effect={"solid"}
data-for={"tooltip-" + key}
/>
</label>
<textarea rows={6} className={"form-control"} disabled={true}
value={this.state.settings[key] ?? ""} id={key} name={key}
/>
<div className={"p-2 text-black"} style={{backgroundColor: "#d2d6de"}} dangerouslySetInnerHTML={{ __html: sanitizeHtml(this.state.settings[key] ?? "") }} />
</div>
);
}
@@ -332,77 +340,10 @@ export default class Settings extends React.Component {
return formGroups;
}
/*
getUncategorisedCard() {
let keys = [];
let tr = [];
for (let key in this.state.settings) {
if (this.state.settings.hasOwnProperty(key)) {
if (!this.generalKeys.includes(key) && !this.mailKeys.includes(key)) {
keys.push(key);
tr.push(<tr key={"tr-" + key}>
<td>{key}</td>
<td>{this.state.settings[key]}</td>
</tr>);
}
}
}
let errors = [];
for (let i = 0; i < this.state.etcErrors.length; i++) {
errors.push(<Alert key={"error-" + i} onClose={() => this.removeError("etcErrors", i)} {...this.state.etcErrors[i]}/>)
}
return <>
<div className={"card-header"} style={{cursor: "pointer"}}
onClick={() => this.toggleCollapse("etcOpened")}>
<h4 className={"card-title"}>
<Icon className={"mr-2"} icon={"cogs"}/>
General Settings
</h4>
<div className={"card-tools"}>
<span className={"btn btn-tool btn-sm"}>
<Icon icon={this.state.etcOpened ? "angle-up" : "angle-down"}/>
</span>
</div>
</div>
<Collapse isOpened={this.state.etcOpened}>
<div className={"card-body"}>
<div className={"row"}>
<div className={"col-12 col-lg-6"}>
{errors}
<table>
<thead>
<tr>
<th>Key</th>
<th>Value</th>
</tr>
</thead>
<tbody>
{tr}
</tbody>
</table>
<div>
<button className={"btn btn-secondary ml-2"} onClick={() => this.onReset("etcErrors", keys)}
disabled={this.state.isResetting || this.state.isSaving}>
{this.state.isResetting ?
<span>Resetting&nbsp;<Icon icon={"circle-notch"}/></span> : "Reset"}
</button>
<button className={"btn btn-success ml-2"} onClick={() => this.onSave("etcErrors", keys)}
disabled={this.state.isResetting || this.state.isSaving}>
{this.state.isSaving ?
<span>Saving&nbsp;<Icon icon={"circle-notch"}/></span> : "Save"}
</button>
</div>
</div>
</div>
</div>
</Collapse>
</>
getUncategorizedForm() {
return <b>Coming soon…</b>
}
*/
render() {
let errors = [];
@@ -415,7 +356,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()},
"uncategorised": {color: "secondary", icon: "stream", title: "Uncategorised", content: <></>},
"uncategorised": {color: "secondary", icon: "stream", title: "Uncategorised", content: this.getUncategorizedForm()},
};
let cards = [];
@@ -446,10 +387,11 @@ export default class Settings extends React.Component {
{cards}
</div>
</div>
<ReactTooltip />
</>
}
onEditorStateChange(editorState, key) {
onEditorStateChange(editorState) {
this.setState({
...this.state,
messages: {