@opentermsarchive/engine 10.6.0 → 11.0.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.
@@ -42,20 +42,9 @@
42
42
  "language": "en"
43
43
  },
44
44
  "logger": {
45
- "smtp": {
46
- "host": "smtp-relay.brevo.com",
47
- "port": 587,
48
- "username": "admin@opentermsarchive.org"
49
- },
50
45
  "sendMailOnError": false,
51
46
  "timestampPrefix": true
52
47
  },
53
- "notifier": {
54
- "sendInBlue": {
55
- "updatesListId": 850,
56
- "updateTemplateId": 7
57
- }
58
- },
59
48
  "dataset": {
60
49
  "publishingSchedule": "30 8 * * MON"
61
50
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opentermsarchive/engine",
3
- "version": "10.6.0",
3
+ "version": "11.0.0",
4
4
  "description": "Tracks and makes visible changes to the terms of online services",
5
5
  "homepage": "https://opentermsarchive.org",
6
6
  "bugs": {
@@ -95,7 +95,6 @@
95
95
  "puppeteer": "^24.22.0",
96
96
  "puppeteer-extra": "^3.3.6",
97
97
  "puppeteer-extra-plugin-stealth": "^2.11.2",
98
- "sib-api-v3-sdk": "^8.5.0",
99
98
  "simple-git": "^3.28.0",
100
99
  "swagger-jsdoc": "^6.2.8",
101
100
  "swagger-ui-express": "^5.0.1",
@@ -50,6 +50,10 @@ export default class DeclarationUtils {
50
50
  if (modifiedFilePath.endsWith('.filters.js') || modifiedFilePath.endsWith('.filters.history.js')) {
51
51
  const declaration = await this.getJSONFromFile(this.defaultBranch, `declarations/${serviceId}.json`);
52
52
 
53
+ if (!declaration) { // Happens when the file declaration exists in the branch but not in the default branch
54
+ return;
55
+ }
56
+
53
57
  servicesTermsTypes[serviceId] = Object.keys(declaration.terms); // Considering how rarely filters are used, simply return all term types that could potentially be impacted to spare implementing a function change check
54
58
 
55
59
  return;
@@ -188,6 +188,23 @@ describe('DeclarationUtils', () => {
188
188
  });
189
189
  });
190
190
 
191
+ context('when a new declaration has been added along with a filters file', () => {
192
+ before(async () => {
193
+ await fs.writeFile(path.resolve(SUBJECT_PATH, COMMIT_PATHS.serviceB), JSON.stringify(FIXTURES.serviceB.content, null, 2));
194
+ await fs.writeFile(path.resolve(SUBJECT_PATH, './declarations/ServiceB.filters.js'), 'module.exports = {};');
195
+ await declarationUtils.git.add([ COMMIT_PATHS.serviceB, './declarations/ServiceB.filters.js' ]);
196
+ await declarationUtils.git.commit('Add declaration with filters for new service');
197
+ });
198
+ after(removeLatestCommit);
199
+
200
+ it('returns the added service ID along with all its terms types', async () => {
201
+ expect(await declarationUtils.getModifiedServicesAndTermsTypes()).to.deep.equal({
202
+ services: ['ServiceB'],
203
+ servicesTermsTypes: { ServiceB: ['Terms of Service'] },
204
+ });
205
+ });
206
+ });
207
+
191
208
  context('when history file is modified without declaration changes', () => {
192
209
  before(() => commitChanges(COMMIT_PATHS.serviceAHistory, FIXTURES.serviceATermsUpdatedHistory.content));
193
210
  after(removeLatestCommit);
package/src/index.js CHANGED
@@ -7,7 +7,6 @@ import cronstrue from 'cronstrue';
7
7
  import { getCollection } from './archivist/collection/index.js';
8
8
  import Archivist from './archivist/index.js';
9
9
  import logger from './logger/index.js';
10
- import Notifier from './notifier/index.js';
11
10
  import Reporter from './reporter/index.js';
12
11
 
13
12
  const require = createRequire(import.meta.url);
@@ -52,16 +51,6 @@ export default async function track({ services, types, schedule }) {
52
51
  // All versions from this pass are labeled as technical upgrades to avoid false notifications about content changes.
53
52
  await archivist.applyTechnicalUpgrades({ services: filteredServices, types });
54
53
 
55
- if (process.env.OTA_ENGINE_SENDINBLUE_API_KEY) {
56
- try {
57
- archivist.attach(new Notifier(archivist.services));
58
- } catch (error) {
59
- logger.error('Cannot instantiate the Notifier module; it will be ignored:', error);
60
- }
61
- } else {
62
- logger.warn('Environment variable "OTA_ENGINE_SENDINBLUE_API_KEY" was not found; the Notifier module will be ignored');
63
- }
64
-
65
54
  if (process.env.OTA_ENGINE_GITHUB_TOKEN || process.env.OTA_ENGINE_GITLAB_TOKEN) {
66
55
  try {
67
56
  const reporter = new Reporter(config.get('@opentermsarchive/engine.reporter'));
@@ -1 +0,0 @@
1
- This module is intended to be considered as a simple consumer of the Archivist application's events API and therefore to be extracted from this repository. It is still in this repository to facilitate quick iterations but is expected to be extracted as soon as the Open Terms Archive app is stabilized.
@@ -1,148 +0,0 @@
1
- import config from 'config';
2
- import sendInBlue from 'sib-api-v3-sdk';
3
-
4
- export default class Notifier {
5
- constructor(passedServiceProviders) {
6
- const defaultClient = sendInBlue.ApiClient.instance;
7
- const authentication = defaultClient.authentications['api-key'];
8
-
9
- authentication.apiKey = process.env.OTA_ENGINE_SENDINBLUE_API_KEY;
10
-
11
- this.apiInstance = new sendInBlue.TransactionalEmailsApi();
12
- this.contactsInstance = new sendInBlue.ContactsApi();
13
-
14
- this.serviceProviders = passedServiceProviders;
15
- this.delayedVersionNotificationsParams = [];
16
- }
17
-
18
- onVersionRecorded(record) {
19
- this.delayedVersionNotificationsParams.push(record);
20
- }
21
-
22
- onTrackingCompleted() {
23
- this.delayedVersionNotificationsParams.forEach(async ({ serviceId, termsType, id }) => {
24
- try {
25
- await this.notifyVersionRecorded(serviceId, termsType, id);
26
- } catch (error) {
27
- console.error(`The notification for version ${id} of ${serviceId} — ${termsType} can not be sent:`, error);
28
- }
29
- });
30
-
31
- this.delayedVersionNotificationsParams = [];
32
- }
33
-
34
- async notifyVersionRecorded(serviceProviderId, termsType, versionId) {
35
- const sendParams = {
36
- templateId: config.get('@opentermsarchive/engine.notifier.sendInBlue.updateTemplateId'),
37
- params: {
38
- SERVICE_PROVIDER_NAME: this.serviceProviders[serviceProviderId].name,
39
- DOCUMENT_TYPE: termsType,
40
- SHA: versionId,
41
- },
42
- };
43
-
44
- const lists = [
45
- config.get('@opentermsarchive/engine.notifier.sendInBlue.updatesListId'),
46
- ];
47
-
48
- const notificationListName = `${this.serviceProviders[serviceProviderId].name} - ${termsType} - Update`;
49
- const notificationList = await this.searchContactList(notificationListName);
50
-
51
- if (notificationList?.id) {
52
- lists.push(notificationList.id);
53
- }
54
-
55
- return this.send(lists, sendParams);
56
- }
57
-
58
- async send(lists, sendParams) {
59
- const promises = lists.map(listId => this.getListContacts(listId));
60
-
61
- let contacts = await Promise.all(promises);
62
-
63
- contacts = contacts.flat();
64
-
65
- const uniqueContacts = [...new Map(contacts.map(item => [ item.id, item ])).values()];
66
-
67
- const sendPromises = uniqueContacts.map(contact =>
68
- this.apiInstance.sendTransacEmail({ ...sendParams, to: [{ email: contact.email }] }));
69
-
70
- return Promise.all(sendPromises);
71
- }
72
-
73
- async getAllContactLists() {
74
- const limit = 50;
75
- const offset = 0;
76
- const { count, lists } = await this.contactsInstance.getLists({
77
- limit,
78
- offset,
79
- });
80
-
81
- return {
82
- count,
83
- lists: await this.getAllPaginatedEntries(
84
- 'getLists',
85
- undefined,
86
- 'lists',
87
- lists,
88
- count,
89
- offset + limit,
90
- ),
91
- };
92
- }
93
-
94
- async searchContactList(name) {
95
- const { lists } = await this.getAllContactLists();
96
-
97
- const list = lists.find(list => list.name === name);
98
-
99
- return list;
100
- }
101
-
102
- async getListContacts(listId) {
103
- const list = await this.contactsInstance.getList(listId);
104
-
105
- return this.getAllPaginatedEntries(
106
- 'getContactsFromList',
107
- listId,
108
- 'contacts',
109
- [],
110
- list.totalSubscribers,
111
- );
112
- }
113
-
114
- async getAllPaginatedEntries(
115
- functionName,
116
- resourceIdParameter,
117
- resultKey,
118
- accumulator,
119
- count,
120
- offset = 0,
121
- paginationSize = 50,
122
- ) {
123
- if (accumulator.length >= count) {
124
- return accumulator;
125
- }
126
-
127
- const promise = resourceIdParameter
128
- ? this.contactsInstance[functionName](resourceIdParameter, {
129
- limit: paginationSize,
130
- offset,
131
- })
132
- : this.contactsInstance[functionName](paginationSize, offset);
133
-
134
- const result = await promise;
135
-
136
- accumulator = accumulator.concat(result[resultKey]);
137
-
138
- return this.getAllPaginatedEntries(
139
- functionName,
140
- resourceIdParameter,
141
- resultKey,
142
- accumulator,
143
- count,
144
- offset + paginationSize,
145
- paginationSize,
146
- );
147
- }
148
- }