openvibers/openvibe.services Commits

Services: OpenVibe.Zone's zones in the console, with delete for project admins (contracts 0.173.0) (#60)

OP OpenVibers committed 29 days ago · 3f2d5787ec · 6 files, +19 −13

* Services: OpenVibe.Zone's zones in the console, with delete for project admins (contracts 0.173.0)

OpenVibe.Zone is an authority (contracts 0.173.0): the console lists a project's zones (kind `zone.object-zone`, from Zone's `zone.resource.read` index), and a project admin can delete a zone through Zone's control API (`zone.resource.control`). The default zone offers no action: it goes only with its environment.

- `portal.js`: `zone.object-zone` in KIND_ACTIONS (admins; Delete except for deleting, deleted and default zones); `provisioning` and `deleting` badges.
- contracts v0.173.0 (the registry picks Zone up from its manifest; nothing is hand-listed).
- Tests: authorities (twelve active resource-read capabilities, eleven authorities, Zone's origin) and control (Zone takes control).

`npm test`: 44/44.

* Services: STATUS names the pinned contracts (v0.173.0)

Changes

ddiff --git a/STATUS.json b/STATUS.json
iindex e4e3b63..10dd5ea 100644
---- a/STATUS.json
++++ b/STATUS.json
@@@ -7,11 +7,11 @@
"runtime": "node 22, express 4, PostgreSQL 18 (openvibe-sdk/db)",
"port": 4930,
"domain": "openvibe.services",
-- "contracts": "openvibe-contracts v0.154.0",
++ "contracts": "openvibe-contracts v0.173.0",
"sdk": "openvibe-sdk v0.44.0",
"shared": "openvibe-shared v4.1.3",
"packages": [
-- "openvibe-contracts v0.154.0",
++ "openvibe-contracts v0.173.0",
"openvibe-sdk v0.44.0",
"openvibe-shared v4.1.3"
],
ddiff --git a/package-lock.json b/package-lock.json
iindex 3b165e5..4ba511e 100644
---- a/package-lock.json
++++ b/package-lock.json
@@@ -16,7 +16,7 @@
"express-rate-limit": "^7.5.0",
"helmet": "^8.1.0",
"iovalkey": "^0.4.0",
-- "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.170.0",
++ "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.173.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.44.0",
"openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.1.3",
"pg": "^8.23.0"
@@@ -890,9 +890,9 @@
}
},
"node_modules/openvibe-contracts": {
-- "version": "0.170.0",
-- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.170.0",
-- "integrity": "sha512-EpOUiqFSYBZ1p7aQTek1IYyHcbD9QT0pdr492+teWvZf425xXSMu7+DQsnzgMP8JdTmdS2VMxoirrBwMUGxjrw==",
++ "version": "0.173.0",
++ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.173.0",
++ "integrity": "sha512-6zHbU9zghIYDd3PPGtgMTsIgxrWwsoBHO/rvuLW1rghr6kRK6VwCmSMZRcjQbcPODPH1XrUAFuLg/T1K4nOCMQ==",
"license": "AGPL-3.0-only",
"dependencies": {
"ajv": "^8.17.1",
ddiff --git a/package.json b/package.json
iindex 4aa3426..a1bd345 100644
---- a/package.json
++++ b/package.json
@@@ -27,7 +27,7 @@
"express-rate-limit": "^7.5.0",
"helmet": "^8.1.0",
"iovalkey": "^0.4.0",
-- "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.170.0",
++ "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.173.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.44.0",
"openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.1.3",
"pg": "^8.23.0"
ddiff --git a/server/http/portal.js b/server/http/portal.js
iindex 1527137..b07d749 100644
---- a/server/http/portal.js
++++ b/server/http/portal.js
@@@ -51,6 +51,9 @@ const KIND_ACTIONS = {
'space.site': { admins: true, actions: (x) => (x.state === 'deleted' ? [] : [['delete', 'Delete…']]) },
'space.deploy': { admins: true, actions: (x) => (x.state === 'deleted' ? [] : [['delete', 'Delete…']]) },
'space.domain': { admins: true, actions: () => [['delete', 'Delete…']] },
++ // A zone (OpenVibe.Zone, contracts 0.173.0): delete it and every object in it, for a project admin. The default zone
++ // goes only with its environment, so it offers nothing.
++ 'zone.object-zone': { admins: true, actions: (x) => (['deleting', 'deleted'].includes(x.state) || /^default \(/.test(String(x.name || '')) ? [] : [['delete', 'Delete…']]) },
default: { actions: (x) => [x.state === 'paused' ? ['resume', 'Resume'] : ['suspend', 'Suspend'], ['delete', 'Delete…']] },
};
@@@ -66,6 +69,7 @@ const RESOURCES_PER_PAGE = 50;
const STATE_KIND = {
ready: 'ok', active: 'ok', published: 'ok', live: 'ok', enabled: 'ok', online: 'ok', open: 'ok',
draft: 'warn', queued: 'warn', pending: 'warn', paused: 'warn', processing: 'warn', deprecated: 'warn', offline: 'warn',
++ provisioning: 'warn', deleting: 'warn',
failed: 'bad', revoked: 'bad', deleted: 'bad', disabled: 'bad', archived: 'bad', suspended: 'bad',
};
const stateBadge = (s) => badge(s, STATE_KIND[s] || '');
ddiff --git a/test/authorities.test.js b/test/authorities.test.js
iindex c5c7af6..f08b9a8 100644
---- a/test/authorities.test.js
++++ b/test/authorities.test.js
@@@ -17,14 +17,15 @@ const { createAuthorities } = require('../server/authorities');
const { check, done } = require('./helpers/app');
const quiet = { warn() {}, log() {}, error() {} };
--// Static hosting's index is Space's since contracts 0.150.0 (the engine moved from Host, plan T20).
--const AUTHORITIES = ['actor', 'bot', 'chat', 'community', 'events', 'media', 'network', 'openre', 'space', 'watch'];
++// Static hosting's index is Space's since contracts 0.150.0 (the engine moved from Host, plan T20); Zone's zones since 0.173.0.
++const AUTHORITIES = ['actor', 'bot', 'chat', 'community', 'events', 'media', 'network', 'openre', 'space', 'watch', 'zone'];
async function main() {
-- await check('the pin lists eleven active <id>.resource.read capabilities, ten of them authorities', () => {
++ await check('the pin lists twelve active <id>.resource.read capabilities, eleven of them authorities', () => {
const ids = contracts.capabilities.manifests.filter((c) => /^([a-z][a-z0-9-]{0,31})\.resource\.read$/.test(c.id) && c.status === 'active').map((c) => c.id).sort();
assert.deepStrictEqual(ids, ['actor.resource.read', 'bot.resource.read', 'chat.resource.read', 'community.resource.read', 'events.resource.read',
-- 'media.resource.read', 'network.resource.read', 'openre.resource.read', 'services.resource.read', 'space.resource.read', 'watch.resource.read']);
++ 'media.resource.read', 'network.resource.read', 'openre.resource.read', 'services.resource.read', 'space.resource.read', 'watch.resource.read',
++ 'zone.resource.read']);
assert.strictEqual(contracts.capabilities.get('host.resource.read').status, 'retired', 'Host serves no hosting index since 0.150.0');
assert.strictEqual(contracts.capabilities.get('codes.resource.read').status, 'retired', 'Codes owns no resources since 0.113.0');
// services.resource.read is Services' own id; Services is never its own authority (the next check).
@@@ -45,6 +46,7 @@ async function main() {
chat: 'http://127.0.0.1:4400',
openre: 'http://127.0.0.1:4500',
community: 'http://127.0.0.1:4200',
++ zone: 'http://127.0.0.1:5050',
};
for (const [id, origin] of Object.entries(expected)) {
const a = registry.get(id);
ddiff --git a/test/control.test.js b/test/control.test.js
iindex 9931a10..febb6e5 100644
---- a/test/control.test.js
++++ b/test/control.test.js
@@@ -88,10 +88,10 @@ function registryOf(list) {
const prj = ids.newId('project');
const object = resources.format({ service: 'media', project_id: prj, type: 'object', id: ids.newId('media') });
-- await check('only an authority with an active <id>.resource.control takes control requests (Watch 0.165, Events 0.168, Actor and Media 0.169, Space 0.170)', async () => {
++ await check('only an authority with an active <id>.resource.control takes control requests (Watch 0.165, Events 0.168, Actor and Media 0.169, Space 0.170, Zone 0.173)', async () => {
const real = createAuthorities(t.config, { log: { warn() {} } });
assert.ok(real.size() > 0);
-- const TAKES = { watch: 'watch.resource.control', events: 'events.resource.control', actor: 'actor.resource.control', media: 'media.resource.control', space: 'space.resource.control' };
++ const TAKES = { watch: 'watch.resource.control', events: 'events.resource.control', actor: 'actor.resource.control', media: 'media.resource.control', space: 'space.resource.control', zone: 'zone.resource.control' };
for (const a of real.list()) assert.strictEqual(a.control, TAKES[a.id] || null, `${a.id}: the control capability in the pinned contracts`);
});