openvibers/openvibe.quest Commits
Quest: Publish a video and Share a picture (mediahub.video.published, mediahub.picture.uploaded; contracts 0.196.0) (#59)
Changes
@@@ -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 definesquests on its own project's events with an app token (audience `openvibe.quest`, capability `quest.app_quest.manage`).@@@ -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@@@ -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@@@ -203,6 +203,11 @@ const progressOf = async (t, subject, questId) => (await rows(t, 'SELECT step, cassert.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 () => {
@@ -138,6 +138,8 @@ OpenVibe.Events delivers an event when a site really does something. Quest count
@@ -138,6 +138,8 @@ OpenVibe.Events delivers an event when a site really does something. Quest count
| `inventory.item.equipped` | OpenVibe.Inventory | `payload.owner` |
| `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) |
| `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) |
| `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
**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`).
quests on its own project's events with an app token (audience `openvibe.quest`, capability `quest.app_quest.manage`).
@@ -65,6 +65,8 @@ function personOf(event) {
@@ -65,6 +65,8 @@ function personOf(event) {
case 'bot.robot.online': // payload.owner (usr_…, contracts 0.192.0; absent from older events)
case 'bot.robot.online': // payload.owner (usr_…, contracts 0.192.0; absent from older events)
return isUser(p.owner) ? p.owner : null;
return isUser(p.owner) ? p.owner : null;
case 'games.world.published': // payload.owner (identity.subject-ref@1, contracts 0.194.0)
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);
return refUser(p.owner);
default:
default:
// An app's own event (app quests, server/quests/app-quests.js): the actor, when the app published it
// An app's own event (app quests, server/quests/app-quests.js): the actor, when the app published it
@@ -42,6 +42,8 @@ const SITES = Object.freeze({
@@ -42,6 +42,8 @@ const SITES = Object.freeze({
'openvibe.run': { name: 'OpenVibe.Run', what: 'jobs run on nodes' },
'openvibe.run': { name: 'OpenVibe.Run', what: 'jobs run on nodes' },
'inventory.openvibe.network': { name: 'OpenVibe.Inventory', what: 'the items you own across OpenVibe' },
'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.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([
@@ -223,6 +225,24 @@ const QUESTS = Object.freeze([
reward: { badge: { id: 'world-builder', name: 'World Builder' }, coins: 20 },
reward: { badge: { id: 'world-builder', name: 'World Builder' }, coins: 20 },
repeatable: false,
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',
id: 'settle-in',
site: 'openvibe.network',
site: 'openvibe.network',
@@ -448,6 +468,8 @@ const EVENTS = Object.freeze([
@@ -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: '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: '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: '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
// The events Quest actually counts: the consumer subscribes to exactly these, and a quest may not count an event
@@ -203,6 +203,11 @@ const progressOf = async (t, subject, questId) => (await rows(t, 'SELECT step, c
@@ -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');
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' }));
await deliver(t, envelope('games.world.published', { ...world, owner: { type: 'user', id: sam.subject } }, { source: 'games' }));
assert.ok((await done()).includes('publish-a-world'));
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 () => {
await check('an event that names nobody creditable is ignored: no subject, a guest, a service, an unknown type', async () => {