@nlabs/reaktor 0.1.1 → 0.1.3

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.
Files changed (57) hide show
  1. package/.DS_Store +0 -0
  2. package/lib/config.js +10 -7
  3. package/lib/data/posts.d.ts +13 -7
  4. package/lib/data/posts.js +77 -39
  5. package/lib/types/posts.d.ts +1 -0
  6. package/package.json +8 -8
  7. package/.vscode/extensions.json +0 -15
  8. package/.vscode/settings.json +0 -82
  9. package/lex.config.js +0 -4
  10. package/src/config.ts +0 -121
  11. package/src/data/conversations.ts +0 -181
  12. package/src/data/dynamodb.ts +0 -157
  13. package/src/data/email.ts +0 -163
  14. package/src/data/files.ts +0 -352
  15. package/src/data/groups.ts +0 -308
  16. package/src/data/images.ts +0 -606
  17. package/src/data/index.ts +0 -23
  18. package/src/data/ios.ts +0 -249
  19. package/src/data/locations.ts +0 -114
  20. package/src/data/messages.ts +0 -237
  21. package/src/data/notifications.ts +0 -48
  22. package/src/data/payments.ts +0 -675
  23. package/src/data/posts.ts +0 -561
  24. package/src/data/reactions.ts +0 -186
  25. package/src/data/s3.ts +0 -117
  26. package/src/data/search.ts +0 -74
  27. package/src/data/sms.ts +0 -60
  28. package/src/data/subscription.ts +0 -228
  29. package/src/data/tags.ts +0 -230
  30. package/src/data/users.ts +0 -254
  31. package/src/index.ts +0 -7
  32. package/src/types/apps.ts +0 -56
  33. package/src/types/arangodb.ts +0 -23
  34. package/src/types/auth.ts +0 -20
  35. package/src/types/conversations.ts +0 -11
  36. package/src/types/email.ts +0 -17
  37. package/src/types/files.ts +0 -31
  38. package/src/types/google.ts +0 -37
  39. package/src/types/groups.ts +0 -27
  40. package/src/types/images.ts +0 -32
  41. package/src/types/index.ts +0 -21
  42. package/src/types/locations.ts +0 -24
  43. package/src/types/messages.ts +0 -16
  44. package/src/types/notifications.ts +0 -26
  45. package/src/types/payments.ts +0 -129
  46. package/src/types/posts.ts +0 -33
  47. package/src/types/reactions.ts +0 -8
  48. package/src/types/tags.ts +0 -13
  49. package/src/types/users.ts +0 -89
  50. package/src/utils/analytics.ts +0 -41
  51. package/src/utils/arangodb.ts +0 -100
  52. package/src/utils/auth.ts +0 -61
  53. package/src/utils/graphql.ts +0 -7
  54. package/src/utils/index.ts +0 -10
  55. package/src/utils/objects.ts +0 -34
  56. package/src/utils/redis.ts +0 -17
  57. package/tsconfig.json +0 -45
