mirror of
https://gitlab.com/wgp/dougal/software.git
synced 2025-12-06 12:47:08 +00:00
226 lines
5.1 KiB
JavaScript
226 lines
5.1 KiB
JavaScript
const Organisation = require('./Organisation');
|
|
|
|
class Organisations {
|
|
|
|
#values = {}
|
|
|
|
#overlord
|
|
|
|
static entries (orgs) {
|
|
return orgs.names().map(name => [name, orgs.get(name)]);
|
|
}
|
|
|
|
constructor (data, overlord) {
|
|
if (data instanceof Organisations) {
|
|
for (const [name, value] of Organisations.entries(data)) {
|
|
this.set(name, new Organisation(value));
|
|
}
|
|
} else if (data instanceof Object) {
|
|
for (const [name, value] of Object.entries(data)) {
|
|
this.set(name, new Organisation(value));
|
|
}
|
|
} else if (data instanceof String) {
|
|
this.set(data, new Organisation());
|
|
} else if (typeof data !== "undefined") {
|
|
throw new Error("Invalid constructor argument");
|
|
}
|
|
|
|
if (overlord) {
|
|
this.#overlord = overlord;
|
|
}
|
|
}
|
|
|
|
get values () {
|
|
return this.#values;
|
|
}
|
|
|
|
get length () {
|
|
return this.names().length;
|
|
}
|
|
|
|
get overlord () {
|
|
return this.#overlord;
|
|
}
|
|
|
|
set overlord (v) {
|
|
this.#overlord = new Organisations(v);
|
|
}
|
|
|
|
/** Get the operations for `name`
|
|
*/
|
|
get (name) {
|
|
const key = Object.keys(this.values).find( k => k.toLowerCase() == name.toLowerCase() ) ?? name;
|
|
return this.values[key];
|
|
}
|
|
|
|
/** Set the operations for `name` to `value`
|
|
*
|
|
* If we have an overlord, ensure we cannot:
|
|
*
|
|
* 1. Add new organisations which the overlord
|
|
* is not a member of
|
|
* 2. Access operations that the overlord is not
|
|
* allowed to access
|
|
*/
|
|
set (name, value) {
|
|
name = String(name).trim();
|
|
const key = Object.keys(this.values).find( k => k.toLowerCase() == name.toLowerCase() ) ?? name;
|
|
const org = new Organisation(value);
|
|
|
|
if (this.overlord) {
|
|
const parent = this.overlord.get(key) ?? this.overlord.get("*");
|
|
if (parent) {
|
|
this.values[key] = parent.filter(org);
|
|
}
|
|
} else {
|
|
this.values[key] = new Organisation(value);
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
/** Enable the operation `op` in all organisations
|
|
*/
|
|
enableOperation (op) {
|
|
if (this.overlord) {
|
|
Object.keys(this.#values)
|
|
.filter( key => (this.overlord.get(key) ?? this.overlord.get("*"))?.[op] )
|
|
.forEach( key => this.#values[key][op] = true );
|
|
} else {
|
|
Object.values(this.#values).forEach( org => org[op] = true );
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
/** Disable the operation `op` in all organisations
|
|
*/
|
|
disableOperation (op) {
|
|
Object.values(this.#values).forEach( org => org[op] = false );
|
|
|
|
return this;
|
|
}
|
|
|
|
/** Create a new organisation object limited by the caller's rights
|
|
*
|
|
* The spawned Organisations instance will have the same organisations
|
|
* and rights as the caller minus the applied `mask`. With the default
|
|
* mask, the spawned object will inherit all rights except for `edit`
|
|
* rights.
|
|
*
|
|
* The "*" organisation must be explicitly assigned. It is not inherited.
|
|
*/
|
|
spawn (mask = {read: true, write: true, edit: false}) {
|
|
|
|
const parent = new Organisations();
|
|
const wildcard = this.get("*").edit; // If true, we can spawn everywhere
|
|
|
|
this.entries().forEach( ([k, v]) => {
|
|
// if (k != "*") { // This organisation is not inherited
|
|
if (v.edit || wildcard) { // We have the right to spawn in this organisation
|
|
const o = new Organisation({
|
|
read: v.read && mask.read,
|
|
write: v.write && mask.write,
|
|
edit: v.edit && mask.edit
|
|
});
|
|
parent.set(k, o);
|
|
}
|
|
// }
|
|
});
|
|
|
|
return new Organisations({}, parent);
|
|
}
|
|
|
|
remove (name) {
|
|
const key = Object.keys(this.values).find( k => k.toLowerCase() == name.toLowerCase() ) ?? name;
|
|
delete this.values[key];
|
|
}
|
|
|
|
/** Return the list of organisation names
|
|
*/
|
|
names () {
|
|
return Object.keys(this.values);
|
|
}
|
|
|
|
/** Same as this.get(name)
|
|
*/
|
|
value (name) {
|
|
return this.values[name];
|
|
}
|
|
|
|
/** Same as Object.prototype.entries
|
|
*/
|
|
entries () {
|
|
return this.names().map( name => [ name, this.value(name) ] );
|
|
}
|
|
|
|
/** Return true if the named organisation is present
|
|
*/
|
|
has (name) {
|
|
return Boolean(this.value(name));
|
|
}
|
|
|
|
/** Return only those of our organisations
|
|
* and operations present in `other`
|
|
*/
|
|
filter (other) {
|
|
const filteredOrganisations = new Organisations();
|
|
|
|
const wildcard = other.value("*");
|
|
|
|
for (const [name, org] of this.entries()) {
|
|
const ownOrg = other.value(name) ?? wildcard;
|
|
if (ownOrg) {
|
|
filteredOrganisations.set(name, org.filter(ownOrg))
|
|
}
|
|
}
|
|
|
|
return filteredOrganisations;
|
|
}
|
|
|
|
/** Return only those organisations
|
|
* that have access to the required
|
|
* operation
|
|
*/
|
|
accessToOperation (op) {
|
|
const filteredOrganisations = new Organisations();
|
|
|
|
for (const [name, org] of this.entries()) {
|
|
if (org[op]) {
|
|
filteredOrganisations.set(name, org);
|
|
}
|
|
}
|
|
|
|
return filteredOrganisations;
|
|
}
|
|
|
|
toJSON () {
|
|
const obj = {};
|
|
for (const key in this.values) {
|
|
obj[key] = this.values[key].toJSON();
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
toString (replacer, space) {
|
|
return JSON.stringify(this.toJSON(), replacer, space);
|
|
}
|
|
|
|
*[Symbol.iterator] () {
|
|
for (const [name, operations] of this.entries()) {
|
|
yield {name, operations};
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
if (typeof module !== 'undefined' && module.exports) {
|
|
module.exports = Organisations; // CJS export
|
|
}
|
|
|
|
// ESM export
|
|
if (typeof exports !== 'undefined' && !exports.default) {
|
|
exports.default = Organisations; // ESM export
|
|
}
|