@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/ios.ts
DELETED
|
@@ -1,249 +0,0 @@
|
|
|
1
|
-
import {createHash} from '@nlabs/utils';
|
|
2
|
-
import {aql} from 'arangojs';
|
|
3
|
-
import {AqlQuery} from 'arangojs/lib/cjs/aql-query';
|
|
4
|
-
import {ArrayCursor} from 'arangojs/lib/cjs/cursor';
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
ApiContext,
|
|
8
|
-
PaymentIOSInAppError,
|
|
9
|
-
PaymentIOSSubscriptionInfo,
|
|
10
|
-
PaymentIOSSubscriptionUpdate,
|
|
11
|
-
PaymentSubscription
|
|
12
|
-
} from '../types';
|
|
13
|
-
import {logError, useDb} from '../utils';
|
|
14
|
-
|
|
15
|
-
const eventCategory: string = 'ios';
|
|
16
|
-
|
|
17
|
-
export const getIOSInAppError = (statusCode: string): PaymentIOSInAppError => {
|
|
18
|
-
const codes = {
|
|
19
|
-
[0]: {error: false, message: 'Active', valid: true},
|
|
20
|
-
[21000]: {error: true, id: 'payment_receipt_unreadable', message: 'App store could not read', valid: false},
|
|
21
|
-
[21002]: {error: true, id: 'payment_data_malformed', message: 'Data was malformed', valid: false},
|
|
22
|
-
[21003]: {error: true, id: 'payment_receipt_unauthorized', message: 'Receipt not authenticated', valid: false},
|
|
23
|
-
[21004]: {error: true, id: 'payment_invalid_secret', message: 'Shared secret does not match', valid: false},
|
|
24
|
-
[21005]: {error: true, id: 'payment_server_unavailable', message: 'Receipt server unavailable', valid: false},
|
|
25
|
-
[21006]: {
|
|
26
|
-
error: false,
|
|
27
|
-
id: 'payment_subscription_expired',
|
|
28
|
-
message: 'Receipt valid but sub expired',
|
|
29
|
-
valid: true
|
|
30
|
-
},
|
|
31
|
-
/**
|
|
32
|
-
* special case for app review handling - forward any request that is intended for the Sandbox but was sent to
|
|
33
|
-
* Production, this is what the app review team does
|
|
34
|
-
*/
|
|
35
|
-
[21007]: {
|
|
36
|
-
error: true,
|
|
37
|
-
id: 'payment_invalid_server',
|
|
38
|
-
message: 'Sandbox receipt sent to Production environment',
|
|
39
|
-
redirect: true,
|
|
40
|
-
valid: false
|
|
41
|
-
},
|
|
42
|
-
[21008]: {
|
|
43
|
-
error: true,
|
|
44
|
-
id: 'payment_invalid_server',
|
|
45
|
-
message: 'Production receipt sent to Sandbox environment',
|
|
46
|
-
valid: false
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
return codes[statusCode] || {};
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
export const iOSSubscriptionUpdate = (database: string, subscriptionUpdate: PaymentIOSSubscriptionUpdate): Promise<void> => {
|
|
54
|
-
const action: string = 'iOSSubscriptionUpdate';
|
|
55
|
-
const {
|
|
56
|
-
auto_renew_adam_id: planId,
|
|
57
|
-
cancellation_date: cancelDate,
|
|
58
|
-
notification_type: status,
|
|
59
|
-
latest_receipt: latestReceipt,
|
|
60
|
-
latest_receipt_info: latestInfo,
|
|
61
|
-
latest_expired_receipt: expiredReceipt,
|
|
62
|
-
latest_expired_receipt_info: expiredInfo,
|
|
63
|
-
original_transaction_id: transactionId
|
|
64
|
-
} = subscriptionUpdate;
|
|
65
|
-
const formatStatus: string = (status || '').toLowerCase();
|
|
66
|
-
const now: number = Date.now();
|
|
67
|
-
const receiptInfo: PaymentIOSSubscriptionInfo[] = latestInfo || expiredInfo;
|
|
68
|
-
const id: string = createHash(`payment-${transactionId}`);
|
|
69
|
-
|
|
70
|
-
const update: PaymentSubscription = {
|
|
71
|
-
cancelDate,
|
|
72
|
-
isValid: receiptInfo[0].expires_date_ms > now,
|
|
73
|
-
modified: now,
|
|
74
|
-
planId,
|
|
75
|
-
receipt: latestReceipt || expiredReceipt,
|
|
76
|
-
status: formatStatus
|
|
77
|
-
};
|
|
78
|
-
const insert: PaymentSubscription = {
|
|
79
|
-
...update,
|
|
80
|
-
_key: id,
|
|
81
|
-
added: now,
|
|
82
|
-
type: 'ios_payment'
|
|
83
|
-
};
|
|
84
|
-
const aqlQry: AqlQuery = aql`UPSERT {transactionId: ${transactionId}}
|
|
85
|
-
INSERT ${insert}
|
|
86
|
-
UPDATE ${update} IN subscriptions
|
|
87
|
-
LIMIT 1`;
|
|
88
|
-
|
|
89
|
-
return useDb(database).query(aqlQry)
|
|
90
|
-
.then(() => null)
|
|
91
|
-
.catch((dbError: Error) => logError({
|
|
92
|
-
action,
|
|
93
|
-
category: eventCategory,
|
|
94
|
-
label: 'db_error'
|
|
95
|
-
}, dbError, {}).then(() => null));
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
// export const addIOSInApp = (
|
|
99
|
-
// context: ApiContext,
|
|
100
|
-
// app,
|
|
101
|
-
// subscription: PaymentSubscription
|
|
102
|
-
// ): Promise<PaymentSubscription> => {
|
|
103
|
-
// const action: string = 'addIOSInApp';
|
|
104
|
-
// const {isProduction, receipt} = subscription;
|
|
105
|
-
// const {database, userId: sessionId} = context;
|
|
106
|
-
|
|
107
|
-
// const productionHost: string = 'buy.itunes.apple.com';
|
|
108
|
-
// const sandboxHost: string = 'sandbox.itunes.apple.com';
|
|
109
|
-
// const endpoint: string = isProduction ? productionHost : sandboxHost;
|
|
110
|
-
// const verifyUrl: string = `https://${endpoint}/verifyReceipt`;
|
|
111
|
-
// const payload: object = {
|
|
112
|
-
// password: app.iap,
|
|
113
|
-
// 'receipt-data': decodeURIComponent(receipt)
|
|
114
|
-
// };
|
|
115
|
-
// const options: object = {
|
|
116
|
-
// headers: {
|
|
117
|
-
// 'Content-Type': 'application/x-www-form-urlencoded'
|
|
118
|
-
// }
|
|
119
|
-
// };
|
|
120
|
-
|
|
121
|
-
// return post(verifyUrl, payload, options)
|
|
122
|
-
// .then((results) => {
|
|
123
|
-
// const json = JSON.parse(results);
|
|
124
|
-
// const {
|
|
125
|
-
// latest_receipt: latestReceipt,
|
|
126
|
-
// latest_receipt_info: latestInfo,
|
|
127
|
-
// status
|
|
128
|
-
// } = json;
|
|
129
|
-
|
|
130
|
-
// const {
|
|
131
|
-
// is_trial_period: trialPeriod,
|
|
132
|
-
// original_purchase_date_ms: added,
|
|
133
|
-
// expires_date: expires,
|
|
134
|
-
// product_id: planId,
|
|
135
|
-
// transaction_id: transactionId
|
|
136
|
-
// } = latestInfo;
|
|
137
|
-
|
|
138
|
-
// if(status === 0 || status === 21006) {
|
|
139
|
-
// const id: string = createHash(`payment-${transactionId}`);
|
|
140
|
-
// const now: number = Date.now();
|
|
141
|
-
// const update: PaymentSubscription = {
|
|
142
|
-
// expires,
|
|
143
|
-
// isTrial: trialPeriod === 'true',
|
|
144
|
-
// isValid: expires > now,
|
|
145
|
-
// modified: now,
|
|
146
|
-
// planId,
|
|
147
|
-
// receipt: latestReceipt,
|
|
148
|
-
// transactionId,
|
|
149
|
-
// userId: sessionId
|
|
150
|
-
// };
|
|
151
|
-
// const insert: PaymentSubscription = {
|
|
152
|
-
// ...update,
|
|
153
|
-
// _key: id,
|
|
154
|
-
// added,
|
|
155
|
-
// type: 'ios_payment'
|
|
156
|
-
// };
|
|
157
|
-
|
|
158
|
-
// const aqlQry: AqlQuery = aql`UPSERT {transactionId: ${transactionId}}
|
|
159
|
-
// INSERT ${insert}
|
|
160
|
-
// UPDATE ${update} IN subscriptions
|
|
161
|
-
// RETURN NEW`;
|
|
162
|
-
|
|
163
|
-
// return useDb(database).query(aqlQry)
|
|
164
|
-
// .then((cursor: ArrayCursor) => cursor.next())
|
|
165
|
-
// .then((updatedSubscription: PaymentSubscription = {}) => updatedSubscription)
|
|
166
|
-
// .catch((dbError: Error) => logError({
|
|
167
|
-
// action,
|
|
168
|
-
// category: eventCategory,
|
|
169
|
-
// label: 'db_error'
|
|
170
|
-
// }, dbError, context).then(() => null));
|
|
171
|
-
// }
|
|
172
|
-
|
|
173
|
-
// // Errors
|
|
174
|
-
// const error: PaymentIOSInAppError = getIOSInAppError(results.status);
|
|
175
|
-
|
|
176
|
-
// return logException({
|
|
177
|
-
// action,
|
|
178
|
-
// category: eventCategory,
|
|
179
|
-
// label: 'payment_error',
|
|
180
|
-
// message: error.message,
|
|
181
|
-
// value: error.id
|
|
182
|
-
// }, context).then(() => null);
|
|
183
|
-
// });
|
|
184
|
-
// };
|
|
185
|
-
|
|
186
|
-
export const getIOSSubscription = (context: ApiContext): Promise<PaymentSubscription> => {
|
|
187
|
-
const action: string = 'getIOSSubscription';
|
|
188
|
-
const {database, userId: sessionId} = context;
|
|
189
|
-
const aqlQry: AqlQuery = aql`FOR s IN subscriptions
|
|
190
|
-
FILTER s.userId == ${sessionId} && s.type == "ios_payment"
|
|
191
|
-
LIMIT 1
|
|
192
|
-
RETURN s`;
|
|
193
|
-
|
|
194
|
-
return useDb(database).query(aqlQry)
|
|
195
|
-
.then((cursor: ArrayCursor) => cursor.next())
|
|
196
|
-
.then((subscription: PaymentSubscription = {}) => subscription)
|
|
197
|
-
.catch((error: Error) => logError({
|
|
198
|
-
action,
|
|
199
|
-
category: eventCategory,
|
|
200
|
-
label: 'db_error'
|
|
201
|
-
}, error, context).then(() => null));
|
|
202
|
-
};
|
|
203
|
-
|
|
204
|
-
export const addIOSInApp = (context: ApiContext, subscription: PaymentSubscription): Promise<PaymentSubscription> => {
|
|
205
|
-
const action: string = 'addIOSInApp';
|
|
206
|
-
const {database, userId: sessionId} = context;
|
|
207
|
-
const now: number = Date.now();
|
|
208
|
-
const {added = now, planId, receipt, transactionId, trialEnd} = subscription;
|
|
209
|
-
const subscriptionId: string = createHash(`subscription-${transactionId}`);
|
|
210
|
-
const insert: PaymentSubscription = {
|
|
211
|
-
_key: subscriptionId,
|
|
212
|
-
added,
|
|
213
|
-
modified: now,
|
|
214
|
-
planId,
|
|
215
|
-
receipt,
|
|
216
|
-
transactionId,
|
|
217
|
-
trialEnd,
|
|
218
|
-
type: 'ios_subscription',
|
|
219
|
-
userId: sessionId
|
|
220
|
-
};
|
|
221
|
-
const aqlQry: AqlQuery = aql`INSERT ${insert} IN subscriptions RETURN NEW`;
|
|
222
|
-
|
|
223
|
-
return useDb(database).query(aqlQry)
|
|
224
|
-
.then((cursor: ArrayCursor) => cursor.next())
|
|
225
|
-
.then((updatedSubscription: PaymentSubscription = {}) => updatedSubscription)
|
|
226
|
-
.catch((error: Error) => logError({
|
|
227
|
-
action,
|
|
228
|
-
category: eventCategory,
|
|
229
|
-
label: 'db_error'
|
|
230
|
-
}, error, context).then(() => null));
|
|
231
|
-
};
|
|
232
|
-
|
|
233
|
-
export const getIOSInApp = (context: ApiContext): Promise<PaymentSubscription> => {
|
|
234
|
-
const action: string = 'getIOSInApp';
|
|
235
|
-
const {database, userId: sessionId} = context;
|
|
236
|
-
const aqlQry: AqlQuery = aql`FOR s IN subscription
|
|
237
|
-
FILTER s.userId == ${sessionId} && s.type == "ios"
|
|
238
|
-
LIMIT 1
|
|
239
|
-
RETURN s`;
|
|
240
|
-
|
|
241
|
-
return useDb(database).query(aqlQry)
|
|
242
|
-
.then((cursor: ArrayCursor) => cursor.next())
|
|
243
|
-
.then((subscription: PaymentSubscription = {}) => subscription)
|
|
244
|
-
.catch((error: Error) => logError({
|
|
245
|
-
action,
|
|
246
|
-
category: eventCategory,
|
|
247
|
-
label: 'db_error'
|
|
248
|
-
}, error, context).then(() => null));
|
|
249
|
-
};
|
package/src/data/locations.ts
DELETED
|
@@ -1,114 +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 {get as httpGet, queryString} from '@nlabs/rip-hunter';
|
|
6
|
-
import {createHash, parseChar, parseId} from '@nlabs/utils';
|
|
7
|
-
import {aql} from 'arangojs';
|
|
8
|
-
import {AqlQuery} from 'arangojs/lib/cjs/aql-query';
|
|
9
|
-
import {ArrayCursor} from 'arangojs/lib/cjs/cursor';
|
|
10
|
-
import get from 'lodash/get';
|
|
11
|
-
|
|
12
|
-
import {Config} from '../config';
|
|
13
|
-
import {ApiContext} from '../types/auth';
|
|
14
|
-
import {GoogleMapsAddressType} from '../types/google';
|
|
15
|
-
import {LocationType} from '../types/locations';
|
|
16
|
-
import {logError, useDb} from '../utils';
|
|
17
|
-
|
|
18
|
-
const eventCategory: string = 'locations';
|
|
19
|
-
|
|
20
|
-
export const addLocation = (context: ApiContext, location: LocationType): Promise<LocationType> => {
|
|
21
|
-
const action: string = 'add';
|
|
22
|
-
const {database, userId: sessionId} = context;
|
|
23
|
-
const {address, itemId, itemType} = location;
|
|
24
|
-
const geocodeUrl: string = Config.get('google.geocode.url');
|
|
25
|
-
const params: object = {
|
|
26
|
-
address,
|
|
27
|
-
key: Config.get('google.geocode.key')
|
|
28
|
-
};
|
|
29
|
-
const url: string = `${geocodeUrl}?${queryString(params)}`;
|
|
30
|
-
|
|
31
|
-
return httpGet(url)
|
|
32
|
-
.then((json) => {
|
|
33
|
-
const {results = [], status = ''} = json;
|
|
34
|
-
|
|
35
|
-
if(status === 'OK' && results.length) {
|
|
36
|
-
const geodata: object = results[0];
|
|
37
|
-
const addressComponents: GoogleMapsAddressType[] = get(geodata, 'address_components');
|
|
38
|
-
const getFieldVal = (name: string): string => {
|
|
39
|
-
const {short_name: shortName = ''} = addressComponents.find((addressField: GoogleMapsAddressType) => {
|
|
40
|
-
const types = addressField.types || [];
|
|
41
|
-
return types.findIndex((fieldType: string) => fieldType === name) >= 0;
|
|
42
|
-
}) || {};
|
|
43
|
-
|
|
44
|
-
return shortName;
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
// Street
|
|
48
|
-
const streetNumber: string = getFieldVal('street_number');
|
|
49
|
-
const route: string = getFieldVal('route');
|
|
50
|
-
|
|
51
|
-
// Location
|
|
52
|
-
const now: number = Date.now();
|
|
53
|
-
|
|
54
|
-
// Item
|
|
55
|
-
const formatItemType: string = parseChar(itemType).toLowerCase();
|
|
56
|
-
const formatItemId: string = parseId(itemId);
|
|
57
|
-
const googleId: string = get(geodata, 'place_id');
|
|
58
|
-
const update: LocationType = {};
|
|
59
|
-
const insert: LocationType = {
|
|
60
|
-
_key: createHash(`post-${sessionId}`),
|
|
61
|
-
added: now,
|
|
62
|
-
city: getFieldVal('locality'),
|
|
63
|
-
country: getFieldVal('country'),
|
|
64
|
-
formatted: get(geodata, 'formatted_address'),
|
|
65
|
-
googleId,
|
|
66
|
-
latitude: get(geodata, 'geometry.location.lat'),
|
|
67
|
-
longitude: get(geodata, 'geometry.location.lng'),
|
|
68
|
-
state: getFieldVal('administrative_area_level_1'),
|
|
69
|
-
street: [streetNumber, route].filter((obj) => obj).join(' '),
|
|
70
|
-
zip: getFieldVal('postal_code')
|
|
71
|
-
};
|
|
72
|
-
const aqlQry: AqlQuery = aql`UPSERT {googleId: ${googleId}}
|
|
73
|
-
INSERT ${insert}
|
|
74
|
-
UPDATE ${update}
|
|
75
|
-
IN locations RETURN NEW`;
|
|
76
|
-
|
|
77
|
-
return useDb(database).query(aqlQry)
|
|
78
|
-
.then((cursor: ArrayCursor) => cursor.next())
|
|
79
|
-
.then((updatedLocation: LocationType = {}) => {
|
|
80
|
-
let itemDocId: string;
|
|
81
|
-
const {_key: updatedLocationKey} = updatedLocation;
|
|
82
|
-
|
|
83
|
-
switch(formatItemType) {
|
|
84
|
-
case 'posts':
|
|
85
|
-
itemDocId = `posts/${formatItemId}`;
|
|
86
|
-
break;
|
|
87
|
-
default:
|
|
88
|
-
itemDocId = '';
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// If there is a valid item doc id, create an edge
|
|
92
|
-
if(itemDocId) {
|
|
93
|
-
const edgeCollection = useDb(database).edgeCollection('hasLocation');
|
|
94
|
-
const locationId: string = updatedLocationKey;
|
|
95
|
-
const locationDocId: string = `locations/${locationId}`;
|
|
96
|
-
const edgeId = createHash(`hasLocation-${locationId}-${sessionId}`);
|
|
97
|
-
const edge: any = {_key: edgeId};
|
|
98
|
-
|
|
99
|
-
return edgeCollection.save(edge, itemDocId, locationDocId).then(() => updatedLocation);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Otherwise just return the new location
|
|
103
|
-
return updatedLocation;
|
|
104
|
-
})
|
|
105
|
-
.catch((error: Error) => logError({
|
|
106
|
-
action,
|
|
107
|
-
category: eventCategory,
|
|
108
|
-
label: 'db_error'
|
|
109
|
-
}, error, context).then(() => null));
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return {};
|
|
113
|
-
});
|
|
114
|
-
};
|
package/src/data/messages.ts
DELETED
|
@@ -1,237 +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, parseId, parseVarChar} from '@nlabs/utils';
|
|
6
|
-
import {aql} from 'arangojs';
|
|
7
|
-
import {AqlQuery} from 'arangojs/lib/cjs/aql-query';
|
|
8
|
-
import {ArrayCursor} from 'arangojs/lib/cjs/cursor';
|
|
9
|
-
import cloneDeep from 'lodash/cloneDeep';
|
|
10
|
-
import isEmpty from 'lodash/isEmpty';
|
|
11
|
-
|
|
12
|
-
import {ArangoDBLimit} from '../types/arangodb';
|
|
13
|
-
import {ApiContext} from '../types/auth';
|
|
14
|
-
import {ConversationType} from '../types/conversations';
|
|
15
|
-
import {MessageType} from '../types/messages';
|
|
16
|
-
import {getLimit, useDb} from '../utils';
|
|
17
|
-
import {getConversation} from './conversations';
|
|
18
|
-
|
|
19
|
-
// const eventCategory: string = 'messages';
|
|
20
|
-
|
|
21
|
-
export const getMessageList = (context: ApiContext, convoId: string, from: number, to: number): Promise<MessageType[]> => {
|
|
22
|
-
const {database} = context;
|
|
23
|
-
const formatConvoId: string = parseId(convoId);
|
|
24
|
-
|
|
25
|
-
return getConversation(context, formatConvoId)
|
|
26
|
-
.then((conversation: ConversationType) => {
|
|
27
|
-
const {_key: conversationKey} = conversation;
|
|
28
|
-
const limit: ArangoDBLimit = getLimit(from, to);
|
|
29
|
-
const aqlQry: string = `FOR m IN messages
|
|
30
|
-
FILTER m.to == "${conversationKey}"
|
|
31
|
-
${limit.aql}
|
|
32
|
-
SORT m.added
|
|
33
|
-
RETURN m`;
|
|
34
|
-
|
|
35
|
-
return useDb(database).query(aqlQry)
|
|
36
|
-
.then((cursor: ArrayCursor) => cursor.all())
|
|
37
|
-
.catch((error: Error) => {
|
|
38
|
-
throw error;
|
|
39
|
-
});
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export const updateMessage = (context: ApiContext, message: MessageType): Promise<MessageType> => {
|
|
44
|
-
const {database, userId: sessionId} = context;
|
|
45
|
-
const {files, id: messageId, toId} = message;
|
|
46
|
-
const formatToId: string = parseId(toId);
|
|
47
|
-
|
|
48
|
-
if(formatToId === '') {
|
|
49
|
-
throw new Error('required_to');
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return getConversation(context, formatToId)
|
|
53
|
-
.then((conversation: ConversationType) => {
|
|
54
|
-
const {_key: conversationKey} = conversation;
|
|
55
|
-
const now: number = (new Date()).getTime();
|
|
56
|
-
const update: MessageType = {
|
|
57
|
-
content: parseVarChar(message.content, 640),
|
|
58
|
-
files: files || [],
|
|
59
|
-
fromId: sessionId,
|
|
60
|
-
modified: now,
|
|
61
|
-
toId: formatToId
|
|
62
|
-
};
|
|
63
|
-
const formatId: string = parseId(messageId);
|
|
64
|
-
const updatedId: string = formatId === '' ? createHash(`message-${sessionId}`) : formatId;
|
|
65
|
-
const insert: MessageType = {
|
|
66
|
-
...cloneDeep(update),
|
|
67
|
-
_key: updatedId,
|
|
68
|
-
added: now
|
|
69
|
-
};
|
|
70
|
-
const aqlQry: AqlQuery = aql`UPSERT {_key: ${updatedId}, to: ${conversationKey}}
|
|
71
|
-
INSERT ${insert}
|
|
72
|
-
UPDATE ${update}
|
|
73
|
-
IN messages RETURN NEW`;
|
|
74
|
-
|
|
75
|
-
return useDb(database).query(aqlQry)
|
|
76
|
-
.then((cursor: ArrayCursor) => cursor.next())
|
|
77
|
-
.then((updatedMessage: MessageType = {}) =>
|
|
78
|
-
// const {
|
|
79
|
-
// _key: msgId,
|
|
80
|
-
// added: msgAdded,
|
|
81
|
-
// content: msgContent,
|
|
82
|
-
// files: msgFiles,
|
|
83
|
-
// fromId: msgFromId,
|
|
84
|
-
// read: msgRead,
|
|
85
|
-
// saved: msgSaved,
|
|
86
|
-
// toId: msgToId
|
|
87
|
-
// } = updatedMessage;
|
|
88
|
-
|
|
89
|
-
// Broadcast to message box
|
|
90
|
-
// if(io) {
|
|
91
|
-
// const msg: MessageType = {
|
|
92
|
-
// added: msgAdded,
|
|
93
|
-
// content: msgContent,
|
|
94
|
-
// files: msgFiles,
|
|
95
|
-
// fromId: msgFromId,
|
|
96
|
-
// id: msgId,
|
|
97
|
-
// read: msgRead,
|
|
98
|
-
// saved: msgSaved,
|
|
99
|
-
// toId: msgToId
|
|
100
|
-
// };
|
|
101
|
-
|
|
102
|
-
// io.to(msgToId).emit('message_update', msg);
|
|
103
|
-
// }
|
|
104
|
-
|
|
105
|
-
updatedMessage
|
|
106
|
-
)
|
|
107
|
-
.catch((error: Error) => {
|
|
108
|
-
throw error;
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
export const saveMessage = (context: ApiContext, msgId: string, convoId: string): Promise<MessageType> => {
|
|
114
|
-
const {database, userId: sessionId} = context;
|
|
115
|
-
const formatId: string = parseId(msgId);
|
|
116
|
-
|
|
117
|
-
return getConversation(context, convoId)
|
|
118
|
-
.then((conversation: ConversationType) => {
|
|
119
|
-
const {_key: conversationKey} = conversation;
|
|
120
|
-
const aqlQry = aql`FOR m IN messages
|
|
121
|
-
FILTER m._key == ${formatId} && m.to == ${conversationKey}
|
|
122
|
-
UPDATE m WITH {saved: APPEND(m.saved, ${sessionId}, true)} IN messages
|
|
123
|
-
RETURN NEW`;
|
|
124
|
-
|
|
125
|
-
return useDb(database).query(aqlQry)
|
|
126
|
-
.then((cursor: ArrayCursor) => cursor.next())
|
|
127
|
-
.then((message: MessageType = {}) => {
|
|
128
|
-
if(!isEmpty(message)) {
|
|
129
|
-
// Broadcast to message box
|
|
130
|
-
// const msg: MessageType = Messages.getMessageObject(message);
|
|
131
|
-
// io.to(message.toId).emit('message_save', msg);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return message;
|
|
135
|
-
})
|
|
136
|
-
.catch((error: Error) => {
|
|
137
|
-
throw error;
|
|
138
|
-
});
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
export const unsaveMessage = (context: ApiContext, msgId: string, convoId: string): Promise<MessageType> => {
|
|
143
|
-
const {database, userId: sessionId} = context;
|
|
144
|
-
const formatId: string = parseId(msgId);
|
|
145
|
-
|
|
146
|
-
return getConversation(context, convoId)
|
|
147
|
-
.then((conversation: ConversationType) => {
|
|
148
|
-
const {_key: conversationKey} = conversation;
|
|
149
|
-
const aqlQry: AqlQuery = aql`FOR m IN messages
|
|
150
|
-
FILTER m._key == ${formatId} && m.to == ${conversationKey}
|
|
151
|
-
UPDATE m WITH {saved: REMOVE_VALUE(m.saved, ${sessionId})} IN messages
|
|
152
|
-
RETURN NEW`;
|
|
153
|
-
|
|
154
|
-
return useDb(database).query(aqlQry)
|
|
155
|
-
.then((cursor: ArrayCursor) => cursor.next())
|
|
156
|
-
.then((message: MessageType = {}) => {
|
|
157
|
-
if(!isEmpty(message)) {
|
|
158
|
-
// Broadcast to message box
|
|
159
|
-
// const msg: MessageType = Messages.getMessageObject(message);
|
|
160
|
-
// io.to(message.id).emit('message_unsave', msg);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
return message;
|
|
164
|
-
})
|
|
165
|
-
.catch((error: Error) => {
|
|
166
|
-
throw error;
|
|
167
|
-
});
|
|
168
|
-
});
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
export const deleteMessage = (context: ApiContext, msgId: string, convoId: string): Promise<MessageType> => {
|
|
172
|
-
const {database, userId: sessionId} = context;
|
|
173
|
-
const formatId: string = parseId(msgId);
|
|
174
|
-
|
|
175
|
-
return getConversation(context, convoId)
|
|
176
|
-
.then((conversation: ConversationType) => {
|
|
177
|
-
const {_key: conversationKey} = conversation;
|
|
178
|
-
const aqlQry = aql`FOR m IN messages
|
|
179
|
-
FILTER m._key == ${formatId} && m.to == ${conversationKey} && m.from == ${sessionId}
|
|
180
|
-
REMOVE m IN messages
|
|
181
|
-
RETURN OLD`;
|
|
182
|
-
|
|
183
|
-
return useDb(database).query(aqlQry)
|
|
184
|
-
.then((cursor: ArrayCursor) => cursor.next())
|
|
185
|
-
.then((message: MessageType = {}) => {
|
|
186
|
-
if(!isEmpty(message)) {
|
|
187
|
-
// Broadcast to message box
|
|
188
|
-
// const msg: MessageType = Messages.getMessageObject(message);
|
|
189
|
-
// io.to(message.toId).emit('message_delete', msg);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
return message;
|
|
193
|
-
})
|
|
194
|
-
.catch((error: Error) => {
|
|
195
|
-
throw error;
|
|
196
|
-
});
|
|
197
|
-
});
|
|
198
|
-
};
|
|
199
|
-
|
|
200
|
-
export const getMessage = (data: MessageType): MessageType => {
|
|
201
|
-
const {
|
|
202
|
-
added: msgAdded,
|
|
203
|
-
content: msgContent,
|
|
204
|
-
files: msgFiles,
|
|
205
|
-
fromId: msgFromId,
|
|
206
|
-
_key: msgId,
|
|
207
|
-
read: msgRead,
|
|
208
|
-
saved: msgSaved,
|
|
209
|
-
toId: msgToId
|
|
210
|
-
} = data;
|
|
211
|
-
|
|
212
|
-
return {
|
|
213
|
-
added: msgAdded,
|
|
214
|
-
content: msgContent,
|
|
215
|
-
files: msgFiles,
|
|
216
|
-
fromId: msgFromId,
|
|
217
|
-
id: msgId,
|
|
218
|
-
read: msgRead,
|
|
219
|
-
saved: msgSaved,
|
|
220
|
-
toId: msgToId
|
|
221
|
-
};
|
|
222
|
-
};
|
|
223
|
-
|
|
224
|
-
export const cleanMessages = (database: string): Promise<number> => {
|
|
225
|
-
// Remove all messages that are over 60 days and not saved
|
|
226
|
-
const aqlQry = aql`FOR m IN messages
|
|
227
|
-
FILTER m.added < DATE_TIMESTAMP(DATE_SUBTRACT(DATE_NOW(), 60, 'day')) && LENGTH(m.saved) > 0
|
|
228
|
-
REMOVE m IN messages
|
|
229
|
-
RETURN OLD`;
|
|
230
|
-
|
|
231
|
-
return useDb(database).query(aqlQry)
|
|
232
|
-
.then((cursor: ArrayCursor) => cursor.all())
|
|
233
|
-
.then((list: MessageType[]) => list.length)
|
|
234
|
-
.catch((error: Error) => {
|
|
235
|
-
throw error;
|
|
236
|
-
});
|
|
237
|
-
};
|
|
@@ -1,48 +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 {Notification as APNNotification, Provider, Responses} from 'apn';
|
|
6
|
-
|
|
7
|
-
import {Config} from '../config';
|
|
8
|
-
import {NotificationType} from '../types/notifications';
|
|
9
|
-
|
|
10
|
-
// const eventCategory: string = 'notifications';
|
|
11
|
-
|
|
12
|
-
// Push Notifications
|
|
13
|
-
export const getAPNProvider = (): Provider => {
|
|
14
|
-
return new Provider({
|
|
15
|
-
ca: Config.get('app.apn.ca'),
|
|
16
|
-
cert: Config.get('app.apn.cert'),
|
|
17
|
-
key: Config.get('app.apn.key'),
|
|
18
|
-
production: Config.get('environment') === 'production'
|
|
19
|
-
});
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export const pushNotification = (deviceTokens: string[], note: NotificationType): Promise<Responses> => {
|
|
23
|
-
// Push notification to device
|
|
24
|
-
const provider: Provider = getAPNProvider();
|
|
25
|
-
const notification: APNNotification = new APNNotification();
|
|
26
|
-
notification.topic = Config.get('app.apn.id');
|
|
27
|
-
notification.alert = note.message;
|
|
28
|
-
|
|
29
|
-
if(note.data) {
|
|
30
|
-
notification.mutableContent = true;
|
|
31
|
-
notification.payload = note.data;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
if(note.badge !== undefined) {
|
|
35
|
-
notification.badge = note.badge;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return provider.send(notification, deviceTokens);
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
export const clearBadges = (deviceTokens: string[]): Promise<Responses> => {
|
|
42
|
-
// Push notification to device
|
|
43
|
-
const provider = getAPNProvider();
|
|
44
|
-
const notification = new APNNotification();
|
|
45
|
-
notification.badge = 0;
|
|
46
|
-
|
|
47
|
-
return provider.send(notification, deviceTokens);
|
|
48
|
-
};
|