piper-utils 1.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.
Files changed (38) hide show
  1. package/.babelrc +12 -0
  2. package/README.md +119 -0
  3. package/bin/main.js +1003 -0
  4. package/bin/main.js.LICENSE.txt +151 -0
  5. package/bin/main.js.map +1 -0
  6. package/bitbucket-pipelines.yml +14 -0
  7. package/jasmine.json +7 -0
  8. package/package.json +62 -0
  9. package/src/database/dbSetUp/migrations.js +45 -0
  10. package/src/database/dbUtils/queryStringUtils/accessRightsUtils.js +149 -0
  11. package/src/database/dbUtils/queryStringUtils/accessRightsUtils.test.js +177 -0
  12. package/src/database/dbUtils/queryStringUtils/createFilters.js +92 -0
  13. package/src/database/dbUtils/queryStringUtils/createFilters.test.js +37 -0
  14. package/src/database/dbUtils/queryStringUtils/createIncludes.js +45 -0
  15. package/src/database/dbUtils/queryStringUtils/createIncludes.test.js +20 -0
  16. package/src/database/dbUtils/queryStringUtils/createSort.js +36 -0
  17. package/src/database/dbUtils/queryStringUtils/createSort.test.js +60 -0
  18. package/src/database/dbUtils/queryStringUtils/defaultFilters.js +108 -0
  19. package/src/database/dbUtils/queryStringUtils/defaultFilters.test.js +50 -0
  20. package/src/database/dbUtils/queryStringUtils/findAll.js +42 -0
  21. package/src/database/dbUtils/queryStringUtils/findAll.test.js +79 -0
  22. package/src/database/dbUtils/queryStringUtils/mocks/mocks.js +127 -0
  23. package/src/dynamo/dynamoUtils.js +16 -0
  24. package/src/eventManager/handleEvents.js +32 -0
  25. package/src/eventManager/handleEvents.test.js +92 -0
  26. package/src/eventManager/handleFile.js +76 -0
  27. package/src/eventManager/handleFile.test.js +352 -0
  28. package/src/eventManager/publishEvents.js +99 -0
  29. package/src/eventManager/publishEvents.test.js +161 -0
  30. package/src/eventManager/watchBucket.js +41 -0
  31. package/src/eventManager/watchBucket.test.js +137 -0
  32. package/src/index.js +40 -0
  33. package/src/requestResonse/errorCodes.js +132 -0
  34. package/src/requestResonse/requestResponse.js +198 -0
  35. package/src/requestResonse/requestResponse.test.js +241 -0
  36. package/src/s3/S3Utils.js/S3Utils.js +20 -0
  37. package/src/sns/SNSUtils.js +18 -0
  38. package/webpack.config.js +50 -0
