UNPKG

solid-ui

Version:

UI library for writing Solid read-write-web applications

477 lines (407 loc) • 19.4 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _typeof = require("@babel/runtime/helpers/typeof"); Object.defineProperty(exports, "__esModule", { value: true }); exports.AccessController = void 0; var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator")); var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator")); var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _acl = require("./acl"); var _rdflib = require("rdflib"); var _accessGroups = require("./access-groups"); var _aclControl = require("./acl-control"); var _authn = require("../authn/authn"); var utils = _interopRequireWildcard(require("../utils")); var debug = _interopRequireWildcard(require("../debug")); var _ns = _interopRequireDefault(require("../ns")); function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; } /** * Contains the [[AccessController]] class * @packageDocumentation */ /** * Rendered HTML component used in the databrowser's Sharing pane. */ var AccessController = /*#__PURE__*/function () { function AccessController(subject, noun, context, statusElement, classes, targetIsProtected, targetDoc, targetACLDoc, defaultHolder, defaultACLDoc, prospectiveDefaultHolder, store, dom) { (0, _classCallCheck2["default"])(this, AccessController); this.subject = subject; this.noun = noun; this.context = context; this.statusElement = statusElement; this.classes = classes; this.targetIsProtected = targetIsProtected; this.targetDoc = targetDoc; this.targetACLDoc = targetACLDoc; this.defaultHolder = defaultHolder; this.defaultACLDoc = defaultACLDoc; this.prospectiveDefaultHolder = prospectiveDefaultHolder; this.store = store; this.dom = dom; (0, _defineProperty2["default"])(this, "mainCombo", void 0); (0, _defineProperty2["default"])(this, "defaultsCombo", void 0); (0, _defineProperty2["default"])(this, "isContainer", void 0); (0, _defineProperty2["default"])(this, "defaultsDiffer", void 0); (0, _defineProperty2["default"])(this, "rootElement", void 0); (0, _defineProperty2["default"])(this, "isUsingDefaults", void 0); this.rootElement = dom.createElement('div'); this.rootElement.classList.add(classes.aclGroupContent); this.isContainer = targetDoc.uri.slice(-1) === '/'; // Give default for all directories if (defaultHolder && defaultACLDoc) { this.isUsingDefaults = true; var aclDefaultStore = (0, _acl.adoptACLDefault)(this.targetDoc, targetACLDoc, defaultHolder, defaultACLDoc); this.mainCombo = new _accessGroups.AccessGroups(targetDoc, targetACLDoc, this, aclDefaultStore, { defaults: this.isContainer }); this.defaultsCombo = null; this.defaultsDiffer = false; } else { this.isUsingDefaults = false; this.mainCombo = new _accessGroups.AccessGroups(targetDoc, targetACLDoc, this, store); this.defaultsCombo = new _accessGroups.AccessGroups(targetDoc, targetACLDoc, this, store, { defaults: this.isContainer }); this.defaultsDiffer = !(0, _acl.sameACL)(this.mainCombo.aclMap, this.defaultsCombo.aclMap); } } (0, _createClass2["default"])(AccessController, [{ key: "isEditable", get: function get() { return !this.isUsingDefaults; } }, { key: "render", value: function render() { this.rootElement.innerHTML = ''; if (this.isUsingDefaults) { this.renderStatus("The sharing for this ".concat(this.noun, " is the default for folder ")); if (this.defaultHolder) { var defaultHolderLink = this.statusElement.appendChild(this.dom.createElement('a')); defaultHolderLink.href = this.defaultHolder.uri; defaultHolderLink.innerText = (0, _aclControl.shortNameForFolder)(this.defaultHolder); } } else if (!this.defaultsDiffer) { this.renderStatus('This is also the default for things in this folder.'); } else { this.renderStatus(''); } this.rootElement.appendChild(this.mainCombo.render()); if (this.defaultsCombo && this.defaultsDiffer) { this.rootElement.appendChild(this.renderRemoveDefaultsController()); this.rootElement.appendChild(this.defaultsCombo.render()); } else if (this.isEditable && this.isContainer) { this.rootElement.appendChild(this.renderAddDefaultsController()); } if (!this.targetIsProtected && this.isUsingDefaults) { this.rootElement.appendChild(this.renderAddAclsController()); } else if (!this.targetIsProtected) { this.rootElement.appendChild(this.renderRemoveAclsController()); } return this.rootElement; } }, { key: "renderRemoveAclsController", value: function renderRemoveAclsController() { var _this = this; var useDefaultButton = this.dom.createElement('button'); useDefaultButton.innerText = "Remove custom sharing settings for this ".concat(this.noun, " -- just use default").concat(this.prospectiveDefaultHolder ? " for ".concat(utils.label(this.prospectiveDefaultHolder)) : ''); useDefaultButton.classList.add(this.classes.bigButton); useDefaultButton.addEventListener('click', function () { return _this.removeAcls().then(function () { return _this.render(); })["catch"](function (error) { return _this.renderStatus(error); }); }); return useDefaultButton; } }, { key: "renderAddAclsController", value: function renderAddAclsController() { var _this2 = this; var addAclButton = this.dom.createElement('button'); addAclButton.innerText = "Set specific sharing for this ".concat(this.noun); addAclButton.classList.add(this.classes.bigButton); addAclButton.addEventListener('click', function () { return _this2.addAcls().then(function () { return _this2.render(); })["catch"](function (error) { return _this2.renderStatus(error); }); }); return addAclButton; } }, { key: "renderAddDefaultsController", value: function renderAddDefaultsController() { var _this3 = this; var containerElement = this.dom.createElement('div'); containerElement.classList.add(this.classes.defaultsController); var noticeElement = containerElement.appendChild(this.dom.createElement('div')); noticeElement.innerText = 'Sharing for things within the folder currently tracks sharing for the folder.'; noticeElement.classList.add(this.classes.defaultsControllerNotice); var button = containerElement.appendChild(this.dom.createElement('button')); button.innerText = 'Set the sharing of folder contents separately from the sharing for the folder'; button.classList.add(this.classes.bigButton); button.addEventListener('click', function () { return _this3.addDefaults().then(function () { return _this3.render(); }); }); return containerElement; } }, { key: "renderRemoveDefaultsController", value: function renderRemoveDefaultsController() { var _this4 = this; var containerElement = this.dom.createElement('div'); containerElement.classList.add(this.classes.defaultsController); var noticeElement = containerElement.appendChild(this.dom.createElement('div')); noticeElement.innerText = 'Access to things within this folder:'; noticeElement.classList.add(this.classes.defaultsControllerNotice); var button = containerElement.appendChild(this.dom.createElement('button')); button.innerText = 'Set default for folder contents to just track the sharing for the folder'; button.classList.add(this.classes.bigButton); button.addEventListener('click', function () { return _this4.removeDefaults().then(function () { return _this4.render(); })["catch"](function (error) { return _this4.renderStatus(error); }); }); return containerElement; } }, { key: "renderTemporaryStatus", value: function renderTemporaryStatus(message) { var _this5 = this; // @@ TODO Introduce better system for error notification to user https://github.com/solid/mashlib/issues/87 this.statusElement.classList.add(this.classes.aclControlBoxStatusRevealed); this.statusElement.innerText = message; this.statusElement.classList.add(this.classes.temporaryStatusInit); setTimeout(function () { _this5.statusElement.classList.add(_this5.classes.temporaryStatusEnd); }); setTimeout(function () { _this5.statusElement.innerText = ''; }, 5000); } }, { key: "renderStatus", value: function renderStatus(message) { // @@ TODO Introduce better system for error notification to user https://github.com/solid/mashlib/issues/87 this.statusElement.classList.toggle(this.classes.aclControlBoxStatusRevealed, !!message); this.statusElement.innerText = message; } }, { key: "addAcls", value: function () { var _addAcls = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee() { var _this6 = this; var message, aclGraph, _message; return _regenerator["default"].wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: if (!(!this.defaultHolder || !this.defaultACLDoc)) { _context.next = 4; break; } message = 'Unable to find defaults to copy'; debug.error(message); return _context.abrupt("return", Promise.reject(message)); case 4: aclGraph = (0, _acl.adoptACLDefault)(this.targetDoc, this.targetACLDoc, this.defaultHolder, this.defaultACLDoc); aclGraph.statements.forEach(function (st) { return _this6.store.add(st.subject, st.predicate, st.object, _this6.targetACLDoc); }); _context.prev = 6; _context.next = 9; return this.store.fetcher.putBack(this.targetACLDoc); case 9: this.isUsingDefaults = false; return _context.abrupt("return", Promise.resolve()); case 13: _context.prev = 13; _context.t0 = _context["catch"](6); _message = " Error writing back access control file! ".concat(_context.t0); debug.error(_message); return _context.abrupt("return", Promise.reject(_message)); case 18: case "end": return _context.stop(); } } }, _callee, this, [[6, 13]]); })); function addAcls() { return _addAcls.apply(this, arguments); } return addAcls; }() }, { key: "addDefaults", value: function () { var _addDefaults = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee2() { return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: this.defaultsCombo = new _accessGroups.AccessGroups(this.targetDoc, this.targetACLDoc, this, this.store, { defaults: true }); this.defaultsDiffer = true; case 2: case "end": return _context2.stop(); } } }, _callee2, this); })); function addDefaults() { return _addDefaults.apply(this, arguments); } return addDefaults; }() }, { key: "removeAcls", value: function () { var _removeAcls = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee3() { var message; return _regenerator["default"].wrap(function _callee3$(_context3) { while (1) { switch (_context3.prev = _context3.next) { case 0: _context3.prev = 0; _context3.next = 3; return this.store.fetcher["delete"](this.targetACLDoc.uri, {}); case 3: this.isUsingDefaults = true; _context3.prev = 4; _context3.next = 7; return (0, _acl.getProspectiveHolder)(this.targetDoc.uri); case 7: this.prospectiveDefaultHolder = _context3.sent; _context3.next = 13; break; case 10: _context3.prev = 10; _context3.t0 = _context3["catch"](4); // No need to show this error in status, but good to warn about it in console debug.warn(_context3.t0); case 13: _context3.next = 20; break; case 15: _context3.prev = 15; _context3.t1 = _context3["catch"](0); message = "Error deleting access control file: ".concat(this.targetACLDoc, ": ").concat(_context3.t1); debug.error(message); return _context3.abrupt("return", Promise.reject(message)); case 20: case "end": return _context3.stop(); } } }, _callee3, this, [[0, 15], [4, 10]]); })); function removeAcls() { return _removeAcls.apply(this, arguments); } return removeAcls; }() }, { key: "removeDefaults", value: function () { var _removeDefaults = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee4() { var fallbackCombo; return _regenerator["default"].wrap(function _callee4$(_context4) { while (1) { switch (_context4.prev = _context4.next) { case 0: fallbackCombo = this.defaultsCombo; _context4.prev = 1; this.defaultsCombo = null; this.defaultsDiffer = false; _context4.next = 6; return this.save(); case 6: _context4.next = 14; break; case 8: _context4.prev = 8; _context4.t0 = _context4["catch"](1); this.defaultsCombo = fallbackCombo; this.defaultsDiffer = true; debug.error(_context4.t0); return _context4.abrupt("return", Promise.reject(_context4.t0)); case 14: case "end": return _context4.stop(); } } }, _callee4, this, [[1, 8]]); })); function removeDefaults() { return _removeDefaults.apply(this, arguments); } return removeDefaults; }() }, { key: "save", value: function save() { var _this7 = this; // build graph var newAClGraph = (0, _rdflib.graph)(); if (!this.isContainer) { (0, _acl.makeACLGraphbyCombo)(newAClGraph, this.targetDoc, this.mainCombo.byCombo, this.targetACLDoc, true); } else if (this.defaultsCombo && this.defaultsDiffer) { // Pair of controls (0, _acl.makeACLGraphbyCombo)(newAClGraph, this.targetDoc, this.mainCombo.byCombo, this.targetACLDoc, true); (0, _acl.makeACLGraphbyCombo)(newAClGraph, this.targetDoc, this.defaultsCombo.byCombo, this.targetACLDoc, false, true); } else { // Linked controls (0, _acl.makeACLGraphbyCombo)(newAClGraph, this.targetDoc, this.mainCombo.byCombo, this.targetACLDoc, true, true); } var updater = newAClGraph.updater || new _rdflib.UpdateManager(newAClGraph); // save ACL resource return new Promise(function (resolve, reject) { // check acl for acl:Write alert and acl:Control confirm var hasWrite = newAClGraph.any(undefined, _ns["default"].acl('mode'), _ns["default"].acl('Write'), _this7.targetACLDoc); var hasControl = newAClGraph.any(undefined, _ns["default"].acl('mode'), _ns["default"].acl('Control'), _this7.targetACLDoc); var user = (0, _authn.currentUser)(); var webId = user ? user.uri : 'user'; if (!hasWrite) { alert('There is no "Write access" this is not allowed'); return reject(new Error('ACL file save rejected : no acl:Write')); } else if (!(hasControl || confirm('There is no "owner access" -- this is a dangerous situation !!!,' + "\n".concat(webId, ",\nyou may lose access to the resources covered by this ACL !!!") + '\n\nDo you confirm ?'))) { return reject(new Error('ACL file save canceled by user')); } else { // save acl updater.put(_this7.targetACLDoc, newAClGraph.statementsMatching(undefined, undefined, undefined, _this7.targetACLDoc), 'text/turtle', function (uri, ok, message) { if (!ok) { return reject(new Error("ACL file save failed: ".concat(message))); } _this7.store.fetcher.unload(_this7.targetACLDoc); _this7.store.add(newAClGraph.statements); _this7.store.fetcher.requested[_this7.targetACLDoc.uri] = 'done'; // missing: save headers _this7.mainCombo.store = _this7.store; if (_this7.defaultsCombo) { _this7.defaultsCombo.store = _this7.store; } _this7.defaultsDiffer = !!_this7.defaultsCombo && !(0, _acl.sameACL)(_this7.mainCombo.aclMap, _this7.defaultsCombo.aclMap); debug.log('ACL modification: success!'); resolve(); }); } }); } }]); return AccessController; }(); exports.AccessController = AccessController; //# sourceMappingURL=access-controller.js.map