@evanp/activitypub-bot 0.15.4 → 0.16.2
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/README.md +5 -0
- package/lib/actorstorage.js +80 -0
- package/lib/botcontext.js +101 -159
- package/lib/migrations/002-last-activity.js +15 -0
- package/lib/migrations/index.js +3 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -276,6 +276,11 @@ Sends an `Undo`/`Like` activity for the passed-in object in [activitystrea.ms](#
|
|
|
276
276
|
|
|
277
277
|
Sends an `Announce` activity for the passed-in object in [activitystrea.ms](#activitystreams) form to followers.
|
|
278
278
|
|
|
279
|
+
#### async unannounceObject (obj)
|
|
280
|
+
|
|
281
|
+
Sends an `Undo`/`Announce` activity for the passed-in object. The addressees
|
|
282
|
+
match the `Announce` activity being undone.
|
|
283
|
+
|
|
279
284
|
#### async followActor (actor)
|
|
280
285
|
|
|
281
286
|
Sends a `Follow` activity for the passed-in actor in [activitystrea.ms](#activitystreams) form.
|
package/lib/actorstorage.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import AS2 from 'activitystrea.ms'
|
|
1
2
|
import as2 from './activitystreams.js'
|
|
2
3
|
import assert from 'node:assert'
|
|
3
4
|
|
|
5
|
+
const AS2_NS = 'https://www.w3.org/ns/activitystreams#'
|
|
6
|
+
|
|
4
7
|
export class ActorStorage {
|
|
5
8
|
#connection = null
|
|
6
9
|
#formatter = null
|
|
@@ -256,6 +259,77 @@ export class ActorStorage {
|
|
|
256
259
|
return usernames
|
|
257
260
|
}
|
|
258
261
|
|
|
262
|
+
async getLastActivity (username, type, object) {
|
|
263
|
+
assert.ok(username, 'username is required')
|
|
264
|
+
assert.equal(typeof username, 'string', 'username must be a string')
|
|
265
|
+
assert.ok(type, 'type is required')
|
|
266
|
+
assert.equal(typeof type, 'string', 'type must be a string')
|
|
267
|
+
assert.ok(object, 'object is required')
|
|
268
|
+
assert.equal(typeof object, 'object', 'object must be an object')
|
|
269
|
+
assert.ok(object.id, 'object.id is required')
|
|
270
|
+
assert.equal(typeof object.id, 'string', 'object.id must be a string')
|
|
271
|
+
|
|
272
|
+
const [result] = await this.#connection.query(
|
|
273
|
+
`SELECT activity_id
|
|
274
|
+
FROM lastactivity
|
|
275
|
+
WHERE username = ? AND type = ? and object_id = ?`,
|
|
276
|
+
{ replacements: [username, this.#clearNS(type), object.id] }
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
return (result.length > 0)
|
|
280
|
+
? result[0].activity_id
|
|
281
|
+
: null
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
async clearLastActivity (username, type, object) {
|
|
285
|
+
assert.ok(username, 'username is required')
|
|
286
|
+
assert.equal(typeof username, 'string', 'username must be a string')
|
|
287
|
+
assert.ok(type, 'type is required')
|
|
288
|
+
assert.equal(typeof type, 'string', 'type must be a string')
|
|
289
|
+
assert.ok(object, 'object is required')
|
|
290
|
+
assert.equal(typeof object, 'object', 'object must be an object')
|
|
291
|
+
assert.ok(object.id, 'object.id is required')
|
|
292
|
+
assert.equal(typeof object.id, 'string', 'object.id must be a string')
|
|
293
|
+
|
|
294
|
+
await this.#connection.query(
|
|
295
|
+
`DELETE FROM lastactivity
|
|
296
|
+
WHERE username = ? AND type = ? and object_id = ?`,
|
|
297
|
+
{ replacements: [username, this.#clearNS(type), object.id] }
|
|
298
|
+
)
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
async setLastActivity (username, activity) {
|
|
302
|
+
assert.ok(username, 'username is required')
|
|
303
|
+
assert.equal(typeof username, 'string', 'username must be a string')
|
|
304
|
+
assert.ok(activity, 'activity is required')
|
|
305
|
+
assert.equal(typeof activity, 'object', 'activity must be an object')
|
|
306
|
+
assert.ok(activity.id, 'activity.id is required')
|
|
307
|
+
assert.equal(typeof activity.id, 'string', 'id must be a string')
|
|
308
|
+
assert.ok(activity.type, 'activity.type is required')
|
|
309
|
+
assert.equal(typeof activity.type, 'string', 'type must be a string')
|
|
310
|
+
assert.ok(activity.object, 'activity.object is required')
|
|
311
|
+
assert.equal(typeof activity.object, 'object', 'activity.object must be an object')
|
|
312
|
+
assert.ok(activity.object.first.id, 'activity.object.id is required')
|
|
313
|
+
assert.equal(typeof activity.object.first.id, 'string', 'activity.object.id must be a string')
|
|
314
|
+
|
|
315
|
+
await this.#connection.query(
|
|
316
|
+
`
|
|
317
|
+
INSERT INTO lastactivity (username, type, object_id, activity_id)
|
|
318
|
+
VALUES (?, ?, ?, ?)
|
|
319
|
+
ON CONFLICT DO UPDATE
|
|
320
|
+
SET activity_id = EXCLUDED.activity_id,
|
|
321
|
+
updatedAt = CURRENT_TIMESTAMP
|
|
322
|
+
`,
|
|
323
|
+
{ replacements: [
|
|
324
|
+
username,
|
|
325
|
+
this.#clearNS(activity.type),
|
|
326
|
+
activity.object.first.id,
|
|
327
|
+
activity.id
|
|
328
|
+
]
|
|
329
|
+
}
|
|
330
|
+
)
|
|
331
|
+
}
|
|
332
|
+
|
|
259
333
|
async #getCollectionInfo (username, property) {
|
|
260
334
|
const [result] = await this.#connection.query(
|
|
261
335
|
`SELECT first, totalItems, createdAt, updatedAt
|
|
@@ -287,4 +361,10 @@ export class ActorStorage {
|
|
|
287
361
|
)
|
|
288
362
|
return rows[0][0].item_count
|
|
289
363
|
}
|
|
364
|
+
|
|
365
|
+
#clearNS (type) {
|
|
366
|
+
return (type.startsWith(AS2_NS))
|
|
367
|
+
? type.slice(AS2_NS.length)
|
|
368
|
+
: type
|
|
369
|
+
}
|
|
290
370
|
}
|
package/lib/botcontext.js
CHANGED
|
@@ -143,14 +143,13 @@ export class BotContext {
|
|
|
143
143
|
attributedTo: this.#formatter.format({ username: this.#botId })
|
|
144
144
|
})
|
|
145
145
|
await this.#objectStorage.create(note)
|
|
146
|
-
const activity = await
|
|
146
|
+
const activity = await this.#doActivity({
|
|
147
|
+
'@context': [
|
|
148
|
+
'https://www.w3.org/ns/activitystreams',
|
|
149
|
+
'https://purl.archive.org/socialweb/thread/1.0',
|
|
150
|
+
{ ostatus: 'http://ostatus.org/schema/1.0/' }
|
|
151
|
+
],
|
|
147
152
|
type: 'Create',
|
|
148
|
-
id: this.#formatter.format({
|
|
149
|
-
username: this.#botId,
|
|
150
|
-
type: 'create',
|
|
151
|
-
nanoid: nanoid()
|
|
152
|
-
}),
|
|
153
|
-
actor: this.#formatter.format({ username: this.#botId }),
|
|
154
153
|
to,
|
|
155
154
|
cc,
|
|
156
155
|
bto,
|
|
@@ -158,10 +157,6 @@ export class BotContext {
|
|
|
158
157
|
audience,
|
|
159
158
|
object: note
|
|
160
159
|
})
|
|
161
|
-
await this.#objectStorage.create(activity)
|
|
162
|
-
await this.#actorStorage.addToCollection(this.#botId, 'outbox', activity)
|
|
163
|
-
await this.#actorStorage.addToCollection(this.#botId, 'inbox', activity)
|
|
164
|
-
await this.#distributor.distribute(activity, this.#botId)
|
|
165
160
|
return note
|
|
166
161
|
}
|
|
167
162
|
|
|
@@ -205,23 +200,14 @@ export class BotContext {
|
|
|
205
200
|
const owners = obj.attributedTo
|
|
206
201
|
? Array.from(obj.attributedTo).map((owner) => owner.id)
|
|
207
202
|
: Array.from(obj.actor).map((owner) => owner.id)
|
|
208
|
-
|
|
203
|
+
await this.#actorStorage.addToCollection(this.#botId, 'liked', obj)
|
|
204
|
+
const activity = await this.#doActivity({
|
|
209
205
|
type: 'Like',
|
|
210
|
-
id: this.#formatter.format({
|
|
211
|
-
username: this.#botId,
|
|
212
|
-
type: 'like',
|
|
213
|
-
nanoid: nanoid()
|
|
214
|
-
}),
|
|
215
|
-
actor: this.#formatter.format({ username: this.#botId }),
|
|
216
206
|
object: obj.id,
|
|
217
207
|
to: owners,
|
|
218
208
|
cc: 'https://www.w3.org/ns/activitystreams#Public'
|
|
219
209
|
})
|
|
220
|
-
await this.#
|
|
221
|
-
await this.#actorStorage.addToCollection(this.#botId, 'outbox', activity)
|
|
222
|
-
await this.#actorStorage.addToCollection(this.#botId, 'inbox', activity)
|
|
223
|
-
await this.#actorStorage.addToCollection(this.#botId, 'liked', obj)
|
|
224
|
-
await this.#distributor.distribute(activity, this.#botId)
|
|
210
|
+
await this.#actorStorage.setLastActivity(this.#botId, activity)
|
|
225
211
|
return activity
|
|
226
212
|
}
|
|
227
213
|
|
|
@@ -234,93 +220,51 @@ export class BotContext {
|
|
|
234
220
|
if (!(await this.#actorStorage.isInCollection(this.#botId, 'liked', obj))) {
|
|
235
221
|
throw new Error(`not already liked: ${obj.id} by ${this.#botId}`)
|
|
236
222
|
}
|
|
237
|
-
const likeActivity = this.#
|
|
223
|
+
const likeActivity = this.#actorStorage.getLastActivity(
|
|
224
|
+
this.#botId,
|
|
225
|
+
'Like',
|
|
226
|
+
obj
|
|
227
|
+
)
|
|
238
228
|
if (!likeActivity) {
|
|
239
229
|
throw new Error('no like activity')
|
|
240
230
|
}
|
|
241
|
-
|
|
231
|
+
await this.#actorStorage.removeFromCollection(this.#botId, 'liked', obj)
|
|
232
|
+
return await this.#doActivity({
|
|
242
233
|
type: 'Undo',
|
|
243
|
-
id: this.#formatter.format({
|
|
244
|
-
username: this.#botId,
|
|
245
|
-
type: 'undo',
|
|
246
|
-
nanoid: nanoid()
|
|
247
|
-
}),
|
|
248
|
-
actor: this.#formatter.format({ username: this.#botId }),
|
|
249
234
|
object: likeActivity,
|
|
250
235
|
to: owners,
|
|
251
236
|
cc: 'https://www.w3.org/ns/activitystreams#Public'
|
|
252
237
|
})
|
|
253
|
-
await this.#objectStorage.create(undoActivity)
|
|
254
|
-
await this.#actorStorage.addToCollection(
|
|
255
|
-
this.#botId,
|
|
256
|
-
'outbox',
|
|
257
|
-
undoActivity
|
|
258
|
-
)
|
|
259
|
-
await this.#actorStorage.addToCollection(
|
|
260
|
-
this.#botId,
|
|
261
|
-
'inbox',
|
|
262
|
-
undoActivity
|
|
263
|
-
)
|
|
264
|
-
await this.#actorStorage.removeFromCollection(this.#botId, 'liked', obj)
|
|
265
|
-
await this.#distributor.distribute(undoActivity, this.#botId)
|
|
266
|
-
return undoActivity
|
|
267
238
|
}
|
|
268
239
|
|
|
269
240
|
async followActor (actor) {
|
|
270
241
|
assert.ok(actor)
|
|
271
242
|
assert.equal(typeof actor, 'object')
|
|
272
|
-
const activity = await as2.import({
|
|
273
|
-
type: 'Follow',
|
|
274
|
-
id: this.#formatter.format({
|
|
275
|
-
username: this.#botId,
|
|
276
|
-
type: 'follow',
|
|
277
|
-
nanoid: nanoid()
|
|
278
|
-
}),
|
|
279
|
-
actor: this.#formatter.format({ username: this.#botId }),
|
|
280
|
-
object: actor.id,
|
|
281
|
-
to: actor.id
|
|
282
|
-
})
|
|
283
|
-
await this.#objectStorage.create(activity)
|
|
284
|
-
await this.#actorStorage.addToCollection(this.#botId, 'outbox', activity)
|
|
285
|
-
await this.#actorStorage.addToCollection(this.#botId, 'inbox', activity)
|
|
286
243
|
await this.#actorStorage.addToCollection(
|
|
287
244
|
this.#botId,
|
|
288
245
|
'pendingFollowing',
|
|
289
246
|
actor
|
|
290
247
|
)
|
|
291
|
-
await this.#
|
|
248
|
+
const activity = await this.#doActivity({
|
|
249
|
+
type: 'Follow',
|
|
250
|
+
object: actor.id,
|
|
251
|
+
to: actor.id
|
|
252
|
+
})
|
|
253
|
+
await this.#actorStorage.setLastActivity(this.#botId, activity)
|
|
292
254
|
return activity
|
|
293
255
|
}
|
|
294
256
|
|
|
295
257
|
async unfollowActor (actor) {
|
|
296
258
|
assert.ok(actor)
|
|
297
259
|
assert.equal(typeof actor, 'object')
|
|
298
|
-
const followActivity = this.#
|
|
260
|
+
const followActivity = this.#actorStorage.getLastActivity(
|
|
261
|
+
this.#botId,
|
|
262
|
+
'Follow',
|
|
263
|
+
actor
|
|
264
|
+
)
|
|
299
265
|
if (!followActivity) {
|
|
300
266
|
throw new Error('no follow activity')
|
|
301
267
|
}
|
|
302
|
-
const undoActivity = await as2.import({
|
|
303
|
-
type: 'Undo',
|
|
304
|
-
id: this.#formatter.format({
|
|
305
|
-
username: this.#botId,
|
|
306
|
-
type: 'undo',
|
|
307
|
-
nanoid: nanoid()
|
|
308
|
-
}),
|
|
309
|
-
actor: this.#formatter.format({ username: this.#botId }),
|
|
310
|
-
object: followActivity,
|
|
311
|
-
to: actor.id
|
|
312
|
-
})
|
|
313
|
-
await this.#objectStorage.create(undoActivity)
|
|
314
|
-
await this.#actorStorage.addToCollection(
|
|
315
|
-
this.#botId,
|
|
316
|
-
'outbox',
|
|
317
|
-
undoActivity
|
|
318
|
-
)
|
|
319
|
-
await this.#actorStorage.addToCollection(
|
|
320
|
-
this.#botId,
|
|
321
|
-
'inbox',
|
|
322
|
-
undoActivity
|
|
323
|
-
)
|
|
324
268
|
await this.#actorStorage.removeFromCollection(
|
|
325
269
|
this.#botId,
|
|
326
270
|
'pendingFollowing',
|
|
@@ -331,26 +275,16 @@ export class BotContext {
|
|
|
331
275
|
'following',
|
|
332
276
|
actor
|
|
333
277
|
)
|
|
334
|
-
await this.#
|
|
335
|
-
|
|
278
|
+
return await this.#doActivity({
|
|
279
|
+
type: 'Undo',
|
|
280
|
+
object: followActivity,
|
|
281
|
+
to: actor.id
|
|
282
|
+
})
|
|
336
283
|
}
|
|
337
284
|
|
|
338
285
|
async blockActor (actor) {
|
|
339
286
|
assert.ok(actor)
|
|
340
287
|
assert.equal(typeof actor, 'object')
|
|
341
|
-
const activity = await as2.import({
|
|
342
|
-
type: 'Block',
|
|
343
|
-
id: this.#formatter.format({
|
|
344
|
-
username: this.#botId,
|
|
345
|
-
type: 'block',
|
|
346
|
-
nanoid: nanoid()
|
|
347
|
-
}),
|
|
348
|
-
actor: this.#formatter.format({ username: this.#botId }),
|
|
349
|
-
object: actor.id
|
|
350
|
-
})
|
|
351
|
-
await this.#objectStorage.create(activity)
|
|
352
|
-
await this.#actorStorage.addToCollection(this.#botId, 'outbox', activity)
|
|
353
|
-
await this.#actorStorage.addToCollection(this.#botId, 'inbox', activity)
|
|
354
288
|
await this.#actorStorage.addToCollection(this.#botId, 'blocked', actor)
|
|
355
289
|
for (const coll of [
|
|
356
290
|
'following',
|
|
@@ -360,45 +294,34 @@ export class BotContext {
|
|
|
360
294
|
]) {
|
|
361
295
|
await this.#actorStorage.removeFromCollection(this.#botId, coll, actor)
|
|
362
296
|
}
|
|
363
|
-
|
|
297
|
+
const activity = await this.#doActivity({
|
|
298
|
+
type: 'Block',
|
|
299
|
+
object: actor.id
|
|
300
|
+
}, false)
|
|
301
|
+
await this.#actorStorage.setLastActivity(this.#botId, activity)
|
|
364
302
|
return activity
|
|
365
303
|
}
|
|
366
304
|
|
|
367
305
|
async unblockActor (actor) {
|
|
368
306
|
assert.ok(actor)
|
|
369
307
|
assert.equal(typeof actor, 'object')
|
|
370
|
-
const blockActivity = this.#
|
|
308
|
+
const blockActivity = this.#actorStorage.getLastActivity(
|
|
309
|
+
this.#botId,
|
|
310
|
+
'Block',
|
|
311
|
+
actor
|
|
312
|
+
)
|
|
371
313
|
if (!blockActivity) {
|
|
372
314
|
throw new Error('no block activity')
|
|
373
315
|
}
|
|
374
|
-
const undoActivity = await as2.import({
|
|
375
|
-
type: 'Undo',
|
|
376
|
-
id: this.#formatter.format({
|
|
377
|
-
username: this.#botId,
|
|
378
|
-
type: 'undo',
|
|
379
|
-
nanoid: nanoid()
|
|
380
|
-
}),
|
|
381
|
-
actor: this.#formatter.format({ username: this.#botId }),
|
|
382
|
-
object: blockActivity
|
|
383
|
-
})
|
|
384
|
-
await this.#objectStorage.create(undoActivity)
|
|
385
|
-
await this.#actorStorage.addToCollection(
|
|
386
|
-
this.#botId,
|
|
387
|
-
'outbox',
|
|
388
|
-
undoActivity
|
|
389
|
-
)
|
|
390
|
-
await this.#actorStorage.addToCollection(
|
|
391
|
-
this.#botId,
|
|
392
|
-
'inbox',
|
|
393
|
-
undoActivity
|
|
394
|
-
)
|
|
395
316
|
await this.#actorStorage.removeFromCollection(
|
|
396
317
|
this.#botId,
|
|
397
318
|
'blocked',
|
|
398
319
|
actor
|
|
399
320
|
)
|
|
400
|
-
|
|
401
|
-
|
|
321
|
+
return await this.#doActivity({
|
|
322
|
+
type: 'Undo',
|
|
323
|
+
object: blockActivity
|
|
324
|
+
}, false)
|
|
402
325
|
}
|
|
403
326
|
|
|
404
327
|
async updateNote (note, content) {
|
|
@@ -410,14 +333,9 @@ export class BotContext {
|
|
|
410
333
|
exported.content = content
|
|
411
334
|
const updated = await as2.import(exported)
|
|
412
335
|
const { to, cc, bto, bcc, audience } = this.#getRecipients(note)
|
|
413
|
-
|
|
336
|
+
await this.#objectStorage.update(updated)
|
|
337
|
+
await this.#doActivity({
|
|
414
338
|
type: 'Update',
|
|
415
|
-
id: this.#formatter.format({
|
|
416
|
-
username: this.#botId,
|
|
417
|
-
type: 'update',
|
|
418
|
-
nanoid: nanoid()
|
|
419
|
-
}),
|
|
420
|
-
actor: this.#formatter.format({ username: this.#botId }),
|
|
421
339
|
object: updated,
|
|
422
340
|
to,
|
|
423
341
|
cc,
|
|
@@ -425,11 +343,6 @@ export class BotContext {
|
|
|
425
343
|
bcc,
|
|
426
344
|
audience
|
|
427
345
|
})
|
|
428
|
-
await this.#objectStorage.update(updated)
|
|
429
|
-
await this.#objectStorage.create(activity)
|
|
430
|
-
await this.#actorStorage.addToCollection(this.#botId, 'outbox', activity)
|
|
431
|
-
await this.#actorStorage.addToCollection(this.#botId, 'inbox', activity)
|
|
432
|
-
await this.#distributor.distribute(activity, this.#botId)
|
|
433
346
|
return updated
|
|
434
347
|
}
|
|
435
348
|
|
|
@@ -449,14 +362,9 @@ export class BotContext {
|
|
|
449
362
|
bcc,
|
|
450
363
|
audience
|
|
451
364
|
})
|
|
452
|
-
|
|
365
|
+
await this.#objectStorage.update(tombstone)
|
|
366
|
+
return await this.#doActivity({
|
|
453
367
|
type: 'Delete',
|
|
454
|
-
id: this.#formatter.format({
|
|
455
|
-
username: this.#botId,
|
|
456
|
-
type: 'delete',
|
|
457
|
-
nanoid: nanoid()
|
|
458
|
-
}),
|
|
459
|
-
actor: this.#formatter.format({ username: this.#botId }),
|
|
460
368
|
object: tombstone,
|
|
461
369
|
to,
|
|
462
370
|
cc,
|
|
@@ -464,12 +372,6 @@ export class BotContext {
|
|
|
464
372
|
bcc,
|
|
465
373
|
audience
|
|
466
374
|
})
|
|
467
|
-
await this.#objectStorage.update(tombstone)
|
|
468
|
-
await this.#objectStorage.create(activity)
|
|
469
|
-
await this.#actorStorage.addToCollection(this.#botId, 'outbox', activity)
|
|
470
|
-
await this.#actorStorage.addToCollection(this.#botId, 'inbox', activity)
|
|
471
|
-
await this.#distributor.distribute(activity, this.#botId)
|
|
472
|
-
return activity
|
|
473
375
|
}
|
|
474
376
|
|
|
475
377
|
async toActorId (webfinger) {
|
|
@@ -510,14 +412,8 @@ export class BotContext {
|
|
|
510
412
|
const owners = obj.attributedTo
|
|
511
413
|
? Array.from(obj.attributedTo).map((owner) => owner.id)
|
|
512
414
|
: Array.from(obj.actor).map((owner) => owner.id)
|
|
513
|
-
const activity = await
|
|
415
|
+
const activity = await this.#doActivity({
|
|
514
416
|
type: 'Announce',
|
|
515
|
-
id: this.#formatter.format({
|
|
516
|
-
username: this.#botId,
|
|
517
|
-
type: 'Announce',
|
|
518
|
-
nanoid: nanoid()
|
|
519
|
-
}),
|
|
520
|
-
actor: this.#formatter.format({ username: this.#botId }),
|
|
521
417
|
summary: {
|
|
522
418
|
en: `${this.#botId} shared "${await this.#nameOf(obj)}"`
|
|
523
419
|
},
|
|
@@ -531,13 +427,32 @@ export class BotContext {
|
|
|
531
427
|
],
|
|
532
428
|
cc: owners
|
|
533
429
|
})
|
|
534
|
-
await this.#
|
|
535
|
-
await this.#actorStorage.addToCollection(this.#botId, 'outbox', activity)
|
|
536
|
-
await this.#actorStorage.addToCollection(this.#botId, 'inbox', activity)
|
|
537
|
-
await this.#distributor.distribute(activity, this.#botId)
|
|
430
|
+
await this.#actorStorage.setLastActivity(this.#botId, activity)
|
|
538
431
|
return activity
|
|
539
432
|
}
|
|
540
433
|
|
|
434
|
+
async unannounceObject (obj) {
|
|
435
|
+
assert.ok(obj)
|
|
436
|
+
assert.equal(typeof obj, 'object')
|
|
437
|
+
const announceActivity = await this.#actorStorage.getLastActivity(
|
|
438
|
+
this.#botId,
|
|
439
|
+
'Announce',
|
|
440
|
+
obj
|
|
441
|
+
)
|
|
442
|
+
if (!announceActivity) {
|
|
443
|
+
throw new Error(`No matching announce activity for ${obj.id}`)
|
|
444
|
+
}
|
|
445
|
+
const recipients = this.#getRecipients(announceActivity)
|
|
446
|
+
return await this.#doActivity({
|
|
447
|
+
type: 'Undo',
|
|
448
|
+
summary: {
|
|
449
|
+
en: `${this.#botId} shared "${await this.#nameOf(obj)}"`
|
|
450
|
+
},
|
|
451
|
+
object: announceActivity,
|
|
452
|
+
...recipients
|
|
453
|
+
})
|
|
454
|
+
}
|
|
455
|
+
|
|
541
456
|
async #findInOutbox (type, obj) {
|
|
542
457
|
const full = `https://www.w3.org/ns/activitystreams#${type}`
|
|
543
458
|
let found = null
|
|
@@ -576,6 +491,33 @@ export class BotContext {
|
|
|
576
491
|
}
|
|
577
492
|
}
|
|
578
493
|
|
|
494
|
+
async #doActivity (activityData, distribute = true) {
|
|
495
|
+
const now = new Date().toISOString()
|
|
496
|
+
const type = activityData.type || 'Activity'
|
|
497
|
+
const activity = await as2.import({
|
|
498
|
+
...activityData,
|
|
499
|
+
type,
|
|
500
|
+
id: this.#formatter.format({
|
|
501
|
+
username: this.#botId,
|
|
502
|
+
type: type,
|
|
503
|
+
nanoid: nanoid()
|
|
504
|
+
}),
|
|
505
|
+
actor: {
|
|
506
|
+
id: this.#formatter.format({ username: this.#botId }),
|
|
507
|
+
type: 'Service'
|
|
508
|
+
},
|
|
509
|
+
published: now,
|
|
510
|
+
updated: now
|
|
511
|
+
})
|
|
512
|
+
await this.#objectStorage.create(activity)
|
|
513
|
+
await this.#actorStorage.addToCollection(this.#botId, 'outbox', activity)
|
|
514
|
+
await this.#actorStorage.addToCollection(this.#botId, 'inbox', activity)
|
|
515
|
+
if (distribute) {
|
|
516
|
+
await this.#distributor.distribute(activity, this.#botId)
|
|
517
|
+
}
|
|
518
|
+
return activity
|
|
519
|
+
}
|
|
520
|
+
|
|
579
521
|
async onIdle () {
|
|
580
522
|
await this.#distributor.onIdle()
|
|
581
523
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const id = '002-last-activity'
|
|
2
|
+
|
|
3
|
+
export async function up (connection) {
|
|
4
|
+
await connection.query(`
|
|
5
|
+
CREATE TABLE lastactivity (
|
|
6
|
+
username varchar(512) NOT NULL,
|
|
7
|
+
type varchar(512) NOT NULL,
|
|
8
|
+
object_id varchar(512) NOT NULL,
|
|
9
|
+
activity_id varchar(512),
|
|
10
|
+
createdAt DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
11
|
+
updatedAt DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
12
|
+
PRIMARY KEY (username, type, object_id)
|
|
13
|
+
);
|
|
14
|
+
`)
|
|
15
|
+
}
|
package/lib/migrations/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { id as initialId, up as initialUp } from './001-initial.js'
|
|
2
|
+
import { id as lastId, up as lastUp } from './002-last-activity.js'
|
|
2
3
|
|
|
3
4
|
const migrations = [
|
|
4
|
-
{ id: initialId, up: initialUp }
|
|
5
|
+
{ id: initialId, up: initialUp },
|
|
6
|
+
{ id: lastId, up: lastUp }
|
|
5
7
|
]
|
|
6
8
|
|
|
7
9
|
export async function runMigrations (connection) {
|