Add missing context fields
[oweals/peertube.git] / server / helpers / activitypub.ts
1 import { ResultList } from '../../shared/models'
2 import { Activity } from '../../shared/models/activitypub'
3 import { ACTIVITY_PUB } from '../initializers'
4 import { ActorModel } from '../models/activitypub/actor'
5 import { signObject } from './peertube-crypto'
6
7 function activityPubContextify <T> (data: T) {
8   return Object.assign(data,{
9     '@context': [
10       'https://www.w3.org/ns/activitystreams',
11       'https://w3id.org/security/v1',
12       {
13         'RsaSignature2017': 'https://w3id.org/security#RsaSignature2017',
14         'Hashtag': 'as:Hashtag',
15         'uuid': 'http://schema.org/identifier',
16         'category': 'http://schema.org/category',
17         'licence': 'http://schema.org/license',
18         'sensitive': 'as:sensitive',
19         'language': 'http://schema.org/inLanguage',
20         'views': 'http://schema.org/Number',
21         'size': 'http://schema.org/Number',
22         'commentsEnabled': 'http://schema.org/Boolean'
23       },
24       {
25         likes: {
26           '@id': 'as:likes',
27           '@type': '@id'
28         },
29         dislikes: {
30           '@id': 'as:dislikes',
31           '@type': '@id'
32         },
33         shares: {
34           '@id': 'as:shares',
35           '@type': '@id'
36         },
37         comments: {
38           '@id': 'as:comments',
39           '@type': '@id'
40         }
41       }
42     ]
43   })
44 }
45
46 function activityPubCollection (url: string, results: any[]) {
47   return {
48     id: url,
49     type: 'OrderedCollection',
50     totalItems: results.length,
51     orderedItems: results
52   }
53 }
54
55 function activityPubCollectionPagination (url: string, page: any, result: ResultList<any>) {
56   let next: string
57   let prev: string
58
59   // Assert page is a number
60   page = parseInt(page, 10)
61
62   // There are more results
63   if (result.total > page * ACTIVITY_PUB.COLLECTION_ITEMS_PER_PAGE) {
64     next = url + '?page=' + (page + 1)
65   }
66
67   if (page > 1) {
68     prev = url + '?page=' + (page - 1)
69   }
70
71   const orderedCollectionPagination = {
72     id: url + '?page=' + page,
73     type: 'OrderedCollectionPage',
74     prev,
75     next,
76     partOf: url,
77     orderedItems: result.data
78   }
79
80   if (page === 1) {
81     return activityPubContextify({
82       id: url,
83       type: 'OrderedCollection',
84       totalItems: result.total,
85       first: orderedCollectionPagination
86     })
87   } else {
88     orderedCollectionPagination['totalItems'] = result.total
89   }
90
91   return orderedCollectionPagination
92 }
93
94 function buildSignedActivity (byActor: ActorModel, data: Object) {
95   const activity = activityPubContextify(data)
96
97   return signObject(byActor, activity) as Promise<Activity>
98 }
99
100 // ---------------------------------------------------------------------------
101
102 export {
103   activityPubContextify,
104   activityPubCollectionPagination,
105   activityPubCollection,
106   buildSignedActivity
107 }