diff --git a/back-end/deploy/api-stack.ts b/back-end/deploy/api-stack.ts index 6dd4c1f..ad5b729 100644 --- a/back-end/deploy/api-stack.ts +++ b/back-end/deploy/api-stack.ts @@ -27,6 +27,7 @@ export interface ApiProps extends cdk.StackProps { ses: { identityArn: string; notificationTopicArn: string }; cognito: { userPoolId: string; audience: string[] }; removalPolicy: RemovalPolicy; + lambdaLogLevel: 'TRACE' | 'DEBUG' | 'INFO' | 'WARN' | 'ERROR' | 'FATAL'; } export interface ResourceController { name: string; @@ -48,7 +49,8 @@ const defaultLambdaFnProps: NodejsFunctionProps = { memorySize: 1024, bundling: { minify: true, sourceMap: true }, environment: { NODE_OPTIONS: '--enable-source-maps' }, - logRetention: RetentionDays.TWO_WEEKS + logRetention: RetentionDays.TWO_WEEKS, + logFormat: Lambda.LogFormat.JSON }; const defaultDDBTableProps: DDB.TableProps | any = { @@ -77,7 +79,8 @@ export class ApiStack extends cdk.Stack { defaultLambdaFnProps, project: props.project, stage: props.stage, - versionStatus: props.versionStatus + versionStatus: props.versionStatus, + lambdaLogLevel: props.lambdaLogLevel }); this.allowLambdaFunctionsToAccessCognitoUserPool({ cognitoUserPoolId: props.cognito.userPoolId, @@ -172,6 +175,7 @@ export class ApiStack extends cdk.Stack { defaultLambdaFnProps: NodejsFunctionProps; api: cdk.aws_apigatewayv2.CfnApi; versionStatus: VersionStatus; + lambdaLogLevel: 'TRACE' | 'DEBUG' | 'INFO' | 'WARN' | 'ERROR' | 'FATAL'; }): { lambdaFunctions: { [resourceName: string]: NodejsFunction }; } { @@ -189,7 +193,8 @@ export class ApiStack extends cdk.Stack { const lambdaFn = new NodejsFunction(this, resource.name.concat('Function'), { ...params.defaultLambdaFnProps, functionName: lambdaFnName, - entry: `./src/handlers/${resource.name}.ts` + entry: `./src/handlers/${resource.name}.ts`, + applicationLogLevel: params.lambdaLogLevel }); // link the Lambda function to the Resource Controller's paths (if any) diff --git a/back-end/deploy/environments.ts b/back-end/deploy/environments.ts index 64fd854..4934530 100644 --- a/back-end/deploy/environments.ts +++ b/back-end/deploy/environments.ts @@ -12,12 +12,14 @@ export const stages: { [stage: string]: Stage } = { domain: 'egm-app.click', alternativeDomain: 'app.erasmusgeneration.org', frontEndCertificateARN: 'arn:aws:acm:us-east-1:767203414619:certificate/a82a1829-9d1b-4e0e-a2e7-fda8ef7a72d6', - destroyDataOnDelete: false + destroyDataOnDelete: false, + logLevel: 'INFO' }, dev: { domain: 'dev.egm-app.click', frontEndCertificateARN: 'arn:aws:acm:us-east-1:767203414619:certificate/fb400353-44df-4148-a1f7-53f180c7db70', - destroyDataOnDelete: true + destroyDataOnDelete: true, + logLevel: 'DEBUG' } }; @@ -72,6 +74,10 @@ export interface Stage { * It should be True for dev and False for prod environments. */ destroyDataOnDelete: boolean; + /** + * The minimum level of log to print in functions (default: `INFO`). + */ + logLevel?: 'TRACE' | 'DEBUG' | 'INFO' | 'WARN' | 'ERROR' | 'FATAL'; } export interface VersionStatus { diff --git a/back-end/deploy/idea-stack.ts b/back-end/deploy/idea-stack.ts index e3122fb..2217b50 100644 --- a/back-end/deploy/idea-stack.ts +++ b/back-end/deploy/idea-stack.ts @@ -14,14 +14,6 @@ export class IDEAStack extends cdk.Stack { pointInTimeRecovery: true }); - new DDB.Table(this, 'idea_ISID', { - tableName: 'idea_ISID', - partitionKey: { name: 'project', type: DDB.AttributeType.STRING }, - sortKey: { name: 'id', type: DDB.AttributeType.STRING }, - billingMode: DDB.BillingMode.PAY_PER_REQUEST, - pointInTimeRecovery: true - }); - new DDB.Table(this, 'idea_atomicCounters', { tableName: 'idea_atomicCounters', partitionKey: { name: 'key', type: DDB.AttributeType.STRING }, diff --git a/back-end/deploy/main.ts b/back-end/deploy/main.ts index 61fe999..c840a2c 100755 --- a/back-end/deploy/main.ts +++ b/back-end/deploy/main.ts @@ -182,6 +182,7 @@ const createApp = async (): Promise => { userPoolId: cognitoStack.userPool.userPoolId, audience: [cognitoStack.clientFrontEnd.userPoolClientId, cognitoStack.clientBackEnd.userPoolClientId] }, + lambdaLogLevel: STAGE_VARIABLES.logLevel ?? 'INFO', removalPolicy: STAGE_VARIABLES.destroyDataOnDelete ? cdk.RemovalPolicy.DESTROY : cdk.RemovalPolicy.RETAIN }); apiStack.addDependency(mediaStack); diff --git a/back-end/package-lock.json b/back-end/package-lock.json index f6206f5..8235d89 100644 --- a/back-end/package-lock.json +++ b/back-end/package-lock.json @@ -10,7 +10,7 @@ "dependencies": { "axios": "^1.5.1", "date-fns": "^2.30.0", - "idea-aws": "^4.2.1", + "idea-aws": "^4.3.4", "idea-html2pdf": "^2.2.5", "idea-toolbox": "^7.0.3", "jsonwebtoken": "^9.0.2", @@ -26,9 +26,9 @@ "@types/xml2js": "^0.4.12", "@typescript-eslint/eslint-plugin": "^5.47.0", "@typescript-eslint/parser": "^5.47.0", - "aws-cdk": "^2.90.0", - "aws-cdk-lib": "^2.90.0", - "constructs": "^10.2.69", + "aws-cdk": "^2.118.0", + "aws-cdk-lib": "^2.118.0", + "constructs": "^10.3.0", "esbuild": "^0.19.0", "eslint": "^8.46.0", "typescript": "^5.1.6" @@ -88,9 +88,9 @@ } }, "node_modules/@aws-cdk/asset-awscli-v1": { - "version": "2.2.200", - "resolved": "https://registry.npmjs.org/@aws-cdk/asset-awscli-v1/-/asset-awscli-v1-2.2.200.tgz", - "integrity": "sha512-Kf5J8DfJK4wZFWT2Myca0lhwke7LwHcHBo+4TvWOGJrFVVKVuuiLCkzPPRBQQVDj0Vtn2NBokZAz8pfMpAqAKg==", + "version": "2.2.202", + "resolved": "https://registry.npmjs.org/@aws-cdk/asset-awscli-v1/-/asset-awscli-v1-2.2.202.tgz", + "integrity": "sha512-JqlF0D4+EVugnG5dAsNZMqhu3HW7ehOXm5SDMxMbXNDMdsF0pxtQKNHRl52z1U9igsHmaFpUgSGjbhAJ+0JONg==", "dev": true }, "node_modules/@aws-cdk/asset-kubectl-v20": { @@ -247,19 +247,36 @@ "peer": true }, "node_modules/@aws-lambda-powertools/commons": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/commons/-/commons-1.13.0.tgz", - "integrity": "sha512-jIL1dj1pjAX5SOtQCagUF3ChIntbcDzy2Xwp08vTfvrRAqf4DMcWaW8z0Qb5A5CwrbIEXR0yFUIEEylkA4XXSQ==" + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/commons/-/commons-1.18.1.tgz", + "integrity": "sha512-gFRgQ2GJDghKvf+fXvT0kQVftgOT05W+hCa7RkfZj6HSjVAO+9DZZeJL3JK1HcsLAjWRj7W9ra0/MqB3Abf+PQ==" }, "node_modules/@aws-lambda-powertools/metrics": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/metrics/-/metrics-1.13.0.tgz", - "integrity": "sha512-PQqoD0GIrzEZx2sWi/fxzxXL+rjzFoplt1mcn7J7MDnqb326/LUlrxX/9koX2q/aVflbXGTLQpSVjC7X322bHg==", + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/metrics/-/metrics-1.18.1.tgz", + "integrity": "sha512-ebojjuoOlm0bOtZ6H5fyTnC5B0owVX1nNqDUPEQSejkeiiBW0m6DVzy6hFWuKmGtBtm2WNnWwTE//WtF+CD6Ug==", "dependencies": { - "@aws-lambda-powertools/commons": "^1.13.0" + "@aws-lambda-powertools/commons": "^1.18.1" }, "peerDependencies": { - "@middy/core": ">=3.x <4.x" + "@middy/core": ">=3.x" + }, + "peerDependenciesMeta": { + "@middy/core": { + "optional": true + } + } + }, + "node_modules/@aws-lambda-powertools/tracer": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/tracer/-/tracer-1.18.1.tgz", + "integrity": "sha512-bMLBtdEFNmLUR9RJvBULR6XJD0XopUhhS1mlpeQlm2BCPIN3gLbqAlJK8dMXyAw8GCpLpHaziCo2+7a/AIh7lA==", + "dependencies": { + "@aws-lambda-powertools/commons": "^1.18.1", + "aws-xray-sdk-core": "^3.5.3" + }, + "peerDependencies": { + "@middy/core": ">=3.x" }, "peerDependenciesMeta": { "@middy/core": { @@ -1854,7 +1871,6 @@ "version": "3.413.0", "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.413.0.tgz", "integrity": "sha512-j1xib0f/TazIFc5ySIKOlT1ujntRbaoG4LJFeEezz4ji03/wSJMI8Vi4KjzpBp8J1tTu0oRDnsxRIGixsUBeYQ==", - "peer": true, "dependencies": { "@smithy/types": "^2.3.1", "tslib": "^2.5.0" @@ -2907,12 +2923,11 @@ } }, "node_modules/@smithy/service-error-classification": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-2.0.2.tgz", - "integrity": "sha512-GTUd2j63gKy7A+ggvSdn2hc4sejG7LWfE+ZMF17vzWoNyqERWbRP7HTPS0d0Lwg1p6OQCAzvNigSrEIWVFt6iA==", - "peer": true, + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-2.1.1.tgz", + "integrity": "sha512-txEdZxPUgM1PwGvDvHzqhXisrc5LlRWYCf2yyHfvITWioAKat7srQvpjMAvgzf0t6t7j8yHrryXU9xt7RZqFpw==", "dependencies": { - "@smithy/types": "^2.3.3" + "@smithy/types": "^2.9.1" }, "engines": { "node": ">=14.0.0" @@ -2966,10 +2981,9 @@ } }, "node_modules/@smithy/types": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.3.3.tgz", - "integrity": "sha512-zTdIPR9PvFVNRdIKMQu4M5oyTaycIbUqLheQqaOi9rTWPkgjGO2wDBxMA1rBHQB81aqAEv+DbSS4jfKyQMnXRA==", - "peer": true, + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.9.1.tgz", + "integrity": "sha512-vjXlKNXyprDYDuJ7UW5iobdmyDm6g8dDG+BFUncAg/3XJaN45Gy5RWWWUVgrzIK7S4R1KWgIX5LeJcfvSI24bw==", "dependencies": { "tslib": "^2.5.0" }, @@ -3190,6 +3204,14 @@ "integrity": "sha512-Y/jsUwO18HuC0a39BuMQkSOd/kMGATh/h5LNksw8FlTafbQ3Ge3578ZoT8w8gSOsWl2qH1p/SS/R61vc0X5jIQ==", "dev": true }, + "node_modules/@types/cls-hooked": { + "version": "4.3.8", + "resolved": "https://registry.npmjs.org/@types/cls-hooked/-/cls-hooked-4.3.8.tgz", + "integrity": "sha512-tf/7H883gFA6MPlWI15EQtfNZ+oPL0gLKkOlx9UHFrun1fC/FkuyNBpTKq1B5E3T4fbvjId6WifHUdSGsMMuPg==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/json-schema": { "version": "7.0.13", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.13.tgz", @@ -3208,8 +3230,7 @@ "node_modules/@types/node": { "version": "18.17.18", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.17.18.tgz", - "integrity": "sha512-/4QOuy3ZpV7Ya1GTRz5CYSz3DgkKpyUptXuQ5PPce7uuyJAOR7r9FhkmxJfvcNUXyklbC63a+YvB3jxy7s9ngw==", - "dev": true + "integrity": "sha512-/4QOuy3ZpV7Ya1GTRz5CYSz3DgkKpyUptXuQ5PPce7uuyJAOR7r9FhkmxJfvcNUXyklbC63a+YvB3jxy7s9ngw==" }, "node_modules/@types/semver": { "version": "7.5.2", @@ -3507,15 +3528,31 @@ "node": ">=8" } }, + "node_modules/async-hook-jl": { + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/async-hook-jl/-/async-hook-jl-1.7.6.tgz", + "integrity": "sha512-gFaHkFfSxTjvoxDMYqDuGHlcRyUuamF8s+ZTtJdDzqjws4mCt7v0vuV79/E2Wr2/riMQgtG4/yUtXWs1gZ7JMg==", + "dependencies": { + "stack-chain": "^1.3.7" + }, + "engines": { + "node": "^4.7 || >=6.9 || >=7.3" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, + "node_modules/atomic-batcher": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/atomic-batcher/-/atomic-batcher-1.0.2.tgz", + "integrity": "sha512-EFGCRj4kLX1dHv1cDzTk+xbjBFj1GnJDpui52YmEcxxHHEWjYyT6l51U7n6WQ28osZH4S9gSybxe56Vm7vB61Q==" + }, "node_modules/aws-cdk": { - "version": "2.96.2", - "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.96.2.tgz", - "integrity": "sha512-13ERpPV99OFAD75PLOtl0rRMXTWn6bCrmUPwYKkLwIMkj2xWCBiwo2Y9Qg+UzEszm5NMHA1N4ichSvuZ0mt2IQ==", + "version": "2.129.0", + "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.129.0.tgz", + "integrity": "sha512-Gh/dG2aY0cvlLumYUXalg28/knVI/TrN6NZMBpRWe4gGJe/RH5JROIVB2GOEMMajkew9EiFH0ZeoC+pQ57diaQ==", "dev": true, "bin": { "cdk": "bin/cdk" @@ -3528,9 +3565,9 @@ } }, "node_modules/aws-cdk-lib": { - "version": "2.96.2", - "resolved": "https://registry.npmjs.org/aws-cdk-lib/-/aws-cdk-lib-2.96.2.tgz", - "integrity": "sha512-wDAdPUfNlteLQKrapd5c7hNYHWPzHmFfuMSrddFCajjoscsnd0LeUxM2yAzwJV7vLNp00q2SgUZqRQHcN98dmg==", + "version": "2.129.0", + "resolved": "https://registry.npmjs.org/aws-cdk-lib/-/aws-cdk-lib-2.129.0.tgz", + "integrity": "sha512-EM3zInM95YN0CM9XWmnFPlfZnXbRCm639OUeKEd1YiSGS+LW+Jbs5lSpIaXyFCR4sUXFYa6ZfaH917Gkf3yxrw==", "bundleDependencies": [ "@balena/dockerignore", "case", @@ -3545,17 +3582,17 @@ ], "dev": true, "dependencies": { - "@aws-cdk/asset-awscli-v1": "^2.2.200", + "@aws-cdk/asset-awscli-v1": "^2.2.202", "@aws-cdk/asset-kubectl-v20": "^2.1.2", "@aws-cdk/asset-node-proxy-agent-v6": "^2.0.1", "@balena/dockerignore": "^1.0.2", "case": "1.6.3", - "fs-extra": "^11.1.1", - "ignore": "^5.2.4", + "fs-extra": "^11.2.0", + "ignore": "^5.3.1", "jsonschema": "^1.4.1", "minimatch": "^3.1.2", - "punycode": "^2.3.0", - "semver": "^7.5.4", + "punycode": "^2.3.1", + "semver": "^7.6.0", "table": "^6.8.1", "yaml": "1.10.2" }, @@ -3683,7 +3720,7 @@ "license": "MIT" }, "node_modules/aws-cdk-lib/node_modules/fs-extra": { - "version": "11.1.1", + "version": "11.2.0", "dev": true, "inBundle": true, "license": "MIT", @@ -3703,7 +3740,7 @@ "license": "ISC" }, "node_modules/aws-cdk-lib/node_modules/ignore": { - "version": "5.2.4", + "version": "5.3.1", "dev": true, "inBundle": true, "license": "MIT", @@ -3778,7 +3815,7 @@ } }, "node_modules/aws-cdk-lib/node_modules/punycode": { - "version": "2.3.0", + "version": "2.3.1", "dev": true, "inBundle": true, "license": "MIT", @@ -3796,7 +3833,7 @@ } }, "node_modules/aws-cdk-lib/node_modules/semver": { - "version": "7.5.4", + "version": "7.6.0", "dev": true, "inBundle": true, "license": "ISC", @@ -3870,7 +3907,7 @@ } }, "node_modules/aws-cdk-lib/node_modules/universalify": { - "version": "2.0.0", + "version": "2.0.1", "dev": true, "inBundle": true, "license": "MIT", @@ -3902,6 +3939,22 @@ "node": ">= 6" } }, + "node_modules/aws-xray-sdk-core": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/aws-xray-sdk-core/-/aws-xray-sdk-core-3.5.3.tgz", + "integrity": "sha512-FxDRVvIHqf3bzj76M+LSyh/1V5cYuhn+YLRS+u6Xs6WindPMDn9j03v2PNskPgvUi7pMqU40aVhQphRX/YWTfQ==", + "dependencies": { + "@aws-sdk/types": "^3.4.1", + "@smithy/service-error-classification": "^2.0.4", + "@types/cls-hooked": "^4.3.3", + "atomic-batcher": "^1.0.2", + "cls-hooked": "^4.2.2", + "semver": "^7.5.3" + }, + "engines": { + "node": ">= 14.x" + } + }, "node_modules/axios": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.1.tgz", @@ -4017,6 +4070,27 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/cls-hooked": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/cls-hooked/-/cls-hooked-4.2.2.tgz", + "integrity": "sha512-J4Xj5f5wq/4jAvcdgoGsL3G103BtWpZrMo8NEinRltN+xpTZdI+M38pyQqhuFU/P792xkMFvnKSf+Lm81U1bxw==", + "dependencies": { + "async-hook-jl": "^1.7.6", + "emitter-listener": "^1.0.1", + "semver": "^5.4.1" + }, + "engines": { + "node": "^4.7 || >=6.9 || >=7.3 || >=8.2.1" + } + }, + "node_modules/cls-hooked/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "bin": { + "semver": "bin/semver" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -4053,9 +4127,9 @@ "dev": true }, "node_modules/constructs": { - "version": "10.2.70", - "resolved": "https://registry.npmjs.org/constructs/-/constructs-10.2.70.tgz", - "integrity": "sha512-z6zr1E8K/9tzJbCQzY0UGX0/oVKPFKu9C/mzEnghCG6TAJINnvlq0CMKm63XqqeMleadZYm5T3sZGJKcxJS/Pg==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/constructs/-/constructs-10.3.0.tgz", + "integrity": "sha512-vbK8i3rIb/xwZxSpTjz3SagHn1qq9BChLEfy5Hf6fB3/2eFbrwt2n9kHwQcS0CPTRBesreeAcsJfMq2229FnbQ==", "dev": true, "engines": { "node": ">= 16.14.0" @@ -4153,6 +4227,14 @@ "safe-buffer": "^5.0.1" } }, + "node_modules/emitter-listener": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/emitter-listener/-/emitter-listener-1.1.2.tgz", + "integrity": "sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ==", + "dependencies": { + "shimmer": "^1.2.0" + } + }, "node_modules/esbuild": { "version": "0.19.3", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.3.tgz", @@ -4737,17 +4819,16 @@ } }, "node_modules/idea-aws": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/idea-aws/-/idea-aws-4.2.1.tgz", - "integrity": "sha512-2M06Pd0LCKyyjNFBN5nxvsDaHfdzgdioCJiFUSDXWxANuFU08p69mYcZ4w1VQYD+KjNECVfEHhczjqADm9EIuA==", - "dependencies": { - "@aws-lambda-powertools/metrics": "^1.12.1", - "idea-toolbox": "^7.0.1", - "nanoid": "^3.3.4", - "nodemailer": "^6.9.4", - "shortid": "^2.2.16", - "source-map-support": "^0.5.21", - "uuid": "^9.0.0" + "version": "4.4.7", + "resolved": "https://registry.npmjs.org/idea-aws/-/idea-aws-4.4.7.tgz", + "integrity": "sha512-e3cz0Ahk36TcXzEXdBca/2fCuElWLkDVXkixHTUVm9cx0IvG3punFE6EhIBwahIRaV5AtY8xeAPvdkV2A+MgHw==", + "dependencies": { + "@aws-lambda-powertools/metrics": "^1.17.0", + "@aws-lambda-powertools/tracer": "^1.18.0", + "idea-toolbox": "^7.0.3", + "nanoid": "^3.3.7", + "nodemailer": "^6.9.8", + "source-map-support": "^0.5.21" }, "peerDependencies": { "@aws-sdk/client-cognito-identity-provider": "^3.388.0", @@ -4768,18 +4849,6 @@ "@aws-sdk/util-dynamodb": "^3.388.0" } }, - "node_modules/idea-aws/node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "bin": { - "uuid": "dist/bin/uuid" - } - }, "node_modules/idea-html2pdf": { "version": "2.2.5", "resolved": "https://registry.npmjs.org/idea-html2pdf/-/idea-html2pdf-2.2.5.tgz", @@ -5154,9 +5223,9 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "funding": [ { "type": "github", @@ -5188,9 +5257,9 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, "node_modules/nodemailer": { - "version": "6.9.5", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.5.tgz", - "integrity": "sha512-/dmdWo62XjumuLc5+AYQZeiRj+PRR8y8qKtFCOyuOl1k/hckZd8durUUHs/ucKx6/8kN+wFxqKJlQ/LK/qR5FA==", + "version": "6.9.9", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.9.tgz", + "integrity": "sha512-dexTll8zqQoVJEZPwQAKzxxtFn0qTnjdQTchoU6Re9BUUGBJiOy3YMn/0ShTW6J5M0dfQ1NeDeRTTl4oIWgQMA==", "engines": { "node": ">=6.0.0" } @@ -5511,19 +5580,10 @@ "node": ">=8" } }, - "node_modules/shortid": { - "version": "2.2.16", - "resolved": "https://registry.npmjs.org/shortid/-/shortid-2.2.16.tgz", - "integrity": "sha512-Ugt+GIZqvGXCIItnsL+lvFJOiN7RYqlGy7QE41O3YC1xbNSeDGIRO7xg2JJXIAj1cAGnOeC1r7/T9pgrtQbv4g==", - "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", - "dependencies": { - "nanoid": "^2.1.0" - } - }, - "node_modules/shortid/node_modules/nanoid": { - "version": "2.1.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-2.1.11.tgz", - "integrity": "sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA==" + "node_modules/shimmer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", + "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==" }, "node_modules/slash": { "version": "3.0.0", @@ -5557,6 +5617,11 @@ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, + "node_modules/stack-chain": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/stack-chain/-/stack-chain-1.3.7.tgz", + "integrity": "sha512-D8cWtWVdIe/jBA7v5p5Hwl5yOSOrmZPWDPe2KxQ5UAGD+nxbxU0lKXA4h85Ta6+qgdKVL3vUxsbIZjc1kBG7ug==" + }, "node_modules/stream-browserify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", @@ -5639,8 +5704,7 @@ "node_modules/tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "peer": true + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "node_modules/tsutils": { "version": "3.21.0", diff --git a/back-end/package.json b/back-end/package.json index d4ff94b..3a9b295 100644 --- a/back-end/package.json +++ b/back-end/package.json @@ -12,7 +12,7 @@ "dependencies": { "axios": "^1.5.1", "date-fns": "^2.30.0", - "idea-aws": "^4.2.1", + "idea-aws": "^4.3.4", "idea-html2pdf": "^2.2.5", "idea-toolbox": "^7.0.3", "jsonwebtoken": "^9.0.2", @@ -28,9 +28,9 @@ "@types/xml2js": "^0.4.12", "@typescript-eslint/eslint-plugin": "^5.47.0", "@typescript-eslint/parser": "^5.47.0", - "aws-cdk": "^2.90.0", - "aws-cdk-lib": "^2.90.0", - "constructs": "^10.2.69", + "aws-cdk": "^2.118.0", + "aws-cdk-lib": "^2.118.0", + "constructs": "^10.3.0", "esbuild": "^0.19.0", "eslint": "^8.46.0", "typescript": "^5.1.6" diff --git a/back-end/src/handlers/cognito.ts b/back-end/src/handlers/cognito.ts index 644669e..7cd7320 100644 --- a/back-end/src/handlers/cognito.ts +++ b/back-end/src/handlers/cognito.ts @@ -2,7 +2,7 @@ /// IMPORTS /// -import { Cognito, DynamoDB, RCError, ResourceController, SystemsManager } from 'idea-aws'; +import { Cognito, DynamoDB, HandledError, ResourceController, SystemsManager } from 'idea-aws'; import { createAuthTokenWithUserId } from '../utils/auth.utils'; @@ -43,7 +43,7 @@ class CognitoRC extends ResourceController { case 'RESET_PASSWORD_CONFIRM': return this.confirmResetPassword(this.body.email, this.body.password, this.body.confirmationCode); default: - throw new RCError('Unsupported action'); + throw new HandledError('Unsupported action'); } } private async signIn(email: string, password: string): Promise<{ token: string }> { @@ -51,7 +51,7 @@ class CognitoRC extends ResourceController { await cognito.signIn(email, password, COGNITO_USER_POOL_ID, COGNITO_USER_POOL_CLIENT_ID); } catch (error) { this.logger.error('Cognito sign in failed', error); - throw new RCError('Cognito sign-in failed'); + throw new HandledError('Cognito sign-in failed'); } const cognitoUser = await cognito.getUserByEmail(email, COGNITO_USER_POOL_ID); @@ -78,7 +78,7 @@ class CognitoRC extends ResourceController { const user = new User({ authService: AuthServices.COGNITO, firstName, lastName, email }); const errors = user.validate(); - if (errors.length) throw new RCError(`Invalid fields: ${errors.join(', ')}`); + if (errors.length) throw new HandledError(`Invalid fields: ${errors.join(', ')}`); try { const cognitoUserId = await cognito.createUser(email, COGNITO_USER_POOL_ID, { @@ -91,7 +91,7 @@ class CognitoRC extends ResourceController { await ddb.put({ TableName: DDB_TABLES.users, Item: user }); } catch (error) { this.logger.error('Cognito sign up failed', error); - throw new RCError('Cognito sign up failed'); + throw new HandledError('Cognito sign up failed'); } const token = await createAuthTokenWithUserId(ssm, user.userId); diff --git a/back-end/src/handlers/communications.ts b/back-end/src/handlers/communications.ts index d28e1ea..4e50b74 100644 --- a/back-end/src/handlers/communications.ts +++ b/back-end/src/handlers/communications.ts @@ -2,7 +2,7 @@ /// IMPORTS /// -import { DynamoDB, RCError, ResourceController } from 'idea-aws'; +import { DynamoDB, HandledError, ResourceController } from 'idea-aws'; import { Communication, CommunicationWithMarker } from '../models/communication.model'; import { User } from '../models/user.model'; @@ -39,7 +39,7 @@ class Communications extends ResourceController { try { this.user = new User(await ddb.get({ TableName: DDB_TABLES.users, Key: { userId: this.principalId } })); } catch (err) { - throw new RCError('User not found'); + throw new HandledError('User not found'); } if (!this.resourceId) return; @@ -49,7 +49,7 @@ class Communications extends ResourceController { await ddb.get({ TableName: DDB_TABLES.communications, Key: { communicationId: this.resourceId } }) ); } catch (err) { - throw new RCError('Communication not found'); + throw new HandledError('Communication not found'); } } @@ -69,7 +69,7 @@ class Communications extends ResourceController { } protected async putResource(): Promise { - if (!this.user.permissions.canManageContents) throw new RCError('Unauthorized'); + if (!this.user.permissions.canManageContents) throw new HandledError('Unauthorized'); const oldResource = new Communication(this.communication); this.communication.safeLoad(this.body, oldResource); @@ -78,7 +78,7 @@ class Communications extends ResourceController { } private async putSafeResource(opts: { noOverwrite?: boolean } = {}): Promise { const errors = this.communication.validate(); - if (errors.length) throw new RCError(`Invalid fields: ${errors.join(', ')}`); + if (errors.length) throw new HandledError(`Invalid fields: ${errors.join(', ')}`); try { const putParams: any = { TableName: DDB_TABLES.communications, Item: this.communication }; @@ -87,7 +87,7 @@ class Communications extends ResourceController { return this.communication; } catch (err) { - throw new RCError('Operation failed'); + throw new HandledError('Operation failed'); } } @@ -98,7 +98,7 @@ class Communications extends ResourceController { case 'MARK_AS_UNREAD': return await this.markAsReadForUser(false); default: - throw new RCError('Unsupported action'); + throw new HandledError('Unsupported action'); } } private async markAsReadForUser(markRead: boolean): Promise { @@ -109,17 +109,17 @@ class Communications extends ResourceController { } protected async deleteResource(): Promise { - if (!this.user.permissions.canManageContents) throw new RCError('Unauthorized'); + if (!this.user.permissions.canManageContents) throw new HandledError('Unauthorized'); try { await ddb.delete({ TableName: DDB_TABLES.communications, Key: { communicationId: this.resourceId } }); } catch (err) { - throw new RCError('Delete failed'); + throw new HandledError('Delete failed'); } } protected async postResources(): Promise { - if (!this.user.permissions.canManageContents) throw new RCError('Unauthorized'); + if (!this.user.permissions.canManageContents) throw new HandledError('Unauthorized'); this.communication = new Communication(this.body); this.communication.communicationId = await ddb.IUNID(PROJECT); @@ -151,7 +151,7 @@ class Communications extends ResourceController { return sortedCommunications; } catch (err) { - throw new RCError('Operation failed'); + throw new HandledError('Operation failed'); } } } diff --git a/back-end/src/handlers/configurations.ts b/back-end/src/handlers/configurations.ts index a968946..55d103a 100644 --- a/back-end/src/handlers/configurations.ts +++ b/back-end/src/handlers/configurations.ts @@ -2,7 +2,7 @@ /// IMPORTS /// -import { DynamoDB, GetObjectTypes, RCError, ResourceController, S3, SES } from 'idea-aws'; +import { DynamoDB, HandledError, ResourceController, S3, SES } from 'idea-aws'; import { toISODate } from 'idea-toolbox'; import { sendEmail } from '../utils/notifications.utils'; @@ -60,17 +60,17 @@ class ConfigurationsRC extends ResourceController { try { this.user = new User(await ddb.get({ TableName: DDB_TABLES.users, Key: { userId: this.principalId } })); } catch (err) { - throw new RCError('User not found'); + throw new HandledError('User not found'); } - if (!this.user.permissions.isAdmin) throw new RCError('Unauthorized'); + if (!this.user.permissions.isAdmin) throw new HandledError('Unauthorized'); try { this.configurations = new Configurations( await ddb.get({ TableName: DDB_TABLES.configurations, Key: { PK: Configurations.PK } }) ); } catch (err) { - throw new RCError('Configuration not found'); + throw new HandledError('Configuration not found'); } } @@ -86,7 +86,7 @@ class ConfigurationsRC extends ResourceController { } private async putSafeResource(): Promise { const errors = this.configurations.validate(); - if (errors.length) throw new RCError(`Invalid fields: ${errors.join(', ')}`); + if (errors.length) throw new HandledError(`Invalid fields: ${errors.join(', ')}`); await ddb.put({ TableName: DDB_TABLES.configurations, Item: this.configurations }); return this.configurations; @@ -103,7 +103,7 @@ class ConfigurationsRC extends ResourceController { case 'TEST_EMAIL_TEMPLATE': return await this.testEmailTemplate(this.body.template); default: - throw new RCError('Unsupported action'); + throw new HandledError('Unsupported action'); } } private async getEmailTemplate(emailTemplate: string): Promise<{ subject: string; content: string }> { @@ -111,12 +111,12 @@ class ConfigurationsRC extends ResourceController { const template = await ses.getTemplate(`${emailTemplate}-${STAGE}`); return { subject: template.Subject, content: template.Html }; } catch (error) { - throw new RCError('Template not found'); + throw new HandledError('Template not found'); } } private async setEmailTemplate(emailTemplate: string, subject: string, content: string): Promise { - if (!subject) throw new RCError('Missing subject'); - if (!content) throw new RCError('Missing content'); + if (!subject) throw new HandledError('Missing subject'); + if (!content) throw new HandledError('Missing content'); await ses.setTemplate(`${emailTemplate}-${STAGE}`, subject, content, true); } @@ -140,22 +140,21 @@ class ConfigurationsRC extends ResourceController { await sendEmail(toAddresses, template, templateData); } catch (error) { this.logger.warn('Error sending email', error, { template }); - throw new RCError('Error sending email'); + throw new HandledError('Error sending email'); } try { await ses.sendTemplatedEmail({ toAddresses, template, templateData }, SES_CONFIG); } catch (error) { this.logger.warn('Sending template', error, { template }); - throw new RCError('Sending failed'); + throw new HandledError('Sending failed'); } } private async resetEmailTemplate(emailTemplate: string): Promise { const subject = `${emailTemplate}-${STAGE}`; - const content = (await s3.getObject({ + const content = (await s3.getObjectAsText({ bucket: S3_BUCKET_MEDIA, - key: S3_ASSETS_FOLDER.concat('/', emailTemplate, '.hbs'), - type: GetObjectTypes.TEXT + key: S3_ASSETS_FOLDER.concat('/', emailTemplate, '.hbs') })) as string; await ses.setTemplate(`${emailTemplate}-${STAGE}`, subject, content, true); } diff --git a/back-end/src/handlers/connections.ts b/back-end/src/handlers/connections.ts index 23154ac..e00639c 100644 --- a/back-end/src/handlers/connections.ts +++ b/back-end/src/handlers/connections.ts @@ -2,7 +2,7 @@ /// IMPORTS /// -import { DynamoDB, RCError, ResourceController } from 'idea-aws'; +import { DynamoDB, HandledError, ResourceController } from 'idea-aws'; import { Connection, ConnectionWithUserData } from '../models/connection.model'; import { User } from '../models/user.model'; @@ -70,30 +70,30 @@ class Connections extends ResourceController { return sortedUserConnections; } catch (err) { - throw new RCError('Operation failed'); + throw new HandledError('Operation failed'); } } protected async postResources(): Promise { - if (!this.body.userId) throw new RCError('Missing target user'); - if (this.principalId === this.body.userId) throw new RCError('Same user'); + if (!this.body.userId) throw new HandledError('Missing target user'); + if (this.principalId === this.body.userId) throw new HandledError('Same user'); let target: User; try { target = new User(await ddb.get({ TableName: DDB_TABLES.users, Key: { userId: this.body.userId } })); } catch (error) { - throw new RCError('Target profile not found'); + throw new HandledError('Target profile not found'); } - if (!target.getName()) throw new RCError('Target profile incomplete'); + if (!target.getName()) throw new HandledError('Target profile incomplete'); let connection = await this.getConnectionOfUserWithTarget(target.userId); if (connection) { if (connection.requesterId === this.principalId) { - if (connection.isPending) throw new RCError('Connection is pending'); - else throw new RCError('Already connected'); + if (connection.isPending) throw new HandledError('Connection is pending'); + else throw new HandledError('Already connected'); } else { if (connection.isPending) delete connection.isPending; - else throw new RCError('Already connected'); + else throw new HandledError('Already connected'); } } else { connection = new Connection({ @@ -109,7 +109,7 @@ class Connections extends ResourceController { return new ConnectionWithUserData({ ...connection, userProfile: target }); } catch (err) { - throw new RCError('Connection failed'); + throw new HandledError('Connection failed'); } } @@ -118,16 +118,16 @@ class Connections extends ResourceController { try { connection = await ddb.get({ TableName: DDB_TABLES.connections, Key: { connectionId: this.resourceId } }); } catch (error) { - throw new RCError('Not found'); + throw new HandledError('Not found'); } if (connection.requesterId !== this.principalId && connection.targetId !== this.principalId) - throw new RCError('Unauthorized'); + throw new HandledError('Unauthorized'); try { await ddb.delete({ TableName: DDB_TABLES.connections, Key: { connectionId: this.resourceId } }); } catch (err) { - throw new RCError('Delete failed'); + throw new HandledError('Delete failed'); } } diff --git a/back-end/src/handlers/eventSpots.ts b/back-end/src/handlers/eventSpots.ts index 61c43d0..fc18964 100644 --- a/back-end/src/handlers/eventSpots.ts +++ b/back-end/src/handlers/eventSpots.ts @@ -4,7 +4,7 @@ import { addWeeks } from 'date-fns'; -import { DynamoDB, RCError, ResourceController } from 'idea-aws'; +import { DynamoDB, HandledError, ResourceController } from 'idea-aws'; import { toISODate } from 'idea-toolbox'; import { sendEmail } from '../utils/notifications.utils'; @@ -47,13 +47,13 @@ class EventSpotsRC extends ResourceController { await ddb.get({ TableName: DDB_TABLES.configurations, Key: { PK: Configurations.PK } }) ); } catch (err) { - throw new RCError('Configuration not found'); + throw new HandledError('Configuration not found'); } try { this.user = new User(await ddb.get({ TableName: DDB_TABLES.users, Key: { userId: this.principalId } })); } catch (err) { - throw new RCError('User not found'); + throw new HandledError('User not found'); } if ( @@ -61,18 +61,18 @@ class EventSpotsRC extends ResourceController { !this.user.permissions.canManageRegistrations && !this.user.permissions.isCountryLeader ) - throw new RCError('Unauthorized'); + throw new HandledError('Unauthorized'); if (!this.resourceId) return; try { this.spot = new EventSpot(await ddb.get({ TableName: DDB_TABLES.eventSpots, Key: { spotId: this.resourceId } })); } catch (err) { - throw new RCError('Spot not found'); + throw new HandledError('Spot not found'); } if (!this.user.permissions.canManageRegistrations && this.spot.sectionCountry !== this.user.sectionCountry) - throw new RCError('Unauthorized'); + throw new HandledError('Unauthorized'); } protected async getResource(): Promise { @@ -94,21 +94,21 @@ class EventSpotsRC extends ResourceController { case 'EDIT_DESCRIPTION': return await this.editDescription(this.body.description); default: - throw new RCError('Unsupported action'); + throw new HandledError('Unsupported action'); } } private async assignToUser(userId: string): Promise { if (!this.user.permissions.isAdmin && !this.configurations.canCountryLeadersAssignSpots) - throw new RCError('Unauthorized'); + throw new HandledError('Unauthorized'); let user: User; try { user = new User(await ddb.get({ TableName: DDB_TABLES.users, Key: { userId } })); } catch (error) { - throw new RCError("User doesn't exist"); + throw new HandledError("User doesn't exist"); } - if (user.spot) throw new RCError('User already has spot'); + if (user.spot) throw new HandledError('User already has spot'); const updateSpot = { TableName: DDB_TABLES.eventSpots, @@ -143,23 +143,23 @@ class EventSpotsRC extends ResourceController { } } private async transferToUser(targetUserId: string): Promise { - if (!this.user.permissions.isAdmin) throw new RCError('Unauthorized'); + if (!this.user.permissions.isAdmin) throw new HandledError('Unauthorized'); let sourceUser: User; try { sourceUser = new User(await ddb.get({ TableName: DDB_TABLES.users, Key: { userId: this.spot.userId } })); } catch (error) { - throw new RCError("Source user doesn't exist"); + throw new HandledError("Source user doesn't exist"); } let targetUser: User; try { targetUser = new User(await ddb.get({ TableName: DDB_TABLES.users, Key: { userId: targetUserId } })); } catch (error) { - throw new RCError("Target user doesn't exist"); + throw new HandledError("Target user doesn't exist"); } - if (targetUser.spot) throw new RCError('Target user already has spot'); + if (targetUser.spot) throw new HandledError('Target user already has spot'); const updateSpot = { TableName: DDB_TABLES.eventSpots, @@ -213,7 +213,7 @@ class EventSpotsRC extends ResourceController { } } private async confirmPayment(): Promise { - if (!this.user.permissions.canManageRegistrations) throw new RCError('Unauthorized'); + if (!this.user.permissions.canManageRegistrations) throw new HandledError('Unauthorized'); if (this.spot.paymentConfirmedAt) return; @@ -234,7 +234,7 @@ class EventSpotsRC extends ResourceController { try { user = new User(await ddb.get({ TableName: DDB_TABLES.users, Key: { userId: this.spot.userId } })); } catch (error) { - throw new RCError("User doesn't exist"); + throw new HandledError("User doesn't exist"); } const updateUser = { @@ -264,7 +264,7 @@ class EventSpotsRC extends ResourceController { } } private async assignToCountry(sectionCountry: string): Promise { - if (!this.user.permissions.isAdmin) throw new RCError('Unauthorized'); + if (!this.user.permissions.isAdmin) throw new HandledError('Unauthorized'); await ddb.update({ TableName: DDB_TABLES.eventSpots, @@ -274,7 +274,7 @@ class EventSpotsRC extends ResourceController { }); } private async release(): Promise { - if (!this.user.permissions.isAdmin) throw new RCError('Unauthorized'); + if (!this.user.permissions.isAdmin) throw new HandledError('Unauthorized'); if (!this.spot.userId && !this.spot.sectionCountry) return; @@ -291,7 +291,7 @@ class EventSpotsRC extends ResourceController { try { user = new User(await ddb.get({ TableName: DDB_TABLES.users, Key: { userId: this.spot.userId } })); } catch (error) { - throw new RCError("User doesn't exist"); + throw new HandledError("User doesn't exist"); } const updateUser = { @@ -320,7 +320,7 @@ class EventSpotsRC extends ResourceController { } } private async editDescription(description: string): Promise { - if (!this.user.permissions.isAdmin) throw new RCError('Unauthorized'); + if (!this.user.permissions.isAdmin) throw new HandledError('Unauthorized'); await ddb.update({ TableName: DDB_TABLES.eventSpots, @@ -331,9 +331,9 @@ class EventSpotsRC extends ResourceController { } protected async deleteResource(): Promise { - if (!this.user.permissions.isAdmin) throw new RCError('Unauthorized'); + if (!this.user.permissions.isAdmin) throw new HandledError('Unauthorized'); - if (this.spot.userId) throw new RCError('Release the spot first'); + if (this.spot.userId) throw new HandledError('Release the spot first'); await ddb.delete({ TableName: DDB_TABLES.eventSpots, Key: { spotId: this.spot.spotId } }); } @@ -346,7 +346,7 @@ class EventSpotsRC extends ResourceController { } protected async postResources(): Promise { - if (!this.user.permissions.isAdmin) throw new RCError('Unauthorized'); + if (!this.user.permissions.isAdmin) throw new HandledError('Unauthorized'); const numOfSpots = Number(this.body.numOfSpots ?? 1); this.spot = new EventSpot({ @@ -357,7 +357,7 @@ class EventSpotsRC extends ResourceController { const errors = this.spot.validate(); if (numOfSpots < 1) errors.push('numOfSpots'); - if (errors.length) throw new RCError(`Invalid fields: ${errors.join(', ')}`); + if (errors.length) throw new HandledError(`Invalid fields: ${errors.join(', ')}`); const batchId = Math.round(Date.now() / 1000).toString(); const spotsToAdd: EventSpot[] = []; diff --git a/back-end/src/handlers/galaxy.ts b/back-end/src/handlers/galaxy.ts index 4c5cf20..44cd4f0 100644 --- a/back-end/src/handlers/galaxy.ts +++ b/back-end/src/handlers/galaxy.ts @@ -4,7 +4,7 @@ import { default as Axios } from 'axios'; import { parseStringPromise } from 'xml2js'; -import { DynamoDB, RCError, ResourceController, SystemsManager } from 'idea-aws'; +import { DynamoDB, HandledError, ResourceController, SystemsManager } from 'idea-aws'; import { createAuthTokenWithUserId } from '../utils/auth.utils'; @@ -51,7 +51,7 @@ class GalaxyRC extends ResourceController { this.logger.debug('CAS ticket validated and parsed', { ticket: jsonWithUserData }); const success = !!jsonWithUserData['cas:serviceResponse']['cas:authenticationSuccess']; - if (!success) throw new RCError('ESN accounts sign-in failed'); + if (!success) throw new HandledError('ESN accounts sign-in failed'); const data = jsonWithUserData['cas:serviceResponse']['cas:authenticationSuccess'][0]; const attributes = data['cas:attributes'][0]; @@ -96,7 +96,7 @@ class GalaxyRC extends ResourceController { this.callback(null, { statusCode: 302, headers: { Location: `${appURL}/auth?token=${token}` } }); } catch (err) { this.logger.error('ESN Accounts sign-in failed', err); - throw new RCError('ESN Accounts sign-in failed'); + throw new HandledError('ESN Accounts sign-in failed'); } } } diff --git a/back-end/src/handlers/organizations.ts b/back-end/src/handlers/organizations.ts index b99da7a..226016d 100644 --- a/back-end/src/handlers/organizations.ts +++ b/back-end/src/handlers/organizations.ts @@ -2,7 +2,7 @@ /// IMPORTS /// -import { DynamoDB, RCError, ResourceController } from 'idea-aws'; +import { DynamoDB, HandledError, ResourceController } from 'idea-aws'; import { Organization } from '../models/organization.model'; import { User } from '../models/user.model'; @@ -56,7 +56,7 @@ class Organizations extends ResourceController { try { this.user = new User(await ddb.get({ TableName: DDB_TABLES.users, Key: { userId: this.principalId } })); } catch (err) { - throw new RCError('User not found'); + throw new HandledError('User not found'); } if (!this.resourceId) return; @@ -66,7 +66,7 @@ class Organizations extends ResourceController { await ddb.get({ TableName: DDB_TABLES.organizations, Key: { organizationId: this.resourceId } }) ); } catch (err) { - throw new RCError('Organization not found'); + throw new HandledError('Organization not found'); } } @@ -75,7 +75,7 @@ class Organizations extends ResourceController { } protected async putResource(): Promise { - if (!this.user.permissions.canManageContents) throw new RCError('Unauthorized'); + if (!this.user.permissions.canManageContents) throw new HandledError('Unauthorized'); const oldResource = new Organization(this.organization); this.organization.safeLoad(this.body, oldResource); @@ -84,7 +84,7 @@ class Organizations extends ResourceController { } private async putSafeResource(opts: { noOverwrite?: boolean } = {}): Promise { const errors = this.organization.validate(); - if (errors.length) throw new RCError(`Invalid fields: ${errors.join(', ')}`); + if (errors.length) throw new HandledError(`Invalid fields: ${errors.join(', ')}`); try { const putParams: any = { TableName: DDB_TABLES.organizations, Item: this.organization }; @@ -93,7 +93,7 @@ class Organizations extends ResourceController { return this.organization; } catch (err) { - throw new RCError('Operation failed'); + throw new HandledError('Operation failed'); } } @@ -102,7 +102,7 @@ class Organizations extends ResourceController { // case 'SEND_USER_CONTACTS': // return await this.sendUserContacts(); // default: - // throw new RCError('Unsupported action'); + // throw new HandledError('Unsupported action'); // } // } @@ -137,17 +137,17 @@ class Organizations extends ResourceController { // } protected async deleteResource(): Promise { - if (!this.user.permissions.canManageContents) throw new RCError('Unauthorized'); + if (!this.user.permissions.canManageContents) throw new HandledError('Unauthorized'); try { await ddb.delete({ TableName: DDB_TABLES.organizations, Key: { organizationId: this.resourceId } }); } catch (err) { - throw new RCError('Delete failed'); + throw new HandledError('Delete failed'); } } protected async postResources(): Promise { - if (!this.user.permissions.canManageContents) throw new RCError('Unauthorized'); + if (!this.user.permissions.canManageContents) throw new HandledError('Unauthorized'); this.organization = new Organization(this.body); this.organization.organizationId = await ddb.IUNID(PROJECT); @@ -161,7 +161,7 @@ class Organizations extends ResourceController { .map((x: Organization) => new Organization(x)) .sort((a, b) => a.name.localeCompare(b.name)); } catch (err) { - throw new RCError('Operation failed'); + throw new HandledError('Operation failed'); } } } diff --git a/back-end/src/handlers/registrations.ts b/back-end/src/handlers/registrations.ts index 8c2c9da..77bea17 100644 --- a/back-end/src/handlers/registrations.ts +++ b/back-end/src/handlers/registrations.ts @@ -2,7 +2,7 @@ /// IMPORTS /// -import { DynamoDB, RCError, ResourceController } from 'idea-aws'; +import { DynamoDB, HandledError, ResourceController } from 'idea-aws'; import { Session } from '../models/session.model'; import { SessionRegistration } from '../models/sessionRegistration.model'; @@ -38,7 +38,7 @@ class SessionRegistrations extends ResourceController { try { this.user = new User(await ddb.get({ TableName: DDB_TABLES.users, Key: { userId: this.principalId } })); } catch (err) { - throw new RCError('User not found'); + throw new HandledError('User not found'); } if (!this.resourceId || this.httpMethod === 'POST') return; @@ -51,7 +51,7 @@ class SessionRegistrations extends ResourceController { }) ); } catch (err) { - throw new RCError('Registration not found'); + throw new HandledError('Registration not found'); } } @@ -65,7 +65,7 @@ class SessionRegistrations extends ResourceController { }); return registrationsOfSession.map(s => new SessionRegistration(s)); } catch (error) { - throw new RCError('Could not load registrations for this session'); + throw new HandledError('Could not load registrations for this session'); } } else { return await this.getUsersRegistrations(this.principalId); @@ -107,7 +107,7 @@ class SessionRegistrations extends ResourceController { await ddb.transactWrites([{ Delete: deleteSessionRegistration }, { Update: updateSessionCount }]); } catch (err) { - throw new RCError('Delete failed'); + throw new HandledError('Delete failed'); } } @@ -115,7 +115,7 @@ class SessionRegistrations extends ResourceController { const { sessionId, userId } = this.registration; const isValid = await this.validateRegistration(sessionId, userId); - if (!isValid) throw new RCError("User can't sign up for this session!"); + if (!isValid) throw new HandledError("User can't sign up for this session!"); try { const putSessionRegistration = { TableName: DDB_TABLES.registrations, Item: this.registration }; @@ -133,15 +133,15 @@ class SessionRegistrations extends ResourceController { return this.registration; } catch (err) { - throw new RCError('Operation failed'); + throw new HandledError('Operation failed'); } } private async validateRegistration(sessionId: string, userId: string) { const session: Session = new Session(await ddb.get({ TableName: DDB_TABLES.sessions, Key: { sessionId } })); - if (!session.requiresRegistration) throw new RCError("User can't sign up for this session!"); - if (session.isFull()) throw new RCError('Session is full! Refresh your page.'); + if (!session.requiresRegistration) throw new HandledError("User can't sign up for this session!"); + if (session.isFull()) throw new HandledError('Session is full! Refresh your page.'); const userRegistrations: SessionRegistration[] = await this.getUsersRegistrations(userId); @@ -167,7 +167,7 @@ class SessionRegistrations extends ResourceController { }); if (sessions.length !== validSessions.length) - throw new RCError('You have 1 or more sessions during this time period.'); + throw new HandledError('You have 1 or more sessions during this time period.'); return true; } @@ -182,7 +182,7 @@ class SessionRegistrations extends ResourceController { }); return registrationsOfUser.map(s => new SessionRegistration(s)); } catch (error) { - throw new RCError('Could not load registrations for this user'); + throw new HandledError('Could not load registrations for this user'); } } } diff --git a/back-end/src/handlers/rooms.ts b/back-end/src/handlers/rooms.ts index 4d9e209..0d4c8d1 100644 --- a/back-end/src/handlers/rooms.ts +++ b/back-end/src/handlers/rooms.ts @@ -2,7 +2,7 @@ /// IMPORTS /// -import { DynamoDB, RCError, ResourceController } from 'idea-aws'; +import { DynamoDB, HandledError, ResourceController } from 'idea-aws'; import { Room } from '../models/room.model'; import { VenueLinked } from '../models/venue.model'; @@ -40,7 +40,7 @@ class Rooms extends ResourceController { try { this.user = new User(await ddb.get({ TableName: DDB_TABLES.users, Key: { userId: this.principalId } })); } catch (err) { - throw new RCError('User not found'); + throw new HandledError('User not found'); } if (!this.resourceId) return; @@ -48,7 +48,7 @@ class Rooms extends ResourceController { try { this.room = new Room(await ddb.get({ TableName: DDB_TABLES.rooms, Key: { roomId: this.resourceId } })); } catch (err) { - throw new RCError('Room not found'); + throw new HandledError('Room not found'); } } @@ -57,7 +57,7 @@ class Rooms extends ResourceController { } protected async putResource(): Promise { - if (!this.user.permissions.canManageContents) throw new RCError('Unauthorized'); + if (!this.user.permissions.canManageContents) throw new HandledError('Unauthorized'); const oldResource = new Room(this.room); this.room.safeLoad(this.body, oldResource); @@ -66,7 +66,7 @@ class Rooms extends ResourceController { } private async putSafeResource(opts: { noOverwrite?: boolean } = {}): Promise { const errors = this.room.validate(); - if (errors.length) throw new RCError(`Invalid fields: ${errors.join(', ')}`); + if (errors.length) throw new HandledError(`Invalid fields: ${errors.join(', ')}`); this.room.venue = new VenueLinked( await ddb.get({ TableName: DDB_TABLES.venues, Key: { venueId: this.room.venue.venueId } }) @@ -79,22 +79,22 @@ class Rooms extends ResourceController { return this.room; } catch (err) { - throw new RCError('Operation failed'); + throw new HandledError('Operation failed'); } } protected async deleteResource(): Promise { - if (!this.user.permissions.canManageContents) throw new RCError('Unauthorized'); + if (!this.user.permissions.canManageContents) throw new HandledError('Unauthorized'); try { await ddb.delete({ TableName: DDB_TABLES.rooms, Key: { roomId: this.resourceId } }); } catch (err) { - throw new RCError('Delete failed'); + throw new HandledError('Delete failed'); } } protected async postResources(): Promise { - if (!this.user.permissions.canManageContents) throw new RCError('Unauthorized'); + if (!this.user.permissions.canManageContents) throw new HandledError('Unauthorized'); this.room = new Room(this.body); this.room.roomId = await ddb.IUNID(PROJECT); @@ -114,7 +114,7 @@ class Rooms extends ResourceController { return sortedRooms; } catch (err) { - throw new RCError('Operation failed'); + throw new HandledError('Operation failed'); } } } diff --git a/back-end/src/handlers/sessions.ts b/back-end/src/handlers/sessions.ts index d88f234..3680b35 100644 --- a/back-end/src/handlers/sessions.ts +++ b/back-end/src/handlers/sessions.ts @@ -2,7 +2,7 @@ /// IMPORTS /// -import { DynamoDB, RCError, ResourceController } from 'idea-aws'; +import { DynamoDB, HandledError, ResourceController } from 'idea-aws'; import { Session } from '../models/session.model'; import { SpeakerLinked } from '../models/speaker.model'; @@ -42,7 +42,7 @@ class Sessions extends ResourceController { try { this.user = new User(await ddb.get({ TableName: DDB_TABLES.users, Key: { userId: this.principalId } })); } catch (err) { - throw new RCError('User not found'); + throw new HandledError('User not found'); } if (!this.resourceId) return; @@ -52,7 +52,7 @@ class Sessions extends ResourceController { await ddb.get({ TableName: DDB_TABLES.sessions, Key: { sessionId: this.resourceId } }) ); } catch (err) { - throw new RCError('Session not found'); + throw new HandledError('Session not found'); } } @@ -61,7 +61,7 @@ class Sessions extends ResourceController { } protected async putResource(): Promise { - if (!this.user.permissions.canManageContents) throw new RCError('Unauthorized'); + if (!this.user.permissions.canManageContents) throw new HandledError('Unauthorized'); const oldResource = new Session(this.session); this.session.safeLoad(this.body, oldResource); @@ -70,7 +70,7 @@ class Sessions extends ResourceController { } private async putSafeResource(opts: { noOverwrite?: boolean } = {}): Promise { const errors = this.session.validate(); - if (errors.length) throw new RCError(`Invalid fields: ${errors.join(', ')}`); + if (errors.length) throw new HandledError(`Invalid fields: ${errors.join(', ')}`); this.session.room = new RoomLinked( await ddb.get({ TableName: DDB_TABLES.rooms, Key: { roomId: this.session.room.roomId } }) @@ -91,22 +91,22 @@ class Sessions extends ResourceController { return this.session; } catch (err) { - throw new RCError('Operation failed'); + throw new HandledError('Operation failed'); } } protected async deleteResource(): Promise { - if (!this.user.permissions.canManageContents) throw new RCError('Unauthorized'); + if (!this.user.permissions.canManageContents) throw new HandledError('Unauthorized'); try { await ddb.delete({ TableName: DDB_TABLES.sessions, Key: { sessionId: this.resourceId } }); } catch (err) { - throw new RCError('Delete failed'); + throw new HandledError('Delete failed'); } } protected async postResources(): Promise { - if (!this.user.permissions.canManageContents) throw new RCError('Unauthorized'); + if (!this.user.permissions.canManageContents) throw new HandledError('Unauthorized'); this.session = new Session(this.body); this.session.sessionId = await ddb.IUNID(PROJECT); @@ -128,7 +128,7 @@ class Sessions extends ResourceController { return sortedSessions; } catch (err) { - throw new RCError('Operation failed'); + throw new HandledError('Operation failed'); } } } diff --git a/back-end/src/handlers/speakers.ts b/back-end/src/handlers/speakers.ts index 4ef7140..a9f7994 100644 --- a/back-end/src/handlers/speakers.ts +++ b/back-end/src/handlers/speakers.ts @@ -2,7 +2,7 @@ /// IMPORTS /// -import { DynamoDB, RCError, ResourceController } from 'idea-aws'; +import { DynamoDB, HandledError, ResourceController } from 'idea-aws'; import { Speaker } from '../models/speaker.model'; import { OrganizationLinked } from '../models/organization.model'; @@ -40,7 +40,7 @@ class Speakers extends ResourceController { try { this.user = new User(await ddb.get({ TableName: DDB_TABLES.users, Key: { userId: this.principalId } })); } catch (err) { - throw new RCError('User not found'); + throw new HandledError('User not found'); } if (!this.resourceId) return; @@ -50,7 +50,7 @@ class Speakers extends ResourceController { await ddb.get({ TableName: DDB_TABLES.speakers, Key: { speakerId: this.resourceId } }) ); } catch (err) { - throw new RCError('Speaker not found'); + throw new HandledError('Speaker not found'); } } @@ -59,7 +59,7 @@ class Speakers extends ResourceController { } protected async putResource(): Promise { - if (!this.user.permissions.canManageContents) throw new RCError('Unauthorized'); + if (!this.user.permissions.canManageContents) throw new HandledError('Unauthorized'); const oldResource = new Speaker(this.speaker); this.speaker.safeLoad(this.body, oldResource); @@ -68,7 +68,7 @@ class Speakers extends ResourceController { } private async putSafeResource(opts: { noOverwrite?: boolean } = {}): Promise { const errors = this.speaker.validate(); - if (errors.length) throw new RCError(`Invalid fields: ${errors.join(', ')}`); + if (errors.length) throw new HandledError(`Invalid fields: ${errors.join(', ')}`); this.speaker.organization = new OrganizationLinked( await ddb.get({ @@ -84,22 +84,22 @@ class Speakers extends ResourceController { return this.speaker; } catch (err) { - throw new RCError('Operation failed'); + throw new HandledError('Operation failed'); } } protected async deleteResource(): Promise { - if (!this.user.permissions.canManageContents) throw new RCError('Unauthorized'); + if (!this.user.permissions.canManageContents) throw new HandledError('Unauthorized'); try { await ddb.delete({ TableName: DDB_TABLES.speakers, Key: { speakerId: this.resourceId } }); } catch (err) { - throw new RCError('Delete failed'); + throw new HandledError('Delete failed'); } } protected async postResources(): Promise { - if (!this.user.permissions.canManageContents) throw new RCError('Unauthorized'); + if (!this.user.permissions.canManageContents) throw new HandledError('Unauthorized'); this.speaker = new Speaker(this.body); this.speaker.speakerId = await ddb.IUNID(PROJECT); @@ -119,7 +119,7 @@ class Speakers extends ResourceController { return sortedSpeakers; } catch (err) { - throw new RCError('Operation failed'); + throw new HandledError('Operation failed'); } } } diff --git a/back-end/src/handlers/status.ts b/back-end/src/handlers/status.ts index c17fdc7..b524e88 100644 --- a/back-end/src/handlers/status.ts +++ b/back-end/src/handlers/status.ts @@ -2,7 +2,7 @@ /// IMPORTS /// -import { DynamoDB, RCError, ResourceController } from 'idea-aws'; +import { DynamoDB, HandledError, ResourceController } from 'idea-aws'; import { AppStatus, InternalAppVersionStatus } from 'idea-toolbox'; /// @@ -34,7 +34,7 @@ class Status extends ResourceController { return (await ddb.get({ TableName: DDB_TABLES.status, Key: { version } })) as InternalAppVersionStatus; } catch (err) { if (String(err) === 'Error: Not found') return { version } as InternalAppVersionStatus; - else throw new RCError('Failed to check version'); + else throw new HandledError('Failed to check version'); } } diff --git a/back-end/src/handlers/usefulLinks.ts b/back-end/src/handlers/usefulLinks.ts index 07ac31d..1f9c2b9 100644 --- a/back-end/src/handlers/usefulLinks.ts +++ b/back-end/src/handlers/usefulLinks.ts @@ -2,7 +2,7 @@ /// IMPORTS /// -import { DynamoDB, RCError, ResourceController } from 'idea-aws'; +import { DynamoDB, HandledError, ResourceController } from 'idea-aws'; import { User } from '../models/user.model'; import { UsefulLink } from '../models/usefulLink.model'; @@ -33,7 +33,7 @@ class UsefulLinksRC extends ResourceController { try { this.user = new User(await ddb.get({ TableName: DDB_TABLES.users, Key: { userId: this.principalId } })); } catch (err) { - throw new RCError('User not found'); + throw new HandledError('User not found'); } if (!this.resourceId) return; @@ -43,7 +43,7 @@ class UsefulLinksRC extends ResourceController { await ddb.get({ TableName: DDB_TABLES.usefulLinks, Key: { linkId: this.resourceId } }) ); } catch (err) { - throw new RCError('Link not found'); + throw new HandledError('Link not found'); } } @@ -55,7 +55,7 @@ class UsefulLinksRC extends ResourceController { private async putSafeResource(opts: { noOverwrite: boolean }): Promise { const errors = this.usefulLink.validate(); - if (errors.length) throw new RCError(`Invalid fields: ${errors.join(', ')}`); + if (errors.length) throw new HandledError(`Invalid fields: ${errors.join(', ')}`); const putParams: any = { TableName: DDB_TABLES.usefulLinks, Item: this.usefulLink }; if (opts.noOverwrite) putParams.ConditionExpression = 'attribute_not_exists(linkId)'; @@ -65,7 +65,7 @@ class UsefulLinksRC extends ResourceController { } protected async postResources(): Promise { - if (!this.user.permissions.canManageContents) throw new RCError('Unauthorized'); + if (!this.user.permissions.canManageContents) throw new HandledError('Unauthorized'); this.usefulLink = new UsefulLink(this.body); this.usefulLink.linkId = await ddb.IUNID(PROJECT); @@ -78,7 +78,7 @@ class UsefulLinksRC extends ResourceController { } protected async putResource(): Promise { - if (!this.user.permissions.canManageContents) throw new RCError('Unauthorized'); + if (!this.user.permissions.canManageContents) throw new HandledError('Unauthorized'); const oldLink = new UsefulLink(this.usefulLink); this.usefulLink.safeLoad(this.body, oldLink); @@ -91,12 +91,12 @@ class UsefulLinksRC extends ResourceController { case 'SWAP_SORT': return await this.swapSort(this.body.otherLinkId); default: - throw new RCError('Unsupported action'); + throw new HandledError('Unsupported action'); } } private async swapSort(otherLinkId: string): Promise { - if (!this.user.permissions.canManageContents) throw new RCError('Unauthorized'); - if (this.usefulLink.linkId === otherLinkId) throw new RCError('Same link'); + if (!this.user.permissions.canManageContents) throw new HandledError('Unauthorized'); + if (this.usefulLink.linkId === otherLinkId) throw new HandledError('Same link'); const otherLink = new UsefulLink( await ddb.get({ TableName: DDB_TABLES.usefulLinks, Key: { linkId: otherLinkId } }) @@ -113,7 +113,7 @@ class UsefulLinksRC extends ResourceController { } protected async deleteResource(): Promise { - if (!this.user.permissions.canManageContents) throw new RCError('Unauthorized'); + if (!this.user.permissions.canManageContents) throw new HandledError('Unauthorized'); await ddb.delete({ TableName: DDB_TABLES.usefulLinks, Key: { linkId: this.usefulLink.linkId } }); } diff --git a/back-end/src/handlers/users.ts b/back-end/src/handlers/users.ts index c763787..650df8f 100644 --- a/back-end/src/handlers/users.ts +++ b/back-end/src/handlers/users.ts @@ -4,7 +4,7 @@ import { addDays } from 'date-fns'; import { SignedURL, toISODate } from 'idea-toolbox'; -import { Cognito, DynamoDB, GetObjectTypes, RCError, ResourceController, S3 } from 'idea-aws'; +import { Cognito, DynamoDB, HandledError, ResourceController, S3 } from 'idea-aws'; import { HTML2PDF } from 'idea-html2pdf'; import { AuthServices, User, UserPermissions } from '../models/user.model'; @@ -56,13 +56,13 @@ class UsersRC extends ResourceController { await ddb.get({ TableName: DDB_TABLES.configurations, Key: { PK: Configurations.PK } }) ); } catch (err) { - throw new RCError('Configuration not found'); + throw new HandledError('Configuration not found'); } try { this.reqUser = new User(await ddb.get({ TableName: DDB_TABLES.users, Key: { userId: this.principalId } })); } catch (err) { - throw new RCError('Requesting user not found'); + throw new HandledError('Requesting user not found'); } if (this.resourceId === 'me') this.resourceId = this.principalId; @@ -77,7 +77,7 @@ class UsersRC extends ResourceController { try { this.targetUser = new User(await ddb.get({ TableName: DDB_TABLES.users, Key: { userId: this.resourceId } })); } catch (error) { - throw new RCError('Target user not found'); + throw new HandledError('Target user not found'); } const isCountryLeaderThatWantToReadCountryUser = @@ -89,7 +89,7 @@ class UsersRC extends ResourceController { !this.reqUser.permissions.canManageRegistrations && !isCountryLeaderThatWantToReadCountryUser ) - throw new RCError('Unauthorized'); + throw new HandledError('Unauthorized'); } protected async getResource(): Promise { @@ -105,7 +105,7 @@ class UsersRC extends ResourceController { } private async putSafeResource(): Promise { const errors = this.targetUser.validate(); - if (errors.length) throw new RCError(`Invalid fields: ${errors.join(', ')}`); + if (errors.length) throw new HandledError(`Invalid fields: ${errors.join(', ')}`); await ddb.put({ TableName: DDB_TABLES.users, Item: this.targetUser }); return this.targetUser; @@ -134,11 +134,11 @@ class UsersRC extends ResourceController { case 'GET_FAVORITE_SESSIONS': return await this.getFavoriteSessions(); default: - throw new RCError('Unsupported action'); + throw new HandledError('Unsupported action'); } } private async getSignedURLToUploadAvatar(): Promise { - if (this.reqUser !== this.targetUser) throw new RCError('Unauthorized'); + if (this.reqUser !== this.targetUser) throw new HandledError('Unauthorized'); const imageURI = await ddb.IUNID(PROJECT.concat('-avatar')); const key = `${S3_IMAGES_FOLDER}/${imageURI}.png`; @@ -148,16 +148,16 @@ class UsersRC extends ResourceController { } private async registerToEvent(registrationForm: any, isDraft: boolean): Promise { if (!this.configurations.canUserRegister(this.targetUser) && !this.reqUser.permissions.canManageRegistrations) - throw new RCError('Registrations are closed'); + throw new HandledError('Registrations are closed'); if (this.targetUser.registrationAt && !this.reqUser.permissions.canManageRegistrations) - throw new RCError("Can't edit a submitted registration"); + throw new HandledError("Can't edit a submitted registration"); this.targetUser.registrationForm = this.configurations.registrationFormDef.loadSections(registrationForm); if (isDraft) this.targetUser.registrationAt = null; else { const errors = this.configurations.registrationFormDef.validateSections(this.targetUser.registrationForm); - if (errors.length) throw new RCError(`Invalid fields: ${errors.join(', ')}`); + if (errors.length) throw new HandledError(`Invalid fields: ${errors.join(', ')}`); this.targetUser.registrationAt = new Date().toISOString(); } @@ -171,7 +171,7 @@ class UsersRC extends ResourceController { return this.targetUser; } private async changeUserPermissions(permissions: UserPermissions): Promise { - if (!this.reqUser.permissions.isAdmin) throw new RCError('Unauthorized'); + if (!this.reqUser.permissions.isAdmin) throw new HandledError('Unauthorized'); await ddb.update({ TableName: DDB_TABLES.users, @@ -192,10 +192,9 @@ class UsersRC extends ResourceController { const bucket = S3_BUCKET_MEDIA; const key = S3_DOWNLOADS_FOLDER + `/invoices/${filename}`; - const htmlBody = (await s3.getObject({ + const htmlBody = (await s3.getObjectAsText({ bucket: S3_BUCKET_MEDIA, - key: S3_ASSETS_FOLDER.concat('/payment-invoice.hbs'), - type: GetObjectTypes.TEXT + key: S3_ASSETS_FOLDER.concat('/payment-invoice.hbs') })) as string; const pdfVariables = { @@ -227,20 +226,20 @@ class UsersRC extends ResourceController { return await s3.signedURLGet(S3_BUCKET_MEDIA, key); } catch (err) { this.logger.warn('PDF creation failed', err); - throw new RCError('PDF creation failed'); + throw new HandledError('PDF creation failed'); } } private async getSignedURLToDownloadProofOfPayment(): Promise { - if (!this.targetUser.spot?.proofOfPaymentURI) throw new RCError('No proof of payment'); + if (!this.targetUser.spot?.proofOfPaymentURI) throw new HandledError('No proof of payment'); const key = `${S3_ATTACHMENTS_FOLDER}/${this.targetUser.userId}_${this.targetUser.spot.proofOfPaymentURI}`; return await s3.signedURLGet(S3_BUCKET_MEDIA, key); } private async getSignedURLToUploadProofOfPayment(): Promise { - if (this.reqUser !== this.targetUser) throw new RCError('Unauthorized'); - if (!this.targetUser.spot) throw new RCError('No spot'); - if (this.targetUser.spot.paymentConfirmedAt) throw new RCError('Payment already confirmed'); + if (this.reqUser !== this.targetUser) throw new HandledError('Unauthorized'); + if (!this.targetUser.spot) throw new HandledError('No spot'); + if (this.targetUser.spot.paymentConfirmedAt) throw new HandledError('Payment already confirmed'); const fileURI = await ddb.IUNID(PROJECT.concat('-pop')); const key = `${S3_ATTACHMENTS_FOLDER}/${this.targetUser.userId}_${fileURI}`; @@ -249,7 +248,7 @@ class UsersRC extends ResourceController { return signedURL; } private async confirmUploadProofOfPayment(fileURI: string): Promise { - if (!this.targetUser.spot) throw new RCError('No spot'); + if (!this.targetUser.spot) throw new HandledError('No spot'); let spot: EventSpot; try { @@ -257,10 +256,10 @@ class UsersRC extends ResourceController { await ddb.get({ TableName: DDB_TABLES.eventSpots, Key: { spotId: this.targetUser.spot.spotId } }) ); } catch (error) { - throw new RCError("Spot doesn't exist"); + throw new HandledError("Spot doesn't exist"); } - if (spot.userId !== this.targetUser.userId) throw new RCError('Wrong spot'); + if (spot.userId !== this.targetUser.userId) throw new HandledError('Wrong spot'); spot.proofOfPaymentURI = fileURI; @@ -287,7 +286,7 @@ class UsersRC extends ResourceController { protected async deleteResource(): Promise { if (!this.reqUser.permissions.isAdmin && this.reqUser.userId !== this.targetUser.userId) - throw new RCError('Unauthorized'); + throw new HandledError('Unauthorized'); if (this.targetUser.authService === AuthServices.COGNITO) { const cognitoUserId = this.targetUser.getAuthServiceUserId(); @@ -305,7 +304,7 @@ class UsersRC extends ResourceController { protected async getResources(): Promise { if (!(this.reqUser.permissions.canManageRegistrations || this.reqUser.permissions.isCountryLeader)) - throw new RCError('Unauthorized'); + throw new HandledError('Unauthorized'); // @todo we may want to add an index here to limit the fields in lists let users = (await ddb.scan({ TableName: DDB_TABLES.users })).map(x => new User(x)); diff --git a/back-end/src/handlers/venues.ts b/back-end/src/handlers/venues.ts index 93f2f9b..af6966a 100644 --- a/back-end/src/handlers/venues.ts +++ b/back-end/src/handlers/venues.ts @@ -2,7 +2,7 @@ /// IMPORTS /// -import { DynamoDB, RCError, ResourceController } from 'idea-aws'; +import { DynamoDB, HandledError, ResourceController } from 'idea-aws'; import { Venue } from '../models/venue.model'; import { User } from '../models/user.model'; @@ -35,7 +35,7 @@ class Venues extends ResourceController { try { this.user = new User(await ddb.get({ TableName: DDB_TABLES.users, Key: { userId: this.principalId } })); } catch (err) { - throw new RCError('User not found'); + throw new HandledError('User not found'); } if (!this.resourceId) return; @@ -43,7 +43,7 @@ class Venues extends ResourceController { try { this.venue = new Venue(await ddb.get({ TableName: DDB_TABLES.venues, Key: { venueId: this.resourceId } })); } catch (err) { - throw new RCError('Venue not found'); + throw new HandledError('Venue not found'); } } @@ -52,7 +52,7 @@ class Venues extends ResourceController { } protected async putResource(): Promise { - if (!this.user.permissions.canManageContents) throw new RCError('Unauthorized'); + if (!this.user.permissions.canManageContents) throw new HandledError('Unauthorized'); const oldResource = new Venue(this.venue); this.venue.safeLoad(this.body, oldResource); @@ -61,7 +61,7 @@ class Venues extends ResourceController { } private async putSafeResource(opts: { noOverwrite?: boolean } = {}): Promise { const errors = this.venue.validate(); - if (errors.length) throw new RCError(`Invalid fields: ${errors.join(', ')}`); + if (errors.length) throw new HandledError(`Invalid fields: ${errors.join(', ')}`); try { const putParams: any = { TableName: DDB_TABLES.venues, Item: this.venue }; @@ -70,22 +70,22 @@ class Venues extends ResourceController { return this.venue; } catch (err) { - throw new RCError('Operation failed'); + throw new HandledError('Operation failed'); } } protected async deleteResource(): Promise { - if (!this.user.permissions.canManageContents) throw new RCError('Unauthorized'); + if (!this.user.permissions.canManageContents) throw new HandledError('Unauthorized'); try { await ddb.delete({ TableName: DDB_TABLES.venues, Key: { venueId: this.resourceId } }); } catch (err) { - throw new RCError('Delete failed'); + throw new HandledError('Delete failed'); } } protected async postResources(): Promise { - if (!this.user.permissions.canManageContents) throw new RCError('Unauthorized'); + if (!this.user.permissions.canManageContents) throw new HandledError('Unauthorized'); this.venue = new Venue(this.body); this.venue.venueId = await ddb.IUNID(PROJECT); @@ -99,7 +99,7 @@ class Venues extends ResourceController { .map((x: Venue) => new Venue(x)) .sort((a, b) => a.name.localeCompare(b.name)); } catch (err) { - throw new RCError('Operation failed'); + throw new HandledError('Operation failed'); } } } diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..88c76f0 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "angular-egm-app", + "lockfileVersion": 3, + "requires": true, + "packages": {} +}