package/src/data/posts.ts DELETED
@@ -1,561 +0,0 @@
1
- /**
2
- * Copyright (c) 2019-Present, Nitrogen Labs, Inc.
3
- * Copyrights licensed under the MIT License. See the accompanying LICENSE file for terms.
4
- */
5
- import {createHash, parseChar, parseId, parseNum, parseString, parseVarChar} from '@nlabs/utils';
6
- import {aql, Database} from 'arangojs';
7
- import {AqlQuery} from 'arangojs/lib/cjs/aql-query';
8
- import {ArrayCursor} from 'arangojs/lib/cjs/cursor';
9
- import flatten from 'lodash/flatten';
10
- import uniqBy from 'lodash/uniqBy';
11
-
12
- import {ApiContext, ArangoDBLimit, FileType, GroupType, PostOptions, PostType, TagType} from '../types';
13
- import {getLimit, useDb} from '../utils';
14
- import {updateFiles} from './files';
15
- import {extractTags} from './tags';
16
-
17
- // const eventCategory: string = 'posts';
18
- const MAX_CONTENT_LENGTH: number = 100000;
19
-
20
- export const getPostOptional = (fields: string[]) =>
21
- fields.reduce((selects: any, field: string) => {
22
- switch(field) {
23
- case 'reactions': {
24
- selects.queries.push(`LET reactions = (
25
- FOR post, r IN INBOUND p._id reactions
26
- COLLECT reactionName = r.value INTO reactionItems
27
- RETURN {name: reactionName, count: LENGTH(reactionItems[*].r.value)}
28
- )`);
29
- selects.objects.push('reactions:reactions');
30
- return selects;
31
- }
32
- case 'tags': {
33
- selects.queries.push(`LET tags = (
34
- FOR t, pl IN INBOUND p._id isTagged
35
- RETURN t
36
- )`);
37
- selects.objects.push('tags:tags');
38
- return selects;
39
- }
40
- case 'user': {
41
- selects.queries.push(`LET user = FIRST(
42
- FOR u IN users
43
- FILTER p.userId == u._key
44
- LIMIT 1
45
- RETURN u
46
- )`);
47
- selects.objects.push('user:user');
48
- return selects;
49
- }
50
- default: {
51
- return selects;
52
- }
53
- }
54
- }, {objects: [], queries: []});
55
-
56
- export const getPostList = (context: ApiContext, from: number, to: number): Promise<PostType[]> => {
57
- // const action: string = 'getListByApp';
58
- const {database, fields} = context;
59
- const limit: ArangoDBLimit = getLimit(from, to);
60
- const {objects: selectObjects, queries: selectQueries} = getPostOptional(fields);
61
- const aqlQry: string = `FOR p IN posts
62
- FILTER p.privacy == "public" && p.parent == null
63
- ${selectQueries.join('\n')}
64
- ${limit.aql}
65
- SORT p.added
66
- RETURN DISTINCT MERGE(p, {${selectObjects.join(', ')}})`;
67
-
68
- return useDb(database).query(aqlQry)
69
- .then((cursor: ArrayCursor) => cursor.all())
70
- .catch((error: Error) => {
71
- throw error;
72
- });
73
- };
74
-
75
- export const getPostListByGroup = (context: ApiContext, groupId: string, from: number, to: number): Promise<PostType[]> => {
76
- // const action: string = 'getListByGroup';
77
- const {database, fields, userId: sessionId} = context;
78
- const {objects: selectObjects, queries: selectQueries} = getPostOptional(fields);
79
-
80
- // Group id
81
- const formatGroupId: string = parseId(groupId);
82
- const db = useDb(database);
83
- const aqlQry: string = `FOR u, g IN INBOUND ${formatGroupId} hasGroup
84
- FILTER u._key == ${sessionId}
85
- RETURN g`;
86
-
87
- return db.query(aqlQry)
88
- .then((cursor: ArrayCursor) => cursor.all())
89
- .then((groups: GroupType[] = []) => {
90
- if(groups.length) {
91
- const limit: ArangoDBLimit = getLimit(from, to);
92
- const postAqlQry: string = `FOR p IN posts
93
- FILTER p.groupId == "${formatGroupId}" && p.parent == null
94
- ${selectQueries.join('\n')}
95
- ${limit.aql}
96
- SORT p.added
97
- RETURN DISTINCT MERGE(p, {${selectObjects.join(', ')}})`;
98
-
99
- return db.query(postAqlQry)
100
- .then((cursor: ArrayCursor) => cursor.all())
101
- .catch((error: Error) => {
102
- throw error;
103
- });
104
- }
105
-
106
- return [];
107
- })
108
- .catch((error: Error) => {
109
- throw error;
110
- });
111
- };
112
-
113
- export const getPostListByLatest = (context: ApiContext, from: number, to: number): Promise<PostType[]> => {
114
- // const action: string = 'getListByLatest';
115
- const {database, fields} = context;
116
- const limit: ArangoDBLimit = getLimit(from, to);
117
- const {objects: selectObjects, queries: selectQueries} = getPostOptional(fields);
118
- const aqlQry: string = `FOR p IN posts
119
- FILTER p.privacy == "public" && p.parent == null
120
- ${selectQueries.join('\n')}
121
- ${limit.aql}
122
- SORT p.added
123
- RETURN DISTINCT MERGE(p, {${selectObjects.join(', ')}})`;
124
-
125
- return useDb(database).query(aqlQry)
126
- .then((cursor: ArrayCursor) => cursor.all())
127
- .catch((error: Error) => {
128
- throw error;
129
- });
130
- };
131
-
132
- export const getPostListByTags = (
133
- context: ApiContext,
134
- tagNames: string[],
135
- options: PostOptions
136
- ): Promise<PostType[]> => {
137
- // const action: string = 'getListByTags';
138
- const {database, fields} = context;
139
- const {latitude, longitude, from = 0, to = 30} = options;
140
- const {objects: selectObjects, queries: selectQueries} = getPostOptional(fields);
141
- const sortBy: string[] = [];
142
-
143
- if(latitude !== undefined && longitude !== undefined) {
144
- const formatLatitude: number = parseNum(latitude);
145
- const formatLongitude: number = parseNum(longitude);
146
- selectQueries.push(`LET distance = DISTANCE(
147
- ${formatLatitude},
148
- ${formatLongitude},
149
- NOT_NULL(p.latitude, 0),
150
- NOT_NULL(p.longitude, 0))
151
- `);
152
- selectObjects.push('distance:distance');
153
- sortBy.push('distance');
154
- }
155
-
156
- sortBy.push('p.added');
157
-
158
- return Promise.all(
159
- tagNames.map((tagName: string) => {
160
- const limit: ArangoDBLimit = getLimit(from, to);
161
- const aqlQry: string = `FOR targetTag IN tags
162
- FILTER targetTag.name == "${tagName}"
163
- FOR p, e IN OUTBOUND targetTag._id isTagged
164
- ${selectQueries.join('\n')}
165
- FILTER p.privacy == "public" && e.type == 'posts'
166
- ${limit.aql}
167
- SORT ${sortBy.join(', ')}
168
- RETURN DISTINCT MERGE(p, {${selectObjects.join(', ')}})`;
169
-
170
- console.log(aqlQry);
171
- return useDb(database).query(aqlQry)
172
- .then((cursor: ArrayCursor) => cursor.all())
173
- .catch(() => []);
174
- }))
175
- .then((results) => uniqBy(flatten(results), '_key'))
176
- .catch((error: Error) => {
177
- throw error;
178
- });
179
- };
180
-
181
- export const getPostListByUser = (context: ApiContext, userId: string, options): Promise<PostType[]> => {
182
- // const action: string = 'getListByUser';
183
- const {database, fields} = context;
184
- const {from = 0, to = 30} = options;
185
- const formatUserId: string = parseId(userId);
186
- const limit: ArangoDBLimit = getLimit(from, to);
187
- const {objects: selectObjects, queries: selectQueries} = getPostOptional(fields);
188
- const aqlQry: string = `FOR p IN posts
189
- FILTER p.userId == "${formatUserId}" && p.privacy == "public" && p.parent == null
190
- ${selectQueries.join('\n')}
191
- ${limit.aql}
192
- SORT p.added
193
- RETURN DISTINCT MERGE(p, {${selectObjects.join(', ')}})`;
194
-
195
- return useDb(database).query(aqlQry)
196
- .then((cursor: ArrayCursor) => cursor.all())
197
- .catch((error: Error) => {
198
- throw error;
199
- });
200
- };
201
-
202
- export const getPostListByArea = (
203
- context: ApiContext,
204
- latitude: number,
205
- longitude: number,
206
- from: number,
207
- to: number
208
- ): Promise<PostType[]> => {
209
- // const action: string = 'getListByUser';
210
- const {database, fields} = context;
211
- const formatLatitude: number = parseNum(latitude);
212
- const formatLongitude: number = parseNum(longitude);
213
- const limit: ArangoDBLimit = getLimit(from, to);
214
- const {objects: selectObjects, queries: selectQueries} = getPostOptional(fields);
215
- selectQueries.push(`LET distance = DISTANCE(
216
- ${formatLatitude},
217
- ${formatLongitude},
218
- NOT_NULL(p.latitude, 0),
219
- NOT_NULL(p.longitude, 0))
220
- `);
221
- selectObjects.push('distance:distance');
222
-
223
- const aqlQry: string = `FOR p IN posts
224
- ${selectQueries.join('\n')}
225
- FILTER p.privacy == "public" && p.parentId == null
226
- ${limit.aql}
227
- SORT distance, p.added
228
- RETURN DISTINCT MERGE(p, {${selectObjects.join(', ')}})`;
229
-
230
- return useDb(database).query(aqlQry)
231
- .then((cursor: ArrayCursor) => cursor.all())
232
- .catch((error: Error) => {
233
- throw error;
234
- });
235
- };
236
-
237
- export const getPost = (context: ApiContext, itemId: string): Promise<PostType> => {
238
- // const action: string = 'getItem';
239
- const {database, fields, userId: sessionId} = context;
240
- const formatItemId: string = parseId(itemId);
241
- const db = useDb(database);
242
- const {objects: selectObjects, queries: selectQueries} = getPostOptional(fields);
243
- const aqlQry: AqlQuery = aql`FOR p IN posts
244
- FILTER p._key == ${formatItemId}
245
- LIMIT 1
246
- RETURN p`;
247
-
248
- return db.query(aqlQry)
249
- .then((cursor: ArrayCursor) => cursor.next())
250
- .then((post: PostType = {}) => {
251
- const {
252
- _key,
253
- groupId,
254
- privacy = 'default'
255
- }: PostType = post;
256
-
257
- // Query based on privacy level
258
- let privacyAqlQry: string;
259
-
260
- if(groupId && privacy === 'group') {
261
- privacyAqlQry = `FOR p IN posts
262
- FILTER p._key == "${_key}"
263
- ${selectQueries.join('\n')}
264
- FOR group IN groups
265
- FILTER group._key == p.groupId
266
- FOR u, e IN OUTBOUND group._id isGrouped
267
- FILTER u._key == ${sessionId}
268
- LIMIT 1
269
- RETURN MERGE(p, {${selectObjects.join(', ')}})`;
270
- } else if(privacy === 'public') {
271
- privacyAqlQry = `FOR p IN posts
272
- FILTER p._key == "${_key}"
273
- ${selectQueries.join('\n')}
274
- LIMIT 1
275
- RETURN MERGE(p, {${selectObjects.join(', ')}})`;
276
- }
277
-
278
- if(privacyAqlQry) {
279
- return db.query(privacyAqlQry)
280
- .then((cursor: ArrayCursor) => cursor.next())
281
- .then((filteredPost: PostType = {}) => filteredPost)
282
- .catch((error: Error) => {
283
- throw error;
284
- });
285
- }
286
-
287
- return {};
288
- })
289
- .catch((error: Error) => {
290
- throw error;
291
- });
292
- };
293
-
294
- export const getPostComments = (context: ApiContext, itemId: string, from: number, to: number): Promise<PostType[]> => {
295
- // const action: string = 'getComments';
296
- const {database, userId: sessionId} = context;
297
- const formatItemId: string = parseId(itemId);
298
-
299
- // Get the parent post to get restrictions
300
- const db = useDb(database);
301
- const aqlQry: AqlQuery = aql`FOR p IN posts
302
- FILTER p._key == ${formatItemId}
303
- LIMIT 1
304
- RETURN p`;
305
-
306
- return db.query(aqlQry)
307
- .then((cursor: ArrayCursor) => cursor.next())
308
- .then((post: PostType = {}) => {
309
- const {
310
- _key,
311
- groupId,
312
- privacy = 'public'
313
- }: PostType = post;
314
-
315
- // Query based on privacy level
316
- let privacyAqlQry: string;
317
- const limit = getLimit(from, to);
318
-
319
- if(groupId && privacy === 'group') {
320
- privacyAqlQry = `FOR p IN posts
321
- FOR user IN users
322
- FILTER p.parent == "${_key}" && user._key == p.userId
323
- LET reactions = (
324
- FOR post, r IN INBOUND p._id reactions
325
- COLLECT reactionName = r.value INTO reactionItems
326
- RETURN {name: reactionName, count: LENGTH(reactionItems[*].r.value)}
327
- )
328
- FOR group IN groups
329
- FILTER group._key == p.groupId
330
- FOR u, e IN OUTBOUND group._id isGrouped
331
- FILTER u._key == "${sessionId}"
332
- SORT p.added
333
- ${limit.aql}
334
- RETURN MERGE(p, {user: user, reactions: reactions})`;
335
- } else if(privacy === 'public') {
336
- privacyAqlQry = `FOR p IN posts
337
- FOR user IN users
338
- FILTER p.parent == "${_key}" && user._key == p.userId
339
- LET reactions = (
340
- FOR post, r IN INBOUND p._id reactions
341
- COLLECT reactionName = r.value INTO reactionItems
342
- RETURN {name: reactionName, count: LENGTH(reactionItems[*].r.value)}
343
- )
344
- SORT p.added
345
- ${limit.aql}
346
- RETURN MERGE(p, {user: user, reactions: reactions})`;
347
- }
348
-
349
- if(privacyAqlQry) {
350
- return db.query(privacyAqlQry)
351
- .then((cursor: ArrayCursor) => cursor.all())
352
- .catch((error: Error) => {
353
- throw error;
354
- });
355
- }
356
-
357
- return [];
358
- })
359
- .catch((error: Error) => {
360
- throw error;
361
- });
362
- };
363
-
364
- export const addPost = (context: ApiContext, item: PostType): Promise<PostType> => {
365
- // const action: string = 'add';
366
- const {database, userId: sessionId} = context;
367
-
368
- const {
369
- content = '',
370
- groupId = '',
371
- location,
372
- latitude,
373
- longitude,
374
- name = '',
375
- parentId = null,
376
- privacy = 'public'
377
- }: PostType = item;
378
-
379
- const now: number = Date.now();
380
-
381
- const insert: PostType = {
382
- _key: createHash(`post-${sessionId}`),
383
- added: now,
384
- content: parseString(content, MAX_CONTENT_LENGTH),
385
- groupId: groupId ? parseId(groupId) : undefined,
386
- latitude: latitude !== undefined ? parseNum(latitude) : undefined,
387
- location: location ? parseString(location, 160) : undefined,
388
- longitude: longitude !== undefined ? parseNum(longitude) : undefined,
389
- modified: now,
390
- name: parseString(name, 160),
391
- parentId: parentId ? parseId(parentId) : undefined,
392
- privacy: privacy ? parseVarChar(privacy, 16) : undefined,
393
- userId: sessionId
394
- };
395
-
396
- const db: Database = useDb(database);
397
- const aqlQry: AqlQuery = aql`INSERT ${insert} IN posts RETURN NEW`;
398
-
399
- return db.query(aqlQry)
400
- .then((cursor: ArrayCursor) => cursor.next())
401
- .then((post: PostType = {}) => {
402
- const {_key: postKey} = post;
403
-
404
- // Update linked tags within posts
405
- return extractTags(db, 'posts', postKey, insert.content)
406
- .then((tagList: TagType[]) => {
407
- post.tags = tagList;
408
- return post;
409
- });
410
- })
411
- .catch((error: Error) => {
412
- throw error;
413
- });
414
- };
415
-
416
- export const updatePost = (context: ApiContext, item: PostType): Promise<PostType> => {
417
- // const action: string = 'update';
418
- const {database, userId: sessionId} = context;
419
- const now: number = Date.now();
420
- const {
421
- content,
422
- groupId,
423
- name,
424
- parentId,
425
- postId,
426
- privacy
427
- }: PostType = item;
428
-
429
- const update: PostType = {
430
- content: content ? parseString(content, MAX_CONTENT_LENGTH) : undefined,
431
- modified: now,
432
- name: name ? parseString(name, 160) : undefined,
433
- parentId: parentId ? parseString(parentId, 160) : undefined,
434
- privacy: privacy ? parseVarChar(privacy, 16) : undefined,
435
- };
436
-
437
- let formatId: string = parseId(postId);
438
- formatId = formatId === '' ? createHash(`post-${sessionId}`) : formatId;
439
- const formatGroupId: string = parseId(groupId);
440
- const insert: any = {
441
- ...update,
442
- _key: formatId,
443
- added: now,
444
- groupId: formatGroupId,
445
- privacy,
446
- userId: sessionId
447
- };
448
- const db: Database = useDb(database);
449
- const aqlQry: AqlQuery = aql`UPSERT {_key: ${formatId}, userId: ${sessionId}}
450
- INSERT ${insert}
451
- UPDATE ${update}
452
- IN posts RETURN NEW`;
453
-
454
- return db.query(aqlQry)
455
- .then((cursor: ArrayCursor) => cursor.next())
456
- .then((updatedPost: PostType = {}) => {
457
- const {_key: updatedPostKey} = updatedPost;
458
-
459
- // Update linked tags
460
- return extractTags(db, 'posts', updatedPostKey, update.content || '')
461
- .then((tagList = []) => {
462
- updatedPost.tags = tagList;
463
-
464
- // Update linked files
465
- const files: FileType[] = updatedPost.files || [];
466
-
467
- if(files.length) {
468
- return updateFiles(db, formatId, files)
469
- .then((fileList = []) => {
470
- updatedPost.files = fileList;
471
- return updatedPost;
472
- });
473
- }
474
-
475
- updatedPost.files = [];
476
- return updatedPost;
477
- });
478
- })
479
- .catch((error: Error) => {
480
- throw error;
481
- });
482
- };
483
-
484
- export const deletePost = (context: ApiContext, itemId: string): Promise<PostType> => {
485
- // const action: string = 'delete';
486
- const {database, userId: sessionId} = context;
487
- const formatItemId: string = parseId(itemId);
488
- const db: Database = useDb(database);
489
- const aqlQry = aql`FOR p IN posts
490
- FILTER p._key == ${formatItemId} && p.userId == ${sessionId}
491
- LIMIT 1
492
- REMOVE p IN posts
493
- RETURN OLD`;
494
-
495
- return db.query(aqlQry)
496
- .then((cursor: ArrayCursor) => cursor.next())
497
- .then((post: PostType = {}) => {
498
- if(post) {
499
- // Remove tag links
500
- const edgeAqlQry: AqlQuery = aql`FOR t IN isTagged
501
- FILTER t._to == ${formatItemId}
502
- REMOVE t IN isTagged`;
503
-
504
- return db.query(edgeAqlQry)
505
- .then(() => {
506
- // Remove attached files
507
- const fileAqlQry: AqlQuery = aql`FOR f IN hasFile
508
- FILTER f._to == ${formatItemId}
509
- REMOVE f IN hasFile`;
510
-
511
- return db.query(fileAqlQry)
512
- .then(() => post)
513
- .catch((error: Error) => {
514
- throw error;
515
- });
516
- })
517
- .catch((error: Error) => {
518
- throw error;
519
- });
520
- }
521
- return {};
522
- })
523
- .catch((error: Error) => {
524
- throw error;
525
- });
526
- };
527
-
528
- export const cleanPosts = (database: string): Promise<number> => {
529
- // Remove all messages that are over 60 days and not saved
530
- const aqlQry: AqlQuery = aql`FOR p IN posts
531
- FILTER p.added < DATE_TIMESTAMP(DATE_SUBTRACT(DATE_NOW(), 60, 'day')) && p.type == 1
532
- REMOVE p IN posts
533
- RETURN OLD`;
534
-
535
- return useDb(database).query(aqlQry)
536
- .then((cursor: ArrayCursor) => cursor.all())
537
- .then((results: PostType[] = []) => results.length)
538
- .catch((error: Error) => {
539
- throw error;
540
- });
541
- }
542
-
543
- export const createPostEdge = (db: Database, file: FileType, postId: string): Promise<FileType> => {
544
- const edgeCollection = db.edgeCollection('isPosted');
545
- const fileId: string = parseId(file.id);
546
- const edgeId: string = createHash(`file-${postId}-${fileId}`);
547
- const formatPostId: string = parseId(postId);
548
- const fileType: string = parseChar(file.fileType, 16);
549
-
550
- const edge: any = {
551
- _key: edgeId,
552
- added: Date.now(),
553
- type: fileType
554
- };
555
-
556
- return edgeCollection.save(edge, `posts/${formatPostId}`, `files/${fileId}`)
557
- .then(() => file)
558
- .catch((error: Error) => {
559
- throw error;
560
- });
561
- };