User Edit
This commit is contained in:
1 parent
b6c726bad5
commit
9cbd129d4e
6 files changed
+226
-34
No files matched your search
+24
-11
@@ -286,8 +286,7 @@ namespace Api\User {
|
||||
);
|
||||
|
||||
foreach($user as $row) {
|
||||
$this->result["user"]["groups"][] = array(
|
||||
"uid" => $row["groupId"],
|
||||
$this->result["user"]["groups"][$row["groupId"]] = array(
|
||||
"name" => $row["groupName"],
|
||||
"color" => $row["groupColor"],
|
||||
);
|
||||
@@ -482,7 +481,7 @@ If the invitation was not intended, you can simply ignore this email.<br><br><a
|
||||
$validUntil = (new DateTime())->modify("+48 hour");
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->insert("UserToken", array("user_id", "token", "token_type", "valid_until"))
|
||||
->addRow(array($this->userId, $this->token, "confirmation", $validUntil))
|
||||
->addRow($this->userId, $this->token, "confirmation", $validUntil)
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
@@ -606,8 +605,20 @@ If the registration was not intended, you can simply ignore this email.<br><br><
|
||||
$password = $this->getParam("password");
|
||||
$groups = $this->getParam("groups");
|
||||
|
||||
$groupIds = array();
|
||||
if (!is_null($groups)) {
|
||||
if ($id === $this->user->getId() && !in_array(USER_GROUP_ADMIN, $groups)) {
|
||||
$param = new Parameter('groupId', Parameter::TYPE_INT);
|
||||
|
||||
foreach($groups as $groupId) {
|
||||
if (!$param->parseParam($groupId)) {
|
||||
$value = print_r($groupId, true);
|
||||
return $this->createError("Invalid Type for groupId in parameter groups: '$value' (Required: " . $param->getTypeName() . ")");
|
||||
}
|
||||
|
||||
$groupIds[] = $param->value;
|
||||
}
|
||||
|
||||
if ($id === $this->user->getId() && !in_array(USER_GROUP_ADMIN, $groupIds)) {
|
||||
return $this->createError("Cannot remove Administrator group from own user.");
|
||||
}
|
||||
}
|
||||
@@ -628,18 +639,20 @@ If the registration was not intended, you can simply ignore this email.<br><br><
|
||||
if ($emailChanged) $query->set("email", $email);
|
||||
if (!is_null($password)) $query->set("password", $this->hashPassword($password));
|
||||
|
||||
$query->where(new Compare("User.uid", $id));
|
||||
$res = $query->execute();
|
||||
$this->lastError = $sql->getLastError();
|
||||
$this->success = ($res !== FALSE);
|
||||
if (!empty($query->getValues())) {
|
||||
$query->where(new Compare("User.uid", $id));
|
||||
$res = $query->execute();
|
||||
$this->lastError = $sql->getLastError();
|
||||
$this->success = ($res !== FALSE);
|
||||
}
|
||||
|
||||
if ($this->success && !is_null($groups)) {
|
||||
if ($this->success && !empty($groupIds)) {
|
||||
|
||||
$deleteQuery = $sql->delete("UserGroup")->where(new Compare("user_id", $id));
|
||||
$insertQuery = $sql->insert("UserGroup", array("user_id", "group_id"));
|
||||
|
||||
foreach($groups as $groupId) {
|
||||
$insertQuery->addRow(array($id, $groupId));
|
||||
foreach($groupIds as $groupId) {
|
||||
$insertQuery->addRow($id, $groupId);
|
||||
}
|
||||
|
||||
$this->success = ($deleteQuery->execute() !== FALSE) && ($insertQuery->execute() !== FALSE);
|
||||
|
||||
@@ -203,12 +203,13 @@ abstract class SQL {
|
||||
|
||||
public function executeDelete(Delete $delete) {
|
||||
|
||||
$params = array();
|
||||
$table = $this->tableName($delete->getTable());
|
||||
$where = $this->getWhereClause($delete->getConditions(), $params);
|
||||
|
||||
$query = "DELETE FROM $table$where";
|
||||
if($delete->dump) { var_dump($query); }
|
||||
return $this->execute($query);
|
||||
return $this->execute($query, $params);
|
||||
}
|
||||
|
||||
public function executeTruncate(Truncate $truncate) {
|
||||
@@ -222,7 +223,7 @@ abstract class SQL {
|
||||
|
||||
$valueStr = array();
|
||||
foreach($update->getValues() as $key => $val) {
|
||||
$valueStr[] = "$key=" . $this->addValue($val, $params);
|
||||
$valueStr[] = $this->columnName($key) . "=" . $this->addValue($val, $params);
|
||||
}
|
||||
$valueStr = implode(",", $valueStr);
|
||||
|
||||
|
||||
Vendored
+24
-2
@@ -4039,6 +4039,17 @@ eval("// Imports\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../.
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ "./node_modules/css-loader/dist/cjs.js!./src/include/select2.min.css":
|
||||
/*!***************************************************************************!*\
|
||||
!*** ./node_modules/css-loader/dist/cjs.js!./src/include/select2.min.css ***!
|
||||
\***************************************************************************/
|
||||
/*! no static exports found */
|
||||
/***/ (function(module, exports, __webpack_require__) {
|
||||
|
||||
eval("// Imports\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\nexports = ___CSS_LOADER_API_IMPORT___(false);\n// Module\nexports.push([module.i, \".select2-container{box-sizing:border-box;display:inline-block;margin:0;position:relative;vertical-align:middle}.select2-container .select2-selection--single{box-sizing:border-box;cursor:pointer;display:block;height:28px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--single .select2-selection__rendered{display:block;padding-left:8px;padding-right:20px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-selection--single .select2-selection__clear{position:relative}.select2-container[dir=\\\"rtl\\\"] .select2-selection--single .select2-selection__rendered{padding-right:8px;padding-left:20px}.select2-container .select2-selection--multiple{box-sizing:border-box;cursor:pointer;display:block;min-height:32px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--multiple .select2-selection__rendered{display:inline-block;overflow:hidden;padding-left:8px;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-search--inline{float:left}.select2-container .select2-search--inline .select2-search__field{box-sizing:border-box;border:none;font-size:100%;margin-top:5px;padding:0}.select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-dropdown{background-color:white;border:1px solid #aaa;border-radius:4px;box-sizing:border-box;display:block;position:absolute;left:-100000px;width:100%;z-index:1051}.select2-results{display:block}.select2-results__options{list-style:none;margin:0;padding:0}.select2-results__option{padding:6px;user-select:none;-webkit-user-select:none}.select2-results__option[aria-selected]{cursor:pointer}.select2-container--open .select2-dropdown{left:0}.select2-container--open .select2-dropdown--above{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--open .select2-dropdown--below{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-search--dropdown{display:block;padding:4px}.select2-search--dropdown .select2-search__field{padding:4px;width:100%;box-sizing:border-box}.select2-search--dropdown .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-search--dropdown.select2-search--hide{display:none}.select2-close-mask{border:0;margin:0;padding:0;display:block;position:fixed;left:0;top:0;min-height:100%;min-width:100%;height:auto;width:auto;opacity:0;z-index:99;background-color:#fff;filter:alpha(opacity=0)}.select2-hidden-accessible{border:0 !important;clip:rect(0 0 0 0) !important;-webkit-clip-path:inset(50%) !important;clip-path:inset(50%) !important;height:1px !important;overflow:hidden !important;padding:0 !important;position:absolute !important;width:1px !important;white-space:nowrap !important}.select2-container--default .select2-selection--single{background-color:#fff;border:1px solid #aaa;border-radius:4px}.select2-container--default .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--default .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold}.select2-container--default .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--default .select2-selection--single .select2-selection__arrow{height:26px;position:absolute;top:1px;right:1px;width:20px}.select2-container--default .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--default[dir=\\\"rtl\\\"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--default[dir=\\\"rtl\\\"] .select2-selection--single .select2-selection__arrow{left:1px;right:auto}.select2-container--default.select2-container--disabled .select2-selection--single{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear{display:none}.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--default .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text}.select2-container--default .select2-selection--multiple .select2-selection__rendered{box-sizing:border-box;list-style:none;margin:0;padding:0 5px;width:100%}.select2-container--default .select2-selection--multiple .select2-selection__rendered li{list-style:none}.sLine truncated
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ "./node_modules/css-loader/dist/runtime/api.js":
|
||||
/*!*****************************************************!*\
|
||||
!*** ./node_modules/css-loader/dist/runtime/api.js ***!
|
||||
@@ -7559,7 +7570,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: \"logout\",\n value: function () {\n var _logout = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3() {\n return regeneratorRuntime.wrap(function _calleeLine 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
|
||||
|
||||
/***/ }),
|
||||
|
||||
@@ -7657,6 +7668,17 @@ eval("\nvar content = __webpack_require__(/*! !../../node_modules/css-loader/dis
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ "./src/include/select2.min.css":
|
||||
/*!*************************************!*\
|
||||
!*** ./src/include/select2.min.css ***!
|
||||
\*************************************/
|
||||
/*! no static exports found */
|
||||
/***/ (function(module, exports, __webpack_require__) {
|
||||
|
||||
eval("\nvar content = __webpack_require__(/*! !../../node_modules/css-loader/dist/cjs.js!./select2.min.css */ \"./node_modules/css-loader/dist/cjs.js!./src/include/select2.min.css\");\n\nif(typeof content === 'string') content = [[module.i, content, '']];\n\nvar transform;\nvar insertInto;\n\n\n\nvar options = {\"hmr\":true}\n\noptions.transform = transform\noptions.insertInto = undefined;\n\nvar update = __webpack_require__(/*! ../../node_modules/style-loader/lib/addStyles.js */ \"./node_modules/style-loader/lib/addStyles.js\")(content, options);\n\nif(content.locals) module.exports = content.locals;\n\nif(false) {}\n\n//# sourceURL=webpack:///./src/include/select2.min.css?");
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ "./src/index.js":
|
||||
/*!**********************!*\
|
||||
!*** ./src/index.js ***!
|
||||
@@ -7701,7 +7723,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 EditUser; });\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 _elements_icon__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../elements/icon */ \"./src/elements/icon.js\");\n/* harmony import */ var _elements_alert__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../elements/alert */ \"./src/elements/alert.js\");\n/* harmony import */ var react_router_dom__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! react-router-dom */ \"./node_modules/react-router-dom/esm/react-router-dom.js\");\n/* harmony import */ var react_collapse_lib_Collapse__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! react-collapse/lib/Collapse */ \"./node_modules/react-collapse/lib/Collapse.js\");\n/* harmony import */ var react_collapse_lib_Collapse__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(react_collapse_lib_Collapse__WEBPACK_IMPORTED_MODULE_4__);\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]); }); } 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 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\nfunctionLine truncated
|
||||
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"default\", function() { return EditUser; });\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 _elements_icon__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../elements/icon */ \"./src/elements/icon.js\");\n/* harmony import */ var _elements_alert__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../elements/alert */ \"./src/elements/alert.js\");\n/* harmony import */ var react_router_dom__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! react-router-dom */ \"./node_modules/react-router-dom/esm/react-router-dom.js\");\n/* harmony import */ var _include_select2_min_css__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../include/select2.min.css */ \"./src/include/select2.min.css\");\n/* harmony import */ var _include_select2_min_css__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_include_select2_min_css__WEBPACK_IMPORTED_MODULE_4__);\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]); }); } 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 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(seLine truncated
|
||||
|
||||
/***/ }),
|
||||
|
||||
|
||||
@@ -35,6 +35,10 @@ export default class API {
|
||||
return data && data.success && data.loggedIn;
|
||||
}
|
||||
|
||||
async editUser(id, username, email, password, groups) {
|
||||
return this.apiCall("user/edit", { "id": id, "username": username, "email": email, "password": password, "groups": groups });
|
||||
}
|
||||
|
||||
async logout() {
|
||||
return this.apiCall("user/logout");
|
||||
}
|
||||
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
.select2-container{box-sizing:border-box;display:inline-block;margin:0;position:relative;vertical-align:middle}.select2-container .select2-selection--single{box-sizing:border-box;cursor:pointer;display:block;height:28px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--single .select2-selection__rendered{display:block;padding-left:8px;padding-right:20px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-selection--single .select2-selection__clear{position:relative}.select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered{padding-right:8px;padding-left:20px}.select2-container .select2-selection--multiple{box-sizing:border-box;cursor:pointer;display:block;min-height:32px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--multiple .select2-selection__rendered{display:inline-block;overflow:hidden;padding-left:8px;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-search--inline{float:left}.select2-container .select2-search--inline .select2-search__field{box-sizing:border-box;border:none;font-size:100%;margin-top:5px;padding:0}.select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-dropdown{background-color:white;border:1px solid #aaa;border-radius:4px;box-sizing:border-box;display:block;position:absolute;left:-100000px;width:100%;z-index:1051}.select2-results{display:block}.select2-results__options{list-style:none;margin:0;padding:0}.select2-results__option{padding:6px;user-select:none;-webkit-user-select:none}.select2-results__option[aria-selected]{cursor:pointer}.select2-container--open .select2-dropdown{left:0}.select2-container--open .select2-dropdown--above{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--open .select2-dropdown--below{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-search--dropdown{display:block;padding:4px}.select2-search--dropdown .select2-search__field{padding:4px;width:100%;box-sizing:border-box}.select2-search--dropdown .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-search--dropdown.select2-search--hide{display:none}.select2-close-mask{border:0;margin:0;padding:0;display:block;position:fixed;left:0;top:0;min-height:100%;min-width:100%;height:auto;width:auto;opacity:0;z-index:99;background-color:#fff;filter:alpha(opacity=0)}.select2-hidden-accessible{border:0 !important;clip:rect(0 0 0 0) !important;-webkit-clip-path:inset(50%) !important;clip-path:inset(50%) !important;height:1px !important;overflow:hidden !important;padding:0 !important;position:absolute !important;width:1px !important;white-space:nowrap !important}.select2-container--default .select2-selection--single{background-color:#fff;border:1px solid #aaa;border-radius:4px}.select2-container--default .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--default .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold}.select2-container--default .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--default .select2-selection--single .select2-selection__arrow{height:26px;position:absolute;top:1px;right:1px;width:20px}.select2-container--default .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__arrow{left:1px;right:auto}.select2-container--default.select2-container--disabled .select2-selection--single{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear{display:none}.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--default .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text}.select2-container--default .select2-selection--multiple .select2-selection__rendered{box-sizing:border-box;list-style:none;margin:0;padding:0 5px;width:100%}.select2-container--default .select2-selection--multiple .select2-selection__rendered li{list-style:none}.select2-container--default .select2-selection--multiple .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;margin-top:5px;margin-right:10px;padding:1px}.select2-container--default .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;bordeLine truncated
|
||||
+170
-19
@@ -2,6 +2,7 @@ import * as React from "react";
|
||||
import Icon from "../elements/icon";
|
||||
import Alert from "../elements/alert";
|
||||
import {Link} from "react-router-dom";
|
||||
import "../include/select2.min.css";
|
||||
|
||||
export default class EditUser extends React.Component {
|
||||
|
||||
@@ -13,33 +14,102 @@ export default class EditUser extends React.Component {
|
||||
|
||||
this.state = {
|
||||
user: {},
|
||||
errors: [],
|
||||
alerts: [],
|
||||
fetchError: null,
|
||||
loaded: false,
|
||||
isSaving: false
|
||||
}
|
||||
isSaving: false,
|
||||
groups: { },
|
||||
searchString: "",
|
||||
searchActive: false
|
||||
};
|
||||
|
||||
this.searchBox = React.createRef();
|
||||
}
|
||||
|
||||
removeError(i) {
|
||||
if (i >= 0 && i < this.state.errors.length) {
|
||||
let errors = this.state.errors.slice();
|
||||
errors.splice(i, 1);
|
||||
this.setState({...this.state, errors: errors});
|
||||
removeAlert(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.getUser(this.props.match.params["userId"]).then((res) => {
|
||||
if (res.success) {
|
||||
this.setState({ ...this.state, user: res.user, loaded: true });
|
||||
this.setState({ ...this.state, user: {... res.user, password: ""} });
|
||||
this.parent.api.fetchGroups(1, 50).then((res) => {
|
||||
if (res.success) {
|
||||
this.setState({ ...this.state, groups: res.groups, loaded: true });
|
||||
} else {
|
||||
this.setState({ ...this.state, fetchError: res.msg, loaded: true });
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.setState({ ...this.state, fetchError: res.msg, loaded: true });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
onChangeInput(event) {
|
||||
const target = event.target;
|
||||
const value = target.value;
|
||||
const name = target.name;
|
||||
|
||||
if (name === "search") {
|
||||
this.setState({ ...this.state, searchString: value });
|
||||
} else {
|
||||
this.setState({ ...this.state, user: { ...this.state.user, [name]: value } });
|
||||
}
|
||||
}
|
||||
|
||||
onToggleSearch(e) {
|
||||
e.stopPropagation();
|
||||
this.setState({ ...this.state, searchActive: !this.state.searchActive });
|
||||
this.searchBox.current.focus();
|
||||
}
|
||||
|
||||
onSubmitForm(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
const id = this.props.match.params["userId"];
|
||||
const username = this.state.user["name"];
|
||||
const email = this.state.user["email"];
|
||||
let password = this.state.user["password"].length > 0 ? this.state.user["password"] : null;
|
||||
let groups = Object.keys(this.state.user.groups);
|
||||
|
||||
this.setState({ ...this.state, isSaving: true});
|
||||
this.parent.api.editUser(id, username, email, password, groups).then((res) => {
|
||||
let alerts = this.state.alerts.slice();
|
||||
|
||||
if (res.success) {
|
||||
alerts.push({ title: "Success", message: "User was successfully updated.", type: "success" });
|
||||
this.setState({ ...this.state, isSaving: false, alerts: alerts, user: { ...this.state.user, password: "" } });
|
||||
} else {
|
||||
alerts.push({ title: "Error updating user", message: res.msg, type: "danger" });
|
||||
this.setState({ ...this.state, isSaving: false, alerts: alerts, user: { ...this.state.user, password: "" } });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onRemoveGroup(event, groupId) {
|
||||
event.stopPropagation();
|
||||
if (this.state.user.groups.hasOwnProperty(groupId)) {
|
||||
let groups = { ...this.state.user.groups };
|
||||
delete groups[groupId];
|
||||
this.setState({ ...this.state, user: { ...this.state.user, groups: groups }});
|
||||
}
|
||||
}
|
||||
|
||||
onAddGroup(event, groupId) {
|
||||
event.stopPropagation();
|
||||
if (!this.state.user.groups.hasOwnProperty(groupId)) {
|
||||
let groups = { ...this.state.user.groups, [groupId]: { ...this.state.groups[groupId] } };
|
||||
this.setState({ ...this.state, user: { ...this.state.user, groups: groups }, searchActive: false, searchString: "" });
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.state.loaded) {
|
||||
return <h2 className={"text-center"}>
|
||||
Loading…<br/>
|
||||
@@ -47,31 +117,112 @@ export default class EditUser extends React.Component {
|
||||
</h2>
|
||||
}
|
||||
|
||||
let errors = [];
|
||||
let alerts = [];
|
||||
let form = null;
|
||||
if(this.state.fetchError) {
|
||||
errors.push(
|
||||
<Alert key={"error-fetch"} title={"Error fetching user details"} type={"danger"} message={
|
||||
alerts.push(
|
||||
<Alert key={"error-fetch"} title={"Error fetching data"} type={"danger"} message={
|
||||
<div>{this.state.fetchError}<br/>You can meanwhile return to the
|
||||
<Link to={"/admin/users"}>user overview</Link>
|
||||
</div>
|
||||
}/>
|
||||
)
|
||||
} else {
|
||||
for (let i = 0; i < this.state.errors.length; i++) {
|
||||
errors.push(<Alert key={"error-" + i} onClose={() => this.removeError(i)} {...this.state.errors[i]}/>)
|
||||
|
||||
for (let i = 0; i < this.state.alerts.length; i++) {
|
||||
alerts.push(<Alert key={"error-" + i} onClose={() => this.removeAlert(i)} {...this.state.alerts[i]}/>)
|
||||
}
|
||||
|
||||
form = <form role={"form"} onSubmit={(e) => e.preventDefault()}>
|
||||
let possibleOptions = [];
|
||||
let renderedOptions = [];
|
||||
for (let groupId in this.state.groups) {
|
||||
if (this.state.groups.hasOwnProperty(groupId)) {
|
||||
let groupName = this.state.groups[groupId].name;
|
||||
let groupColor = this.state.groups[groupId].color;
|
||||
if (this.state.user.groups.hasOwnProperty(groupId)) {
|
||||
renderedOptions.push(
|
||||
<li className={"select2-selection__choice"} key={"group-" + groupId} title={groupName} style={{backgroundColor: groupColor}}>
|
||||
<span className="select2-selection__choice__remove" role="presentation"
|
||||
onClick={(e) => this.onRemoveGroup(e, groupId)}>
|
||||
×
|
||||
</span>
|
||||
{groupName}
|
||||
</li>
|
||||
);
|
||||
} else {
|
||||
if (this.state.searchString.length === 0 || groupName.toLowerCase().includes(this.state.searchString.toLowerCase())) {
|
||||
possibleOptions.push(
|
||||
<li className={"select2-results__option"} role={"option"} key={"group-" + groupId} aria-selected={false}
|
||||
onClick={(e) => this.onAddGroup(e, groupId)}>
|
||||
{groupName}
|
||||
</li>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let searchWidth = "100%";
|
||||
let placeholder = "Select Groups";
|
||||
let searchVisible = (this.state.searchString.length > 0 || this.state.searchActive) ? "block" : "none";
|
||||
if (renderedOptions.length > 0) {
|
||||
searchWidth = (0.75 + this.state.searchString.length * 0.75) + "em";
|
||||
placeholder = "";
|
||||
}
|
||||
|
||||
form = <form role={"form"} onSubmit={this.onSubmitForm.bind(this)}>
|
||||
<div className={"form-group"}>
|
||||
<label htmlFor={"username"}>Username</label>
|
||||
<input type={"text"} className={"form-control"} placeholder={"Enter username"}
|
||||
name={"username"} id={"username"} maxLength={32} value={this.state.user.name}/>
|
||||
name={"username"} id={"username"} maxLength={32} value={this.state.user.name}
|
||||
onChange={this.onChangeInput.bind(this)}/>
|
||||
</div>
|
||||
<div className={"form-group"}>
|
||||
<label htmlFor={"email"}>E-Mail</label>
|
||||
<input type={"email"} className={"form-control"} placeholder={"E-Mail address"}
|
||||
id={"email"} name={"email"} maxLength={64} value={this.state.user.email} />
|
||||
id={"email"} name={"email"} maxLength={64} value={this.state.user.email}
|
||||
onChange={this.onChangeInput.bind(this)}/>
|
||||
</div>
|
||||
|
||||
<div className={"form-group"}>
|
||||
<label htmlFor={"password"}>Password</label>
|
||||
<input type={"password"} className={"form-control"} placeholder={"(unchanged)"}
|
||||
id={"password"} name={"password"} value={this.state.user.password}
|
||||
onChange={this.onChangeInput.bind(this)}/>
|
||||
</div>
|
||||
|
||||
<div className={"form-group position-relative"}>
|
||||
<label>Groups</label>
|
||||
<span className={"select2 select2-container select2-container--default select2-container--below"}
|
||||
dir={"ltr"} style={{width: "100%"}} >
|
||||
<span className="selection">
|
||||
<span className={"select2-selection select2-selection--multiple"} role={"combobox"} aria-haspopup={"true"}
|
||||
aria-expanded={false} aria-disabled={false} onClick={this.onToggleSearch.bind(this)}>
|
||||
<ul className={"select2-selection__rendered"}>
|
||||
{renderedOptions}
|
||||
<li className={"select2-search select2-search--inline"}>
|
||||
<input className={"select2-search__field"} type={"search"} tabIndex={0}
|
||||
autoComplete={"off"} autoCorrect={"off"} autoCapitalize={"none"} spellCheck={false}
|
||||
role={"searchbox"} aria-autocomplete={"list"} placeholder={placeholder}
|
||||
name={"search"} style={{width: searchWidth}} value={this.state.searchString}
|
||||
onChange={this.onChangeInput.bind(this)} ref={this.searchBox} />
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
</span>
|
||||
<span className="dropdown-wrapper" aria-hidden="true"/>
|
||||
</span>
|
||||
<span className={"select2-container select2-container--default select2-container--open"}
|
||||
style={{position: "absolute", bottom: 0, left: 0, width: "100%", display: searchVisible}}>
|
||||
<span className={"select2-dropdown select2-dropdown--below"} dir={"ltr"}>
|
||||
<span className={"select2-results"}>
|
||||
<ul className={"select2-results__options"} role={"listbox"}
|
||||
aria-multiselectable={true} aria-expanded={true} aria-hidden={false}>
|
||||
{possibleOptions}
|
||||
</ul>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<Link to={"/admin/users"} className={"btn btn-info mt-2 mr-2"}>
|
||||
@@ -105,7 +256,7 @@ export default class EditUser extends React.Component {
|
||||
<div className={"content"}>
|
||||
<div className={"row"}>
|
||||
<div className={"col-lg-6 pl-5 pr-5"}>
|
||||
{errors}
|
||||
{alerts}
|
||||
{form}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user