UNPKG

d2

Version:

Javascript library for DHIS2

433 lines (388 loc) 17.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _UserAuthorities = _interopRequireDefault(require("./UserAuthorities")); var _UserSettings = _interopRequireDefault(require("./UserSettings")); var _defaultConfig = require("../defaultConfig"); var _UserDataStore = _interopRequireDefault(require("../datastore/UserDataStore")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _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); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } var models = Symbol('models'); var propertiesToIgnore = new Set(['userCredentials', 'userGroups', 'userRoles', 'organisationUnits', 'dataViewOrganisationUnits']); /** * Authorities lookup map to be used for determining the list of authorities to check. * * @private * @type {Object.<string, string[]>} * @readonly * @typedef {Object} AuthorityType * @memberof module:current-user */ var authTypes = { READ: ['READ'], CREATE: ['CREATE', 'CREATE_PUBLIC', 'CREATE_PRIVATE'], CREATE_PUBLIC: ['CREATE_PUBLIC'], CREATE_PRIVATE: ['CREATE_PRIVATE'], DELETE: ['DELETE'], UPDATE: ['UPDATE'], EXTERNALIZE: ['EXTERNALIZE'] /** * Create a map of `propertyName` -> `Symbol`. This map is used to hide values for these properties. We will instead add * add convenience methods for these properties. (e.g. the `userGroups` property on the currentUser object becomes * `getUserGroups()` * * @private * @type {Object.<string, Symbol>} */ }; var propertySymbols = Array.from(propertiesToIgnore).reduce(function (result, property) { result[property] = Symbol(property); return result; }, {}); /** * Creates a map of propertyName and propertyValue pairs of properties to be attached to the currentUser object. * These are all the regular properties that are returned when calling `api/27/me` but with the `userCredentials` * merged onto the same object. * * What would originally be `currentUser.userCredentials.username` would just be `currentUser.username` * * @private * @param {Object} currentUserObject The user payload as it is received from the api. https://play.dhis2.org/demo/api/27/me * @returns {Object} A map with propertyName/propertyValue pairs. */ function getPropertiesForCurrentUserObject(currentUserObject) { var properties; // The userCredentials object on the userObject is confusing so we set the properties straight onto the currentUser // object itself if (currentUserObject.userCredentials) { properties = Object.assign({}, currentUserObject.userCredentials, currentUserObject); } else { properties = Object.assign({}, currentUserObject); } return Object.keys(properties).reduce(function (result, property) { if (propertiesToIgnore.has(property)) { if (properties[property].map) { result[propertySymbols[property]] = properties[property].map(function (value) { return value.id; }); } } else { result[property] = properties[property]; } return result; }, {}); } /** * Checks the noCreateAllowedFor list if the object can be created. * * @private * @param {ModelDefinition} modelDefinition The modelDefinition to check for. * @returns {boolean} True when it exists in the list, false otherwise. */ function isInNoCreateAllowedForList(modelDefinition) { return Boolean(modelDefinition && _defaultConfig.noCreateAllowedFor.has(modelDefinition.name)); } /** * Represents the current logged in user * * @memberof module:current-user */ var CurrentUser = /*#__PURE__*/ function () { /** * Creates the CurrentUser. * * @param {Object} userData Payload as returned from the api when requesting the currentUser object. * @param {UserAuthorities} userAuthorities The UserAuthorities object for the currentUsers authorities. * @param {ModelDefinition[]} modelDefinitions The modelDefinitions that need to be used for checking access. * @param {UserSettings} settings The userSettings object to be set onto the current user object. */ function CurrentUser(userData, userAuthorities, modelDefinitions, settings) { _classCallCheck(this, CurrentUser); Object.assign(this, getPropertiesForCurrentUserObject(userData)); /** * * @type {UserAuthorities} */ this.authorities = userAuthorities; this[models] = modelDefinitions; /** * Contains a reference to a `UserSettings` instance that can be used * to retrieve and save system settings. * @type {UserSettings} * @description * ```js * d2.currentUser.userSettings.get('keyUiLocale') * .then(userSettingsValue => { * console.log('UI Locale: ' + userSettingsValue); * }); * ``` */ this.userSettings = settings; /** * Contains a reference to {@link module:current-user.UserDataStore UserDataStore} * @type UserDataStore * */ this.dataStore = _UserDataStore.default.getUserDataStore(); } /** * Get a list of group ids the current user belongs to. * * @returns {Array} The list of ids of all the user's groups. */ _createClass(CurrentUser, [{ key: "getUserGroupIds", value: function getUserGroupIds() { return this[propertySymbols.userGroups]; } /** * Get a ModelCollection of userGroup models that are assigned to the currentUser * * The user groups are lazy loaded on init of the library. This method can be used to load the full representation * of the userGroups. * * The request done is equivalent do doing https://play.dhis2.org/demo/api/27/me.json?fields=userGroups[:all] * * @param {Object} [listOptions={}] Additional query parameters that should be send with the request. * @returns {Promise<ModelCollection>} The model collection that contains the user's groups. */ }, { key: "getUserGroups", value: function getUserGroups() { var listOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var userGroupIds = this[propertySymbols.userGroups]; return this[models].userGroup.list(Object.assign({ paging: false }, listOptions, { filter: ["id:in:[".concat(userGroupIds.join(','), "]")] })); } /** * Get a ModelCollection of userRole models that are assigned to the currentUser * * The user roles are lazy loaded on init of the library. This method can be used to load the full representation * of the userGroups. * * The request done is equivalent do doing https://play.dhis2.org/demo/api/27/me.json?fields=userCredentials[userRoles[:all]] * * @returns {Promise<ModelCollection>} A ModelCollection that contains the user's groups. */ }, { key: "getUserRoles", value: function getUserRoles() { var userRoleIds = this[propertySymbols.userRoles]; return this[models].userRole.list({ filter: ["id:in:[".concat(userRoleIds.join(','), "]")], paging: false }); } /** * Requests a users primary organisation units from the api. * * The users organisation units are lazy loaded on init of the library (just the ids). This method can be used to * load the full representation of the organisationUnits. * * @param {Object} [listOptions={}] Additional query parameters that should be send with the request. * @returns {Promise<ModelCollection>} A ModelCollection that contains the user's organisationUnits. */ }, { key: "getOrganisationUnits", value: function getOrganisationUnits() { var listOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var organisationUnitsIds = this[propertySymbols.organisationUnits]; return this[models].organisationUnit.list(Object.assign({ fields: ':all,displayName,path,children[id,displayName,path,children::isNotEmpty]', paging: false }, listOptions, { filter: ["id:in:[".concat(organisationUnitsIds.join(','), "]")] })); } /** * Requests a users data view organisation units from the api. * * The users data view organisation units are lazy loaded on init of the library (just the ids). This method can * be used to load the full representation of the dataViewOrganisationUnits. * * @param {Object} [listOptions={}] Additional query parameters that should be send with the request. * @returns {Promise<ModelCollection>} A ModelCollection that contains the user's dataViewOrganisationUnits. */ }, { key: "getDataViewOrganisationUnits", value: function getDataViewOrganisationUnits(listOptions) { var organisationUnitsIds = this[propertySymbols.dataViewOrganisationUnits]; return this[models].organisationUnit.list(Object.assign({ fields: ':all,displayName,path,children[id,displayName,path,children::isNotEmpty]', paging: false }, listOptions, { filter: ["id:in:[".concat(organisationUnitsIds.join(','), "]")] })); } /** * Helper function to check if the currentUser can perform an action. * * A schema from the api defines the authorities as follows: * "authorities": [ * { * "type": "CREATE_PUBLIC", * "authorities": [ * "F_DATAELEMENT_PUBLIC_ADD" * ] * }, { * "type": "CREATE_PRIVATE", * "authorities": [ * "F_DATAELEMENT_PRIVATE_ADD" * ] * }, { * "type": "DELETE", * "authorities": [ * "F_DATAELEMENT_DELETE" * ] * } * * ], * * So for example, when asking for `currentUser.canCreate(modelDefinition)` we look at the authorities map for CREATE, we * collect the authorities from the schema based on the values of `CREATE`. So in the case of above schema authorities * we take the authorities for 'CREATE_PUBLIC' and 'CREATE_PRIVATE' and check if the user has at least one of the * authorities in the combined list. If we had asked for `currentUser.canCreatePrivate(modelDefinition)` we would only * need to check if the user has `F_DATAELEMENT_PRIVATE_ADD` However for just create the user could still create when he * has either private or public. * * @private * @param {AuthorityType} authorityType The type of authority to check for. * @param {ModelDefinition} modelDefinition The ModelDefinition for the type of object that the authority should * be checked for. * @returns {boolean} True when the user has the authority to perform the action, otherwise false. */ }, { key: "checkAuthorityForType", value: function checkAuthorityForType(authorityType, modelDefinition) { var _this = this; if (!modelDefinition || !Array.isArray(modelDefinition.authorities)) { return false; } return modelDefinition.authorities // Filter the correct authority to check for from the model .filter(function (authority) { return authorityType.some(function (authToHave) { return authToHave === authority.type; }); }) // Check the left over schema authority types .some(function (schemaAuthority) { return schemaAuthority.authorities.some(function (authorityToCheckFor) { return _this.authorities.has(authorityToCheckFor); }); } // Check if one of the schema authorities are available in the users authorities ); } /** * Helper method to first check the special "not allowed to create list" before checking the users authorities. * * @private * @param {AuthorityType} authType The type of authority that should be checked. (CREATE, CREATE_PRIVATE * or CREATE_PUBLIC) * @param {ModelDefinition} modelDefinition The modelDefinition that the authorities should be checked for. * @returns {boolean} True when the user has the permission to create the object */ }, { key: "checkCreateAuthorityForType", value: function checkCreateAuthorityForType(authType, modelDefinition) { // When the modelDefinition is mentioned in the the list of modelTypes that are not // allowed to be created we return false if (isInNoCreateAllowedForList(modelDefinition)) { return false; } // Otherwise we check using the normal procedure for checking authorities return this.checkAuthorityForType(authType, modelDefinition); } /** * Check if the user has the authority to create objects of a type of Model (based on it's modelDefinition) * If the object supports public and private objects then both are checked, and the method will return true if one * of them is true. (e.g. will also return true if the user can only create private objects) * * @param {ModelDefinition} modelDefinition The modelDefinition that the authorities should be checked for. * @returns {boolean} True when the user has the permission to create the object */ }, { key: "canCreate", value: function canCreate(modelDefinition) { return this.checkCreateAuthorityForType(authTypes.CREATE, modelDefinition); } /** * Check if the user has the authority to create public objects of a type of Model (based on it's modelDefinition) * * @param {ModelDefinition} modelDefinition The modelDefinition that the authorities should be checked for. * @returns {boolean} True when the user has the permission to create the object */ }, { key: "canCreatePublic", value: function canCreatePublic(modelDefinition) { return this.checkCreateAuthorityForType(authTypes.CREATE_PUBLIC, modelDefinition); } /** * Check if the user has the authority to create private objects of a type of Model (based on it's modelDefinition) * * @param {ModelDefinition} modelDefinition The modelDefinition that the authorities should be checked for. * @returns {boolean} True when the user has the permission to create the object */ }, { key: "canCreatePrivate", value: function canCreatePrivate(modelDefinition) { return this.checkCreateAuthorityForType(authTypes.CREATE_PRIVATE, modelDefinition); } /** * Check if the user has the authority to delete objects of a type of Model (based on it's modelDefinition) * * @param {ModelDefinition} modelDefinition The modelDefinition that the authorities should be checked for. * @returns {boolean} True when the user has the permission to delete the object * * @deprecated Delete should be checked through the `Model.access.delete` property instead, as that also takes into * account sharing. Just checking if the user has the authority to delete a specific object does not take into account * the full ACL. */ }, { key: "canDelete", value: function canDelete(modelDefinition) { return this.checkAuthorityForType(authTypes.DELETE, modelDefinition); } /** * Check if the user has the authority to update objects of a type of Model (based on it's modelDefinition) * * @param {ModelDefinition} modelDefinition The modelDefinition that the authorities should be checked for. * @returns {boolean} True when the user has the permission to update the object * * @deprecated Update should be checked through the `Model.access.update` property instead, as that also takes into * account sharing. Just checking if the user has the authority to update a specific object does not take into account * the full ACL. */ }, { key: "canUpdate", value: function canUpdate(modelDefinition) { if (this.checkAuthorityForType(authTypes.UPDATE, modelDefinition)) { return true; } return this.checkAuthorityForType(authTypes.CREATE, modelDefinition); } /** * Factory method for creating a CurrentUser instance * * @param {Object} userData Payload as returned from the api when requesting the currentUser object. * @param {string[]} authorities A list of authorities that the currentUser has. * @param {ModelDefinition[]} modelDefinitions The modelDefinitions that need to be used for checking access. * @param {Object} userSettings Payload as returned from the api when request the userSettings * @returns {CurrentUser} The created CurrentUser object based on the data given. */ }], [{ key: "create", value: function create(userData, authorities, modelDefinitions, userSettings) { return new CurrentUser(userData, _UserAuthorities.default.create(authorities), modelDefinitions, new _UserSettings.default(userSettings)); } }]); return CurrentUser; }(); var _default = CurrentUser; exports.default = _default; //# sourceMappingURL=CurrentUser.js.map