// $Id:
// @ts-check
"use strict";
import { cacheStore } from "./cache.internal.js";
import { RestServices } from "../tools/RestServices.js";
import { ApiResponse } from "../tools/ApiResponse.js";
import { cnContext } from "./cnContext.js";
/**
* @fileoverview
* - Scope domain classes and services.
* - Scope management for admin as well as user.
*
*/
/**
*
* @category COLNEO infohub
*
* @classdesc Licence aggregate (licenced_userid, etc.).
* @example {
* "contract": "",
* "created": "2025-01-01T00:00:00Z",
* "createdby": "user@example.com",
* "expirated": null,
* "id": "00000000-0000-0000-0000-000000000000",
* "licenced_userid": ["user@example.com"],
* "licencee": {
* "address": "{\"street\":\"...\", \"city\":\"...\", \"zip\":\"...\"}",
* "email": "info@example.com",
* "name": "ACME"
* },
* "maxpermissions": "edit",
* "maxseats": 0,
* "module": "objecttypes",
* "scope": "cn_dv",
* "startdate": "2025-01-01T00:00:00Z",
* "updated": "2025-01-01T00:00:00Z",
* "updatedby": "user@example.com"
* }
*/
export class Licence {
constructor(data = /** @type {object[]} */ ([])) {
this._data = data;
}
setData(data = /** @type {object[]} */ ([])) {
this._data = data;
}
getData() {
return this._data;
}
}
/**
*
* @category COLNEO infohub
*
* @classdesc Scope info aggregate (name, description, etc.).
* @property {object} _data - Scope info data
* @example {
* "id": "scope1",
* "name": "Scope 1",
* "description": "Scope 1 description",
* "createdon": "2025-01-01",
* "updatedon": "2025-01-01",
* "createdby": "user1",
* "updatedby": "user1"
* }
*/
export class ScopeInfo {
/**
* @since 09.2025, aab
*/
constructor(data = /** @type {object} */ ({})) {
this._data = data;
}
setData(data = /** @type {object} */ ({})) {
this._data = data;
}
getData() {
return this._data;
}
}
/**
*
* @category COLNEO infohub
*
* @property {ScopeInfo} info - Scope info
* @property {Licence[]} licences - Licences
* @classdesc Scope aggregate (info, licences, userGroups, userRoles).
* @example {
* "info": {
* "id": "scope1",
* "name": "Scope 1",
* "description": "Scope 1 description",
* "createdon": "2025-01-01",
* "updatedon": "2025-01-01",
* "createdby": "user1",
* "updatedby": "user1"
* },
* "licences": [
* {
* "contract": "",
* "created": "2025-01-01T00:00:00Z",
* "createdby": "user@example.com",
* "expirated": null,
* "id": "00000000-0000-0000-0000-000000000000",
* "licenced_userid": ["user@example.com"],
* "licencee": {
* "address": "{\"street\":\"...\", \"city\":\"...\", \"zip\":\"...\"}",
* "email": "info@example.com",
* "name": "ACME"
* },
* "maxpermissions": "edit",
* "maxseats": 0,
* "module": "objecttypes",
* "scope": "cn_dv",
* "startdate": "2025-01-01T00:00:00Z",
* "updated": "2025-01-01T00:00:00Z",
* "updatedby": "user@example.com"
* },
* ]
* }
*/
export class Scope {
/**
* @since 09.2025, aab
*/
constructor(info = {}, licences = []) {
this.info = info;
this.licences = Array.isArray(licences) ? licences : [];
}
/**
* Get user IDs
*
* @returns {string[]}
*/
getUserIds() {
const users = new Set();
for (const lic of this.licences) {
const list = Array.isArray(lic.licenced_userid)
? lic.licenced_userid
: lic.licenced_userid
? [lic.licenced_userid]
: [];
for (const u of list) if (typeof u === "string" && u) users.add(u);
}
return Array.from(users);
}
}
/**
*
* @category COLNEO infohub
*
* @classdesc
* Scope services.
*
*/
export class ScopeServices {
/**
* @since 1.0, 09.2025, aab
* @param {cnContext} ctx - Context instance
*/
constructor(ctx) {
this._ctx = ctx;
this.#cache = cacheStore;
}
#cache;
/**
*
* Get scope from COLNEO infohub
*
* @returns {Promise<ApiResponse>} data: Scope
*
* @param {string} id - Scope ID
*
*/
async getScope(id) {
if (!id) {
return new ApiResponse(400, null);
}
const InfoUrl = `${this._ctx.getServiceUrl(cnContext.SERVICE.IDP)}/admin/scopes/${id}`;
const LicencesUrl = `${this._ctx.getServiceUrl(cnContext.SERVICE.IDP)}/admin/licences?scope=${id}`;
try {
const [infoRes, licRes] = await Promise.all([
RestServices.makeApiCall(
this._ctx.getToken(),
RestServices.METHODS.GET,
InfoUrl
),
RestServices.makeApiCall(
this._ctx.getToken(),
RestServices.METHODS.GET,
LicencesUrl
),
]);
if (infoRes.status < 300 && licRes.status < 300) {
const info = new ScopeInfo(infoRes.data || {});
const licences = new Licence(licRes.data || []);
const scope = new Scope(info.getData(), licences.getData());
return new ApiResponse(200, scope);
}
return new ApiResponse(infoRes.status, null);
} catch (_) {
return new ApiResponse(500, null);
}
}
/**
* Get scope groups
* @param {string} id - Scope ID
* @param {object} query - Query object containing filter, members, etc.
* @returns {Promise<ApiResponse>}
*/
async getScopeGroups(id, query) {
if (!id) {
return new ApiResponse(400, null);
}
const queryString = this.#buildQueryString(query);
const url = `${this._ctx.getServiceUrl("usr")}/${id}/usergroups`;
try {
const res = await RestServices.makeApiCall(
this._ctx.getToken(),
RestServices.METHODS.GET,
url + queryString
);
if (res.status < 300) {
return new ApiResponse(200, res.data);
}
return new ApiResponse(res.status, null);
} catch (_) {
return new ApiResponse(500, null);
}
}
/**
* Get scope roles
* @param {string} id - Scope ID
* @param {object} query - Query object containing filter, members, etc.
* @returns {Promise<ApiResponse>}
*/
async getScopeRoles(id, query) {
if (!id) {
return new ApiResponse(400, null);
}
const queryString = this.#buildQueryString(query);
try {
const url = `${this._ctx.getServiceUrl("usr")}/${id}/userroles`;
const res = await RestServices.makeApiCall(
this._ctx.getToken(),
RestServices.METHODS.GET,
url + queryString
);
if (res.status < 300) {
return new ApiResponse(200, res.data);
}
return new ApiResponse(res.status, null);
} catch (_) {
return new ApiResponse(500, null);
}
}
/**
* Create scope
* @param {object} ScopeInfo_new - Scope information
* @param {string} [ScopeInfo_new.name] - Scope name
* @param {string} [ScopeInfo_new.description] - Scope description
* @returns {Promise<ApiResponse>}
*/
async createScope(ScopeInfo_new) {
if (!ScopeInfo_new?.name) {
return new ApiResponse(400, null);
}
try {
const url = `${this._ctx.getServiceUrl("idp")}/admin/scopes`;
const res = await RestServices.makeApiCall(
this._ctx.getToken(),
RestServices.METHODS.POST,
url,
ScopeInfo_new
);
if (res.status < 300) {
return new ApiResponse(200, res.data);
}
return new ApiResponse(res.status, null);
} catch (_) {
return new ApiResponse(500, null);
}
}
/**
* Update scope
* @param {string} id - Scope ID
* @param {object} ScopeInfo_update - Scope information
* @param {string} [ScopeInfo_update.name] - Scope name
* @param {string} [ScopeInfo_update.description] - Scope description
* @returns {Promise<ApiResponse>}
*/
async updateScope(id, ScopeInfo_update) {
if (!id || !ScopeInfo_update?.name) {
return new ApiResponse(400, null);
}
try {
const url = `${this._ctx.getServiceUrl("idp")}/admin/scopes/${id}`;
const res = await RestServices.makeApiCall(
this._ctx.getToken(),
RestServices.METHODS.PUT,
url,
ScopeInfo_update
);
if (res.status < 300) {
return new ApiResponse(200, res.data);
}
return new ApiResponse(res.status, null);
} catch (_) {
return new ApiResponse(500, null);
}
}
/**
* Delete scope
* @param {string} id - Scope ID
* @returns {Promise<ApiResponse>}
*/
async deleteScope(id) {
if (!id) {
return new ApiResponse(400, null);
}
try {
const url = `${this._ctx.getServiceUrl("idp")}/admin/scopes/${id}`;
const res = await RestServices.makeApiCall(
this._ctx.getToken(),
RestServices.METHODS.DELETE,
url
);
if (res.status < 300) {
return new ApiResponse(200, res.data);
}
return new ApiResponse(res.status, null);
} catch (_) {
return new ApiResponse(500, null);
}
}
/**
* Query string builder
* @param {object} [query] - Query object containing filter, members, etc.
* @param {string} defaultMember - Default member value if not specified
* @returns {string} - Properly formatted query string
*/
#buildQueryString(
query = /** @type {object} */ ({}),
defaultMember = "info"
) {
let queryString = "";
let c = "?";
if (query["filter"]) {
queryString += c + "filter=" + encodeURIComponent(query["filter"]);
c = "&";
}
if (query["members"]) {
let membersString = query["members"];
if (defaultMember && !membersString.includes(defaultMember)) {
membersString = membersString + "," + defaultMember;
}
queryString += c + "members=" + encodeURIComponent(membersString);
c = "&";
} else if (defaultMember) {
queryString += c + "members=" + encodeURIComponent(defaultMember);
c = "&";
}
return queryString;
}
}
Source