openvibers/openvibe.quest Commits

Quest: Publish a video and Share a picture (mediahub.video.published, mediahub.picture.uploaded; contracts 0.196.0) (#59)

OP OpenVibers committed 28 days ago · 4a3f495a4c · 4 files, +31 −0

OpenVibe.Video and OpenVibe.Pics join the quest log: a person whose video is public for the first time gets
Publish a video (badge Premiere, 15 OpenCoins); one who uploads a picture while signed in gets Share a picture
(badge Snapshot, 5 OpenCoins). MediaHub publishes both since MediaHub#83.

Changes

ddiff --git a/README.md b/README.md
iindex 7d2bc8b..9a676a9 100644
---- a/README.md
++++ b/README.md
@@@ -138,6 +138,8 @@ OpenVibe.Events delivers an event when a site really does something. Quest count
| `inventory.item.equipped` | OpenVibe.Inventory | `payload.owner` |
| `bot.robot.online` | OpenVibe.Bot | `payload.owner`, the robot's owner (Bot names it since contracts 0.192.0) |
| `games.world.published` | OpenVibe.Games | `payload.owner`, who published a creator world for the first time (contracts 0.194.0) |
++| `mediahub.video.published` | OpenVibe.Video (MediaHub) | `payload.owner`, whose upload is public and ready for the first time (contracts 0.196.0) |
++| `mediahub.picture.uploaded` | OpenVibe.Pics (MediaHub) | `payload.owner`, who uploaded a picture while signed in (contracts 0.196.0) |
**App quests** (contracts 0.193.0, [server/quests/app-quests.js](server/quests/app-quests.js)): a developer app defines
quests on its own project's events with an app token (audience `openvibe.quest`, capability `quest.app_quest.manage`).
ddiff --git a/server/quests/apply.js b/server/quests/apply.js
iindex dab382a..6eb6c02 100644
---- a/server/quests/apply.js
++++ b/server/quests/apply.js
@@@ -65,6 +65,8 @@ function personOf(event) {
case 'bot.robot.online': // payload.owner (usr_…, contracts 0.192.0; absent from older events)
return isUser(p.owner) ? p.owner : null;
case 'games.world.published': // payload.owner (identity.subject-ref@1, contracts 0.194.0)
++ case 'mediahub.video.published': // payload.owner (contracts 0.196.0)
++ case 'mediahub.picture.uploaded': // payload.owner (contracts 0.196.0)
return refUser(p.owner);
default:
// An app's own event (app quests, server/quests/app-quests.js): the actor, when the app published it
ddiff --git a/server/quests/catalog.js b/server/quests/catalog.js
iindex e2fb049..689b560 100644
---- a/server/quests/catalog.js
++++ b/server/quests/catalog.js
@@@ -42,6 +42,8 @@ const SITES = Object.freeze({
'openvibe.run': { name: 'OpenVibe.Run', what: 'jobs run on nodes' },
'inventory.openvibe.network': { name: 'OpenVibe.Inventory', what: 'the items you own across OpenVibe' },
'openvibe.bot': { name: 'OpenVibe.Bot', what: 'robots you drive from the browser' },
++ 'openvibe.video': { name: 'OpenVibe.Video', what: 'videos you upload or record' },
++ 'openvibe.pics': { name: 'OpenVibe.Pics', what: 'pictures you share' },
});
/**
@@@ -223,6 +225,24 @@ const QUESTS = Object.freeze([
reward: { badge: { id: 'world-builder', name: 'World Builder' }, coins: 20 },
repeatable: false,
},
++ {
++ id: 'publish-a-video',
++ site: 'openvibe.video',
++ title: 'Publish a video',
++ why: 'Upload a video or record one in the browser, then make it public: it gets captions and chapters, and a page anyone can find.',
++ steps: [{ event_type: 'mediahub.video.published', count: 1, label: 'Make one of your videos public at openvibe.video' }],
++ reward: { badge: { id: 'premiere', name: 'Premiere' }, coins: 15 },
++ repeatable: false,
++ },
++ {
++ id: 'share-a-picture',
++ site: 'openvibe.pics',
++ title: 'Share a picture',
++ why: 'Put a picture on OpenVibe.Pics and get a link to share or embed anywhere, with its location and camera details removed.',
++ steps: [{ event_type: 'mediahub.picture.uploaded', count: 1, label: 'Upload a picture at openvibe.pics' }],
++ reward: { badge: { id: 'snapshot', name: 'Snapshot' }, coins: 5 },
++ repeatable: false,
++ },
{
id: 'settle-in',
site: 'openvibe.network',
@@@ -448,6 +468,8 @@ const EVENTS = Object.freeze([
{ event_type: 'inventory.item.equipped', site: 'inventory.openvibe.network', what: 'An item was equipped; the payload names its owner, never what else they own.' },
{ event_type: 'bot.robot.online', site: 'openvibe.bot', what: 'A device connected and serves a robot; the payload names the robot\'s owner (events from before Bot named it are ignored).' },
{ event_type: 'games.world.published', site: 'openvibe.games', what: 'A player published one of their creator worlds for the first time; the payload names the owner.' },
++ { event_type: 'mediahub.video.published', site: 'openvibe.video', what: 'A video a person uploaded or recorded is public and ready for the first time; the payload names the owner.' },
++ { event_type: 'mediahub.picture.uploaded', site: 'openvibe.pics', what: 'A signed-in person uploaded a picture; the payload names the owner (and carries no link).' },
]);
// The events Quest actually counts: the consumer subscribes to exactly these, and a quest may not count an event
ddiff --git a/test/events-consumer.test.js b/test/events-consumer.test.js
iindex edb9aad..78b8406 100644
---- a/test/events-consumer.test.js
++++ b/test/events-consumer.test.js
@@@ -203,6 +203,11 @@ const progressOf = async (t, subject, questId) => (await rows(t, 'SELECT step, c
assert.ok(!(await done()).includes('publish-a-world'), 'a world a service published is nobody\'s');
await deliver(t, envelope('games.world.published', { ...world, owner: { type: 'user', id: sam.subject } }, { source: 'games' }));
assert.ok((await done()).includes('publish-a-world'));
++ const vid = { upload: 'vup_01M516F1WX5NN6C0EMW2V0G8Y9', title: 'Coast', url: 'https://openvibe.video/u/vup_01M516F1WX5NN6C0EMW2V0G8Y9', published_at: iso() };
++ await deliver(t, envelope('mediahub.video.published', { ...vid, owner: { type: 'user', id: sam.subject } }, { source: 'media-hub' }));
++ assert.ok((await done()).includes('publish-a-video'));
++ await deliver(t, envelope('mediahub.picture.uploaded', { picture: 'pic_01M516F1WX5NN6C0EMW2V0G8Y9', owner: { type: 'user', id: sam.subject }, uploaded_at: iso() }, { source: 'media-hub' }));
++ assert.ok((await done()).includes('share-a-picture'));
});
await check('an event that names nobody creditable is ignored: no subject, a guest, a service, an unknown type', async () => {