@@ -0,0 +1,137 @@
1
+ import * as watchBucket from './watchBucket.js';
2
+ import * as handleEvents from './handleEvents.js';
3
+ import * as publishEventsFunc from './publishEvents.js';
4
+ import _ from 'lodash';
5
+
6
+ describe('watchBucket.js', () => {
7
+ describe('watchBucket', () => {
8
+ it('should fail missing event', function () {
9
+ const params = {
10
+ dynamoConfigTable: 'dynamoConfigTable',
11
+ dynamoConfigKey: 'dynamoConfigKey',
12
+ s3Bucket: 's3Bucket',
13
+ snsTopic: 'snsTopic',
14
+ createFunc: _.noop
15
+ };
16
+
17
+ expect(() => {
18
+ watchBucket.watchBucket(params);
19
+ }).toThrow();
20
+ });
21
+
22
+ it('should fail missing dynamoConfigTable', function () {
23
+ const event = {};
24
+ const params = {
25
+ event,
26
+ dynamoConfigKey: 'dynamoConfigKey',
27
+ s3Bucket: 's3Bucket',
28
+ snsTopic: 'snsTopic',
29
+ createFunc: _.noop
30
+ };
31
+
32
+ expect(() => {
33
+ watchBucket.watchBucket(params);
34
+ }).toThrow();
35
+ });
36
+
37
+ it('should fail missing dynamoConfigKey', function () {
38
+ const event = {};
39
+ const params = {
40
+ event,
41
+ dynamoConfigTable: 'dynamoConfigTable',
42
+ s3Bucket: 's3Bucket',
43
+ snsTopic: 'snsTopic',
44
+ createFunc: _.noop
45
+ };
46
+
47
+ expect(() => {
48
+ watchBucket.watchBucket(params);
49
+ }).toThrow();
50
+ });
51
+
52
+ it('should fail missing s3Bucket', function () {
53
+ const event = {};
54
+ const params = {
55
+ event,
56
+ dynamoConfigTable: 'dynamoConfigTable',
57
+ dynamoConfigKey: 'dynamoConfigKey',
58
+ snsTopic: 'snsTopic',
59
+ createFunc: _.noop
60
+ };
61
+
62
+ expect(() => {
63
+ watchBucket.watchBucket(params);
64
+ }).toThrow();
65
+ });
66
+
67
+ it('should fail missing snsTopic', function () {
68
+ const event = {};
69
+ const params = {
70
+ event,
71
+ dynamoConfigTable: 'dynamoConfigTable',
72
+ dynamoConfigKey: 'dynamoConfigKey',
73
+ s3Bucket: 's3Bucket',
74
+ createFunc: _.noop
75
+ };
76
+
77
+ expect(() => {
78
+ watchBucket.watchBucket(params);
79
+ }).toThrow();
80
+ });
81
+
82
+ it('should fail missing transformer', function () {
83
+ const event = {};
84
+ const params = {
85
+ event,
86
+ dynamoConfigTable: 'dynamoConfigTable',
87
+ dynamoConfigKey: 'dynamoConfigKey',
88
+ s3Bucket: 's3Bucket',
89
+ snsTopic: 'snsTopic'
90
+ };
91
+
92
+ expect(() => {
93
+ watchBucket.watchBucket(params);
94
+ }).toThrow();
95
+ });
96
+
97
+ it('should call publish events if not sns', function () {
98
+ const event = {};
99
+ const params = {
100
+ event,
101
+ dynamoConfigTable: 'dynamoConfigTable',
102
+ dynamoConfigKey: 'dynamoConfigKey',
103
+ s3Bucket: 's3Bucket',
104
+ snsTopic: 'snsTopic',
105
+ transformer: _.noop
106
+ };
107
+
108
+ const fromSnsSpy = spyOn(handleEvents, 'handleEvents').and.returnValue(Promise.resolve());
109
+ const publishEventsSpy = spyOn(publishEventsFunc, 'publishEvents').and.returnValue(Promise.resolve());
110
+
111
+ return watchBucket.watchBucket(params).then(() => {
112
+ expect(fromSnsSpy).not.toHaveBeenCalled();
113
+ expect(publishEventsSpy).toHaveBeenCalled();
114
+ });
115
+ });
116
+
117
+ it('should call handleEvents if sns', function () {
118
+ const event = { Records: [{ EventSource: 'aws:sns' }] };
119
+ const params = {
120
+ event,
121
+ dynamoConfigTable: 'dynamoConfigTable',
122
+ dynamoConfigKey: 'dynamoConfigKey',
123
+ s3Bucket: 's3Bucket',
124
+ snsTopic: 'snsTopic',
125
+ transformer: _.noop
126
+ };
127
+
128
+ const fromSnsSpy = spyOn(handleEvents, 'handleEvents').and.returnValue(Promise.resolve());
129
+ const publishEventsSpy = spyOn(publishEventsFunc, 'publishEvents').and.returnValue(Promise.resolve());
130
+
131
+ return watchBucket.watchBucket(params).then(() => {
132
+ expect(fromSnsSpy).toHaveBeenCalled();
133
+ expect(publishEventsSpy).not.toHaveBeenCalled();
134
+ });
135
+ });
136
+ });
137
+ });
package/src/index.js ADDED
@@ -0,0 +1,40 @@
1
+ import { handleFile as handleFileImport } from './eventManager/handleFile.js';
2
+ import { watchBucket as watchBucketImport } from './eventManager/watchBucket.js';
3
+ import { publishEvents as publishEventsImport } from './eventManager/publishEvents.js';
4
+ import { createFilters as createFiltersImport } from './database/dbUtils/queryStringUtils/createFilters.js';
5
+ import { createSort as createSortImport } from './database/dbUtils/queryStringUtils/createSort.js';
6
+ import { findAll as findAllImport } from './database/dbUtils/queryStringUtils/findAll.js';
7
+ import { checkModule as checkModuleImport } from './database/dbUtils/queryStringUtils/accessRightsUtils.js';
8
+ import { failure as failureImport, success as successImport } from './requestResonse/requestResponse.js';
9
+ import { runMigrations as runMigrationsImport } from './database/dbSetup/migrations.js';
10
+ import { getCurrentUser as getCurrentUserImport } from './requestResonse/requestResponse.js';
11
+ import { successHtml as successHtmlImport } from './requestResonse/requestResponse.js';
12
+ import { getCurrentUserNameFromCognitoEvent as getCurrentUserNameFromCognitoEventImport } from './requestResonse/requestResponse.js';
13
+ import { defaultFilters as defaultFiltersImport } from './database/dbUtils/queryStringUtils/defaultFilters.js';
14
+ import { accessRightsUtils as accessRightsUtilsImport } from './database/dbUtils/queryStringUtils/accessRightsUtils.js';
15
+ import { parseBody as parseBodyImport } from './requestResonse/requestResponse.js';
16
+ import { parseEvent as parseEventImport } from './requestResonse/requestResponse.js';
17
+ import { getBusinessesInfo as getBusinessesInfoImport } from './database/dbUtils/queryStringUtils/accessRightsUtils.js';
18
+ import { userDefaultBid as userDefaultBidImport } from './database/dbUtils/queryStringUtils/accessRightsUtils.js';
19
+ import { checkWriteAccess as checkWriteAccessImport } from './database/dbUtils/queryStringUtils/accessRightsUtils.js';
20
+
21
+ export const handleFile = handleFileImport;
22
+ export const watchBucket = watchBucketImport;
23
+ export const publishEvents = publishEventsImport;
24
+ export const createFilters = createFiltersImport;
25
+ export const createSort = createSortImport;
26
+ export const findAll = findAllImport;
27
+ export const checkModule = checkModuleImport;
28
+ export const failure = failureImport;
29
+ export const success = successImport;
30
+ export const runMigrations = runMigrationsImport;
31
+ export const getCurrentUser = getCurrentUserImport;
32
+ export const successHtml = successHtmlImport;
33
+ export const getCurrentUserNameFromCognitoEvent = getCurrentUserNameFromCognitoEventImport;
34
+ export const defaultFilters = defaultFiltersImport;
35
+ export const accessRightsUtils = accessRightsUtilsImport;
36
+ export const parseBody = parseBodyImport;
37
+ export const parseEvent = parseEventImport;
38
+ export const getBusinessesInfo = getBusinessesInfoImport;
39
+ export const userDefaultBid = userDefaultBidImport;
40
+ export const checkWriteAccess = checkWriteAccessImport;
@@ -0,0 +1,132 @@
1
+ export const errorList = {
2
+ invalidInventoryReleaseRequest: {
3
+ message: 'NOT ENOUGH INVENTORY TO FULFILL RELEASE',
4
+ errorCode: '4010',
5
+ statusCode: 400
6
+ },
7
+ alreadyReleased: {
8
+ message: 'ALREADY RELEASED',
9
+ errorCode: '4011',
10
+ statusCode: 400
11
+ },
12
+ alreadyReceived: {
13
+ message: 'RECEIVABLE ALREADY RECEIVED',
14
+ errorCode: '4012',
15
+ statusCode: 400
16
+ },
17
+ invalidItemsRequest: {
18
+ message: 'VALID ITEMS MUST BE INCLUDED',
19
+ errorCode: '4013',
20
+ statusCode: 400
21
+ },
22
+ invalidID: {
23
+ message: 'ID is invalid',
24
+ errorCode: '4014',
25
+ statusCode: 400
26
+ },
27
+ invalidReceivable: {
28
+ message: 'MUST CONTAIN AT LEAST ONE RECEIVABLE',
29
+ errorCode: '4015',
30
+ statusCode: 400
31
+ },
32
+ invalidRequest: {
33
+ message: 'INVALID REQUEST DATA',
34
+ errorCode: '4016',
35
+ statusCode: 400
36
+ },
37
+ invalidAPIKey: {
38
+ message: 'INVALID REQUEST - API MAY KEY INVALID',
39
+ errorCode: '4017',
40
+ statusCode: 400
41
+ },
42
+ qbCreationError: {
43
+ message: 'QUICKBOOKS ERROR - ERROR CREATING OBJECT IN QUICKBOOKS',
44
+ errorCode: '4018',
45
+ statusCode: 400
46
+ },
47
+ cannotReopen: {
48
+ message: 'CANNOT REOPEN - THE ORDER HAS ALREADY BEEN OPENED',
49
+ errorCode: '4018',
50
+ statusCode: 400
51
+ },
52
+ invalidDateFormat: {
53
+ message: 'INVALID DATE FORMAT',
54
+ errorCode: '4019',
55
+ statusCode: 400
56
+ },
57
+ invalidStartDate: {
58
+ message: 'INVALID START DATE',
59
+ errorCode: '4020',
60
+ statusCode: 400
61
+ },
62
+ invalidEndDate: {
63
+ message: 'INVALID END DATE',
64
+ errorCode: '4021',
65
+ statusCode: 400
66
+ },
67
+ invalidOrderStatus: {
68
+ message: 'UNABLE TO EDIT ORDER ITEMS UNLESS THE ORDER IS IN ESTIMATE STATUS',
69
+ errorCode: '4022',
70
+ statusCode: 400
71
+ },
72
+ invalidPaymentStatus: {
73
+ message: 'UNABLE TO UPDATE PAYMENT STATUS PAYMENT MUST BE OPEN',
74
+ errorCode: '4023',
75
+ statusCode: 400
76
+ },
77
+ invalidReleaseStatus: {
78
+ message: 'UNABLE TO UPDATE RELEASE, STATUS RELEASE MUST BE OPEN',
79
+ errorCode: '4024',
80
+ statusCode: 400
81
+ },
82
+ invalidReceivableStatus: {
83
+ message: 'UNABLE TO UPDATE RECEIVABLE, STATUS RECEIVABLE MUST BE OPEN',
84
+ errorCode: '40025',
85
+ statusCode: 400
86
+ },
87
+ invalidJson:{
88
+ message: 'INVALID JSON',
89
+ errorCode: '4005',
90
+ statusCode: 400
91
+ },
92
+ invalidFilter:{
93
+ message: 'INVALID FILTER',
94
+ errorCode: '4026',
95
+ statusCode: 400
96
+ },
97
+ invalidUserNameUpdate:{
98
+ message: 'UNABLE TO UPDATE USERNAME',
99
+ errorCode: '4027',
100
+ statusCode: 400
101
+ },
102
+ imageSizeLimit:{
103
+ message: 'IMAGE SIZE LIMIT 100KB EXCEEDED',
104
+ errorCode: '4028',
105
+ statusCode: 400
106
+ },
107
+ unauthorized:{
108
+ message: 'UNAUTHORIZED',
109
+ errorCode: '4111',
110
+ statusCode: 401
111
+ },
112
+ notFound:{
113
+ message: 'ITEM NOT FOUND',
114
+ errorCode: '4004',
115
+ statusCode: 404
116
+ },
117
+ emailRequired:{
118
+ message: 'NO EMAIL PROVIDED, CHECK CUSTOMER EMAIL',
119
+ errorCode: '4004',
120
+ statusCode: 404
121
+ },
122
+ mobilePhoneRequired:{
123
+ message: 'NO MOBILE PHONE PROVIDED, CHECK CUSTOMER CONTACTS',
124
+ errorCode: '4004',
125
+ statusCode: 404
126
+ },
127
+ invalidCadenceType: {
128
+ message: 'INVALID CADENCE TYPE',
129
+ errorCode: '5001',
130
+ statusCode: 500
131
+ },
132
+ };
@@ -0,0 +1,198 @@
1
+ import _ from 'lodash';
2
+ import { errorList } from './errorCodes.js';
3
+
4
+ /**
5
+ * @param {Object} body
6
+ * @param {{}} options
7
+ */
8
+ export function success(body, options) {
9
+ const dbClose = _.get(options, 'dbClose', _.noop);
10
+ dbClose();
11
+
12
+ return buildResponse(200, body);
13
+ }
14
+
15
+ /**
16
+ * @param {string} html
17
+ * @param {{dbClose:function|undefined}} options
18
+ */
19
+ export function successHtml(html, options) {
20
+ const dbClose = _.get(options, 'dbClose', _.noop);
21
+
22
+ dbClose();
23
+ return {
24
+ statusCode: 200,
25
+ headers: {
26
+ 'Content-Type': 'text/html',
27
+ 'Access-Control-Allow-Origin': '*',
28
+ 'Access-Control-Allow-Credentials': true
29
+ },
30
+ body: html
31
+ };
32
+ }
33
+
34
+ /**
35
+ * @param {string} event
36
+ * @returns string
37
+ */
38
+ export function getCurrentUserNameFromCognitoEvent(event) {
39
+ const attributes = _.get(event, 'request.userAttributes');
40
+
41
+ return attributes['cognito:email_alias'] || 'UNKNOWN USER';
42
+ }
43
+
44
+ /**
45
+ * Get the user information from the event object
46
+ *
47
+ * @param event {Object} an event object
48
+ * @returns {{username: string, id: number}}
49
+ */
50
+ export function getCurrentUser(event) {
51
+ let jsonToParse = _.get(event, 'requestContext.authorizer.claims.custom:UID') ||
52
+ _.get(event, 'requestContext.authorizer.custom:UID') ||
53
+ '0';
54
+
55
+ const id = JSON.parse(jsonToParse);
56
+
57
+ const username = _.get(event, 'requestContext.authorizer.claims.email') || _.get(event, 'requestContext.authorizer.email') || 'LOCAL TEST USER';
58
+
59
+ return {
60
+ username,
61
+ id
62
+ };
63
+ }
64
+
65
+ /**
66
+ * Create a failure response
67
+ *
68
+ * @param body {Object} an event object
69
+ * @param options {Object} an options object
70
+ * @returns {{statusCode:number, headers:object, body:string}} a response object
71
+ */
72
+ export function failure(body = {}, options) {
73
+ const dbClose = _.get(options, 'dbClose', _.noop);
74
+ dbClose();
75
+ let cleanedErrorBody;
76
+
77
+ if (process.env.UTIL_LOG === 'LOG_ALL') {
78
+ console.error('------->UTIL ERROR:', body);
79
+ }
80
+
81
+ const NORMAL_ERROR = { statusCode: 500, errorCode: '5XX', message: 'INTERNAL UTIL ERROR' };
82
+ cleanedErrorBody = body;
83
+ if (!_.isUndefined(body.details)) {
84
+ cleanedErrorBody = detectJoyError(body);
85
+ } else if (_.isUndefined(body.errorCode) || _.isUndefined(body.statusCode)) {
86
+ cleanedErrorBody = detectSequelizeError(body);
87
+ }
88
+ if(_.get(body, 'response.data.message')) {
89
+ console.error('------->UTIL ERROR: '+_.get(body, 'response.data.message'))
90
+ }
91
+
92
+ const newBody = _.merge(NORMAL_ERROR, cleanedErrorBody);
93
+
94
+ return buildResponse(newBody.statusCode, newBody);
95
+ }
96
+
97
+ /**
98
+ * Create a failure response object
99
+ *
100
+ * @param statusCode {Number} a status code
101
+ * @param body {Object} an event object
102
+ * @returns {{statusCode:number, headers:object, body:string}} a response object
103
+ */
104
+ function buildResponse(statusCode, body) {
105
+ return {
106
+ statusCode: statusCode,
107
+ headers: {
108
+ 'Access-Control-Allow-Origin': '*',
109
+ 'Access-Control-Allow-Credentials': true
110
+ },
111
+ body: JSON.stringify(body)
112
+ };
113
+ }
114
+
115
+ /**
116
+ * parse the body of the event object
117
+ *
118
+ * @param requestEvent {{body:string}} an event object
119
+ * @returns event {*} the json object of the body
120
+ */
121
+ export function parseBody(requestEvent) {
122
+
123
+ let eventBody = {};
124
+ if (_.isString(requestEvent.body)) {
125
+ try {
126
+ eventBody = JSON.parse(requestEvent.body);
127
+ } catch (e) {
128
+ // Invalid JSON
129
+ eventBody = null;
130
+
131
+ throw errorList.invalidJson;
132
+ }
133
+ } else if (_.isObject(requestEvent.body)) {
134
+ eventBody = requestEvent.body;
135
+ }
136
+
137
+ return eventBody;
138
+ }
139
+
140
+ /**
141
+ * parse the body of the event object
142
+ *
143
+ * @param requestEvent {string|object} an event object
144
+ * @param [callback] {function} undefined a call back function
145
+ * @returns event {*} the json object of the body
146
+ */
147
+ export function parseEvent(requestEvent, callback) {
148
+ let event = {};
149
+ if (_.isString(requestEvent)) {
150
+ try {
151
+ event = JSON.parse(requestEvent);
152
+ } catch (e) {
153
+ // Invalid JSON
154
+ event = null;
155
+
156
+ if (callback) {
157
+ callback(Error(e));
158
+ }
159
+ }
160
+ } else if (_.isObject(requestEvent)) {
161
+ event = requestEvent;
162
+ }
163
+
164
+ return event;
165
+ }
166
+
167
+ /**
168
+ * parse the body of the event object
169
+ * look for sequelize errors and return a message
170
+ * ERRORS should not be caught here this is a fallback for unknown database errors
171
+ *
172
+ * @param body {object} part of a body response
173
+ * @returns error message object {message:string}
174
+ */
175
+ export function detectSequelizeError(body) {
176
+ const errorBody = {};
177
+
178
+ let sequelizeError = _.get(body, 'errors', []).reduce((acc, err) => {
179
+ acc = acc + ' ' + _.get(err, 'message');
180
+ return acc;
181
+ }, '');
182
+ const parentError = _.get(body, 'parent', '');
183
+
184
+ sequelizeError = sequelizeError + _.get(body, 'original.detail', '') + _.get(body, 'TypeError', '') + parentError;
185
+ errorBody.message = sequelizeError.trim();
186
+ return errorBody;
187
+ }
188
+
189
+ export function detectJoyError(body) {
190
+ const errorBody = {};
191
+ const joyError = _.get(body, 'details[0]', {});
192
+ console.error('USER VALIDATION ERROR:', body);
193
+
194
+ errorBody.message = joyError.message;
195
+ errorBody.statusCode = 400;
196
+ errorBody.errorCode = '4000';
197
+ return errorBody;
198
+ }