@evanp/activitypub-bot 0.12.1 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/app.js +19 -1
- package/lib/index.js +2 -0
- package/lib/routes/collection.js +83 -67
- package/lib/routes/inbox.js +8 -0
- package/lib/routes/object.js +25 -5
- package/package.json +2 -2
- package/tests/index.test.js +4 -2
- package/tests/routes.collection.test.js +0 -123
- package/tests/routes.inbox.test.js +80 -0
package/lib/app.js
CHANGED
|
@@ -140,12 +140,30 @@ export async function makeApp (databaseUrl, origin, bots, logLevel = 'silent') {
|
|
|
140
140
|
app.use('/', serverRouter)
|
|
141
141
|
app.use('/', userRouter)
|
|
142
142
|
app.use('/', collectionRouter)
|
|
143
|
-
app.use('/', objectRouter)
|
|
144
143
|
app.use('/', inboxRouter)
|
|
144
|
+
app.use('/', objectRouter)
|
|
145
145
|
app.use('/', healthRouter)
|
|
146
146
|
app.use('/', webfingerRouter)
|
|
147
147
|
app.use('/', sharedInboxRouter)
|
|
148
148
|
|
|
149
|
+
app.use(async (req, res) => {
|
|
150
|
+
if (req.accepts('json')) {
|
|
151
|
+
const status = 404
|
|
152
|
+
const title = http.STATUS_CODES[status] || 'Not Found'
|
|
153
|
+
res.status(status)
|
|
154
|
+
res.type('application/problem+json')
|
|
155
|
+
res.json({
|
|
156
|
+
type: 'about:blank',
|
|
157
|
+
title,
|
|
158
|
+
status,
|
|
159
|
+
detail: 'Not found',
|
|
160
|
+
instance: req.originalUrl
|
|
161
|
+
})
|
|
162
|
+
} else {
|
|
163
|
+
res.status(404).send('Not found')
|
|
164
|
+
}
|
|
165
|
+
})
|
|
166
|
+
|
|
149
167
|
app.use((err, req, res, next) => {
|
|
150
168
|
const { logger } = req.app.locals
|
|
151
169
|
let status = 500
|
package/lib/index.js
CHANGED
package/lib/routes/collection.js
CHANGED
|
@@ -2,7 +2,9 @@ import express from 'express'
|
|
|
2
2
|
import as2 from '../activitystreams.js'
|
|
3
3
|
import createHttpError from 'http-errors'
|
|
4
4
|
import BotMaker from '../botmaker.js'
|
|
5
|
+
import assert from 'node:assert'
|
|
5
6
|
|
|
7
|
+
const collections = ['outbox', 'liked', 'followers', 'following']
|
|
6
8
|
const router = express.Router()
|
|
7
9
|
|
|
8
10
|
async function filterAsync (array, asyncPredicate) {
|
|
@@ -16,81 +18,95 @@ async function filterAsync (array, asyncPredicate) {
|
|
|
16
18
|
return array.filter((_, idx) => booleans[idx])
|
|
17
19
|
}
|
|
18
20
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
21
|
+
// This got tricky because Express 5 doesn't let us add regexes to our routes,
|
|
22
|
+
// so the page routes conflict with the object routes in ./object.js. This
|
|
23
|
+
// format lets us define fixed routes for the 4 user collections that support
|
|
24
|
+
// GET
|
|
25
|
+
|
|
26
|
+
function collectionHandler (collection) {
|
|
27
|
+
assert.ok(collections.includes(collection))
|
|
28
|
+
return async (req, res, next) => {
|
|
29
|
+
const { username } = req.params
|
|
30
|
+
const { actorStorage, bots } = req.app.locals
|
|
31
|
+
const bot = await BotMaker.makeBot(bots, username)
|
|
32
|
+
if (!bot) {
|
|
33
|
+
return next(createHttpError(404, `User ${username} not found`))
|
|
34
|
+
}
|
|
35
|
+
const coll = await actorStorage.getCollection(username, collection)
|
|
36
|
+
res.status(200)
|
|
37
|
+
res.type(as2.mediaType)
|
|
38
|
+
res.end(await coll.prettyWrite({ useOriginalContext: true }))
|
|
32
39
|
}
|
|
33
|
-
|
|
34
|
-
res.status(200)
|
|
35
|
-
res.type(as2.mediaType)
|
|
36
|
-
res.end(await coll.prettyWrite({ useOriginalContext: true }))
|
|
37
|
-
})
|
|
40
|
+
}
|
|
38
41
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
function collectionPageHandler (collection) {
|
|
43
|
+
assert.ok(['outbox', 'liked', 'followers', 'following'].includes(collection))
|
|
44
|
+
return async (req, res, next) => {
|
|
45
|
+
const { username, n } = req.params
|
|
46
|
+
let pageNo
|
|
47
|
+
try {
|
|
48
|
+
pageNo = parseInt(n)
|
|
49
|
+
} catch (err) {
|
|
50
|
+
return next(createHttpError(400, `Invalid page ${n}`))
|
|
51
|
+
}
|
|
52
|
+
const { actorStorage, bots, authorizer, objectStorage, formatter, client } = req.app.locals
|
|
53
|
+
const bot = await BotMaker.makeBot(bots, username)
|
|
43
54
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
55
|
+
if (!bot) {
|
|
56
|
+
return next(createHttpError(404, `User ${username} not found`))
|
|
57
|
+
}
|
|
47
58
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
if (!await actorStorage.hasPage(username, collection, parseInt(n))) {
|
|
56
|
-
return next(createHttpError(404, `No such page ${n} for collection ${collection} for user ${username}`))
|
|
57
|
-
}
|
|
59
|
+
if (collection === 'inbox') {
|
|
60
|
+
return next(createHttpError(403, `No access to ${collection} collection`))
|
|
61
|
+
}
|
|
62
|
+
if (!await actorStorage.hasPage(username, collection, parseInt(n))) {
|
|
63
|
+
return next(createHttpError(404, `No such page ${n} for collection ${collection} for user ${username}`))
|
|
64
|
+
}
|
|
58
65
|
|
|
59
|
-
|
|
66
|
+
let exported = null
|
|
60
67
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
try {
|
|
69
|
+
const id = req.auth?.subject
|
|
70
|
+
const remote = (id) ? await as2.import({ id }) : null
|
|
71
|
+
const page = await actorStorage.getCollectionPage(
|
|
72
|
+
username,
|
|
73
|
+
collection,
|
|
74
|
+
pageNo
|
|
75
|
+
)
|
|
76
|
+
exported = await page.export({ useOriginalContext: true })
|
|
70
77
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
78
|
+
if (['outbox', 'liked'].includes(collection)) {
|
|
79
|
+
exported.items = await filterAsync(exported.items, async (id) => {
|
|
80
|
+
const object = (formatter.isLocal(id))
|
|
81
|
+
? await objectStorage.read(id)
|
|
82
|
+
: await client.get(id)
|
|
83
|
+
if (!object) {
|
|
84
|
+
req.log.warn({ id }, 'could not load object')
|
|
85
|
+
return false
|
|
86
|
+
}
|
|
87
|
+
req.log.debug({ id, object }, 'loaded object')
|
|
88
|
+
return await authorizer.canRead(remote, object)
|
|
89
|
+
})
|
|
90
|
+
}
|
|
91
|
+
} catch (error) {
|
|
92
|
+
req.log.error(
|
|
93
|
+
{ err: error, username, collection, n },
|
|
94
|
+
'error loading collection page'
|
|
95
|
+
)
|
|
96
|
+
return next(createHttpError(500, 'Error loading collection page'))
|
|
83
97
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
'error loading collection page'
|
|
88
|
-
)
|
|
89
|
-
return next(createHttpError(500, 'Error loading collection page'))
|
|
98
|
+
res.status(200)
|
|
99
|
+
res.type(as2.mediaType)
|
|
100
|
+
res.end(JSON.stringify(exported))
|
|
90
101
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
})
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
for (const collection of collections) {
|
|
105
|
+
router.get(`/user/:username/${collection}`, collectionHandler(collection))
|
|
106
|
+
router.get(
|
|
107
|
+
`/user/:username/${collection}/:n`,
|
|
108
|
+
collectionPageHandler(collection)
|
|
109
|
+
)
|
|
110
|
+
}
|
|
95
111
|
|
|
96
112
|
export default router
|
package/lib/routes/inbox.js
CHANGED
|
@@ -67,4 +67,12 @@ router.post('/user/:username/inbox', async (req, res, next) => {
|
|
|
67
67
|
res.send('OK')
|
|
68
68
|
})
|
|
69
69
|
|
|
70
|
+
router.get('/user/:username/inbox', async (req, res, next) => {
|
|
71
|
+
return next(createHttpError(403, `No access to inbox collection`))
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
router.get('/user/:username/inbox/:n', async (req, res, next) => {
|
|
75
|
+
return next(createHttpError(403, `No access to inbox collection`))
|
|
76
|
+
})
|
|
77
|
+
|
|
70
78
|
export default router
|
package/lib/routes/object.js
CHANGED
|
@@ -6,8 +6,11 @@ const router = express.Router()
|
|
|
6
6
|
|
|
7
7
|
export default router
|
|
8
8
|
|
|
9
|
-
router.get('/user/:username/:type/:nanoid
|
|
9
|
+
router.get('/user/:username/:type/:nanoid', async (req, res, next) => {
|
|
10
10
|
const { username, type, nanoid } = req.params
|
|
11
|
+
if (!nanoid.match(/^[A-Za-z0-9_\\-]{21}$/)) {
|
|
12
|
+
return next(createHttpError(400, `Invalid nanoid ${nanoid}`))
|
|
13
|
+
}
|
|
11
14
|
const { objectStorage, formatter, authorizer } = req.app.locals
|
|
12
15
|
const id = formatter.format({ username, type, nanoid })
|
|
13
16
|
const object = await objectStorage.read(id)
|
|
@@ -23,12 +26,16 @@ router.get('/user/:username/:type/:nanoid([A-Za-z0-9_\\-]{21})', async (req, res
|
|
|
23
26
|
res.end(await object.prettyWrite())
|
|
24
27
|
})
|
|
25
28
|
|
|
26
|
-
router.get('/user/:username/:type/:nanoid
|
|
29
|
+
router.get('/user/:username/:type/:nanoid/:collection', async (req, res, next) => {
|
|
27
30
|
const { objectStorage, formatter, authorizer } = req.app.locals
|
|
28
31
|
if (!['replies', 'likes', 'shares', 'thread'].includes(req.params.collection)) {
|
|
29
32
|
return next(createHttpError(404, 'Not Found'))
|
|
30
33
|
}
|
|
31
|
-
const
|
|
34
|
+
const { username, type, nanoid } = req.params
|
|
35
|
+
if (!nanoid.match(/^[A-Za-z0-9_\\-]{21}$/)) {
|
|
36
|
+
return next(createHttpError(400, `Invalid nanoid ${nanoid}`))
|
|
37
|
+
}
|
|
38
|
+
const id = formatter.format({ username, type, nanoid })
|
|
32
39
|
const object = await objectStorage.read(id)
|
|
33
40
|
if (!object) {
|
|
34
41
|
return next(createHttpError(404, 'Not Found'))
|
|
@@ -43,8 +50,17 @@ router.get('/user/:username/:type/:nanoid([A-Za-z0-9_\\-]{21})/:collection', asy
|
|
|
43
50
|
res.end(await collection.prettyWrite({ useOriginalContext: true }))
|
|
44
51
|
})
|
|
45
52
|
|
|
46
|
-
router.get('/user/:username/:type/:nanoid
|
|
53
|
+
router.get('/user/:username/:type/:nanoid/:collection/:n', async (req, res, next) => {
|
|
47
54
|
const { username, type, nanoid, collection, n } = req.params
|
|
55
|
+
let pageNo
|
|
56
|
+
try {
|
|
57
|
+
pageNo = parseInt(n)
|
|
58
|
+
} catch (err) {
|
|
59
|
+
return next(createHttpError(400, `Invalid page ${n}`))
|
|
60
|
+
}
|
|
61
|
+
if (!nanoid.match(/^[A-Za-z0-9_\\-]{21}$/)) {
|
|
62
|
+
return next(createHttpError(400, `Invalid nanoid ${nanoid}`))
|
|
63
|
+
}
|
|
48
64
|
const { objectStorage, formatter, authorizer } = req.app.locals
|
|
49
65
|
if (!['replies', 'likes', 'shares', 'thread'].includes(req.params.collection)) {
|
|
50
66
|
return next(createHttpError(404, 'Not Found'))
|
|
@@ -58,7 +74,11 @@ router.get('/user/:username/:type/:nanoid([A-Za-z0-9_\\-]{21})/:collection/:n(\\
|
|
|
58
74
|
if (!await authorizer.canRead(remote, object)) {
|
|
59
75
|
return next(createHttpError(403, 'Forbidden'))
|
|
60
76
|
}
|
|
61
|
-
const collectionPage = await objectStorage.getCollectionPage(
|
|
77
|
+
const collectionPage = await objectStorage.getCollectionPage(
|
|
78
|
+
id,
|
|
79
|
+
collection,
|
|
80
|
+
pageNo
|
|
81
|
+
)
|
|
62
82
|
const exported = await collectionPage.export({ useOriginalContext: true })
|
|
63
83
|
if (!Array.isArray(exported.items)) {
|
|
64
84
|
exported.items = [exported.items]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@evanp/activitypub-bot",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "server-side ActivityPub bot framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@isaacs/ttlcache": "^2.1.4",
|
|
32
32
|
"activitystrea.ms": "3.2",
|
|
33
|
-
"express": "^
|
|
33
|
+
"express": "^5.2.1",
|
|
34
34
|
"http-errors": "^2.0.0",
|
|
35
35
|
"humanhash": "^1.0.4",
|
|
36
36
|
"lru-cache": "^11.1.0",
|
package/tests/index.test.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import assert from 'node:assert'
|
|
2
2
|
import { describe, it } from 'node:test'
|
|
3
3
|
describe('package exports', () => {
|
|
4
|
-
it('exposes Bot, BotFactory, and makeApp', async () => {
|
|
5
|
-
const { Bot, BotFactory, makeApp } = await import('../lib/index.js')
|
|
4
|
+
it('exposes Bot, BotFactory, default bots, and makeApp', async () => {
|
|
5
|
+
const { Bot, BotFactory, makeApp, DoNothingBot, OKBot } = await import('../lib/index.js')
|
|
6
6
|
assert.equal(typeof Bot, 'function')
|
|
7
7
|
assert.equal(typeof BotFactory, 'function')
|
|
8
8
|
assert.equal(typeof makeApp, 'function')
|
|
9
|
+
assert.equal(typeof OKBot, 'function')
|
|
10
|
+
assert.equal(typeof DoNothingBot, 'function')
|
|
9
11
|
})
|
|
10
12
|
})
|
|
@@ -273,129 +273,6 @@ describe('actor collection routes', async () => {
|
|
|
273
273
|
it('should return an object with a detail', async () => {
|
|
274
274
|
assert.strictEqual(typeof response.body.detail, 'string')
|
|
275
275
|
})
|
|
276
|
-
it('should return an object with a detail matching the request', async () => {
|
|
277
|
-
assert.strictEqual(response.body.detail, 'No such collection dne for user ok')
|
|
278
|
-
})
|
|
279
|
-
})
|
|
280
|
-
|
|
281
|
-
describe('GET page for non-existent collection for existent user', async () => {
|
|
282
|
-
let response = null
|
|
283
|
-
it('should work without an error', async () => {
|
|
284
|
-
response = await request(app).get('/user/ok/dne/1')
|
|
285
|
-
})
|
|
286
|
-
it('should return 404 Not Found', async () => {
|
|
287
|
-
assert.strictEqual(response.status, 404)
|
|
288
|
-
})
|
|
289
|
-
it('should return Problem Details JSON', async () => {
|
|
290
|
-
assert.strictEqual(response.type, 'application/problem+json')
|
|
291
|
-
})
|
|
292
|
-
it('should return an object', async () => {
|
|
293
|
-
assert.strictEqual(typeof response.body, 'object')
|
|
294
|
-
})
|
|
295
|
-
it('should return an object with a type', async () => {
|
|
296
|
-
assert.strictEqual(typeof response.body.type, 'string')
|
|
297
|
-
})
|
|
298
|
-
it('should return an object with an type matching the request', async () => {
|
|
299
|
-
assert.strictEqual(response.body.type, 'about:blank')
|
|
300
|
-
})
|
|
301
|
-
it('should return an object with a title', async () => {
|
|
302
|
-
assert.strictEqual(typeof response.body.title, 'string')
|
|
303
|
-
})
|
|
304
|
-
it('should return an object with a title matching the request', async () => {
|
|
305
|
-
assert.strictEqual(response.body.title, 'Not Found')
|
|
306
|
-
})
|
|
307
|
-
it('should return an object with a status', async () => {
|
|
308
|
-
assert.strictEqual(typeof response.body.status, 'number')
|
|
309
|
-
})
|
|
310
|
-
it('should return an object with a status matching the request', async () => {
|
|
311
|
-
assert.strictEqual(response.body.status, 404)
|
|
312
|
-
})
|
|
313
|
-
it('should return an object with a detail', async () => {
|
|
314
|
-
assert.strictEqual(typeof response.body.detail, 'string')
|
|
315
|
-
})
|
|
316
|
-
it('should return an object with a detail matching the request', async () => {
|
|
317
|
-
assert.strictEqual(response.body.detail, 'No such collection dne for user ok')
|
|
318
|
-
})
|
|
319
|
-
})
|
|
320
|
-
|
|
321
|
-
describe('GET /user/{botid}/inbox', async () => {
|
|
322
|
-
let response = null
|
|
323
|
-
it('should work without an error', async () => {
|
|
324
|
-
response = await request(app).get('/user/ok/inbox')
|
|
325
|
-
})
|
|
326
|
-
it('should return 403 Forbidden', async () => {
|
|
327
|
-
assert.strictEqual(response.status, 403)
|
|
328
|
-
})
|
|
329
|
-
it('should return Problem Details JSON', async () => {
|
|
330
|
-
assert.strictEqual(response.type, 'application/problem+json')
|
|
331
|
-
})
|
|
332
|
-
it('should return an object', async () => {
|
|
333
|
-
assert.strictEqual(typeof response.body, 'object')
|
|
334
|
-
})
|
|
335
|
-
it('should return an object with a type', async () => {
|
|
336
|
-
assert.strictEqual(typeof response.body.type, 'string')
|
|
337
|
-
})
|
|
338
|
-
it('should return an object with an type matching the request', async () => {
|
|
339
|
-
assert.strictEqual(response.body.type, 'about:blank')
|
|
340
|
-
})
|
|
341
|
-
it('should return an object with a title', async () => {
|
|
342
|
-
assert.strictEqual(typeof response.body.title, 'string')
|
|
343
|
-
})
|
|
344
|
-
it('should return an object with a title matching the request', async () => {
|
|
345
|
-
assert.strictEqual(response.body.title, 'Forbidden')
|
|
346
|
-
})
|
|
347
|
-
it('should return an object with a status', async () => {
|
|
348
|
-
assert.strictEqual(typeof response.body.status, 'number')
|
|
349
|
-
})
|
|
350
|
-
it('should return an object with a status matching the request', async () => {
|
|
351
|
-
assert.strictEqual(response.body.status, 403)
|
|
352
|
-
})
|
|
353
|
-
it('should return an object with a detail', async () => {
|
|
354
|
-
assert.strictEqual(typeof response.body.detail, 'string')
|
|
355
|
-
})
|
|
356
|
-
it('should return an object with a detail matching the request', async () => {
|
|
357
|
-
assert.strictEqual(response.body.detail, 'No access to inbox collection')
|
|
358
|
-
})
|
|
359
|
-
})
|
|
360
|
-
|
|
361
|
-
describe('GET /user/{botid}/inbox/1', async () => {
|
|
362
|
-
let response = null
|
|
363
|
-
it('should work without an error', async () => {
|
|
364
|
-
response = await request(app).get('/user/ok/inbox/1')
|
|
365
|
-
})
|
|
366
|
-
it('should return 403 Forbidden', async () => {
|
|
367
|
-
assert.strictEqual(response.status, 403)
|
|
368
|
-
})
|
|
369
|
-
it('should return Problem Details JSON', async () => {
|
|
370
|
-
assert.strictEqual(response.type, 'application/problem+json')
|
|
371
|
-
})
|
|
372
|
-
it('should return an object', async () => {
|
|
373
|
-
assert.strictEqual(typeof response.body, 'object')
|
|
374
|
-
})
|
|
375
|
-
it('should return an object with a type', async () => {
|
|
376
|
-
assert.strictEqual(typeof response.body.type, 'string')
|
|
377
|
-
})
|
|
378
|
-
it('should return an object with an type matching the request', async () => {
|
|
379
|
-
assert.strictEqual(response.body.type, 'about:blank')
|
|
380
|
-
})
|
|
381
|
-
it('should return an object with a title', async () => {
|
|
382
|
-
assert.strictEqual(typeof response.body.title, 'string')
|
|
383
|
-
})
|
|
384
|
-
it('should return an object with a title matching the request', async () => {
|
|
385
|
-
assert.strictEqual(response.body.title, 'Forbidden')
|
|
386
|
-
})
|
|
387
|
-
it('should return an object with a status', async () => {
|
|
388
|
-
assert.strictEqual(typeof response.body.status, 'number')
|
|
389
|
-
})
|
|
390
|
-
it('should return an object with a status matching the request', async () => {
|
|
391
|
-
assert.strictEqual(response.body.status, 403)
|
|
392
|
-
})
|
|
393
|
-
it('should return an object with a detail', async () => {
|
|
394
|
-
assert.strictEqual(typeof response.body.detail, 'string')
|
|
395
|
-
})
|
|
396
|
-
it('should return an object with a detail matching the request', async () => {
|
|
397
|
-
assert.strictEqual(response.body.detail, 'No access to inbox collection')
|
|
398
|
-
})
|
|
399
276
|
})
|
|
400
277
|
|
|
401
278
|
describe('GET /user/{botid}/outbox/1 with contents', async () => {
|
|
@@ -20,6 +20,86 @@ describe('routes.inbox', async () => {
|
|
|
20
20
|
app = await makeApp(databaseUrl, origin, bots, 'silent')
|
|
21
21
|
})
|
|
22
22
|
|
|
23
|
+
describe('GET /user/{botid}/inbox', async () => {
|
|
24
|
+
let response = null
|
|
25
|
+
it('should work without an error', async () => {
|
|
26
|
+
response = await request(app).get('/user/ok/inbox')
|
|
27
|
+
})
|
|
28
|
+
it('should return 403 Forbidden', async () => {
|
|
29
|
+
assert.strictEqual(response.status, 403)
|
|
30
|
+
})
|
|
31
|
+
it('should return Problem Details JSON', async () => {
|
|
32
|
+
assert.strictEqual(response.type, 'application/problem+json')
|
|
33
|
+
})
|
|
34
|
+
it('should return an object', async () => {
|
|
35
|
+
assert.strictEqual(typeof response.body, 'object')
|
|
36
|
+
})
|
|
37
|
+
it('should return an object with a type', async () => {
|
|
38
|
+
assert.strictEqual(typeof response.body.type, 'string')
|
|
39
|
+
})
|
|
40
|
+
it('should return an object with an type matching the request', async () => {
|
|
41
|
+
assert.strictEqual(response.body.type, 'about:blank')
|
|
42
|
+
})
|
|
43
|
+
it('should return an object with a title', async () => {
|
|
44
|
+
assert.strictEqual(typeof response.body.title, 'string')
|
|
45
|
+
})
|
|
46
|
+
it('should return an object with a title matching the request', async () => {
|
|
47
|
+
assert.strictEqual(response.body.title, 'Forbidden')
|
|
48
|
+
})
|
|
49
|
+
it('should return an object with a status', async () => {
|
|
50
|
+
assert.strictEqual(typeof response.body.status, 'number')
|
|
51
|
+
})
|
|
52
|
+
it('should return an object with a status matching the request', async () => {
|
|
53
|
+
assert.strictEqual(response.body.status, 403)
|
|
54
|
+
})
|
|
55
|
+
it('should return an object with a detail', async () => {
|
|
56
|
+
assert.strictEqual(typeof response.body.detail, 'string')
|
|
57
|
+
})
|
|
58
|
+
it('should return an object with a detail matching the request', async () => {
|
|
59
|
+
assert.strictEqual(response.body.detail, 'No access to inbox collection')
|
|
60
|
+
})
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
describe('GET /user/{botid}/inbox/1', async () => {
|
|
64
|
+
let response = null
|
|
65
|
+
it('should work without an error', async () => {
|
|
66
|
+
response = await request(app).get('/user/ok/inbox/1')
|
|
67
|
+
})
|
|
68
|
+
it('should return 403 Forbidden', async () => {
|
|
69
|
+
assert.strictEqual(response.status, 403)
|
|
70
|
+
})
|
|
71
|
+
it('should return Problem Details JSON', async () => {
|
|
72
|
+
assert.strictEqual(response.type, 'application/problem+json')
|
|
73
|
+
})
|
|
74
|
+
it('should return an object', async () => {
|
|
75
|
+
assert.strictEqual(typeof response.body, 'object')
|
|
76
|
+
})
|
|
77
|
+
it('should return an object with a type', async () => {
|
|
78
|
+
assert.strictEqual(typeof response.body.type, 'string')
|
|
79
|
+
})
|
|
80
|
+
it('should return an object with an type matching the request', async () => {
|
|
81
|
+
assert.strictEqual(response.body.type, 'about:blank')
|
|
82
|
+
})
|
|
83
|
+
it('should return an object with a title', async () => {
|
|
84
|
+
assert.strictEqual(typeof response.body.title, 'string')
|
|
85
|
+
})
|
|
86
|
+
it('should return an object with a title matching the request', async () => {
|
|
87
|
+
assert.strictEqual(response.body.title, 'Forbidden')
|
|
88
|
+
})
|
|
89
|
+
it('should return an object with a status', async () => {
|
|
90
|
+
assert.strictEqual(typeof response.body.status, 'number')
|
|
91
|
+
})
|
|
92
|
+
it('should return an object with a status matching the request', async () => {
|
|
93
|
+
assert.strictEqual(response.body.status, 403)
|
|
94
|
+
})
|
|
95
|
+
it('should return an object with a detail', async () => {
|
|
96
|
+
assert.strictEqual(typeof response.body.detail, 'string')
|
|
97
|
+
})
|
|
98
|
+
it('should return an object with a detail matching the request', async () => {
|
|
99
|
+
assert.strictEqual(response.body.detail, 'No access to inbox collection')
|
|
100
|
+
})
|
|
101
|
+
})
|
|
102
|
+
|
|
23
103
|
describe('can handle an incoming activity', async () => {
|
|
24
104
|
const username = 'actor1'
|
|
25
105
|
const botName = 'test0'
|