@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.
- package/.DS_Store +0 -0
- package/lib/config.js +10 -7
- package/lib/data/posts.d.ts +13 -7
- package/lib/data/posts.js +77 -39
- package/lib/types/posts.d.ts +1 -0
- package/package.json +8 -8
- package/.vscode/extensions.json +0 -15
- package/.vscode/settings.json +0 -82
- package/lex.config.js +0 -4
- package/src/config.ts +0 -121
- package/src/data/conversations.ts +0 -181
- package/src/data/dynamodb.ts +0 -157
- package/src/data/email.ts +0 -163
- package/src/data/files.ts +0 -352
- package/src/data/groups.ts +0 -308
- package/src/data/images.ts +0 -606
- package/src/data/index.ts +0 -23
- package/src/data/ios.ts +0 -249
- package/src/data/locations.ts +0 -114
- package/src/data/messages.ts +0 -237
- package/src/data/notifications.ts +0 -48
- package/src/data/payments.ts +0 -675
- package/src/data/posts.ts +0 -561
- package/src/data/reactions.ts +0 -186
- package/src/data/s3.ts +0 -117
- package/src/data/search.ts +0 -74
- package/src/data/sms.ts +0 -60
- package/src/data/subscription.ts +0 -228
- package/src/data/tags.ts +0 -230
- package/src/data/users.ts +0 -254
- package/src/index.ts +0 -7
- package/src/types/apps.ts +0 -56
- package/src/types/arangodb.ts +0 -23
- package/src/types/auth.ts +0 -20
- package/src/types/conversations.ts +0 -11
- package/src/types/email.ts +0 -17
- package/src/types/files.ts +0 -31
- package/src/types/google.ts +0 -37
- package/src/types/groups.ts +0 -27
- package/src/types/images.ts +0 -32
- package/src/types/index.ts +0 -21
- package/src/types/locations.ts +0 -24
- package/src/types/messages.ts +0 -16
- package/src/types/notifications.ts +0 -26
- package/src/types/payments.ts +0 -129
- package/src/types/posts.ts +0 -33
- package/src/types/reactions.ts +0 -8
- package/src/types/tags.ts +0 -13
- package/src/types/users.ts +0 -89
- package/src/utils/analytics.ts +0 -41
- package/src/utils/arangodb.ts +0 -100
- package/src/utils/auth.ts +0 -61
- package/src/utils/graphql.ts +0 -7
- package/src/utils/index.ts +0 -10
- package/src/utils/objects.ts +0 -34
- package/src/utils/redis.ts +0 -17
- package/tsconfig.json +0 -45
package/src/data/images.ts
DELETED
|
@@ -1,606 +0,0 @@
|
|
|
1
|
-
import {get as httpGet} from '@nlabs/rip-hunter';
|
|
2
|
-
import {createHash, parseChar, parseId, parseNum} from '@nlabs/utils';
|
|
3
|
-
import {aql} from 'arangojs';
|
|
4
|
-
import {AqlQuery} from 'arangojs/lib/cjs/aql-query';
|
|
5
|
-
import {ArrayCursor} from 'arangojs/lib/cjs/cursor';
|
|
6
|
-
import {DeleteObjectsRequest, PutObjectRequest} from 'aws-sdk/clients/s3';
|
|
7
|
-
import * as gm from 'gm';
|
|
8
|
-
import cloneDeep from 'lodash/cloneDeep';
|
|
9
|
-
import isEmpty from 'lodash/isEmpty';
|
|
10
|
-
import {DateTime} from 'luxon';
|
|
11
|
-
|
|
12
|
-
import {Config} from '../config';
|
|
13
|
-
import {
|
|
14
|
-
ApiContext,
|
|
15
|
-
ArangoDBLimit,
|
|
16
|
-
FileDecodedType,
|
|
17
|
-
FileEdgeType,
|
|
18
|
-
FileType,
|
|
19
|
-
GroupType,
|
|
20
|
-
GroupUserType,
|
|
21
|
-
ImageIdentifyType,
|
|
22
|
-
ImageType,
|
|
23
|
-
ImageUrlData,
|
|
24
|
-
QueryFilter
|
|
25
|
-
} from '../types';
|
|
26
|
-
import {defaultObject, getLimit, logError, logException, lowerCaseKeys, useDb} from '../utils';
|
|
27
|
-
import {decodeBase64} from './files';
|
|
28
|
-
import {getGroupDetails, isGrouped} from './groups';
|
|
29
|
-
import {s3DeleteList, s3Put} from './s3';
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Copyright (c) 2019-Present, Nitrogen Labs, Inc.
|
|
33
|
-
* Copyrights licensed under the MIT License. See the accompanying LICENSE file for terms.
|
|
34
|
-
*/
|
|
35
|
-
const eventCategory: string = 'images';
|
|
36
|
-
|
|
37
|
-
export const getImageListByUser = (context: ApiContext, userId: string, from: number, to: number): Promise<ImageType[]> => {
|
|
38
|
-
const action: string = 'getListByUser';
|
|
39
|
-
const {database} = context;
|
|
40
|
-
const formatUserId: string = parseId(userId);
|
|
41
|
-
const limit: ArangoDBLimit = getLimit(from, to);
|
|
42
|
-
const aqlQry: string = `FOR i IN images
|
|
43
|
-
FILTER i.userId == "${formatUserId}"
|
|
44
|
-
LET user = (
|
|
45
|
-
FOR u IN users
|
|
46
|
-
FILTER u._key == i.userId
|
|
47
|
-
LIMIT 1
|
|
48
|
-
RETURN u
|
|
49
|
-
)
|
|
50
|
-
${limit.aql}
|
|
51
|
-
SORT i.added
|
|
52
|
-
RETURN MERGE(i, {user: FIRST(user)})`;
|
|
53
|
-
|
|
54
|
-
return useDb(database).query(aqlQry)
|
|
55
|
-
.then((cursor: ArrayCursor) => cursor.all())
|
|
56
|
-
.catch((error: Error) => logError({
|
|
57
|
-
action,
|
|
58
|
-
category: eventCategory,
|
|
59
|
-
label: 'db_error'
|
|
60
|
-
}, error, context).then(() => null));
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
export const getImageListByGroup = (context: ApiContext, params): Promise<ImageType[]> => {
|
|
64
|
-
const action: string = 'getListByGroup';
|
|
65
|
-
const {database, userId: sessionId} = context;
|
|
66
|
-
const {filters = [], groupId, from, to} = params;
|
|
67
|
-
const formatGroupId: string = parseId(groupId);
|
|
68
|
-
const limit = getLimit(from, to);
|
|
69
|
-
|
|
70
|
-
filters
|
|
71
|
-
.map((filter: QueryFilter) => {
|
|
72
|
-
const {conditional, name, value} = filter;
|
|
73
|
-
let formatCond: string = conditional;
|
|
74
|
-
|
|
75
|
-
if(conditional !== '>=' && conditional !== '<=' && conditional !== '>' && conditional !== '<') {
|
|
76
|
-
formatCond = '==';
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
switch(name) {
|
|
80
|
-
case 'added':
|
|
81
|
-
return `p.added ${formatCond} ${parseNum(value)}`;
|
|
82
|
-
default:
|
|
83
|
-
return '';
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
return getGroupDetails(context, formatGroupId)
|
|
88
|
-
.then((group: GroupType) => {
|
|
89
|
-
if(group.privacy === 'public') {
|
|
90
|
-
filters.push(`p.groupId == "${groupId}"`);
|
|
91
|
-
const filterStr = filters.join(' && ');
|
|
92
|
-
const aqlQry: string = `FOR i IN
|
|
93
|
-
FLATTEN(
|
|
94
|
-
FOR p IN posts
|
|
95
|
-
FILTER ${filterStr}
|
|
96
|
-
LET images = (
|
|
97
|
-
FOR i, e IN INBOUND p._id hasImage
|
|
98
|
-
RETURN i
|
|
99
|
-
)
|
|
100
|
-
SORT p.added DESC
|
|
101
|
-
RETURN images
|
|
102
|
-
)
|
|
103
|
-
SORT i.added DESC
|
|
104
|
-
${limit.aql}
|
|
105
|
-
RETURN i`;
|
|
106
|
-
|
|
107
|
-
return useDb(database).query(aqlQry)
|
|
108
|
-
.then((cursor: ArrayCursor) => cursor.all())
|
|
109
|
-
.catch((error: Error) => logError({
|
|
110
|
-
action,
|
|
111
|
-
category: eventCategory,
|
|
112
|
-
label: 'db_error'
|
|
113
|
-
}, error, context).then(() => null));
|
|
114
|
-
}
|
|
115
|
-
return isGrouped(database, sessionId, groupId)
|
|
116
|
-
.then((grouped: GroupUserType) => {
|
|
117
|
-
if(grouped.isValid) {
|
|
118
|
-
filters.push(`p.groupId == "${grouped.groupId}"`);
|
|
119
|
-
const filterList: string = filters.join(' && ');
|
|
120
|
-
const aqlQry: string = `FOR p IN post
|
|
121
|
-
FILTER ${filterList}
|
|
122
|
-
FOR f IN p.files
|
|
123
|
-
FILTER f.type == "image/jpeg" || f.type == "image/png"
|
|
124
|
-
${limit.aql}
|
|
125
|
-
SORT p.added DESC
|
|
126
|
-
RETURN f`;
|
|
127
|
-
|
|
128
|
-
return useDb(database).query(aqlQry)
|
|
129
|
-
.then((cursor: ArrayCursor) => cursor.all())
|
|
130
|
-
.catch((error: Error) => logError({
|
|
131
|
-
action,
|
|
132
|
-
category: eventCategory,
|
|
133
|
-
label: 'db_error'
|
|
134
|
-
}, error, context).then(() => null));
|
|
135
|
-
}
|
|
136
|
-
return [];
|
|
137
|
-
});
|
|
138
|
-
});
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
export const getImage = (context: ApiContext, id: string): Promise<ImageType> => {
|
|
142
|
-
const action: string = 'getItem';
|
|
143
|
-
const {database} = context;
|
|
144
|
-
const formatId: string = parseId(id);
|
|
145
|
-
const aqlQry: AqlQuery = aql`FOR i IN images
|
|
146
|
-
FILTER i._key==${formatId}
|
|
147
|
-
LIMIT 1
|
|
148
|
-
RETURN i`;
|
|
149
|
-
|
|
150
|
-
return useDb(database).query(aqlQry)
|
|
151
|
-
.then((cursor: ArrayCursor) => cursor.next())
|
|
152
|
-
.then((image: ImageType = {}) => image)
|
|
153
|
-
.catch((error: Error) => logError({
|
|
154
|
-
action,
|
|
155
|
-
category: eventCategory,
|
|
156
|
-
label: 'db_error'
|
|
157
|
-
}, error, context).then(() => null));
|
|
158
|
-
};
|
|
159
|
-
|
|
160
|
-
export const updateImage = (context: ApiContext, item: FileType): Promise<ImageType> => {
|
|
161
|
-
const action: string = 'update';
|
|
162
|
-
const {database, userId: sessionId} = context;
|
|
163
|
-
|
|
164
|
-
// Item props
|
|
165
|
-
const {
|
|
166
|
-
base64 = '',
|
|
167
|
-
description = '',
|
|
168
|
-
fileType = '',
|
|
169
|
-
id,
|
|
170
|
-
itemId,
|
|
171
|
-
itemType,
|
|
172
|
-
url = ''
|
|
173
|
-
} = item;
|
|
174
|
-
|
|
175
|
-
// Save Base64 data
|
|
176
|
-
const photoId: string = id || createHash(`image-${sessionId}`);
|
|
177
|
-
const now: number = Date.now();
|
|
178
|
-
let contentType: string = fileType;
|
|
179
|
-
const formatItemId: string = parseId(itemId);
|
|
180
|
-
const formatItemType: string = parseChar(itemType).toLowerCase();
|
|
181
|
-
|
|
182
|
-
if(base64 !== '') {
|
|
183
|
-
let decodedBase64: FileDecodedType;
|
|
184
|
-
|
|
185
|
-
try {
|
|
186
|
-
decodedBase64 = decodeBase64(base64);
|
|
187
|
-
} catch(error) {
|
|
188
|
-
return logError({
|
|
189
|
-
action,
|
|
190
|
-
category: eventCategory,
|
|
191
|
-
label: 'decode_base64'
|
|
192
|
-
}, error, context).then(() => null);
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
const {data, type} = decodedBase64;
|
|
196
|
-
const imgParams: FileType = {
|
|
197
|
-
buffer: data,
|
|
198
|
-
description,
|
|
199
|
-
fileType: type,
|
|
200
|
-
id: photoId,
|
|
201
|
-
userId: sessionId
|
|
202
|
-
};
|
|
203
|
-
|
|
204
|
-
return addImage(context, imgParams)
|
|
205
|
-
.then((image: ImageType) => {
|
|
206
|
-
if(formatItemId && formatItemType) {
|
|
207
|
-
const imageEdge: FileEdgeType = {imgId: photoId, itemId: formatItemId, itemType: formatItemType};
|
|
208
|
-
return addImageEdge(context, imageEdge).then(() => image);
|
|
209
|
-
}
|
|
210
|
-
return image;
|
|
211
|
-
})
|
|
212
|
-
.catch((error) => logError({
|
|
213
|
-
action,
|
|
214
|
-
category: eventCategory,
|
|
215
|
-
label: 'image_save_error'
|
|
216
|
-
}, error, context).then(() => null));
|
|
217
|
-
} else if(url !== '') {
|
|
218
|
-
// Download image from the web
|
|
219
|
-
return httpGet(url)
|
|
220
|
-
.then((res: Response) => {
|
|
221
|
-
if(res.status !== 200) {
|
|
222
|
-
return logException({
|
|
223
|
-
action,
|
|
224
|
-
category: eventCategory,
|
|
225
|
-
label: 'fetch_image_url',
|
|
226
|
-
value: res.statusText
|
|
227
|
-
}, context).then(() => null);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
contentType = res.headers.get('content-type');
|
|
231
|
-
|
|
232
|
-
return res;
|
|
233
|
-
})
|
|
234
|
-
.then((res) => res.buffer())
|
|
235
|
-
.then((buffer: Buffer) => {
|
|
236
|
-
const imgParams = {
|
|
237
|
-
buffer,
|
|
238
|
-
description,
|
|
239
|
-
id: photoId,
|
|
240
|
-
type: contentType,
|
|
241
|
-
userId: sessionId
|
|
242
|
-
};
|
|
243
|
-
return addImage(context, imgParams).then((image: ImageType) => {
|
|
244
|
-
if(formatItemId && formatItemType) {
|
|
245
|
-
const imageEdge: FileEdgeType = {imgId: id, itemId: formatItemId, itemType: formatItemType};
|
|
246
|
-
return addImageEdge(context, imageEdge).then(() => image);
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
return image;
|
|
250
|
-
});
|
|
251
|
-
})
|
|
252
|
-
.catch((error: Error) => logError({
|
|
253
|
-
action,
|
|
254
|
-
category: eventCategory,
|
|
255
|
-
label: 'fetch_error'
|
|
256
|
-
}, error, context).then(() => null));
|
|
257
|
-
} else if(id !== '') {
|
|
258
|
-
// Update metadata
|
|
259
|
-
const update: any = {
|
|
260
|
-
description,
|
|
261
|
-
modified: now
|
|
262
|
-
};
|
|
263
|
-
const aqlQry: AqlQuery = aql`UPDATE ${id} WITH ${update} IN images RETURN NEW`;
|
|
264
|
-
|
|
265
|
-
return useDb(database).query(aqlQry)
|
|
266
|
-
.then((cursor: ArrayCursor) => cursor.next())
|
|
267
|
-
.catch((error: Error) => logError({
|
|
268
|
-
action,
|
|
269
|
-
category: eventCategory,
|
|
270
|
-
label: 'db_error'
|
|
271
|
-
}, error, context).then(() => null));
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
return null;
|
|
275
|
-
};
|
|
276
|
-
|
|
277
|
-
export const addImage = (context: ApiContext, image: ImageType): Promise<ImageType> => {
|
|
278
|
-
const action: string = 'addImage';
|
|
279
|
-
const {database} = context;
|
|
280
|
-
const {userId, id, description, buffer, fileType} = image;
|
|
281
|
-
const now: number = Date.now();
|
|
282
|
-
|
|
283
|
-
return resizeSaveImage(userId, id, buffer, fileType)
|
|
284
|
-
.then((resizedImage: any) => {
|
|
285
|
-
const insert: ImageType = {
|
|
286
|
-
...resizedImage,
|
|
287
|
-
_key: id,
|
|
288
|
-
added: now,
|
|
289
|
-
description,
|
|
290
|
-
fileType,
|
|
291
|
-
modified: now,
|
|
292
|
-
userId
|
|
293
|
-
};
|
|
294
|
-
|
|
295
|
-
const aqlQry: AqlQuery = aql`INSERT ${insert} IN images RETURN NEW`;
|
|
296
|
-
|
|
297
|
-
return useDb(database).query(aqlQry)
|
|
298
|
-
.then((cursor: ArrayCursor) => cursor.next())
|
|
299
|
-
.then(defaultObject)
|
|
300
|
-
.catch((error: Error) => logError({
|
|
301
|
-
action,
|
|
302
|
-
category: eventCategory,
|
|
303
|
-
isInternal: true,
|
|
304
|
-
label: 'db_error'
|
|
305
|
-
}, error, context).then(() => null));
|
|
306
|
-
})
|
|
307
|
-
.catch((error: Error) => logError({
|
|
308
|
-
action,
|
|
309
|
-
category: eventCategory,
|
|
310
|
-
isInternal: true,
|
|
311
|
-
label: 'image_resize'
|
|
312
|
-
}, error, context).then(() => null));
|
|
313
|
-
};
|
|
314
|
-
|
|
315
|
-
export const addImageEdge = (context: ApiContext, imageEdge: FileEdgeType): Promise<object> => {
|
|
316
|
-
const action: string = 'addImageEdge';
|
|
317
|
-
const {database, userId: sessionId} = context;
|
|
318
|
-
const {imgId, itemId, itemType} = imageEdge;
|
|
319
|
-
const now: number = Date.now();
|
|
320
|
-
const edgeCollection = useDb(database).edgeCollection('hasImage');
|
|
321
|
-
const edgeId: string = createHash(`hasImage-${imgId}-${itemId}-${sessionId}`);
|
|
322
|
-
const edge: any = {
|
|
323
|
-
_key: edgeId,
|
|
324
|
-
added: now
|
|
325
|
-
};
|
|
326
|
-
|
|
327
|
-
const formatItemType: string = parseChar(itemType).toLowerCase();
|
|
328
|
-
const formatItemId: string = parseId(itemId);
|
|
329
|
-
let itemDocId: string;
|
|
330
|
-
const formatImgId: string = parseId(imgId);
|
|
331
|
-
const imageDocId = `images/${formatImgId}`;
|
|
332
|
-
|
|
333
|
-
switch(formatItemType) {
|
|
334
|
-
case 'posts':
|
|
335
|
-
itemDocId = `posts/${formatItemId}`;
|
|
336
|
-
break;
|
|
337
|
-
default:
|
|
338
|
-
itemDocId = '';
|
|
339
|
-
break;
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
if(itemDocId) {
|
|
343
|
-
return edgeCollection.save(edge, imageDocId, itemDocId)
|
|
344
|
-
.then((fileEdge) => edgeCollection.edge(fileEdge))
|
|
345
|
-
.catch((error: Error) => logError({
|
|
346
|
-
action,
|
|
347
|
-
category: eventCategory,
|
|
348
|
-
isInternal: true,
|
|
349
|
-
label: 'db_error'
|
|
350
|
-
}, error, context).then(() => null));
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
return Promise.resolve({});
|
|
354
|
-
};
|
|
355
|
-
|
|
356
|
-
export const deleteImage = (context: ApiContext, imgId): Promise<ImageType> => {
|
|
357
|
-
const action: string = 'delete';
|
|
358
|
-
const {database, userId: sessionId} = context;
|
|
359
|
-
const formatImgId = parseId(imgId);
|
|
360
|
-
|
|
361
|
-
const aqlQry = aql`FOR i IN images
|
|
362
|
-
FILTER i._key == ${formatImgId} && i.userId == ${sessionId}
|
|
363
|
-
REMOVE i IN images
|
|
364
|
-
RETURN OLD`;
|
|
365
|
-
|
|
366
|
-
return useDb(database).query(aqlQry)
|
|
367
|
-
.then((cursor: ArrayCursor) => cursor.next())
|
|
368
|
-
.then((image: ImageType = {}) => {
|
|
369
|
-
if(!isEmpty(image)) {
|
|
370
|
-
const {_key: imageKey} = image;
|
|
371
|
-
const params: DeleteObjectsRequest = {
|
|
372
|
-
Bucket: null,
|
|
373
|
-
Delete: {
|
|
374
|
-
Objects: [
|
|
375
|
-
{Key: `users/${sessionId}/images/${imageKey}.jpg`},
|
|
376
|
-
{Key: `users/${sessionId}/thumbs/${imageKey}.jpg`}
|
|
377
|
-
],
|
|
378
|
-
Quiet: true
|
|
379
|
-
}
|
|
380
|
-
};
|
|
381
|
-
|
|
382
|
-
return s3DeleteList(params).then(() => image);
|
|
383
|
-
}
|
|
384
|
-
return {};
|
|
385
|
-
})
|
|
386
|
-
.catch((error: Error) => logError({
|
|
387
|
-
action,
|
|
388
|
-
category: eventCategory,
|
|
389
|
-
label: 'db_error'
|
|
390
|
-
}, error, context).then(() => null));
|
|
391
|
-
};
|
|
392
|
-
|
|
393
|
-
// Images
|
|
394
|
-
export const getPathUserImages = (userID: string, photoId: string, type: string, dir: string = 'images'): string => {
|
|
395
|
-
let filename: string = photoId;
|
|
396
|
-
|
|
397
|
-
switch(type) {
|
|
398
|
-
case 'image/png':
|
|
399
|
-
filename = `${photoId}.png`;
|
|
400
|
-
break;
|
|
401
|
-
default:
|
|
402
|
-
filename = `${photoId}.jpg`;
|
|
403
|
-
break;
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
return `users/${userID}/${dir}/${filename}`;
|
|
407
|
-
};
|
|
408
|
-
|
|
409
|
-
export const getUrlImages = (data: ImageUrlData): string => {
|
|
410
|
-
const {imgId, directory = 'images', imgType = 'profile', isThumb, type, typeId} = data;
|
|
411
|
-
const host: string = Config.get('environment') === 'production'
|
|
412
|
-
? `https://box.${Config.get('app.url')}`
|
|
413
|
-
: `https://s3.amazonaws.com/dev.${Config.get('app.url')}`;
|
|
414
|
-
const suffix: string = isThumb ? '-th' : '';
|
|
415
|
-
|
|
416
|
-
if(imgId) {
|
|
417
|
-
switch(type) {
|
|
418
|
-
case 'app':
|
|
419
|
-
// https://box.reaktor.io/myApp/app/images/123.jpg
|
|
420
|
-
return `${host}/${type}/${directory}/${imgId}${suffix}.jpg`;
|
|
421
|
-
case 'users':
|
|
422
|
-
// https://box.reaktor.io/myApp/users/demoUser/images/123.jpg
|
|
423
|
-
return `${host}/${type}/${typeId}/${directory}/${imgId}${suffix}.jpg`;
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
if(imgType === 'profile') {
|
|
427
|
-
return `${host}/defaults/${type}_bk${suffix}.jpg`;
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
return `${host}/defaults/${type}_wh${suffix}.jpg`;
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
return '';
|
|
434
|
-
};
|
|
435
|
-
|
|
436
|
-
export const resizeSaveImage = (userId: string,
|
|
437
|
-
photoId: string,
|
|
438
|
-
buffer: Buffer,
|
|
439
|
-
type: string = 'image/jpeg'): Promise<ImageType> => {
|
|
440
|
-
const action: string = 'resizeSaveImage';
|
|
441
|
-
const imgW: number = Config.get('image.imgSize');
|
|
442
|
-
const imgQ: number = Config.get('image.imgQuality');
|
|
443
|
-
let photo: ImageType = {};
|
|
444
|
-
const format: string = (type.split('/'))[1];
|
|
445
|
-
|
|
446
|
-
return new Promise((resolve) => {
|
|
447
|
-
gm(buffer, 'img')
|
|
448
|
-
.setFormat(format)
|
|
449
|
-
.quality(imgQ)
|
|
450
|
-
.autoOrient()
|
|
451
|
-
.resize(imgW, imgW, '>')
|
|
452
|
-
.identify({bufferStream: true}, (error: Error, val: ImageIdentifyType = {}): any => {
|
|
453
|
-
if(error) {
|
|
454
|
-
logError({
|
|
455
|
-
action,
|
|
456
|
-
category: eventCategory,
|
|
457
|
-
label: 'image_save',
|
|
458
|
-
value: 'gm_image_identify'
|
|
459
|
-
}, error, {id: userId}).catch((error) => {
|
|
460
|
-
throw error;
|
|
461
|
-
});
|
|
462
|
-
} else {
|
|
463
|
-
const formatVals = lowerCaseKeys(val);
|
|
464
|
-
const {make: cameraMake, model: cameraModel, datetimeoriginal: taken}: ImageIdentifyType = formatVals;
|
|
465
|
-
photo = {
|
|
466
|
-
...cloneDeep(photo),
|
|
467
|
-
make: cameraMake,
|
|
468
|
-
model: cameraModel,
|
|
469
|
-
taken: DateTime.fromMillis(taken).millisecond
|
|
470
|
-
};
|
|
471
|
-
|
|
472
|
-
// If no background color, get the mean color value
|
|
473
|
-
const stats = formatVals['channel statistics'];
|
|
474
|
-
|
|
475
|
-
if(stats) {
|
|
476
|
-
let {red, green, blue, mean} = stats;
|
|
477
|
-
|
|
478
|
-
if(red) {
|
|
479
|
-
mean = red['standard deviation'] || red.mean;
|
|
480
|
-
red = mean ? +((mean.split(' ')[0]).substring(0, 3)) : 0;
|
|
481
|
-
} else {
|
|
482
|
-
red = 0;
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
if(green) {
|
|
486
|
-
mean = green['standard deviation'] || green.mean;
|
|
487
|
-
green = mean ? +((mean.split(' ')[0]).substring(0, 3)) : 0;
|
|
488
|
-
} else {
|
|
489
|
-
green = 0;
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
if(blue) {
|
|
493
|
-
mean = blue['standard deviation'] || blue.mean;
|
|
494
|
-
blue = mean ? +((mean.split(' ')[0]).substring(0, 3)) : 0;
|
|
495
|
-
} else {
|
|
496
|
-
blue = 0;
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
const rgb = blue | (green << 8) | (red << 16);
|
|
500
|
-
const color = rgb.toString(16);
|
|
501
|
-
photo.color = color === '0' ? '000000' : color;
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
})
|
|
505
|
-
.stream((error: Error, stdout): any => {
|
|
506
|
-
if(error) {
|
|
507
|
-
logError({
|
|
508
|
-
action,
|
|
509
|
-
category: eventCategory,
|
|
510
|
-
isInternal: true,
|
|
511
|
-
label: 'image_save',
|
|
512
|
-
value: 'gm_image_steam'
|
|
513
|
-
}, error, {id: userId}).then(() => null);
|
|
514
|
-
} else {
|
|
515
|
-
let imageBuffer: Buffer = new Buffer('');
|
|
516
|
-
|
|
517
|
-
stdout.on('data', (data) => {
|
|
518
|
-
imageBuffer = Buffer.concat([imageBuffer, data]);
|
|
519
|
-
});
|
|
520
|
-
|
|
521
|
-
stdout.on('end', () => {
|
|
522
|
-
// Get file size
|
|
523
|
-
photo.fileSize = imageBuffer.length;
|
|
524
|
-
|
|
525
|
-
// Upload data
|
|
526
|
-
const imageObj: PutObjectRequest = {
|
|
527
|
-
ACL: 'public-read',
|
|
528
|
-
Body: imageBuffer,
|
|
529
|
-
Bucket: null,
|
|
530
|
-
ContentType: type,
|
|
531
|
-
Key: getPathUserImages(userId, photoId, type, 'images')
|
|
532
|
-
};
|
|
533
|
-
|
|
534
|
-
s3Put(imageObj)
|
|
535
|
-
.then(() => {
|
|
536
|
-
const thmW = Config.get('image.thmSize');
|
|
537
|
-
const thmQ = Config.get('image.thmQuality');
|
|
538
|
-
|
|
539
|
-
// Upload thumbnail
|
|
540
|
-
gm(imageBuffer, 'img')
|
|
541
|
-
.setFormat('jpeg')
|
|
542
|
-
.size((thumbError: Error, resizeVal) => {
|
|
543
|
-
if(!thumbError) {
|
|
544
|
-
// Get updated resize values
|
|
545
|
-
const {height, width} = resizeVal;
|
|
546
|
-
photo = {...cloneDeep(photo), height, width};
|
|
547
|
-
}
|
|
548
|
-
})
|
|
549
|
-
.gravity('Center')
|
|
550
|
-
.resize(thmW, thmW, '^')
|
|
551
|
-
.extent(thmW, thmW)
|
|
552
|
-
.quality(thmQ)
|
|
553
|
-
.stream((streamError: Error, thumbStdout): any => {
|
|
554
|
-
if(streamError) {
|
|
555
|
-
logError({
|
|
556
|
-
action,
|
|
557
|
-
category: eventCategory,
|
|
558
|
-
label: 'image_save',
|
|
559
|
-
value: 'gm_thumbnail_steam'
|
|
560
|
-
}, streamError, {id: userId})
|
|
561
|
-
.catch((error) => {
|
|
562
|
-
throw error;
|
|
563
|
-
});
|
|
564
|
-
} else {
|
|
565
|
-
let thumbBuffer: Buffer = new Buffer('');
|
|
566
|
-
|
|
567
|
-
thumbStdout.on('data', (data) => {
|
|
568
|
-
thumbBuffer = Buffer.concat([thumbBuffer, data]);
|
|
569
|
-
});
|
|
570
|
-
|
|
571
|
-
thumbStdout.on('end', () => {
|
|
572
|
-
// Upload data
|
|
573
|
-
const thumbObj: PutObjectRequest = {
|
|
574
|
-
ACL: 'public-read',
|
|
575
|
-
Body: thumbBuffer,
|
|
576
|
-
Bucket: null,
|
|
577
|
-
ContentType: type,
|
|
578
|
-
Key: getPathUserImages(userId, photoId, type, 'thumbs')
|
|
579
|
-
};
|
|
580
|
-
|
|
581
|
-
s3Put(thumbObj)
|
|
582
|
-
.then(() => {
|
|
583
|
-
resolve(photo);
|
|
584
|
-
})
|
|
585
|
-
.catch(() => logError({
|
|
586
|
-
action,
|
|
587
|
-
category: eventCategory,
|
|
588
|
-
label: 'image_save',
|
|
589
|
-
value: 's3_put_image'
|
|
590
|
-
}, streamError, {id: userId}).then(() => null));
|
|
591
|
-
});
|
|
592
|
-
}
|
|
593
|
-
});
|
|
594
|
-
})
|
|
595
|
-
.catch(() => logError({
|
|
596
|
-
action,
|
|
597
|
-
category: eventCategory,
|
|
598
|
-
isInternal: true,
|
|
599
|
-
label: 'image_save',
|
|
600
|
-
value: 's3_image_save'
|
|
601
|
-
}, error, {id: userId}).then(() => null));
|
|
602
|
-
});
|
|
603
|
-
}
|
|
604
|
-
});
|
|
605
|
-
});
|
|
606
|
-
};
|
package/src/data/index.ts
DELETED
|
@@ -1,23 +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
|
-
export * from './conversations';
|
|
6
|
-
export * from './dynamodb';
|
|
7
|
-
export * from './email';
|
|
8
|
-
export * from './files';
|
|
9
|
-
export * from './groups';
|
|
10
|
-
export * from './images';
|
|
11
|
-
export * from './ios';
|
|
12
|
-
export * from './locations';
|
|
13
|
-
export * from './messages';
|
|
14
|
-
export * from './notifications';
|
|
15
|
-
export * from './payments';
|
|
16
|
-
export * from './posts';
|
|
17
|
-
export * from './reactions';
|
|
18
|
-
export * from './s3';
|
|
19
|
-
export * from './search';
|
|
20
|
-
export * from './sms';
|
|
21
|
-
export * from './subscription';
|
|
22
|
-
export * from './tags';
|
|
23
|
-
export * from './users';
|