@stamhoofd/backend 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 (150) hide show
  1. package/.env.template.json +63 -0
  2. package/.eslintrc.js +61 -0
  3. package/README.md +40 -0
  4. package/index.ts +172 -0
  5. package/jest.config.js +11 -0
  6. package/migrations.ts +33 -0
  7. package/package.json +48 -0
  8. package/src/crons.ts +845 -0
  9. package/src/endpoints/admin/organizations/GetOrganizationsCountEndpoint.ts +42 -0
  10. package/src/endpoints/admin/organizations/GetOrganizationsEndpoint.ts +320 -0
  11. package/src/endpoints/admin/organizations/PatchOrganizationsEndpoint.ts +171 -0
  12. package/src/endpoints/auth/CreateAdminEndpoint.ts +137 -0
  13. package/src/endpoints/auth/CreateTokenEndpoint.test.ts +68 -0
  14. package/src/endpoints/auth/CreateTokenEndpoint.ts +200 -0
  15. package/src/endpoints/auth/DeleteTokenEndpoint.ts +31 -0
  16. package/src/endpoints/auth/ForgotPasswordEndpoint.ts +70 -0
  17. package/src/endpoints/auth/GetUserEndpoint.test.ts +64 -0
  18. package/src/endpoints/auth/GetUserEndpoint.ts +57 -0
  19. package/src/endpoints/auth/PatchApiUserEndpoint.ts +90 -0
  20. package/src/endpoints/auth/PatchUserEndpoint.ts +122 -0
  21. package/src/endpoints/auth/PollEmailVerificationEndpoint.ts +37 -0
  22. package/src/endpoints/auth/RetryEmailVerificationEndpoint.ts +41 -0
  23. package/src/endpoints/auth/SignupEndpoint.ts +107 -0
  24. package/src/endpoints/auth/VerifyEmailEndpoint.ts +89 -0
  25. package/src/endpoints/global/addresses/SearchRegionsEndpoint.ts +95 -0
  26. package/src/endpoints/global/addresses/ValidateAddressEndpoint.ts +31 -0
  27. package/src/endpoints/global/caddy/CheckDomainCertEndpoint.ts +101 -0
  28. package/src/endpoints/global/email/GetEmailAddressEndpoint.ts +53 -0
  29. package/src/endpoints/global/email/ManageEmailAddressEndpoint.ts +57 -0
  30. package/src/endpoints/global/files/UploadFile.ts +147 -0
  31. package/src/endpoints/global/files/UploadImage.ts +119 -0
  32. package/src/endpoints/global/members/GetMemberFamilyEndpoint.ts +76 -0
  33. package/src/endpoints/global/members/GetMembersCountEndpoint.ts +43 -0
  34. package/src/endpoints/global/members/GetMembersEndpoint.ts +429 -0
  35. package/src/endpoints/global/members/PatchOrganizationMembersEndpoint.ts +734 -0
  36. package/src/endpoints/global/organizations/CheckRegisterCodeEndpoint.ts +45 -0
  37. package/src/endpoints/global/organizations/CreateOrganizationEndpoint.test.ts +105 -0
  38. package/src/endpoints/global/organizations/CreateOrganizationEndpoint.ts +146 -0
  39. package/src/endpoints/global/organizations/GetOrganizationFromDomainEndpoint.test.ts +52 -0
  40. package/src/endpoints/global/organizations/GetOrganizationFromDomainEndpoint.ts +80 -0
  41. package/src/endpoints/global/organizations/GetOrganizationFromUriEndpoint.ts +49 -0
  42. package/src/endpoints/global/organizations/SearchOrganizationEndpoint.test.ts +58 -0
  43. package/src/endpoints/global/organizations/SearchOrganizationEndpoint.ts +62 -0
  44. package/src/endpoints/global/payments/ExchangeSTPaymentEndpoint.ts +153 -0
  45. package/src/endpoints/global/payments/StripeWebhookEndpoint.ts +134 -0
  46. package/src/endpoints/global/platform/GetPlatformAdminsEndpoint.ts +44 -0
  47. package/src/endpoints/global/platform/GetPlatformEnpoint.ts +39 -0
  48. package/src/endpoints/global/platform/PatchPlatformEnpoint.ts +63 -0
  49. package/src/endpoints/global/registration/GetPaymentRegistrations.ts +68 -0
  50. package/src/endpoints/global/registration/GetUserBalanceEndpoint.ts +39 -0
  51. package/src/endpoints/global/registration/GetUserDocumentsEndpoint.ts +80 -0
  52. package/src/endpoints/global/registration/GetUserMembersEndpoint.ts +41 -0
  53. package/src/endpoints/global/registration/PatchUserMembersEndpoint.ts +134 -0
  54. package/src/endpoints/global/registration/RegisterMembersEndpoint.ts +521 -0
  55. package/src/endpoints/global/registration-periods/GetRegistrationPeriodsEndpoint.ts +37 -0
  56. package/src/endpoints/global/registration-periods/PatchRegistrationPeriodsEndpoint.ts +115 -0
  57. package/src/endpoints/global/webshops/GetWebshopFromDomainEndpoint.ts +187 -0
  58. package/src/endpoints/organization/dashboard/billing/ActivatePackagesEndpoint.ts +424 -0
  59. package/src/endpoints/organization/dashboard/billing/DeactivatePackageEndpoint.ts +67 -0
  60. package/src/endpoints/organization/dashboard/billing/GetBillingStatusEndpoint.ts +39 -0
  61. package/src/endpoints/organization/dashboard/documents/GetDocumentTemplateXML.ts +57 -0
  62. package/src/endpoints/organization/dashboard/documents/GetDocumentTemplatesEndpoint.ts +50 -0
  63. package/src/endpoints/organization/dashboard/documents/GetDocumentsEndpoint.ts +50 -0
  64. package/src/endpoints/organization/dashboard/documents/PatchDocumentEndpoint.ts +129 -0
  65. package/src/endpoints/organization/dashboard/documents/PatchDocumentTemplateEndpoint.ts +114 -0
  66. package/src/endpoints/organization/dashboard/email/CheckEmailBouncesEndpoint.ts +50 -0
  67. package/src/endpoints/organization/dashboard/email/EmailEndpoint.ts +234 -0
  68. package/src/endpoints/organization/dashboard/email-templates/GetEmailTemplatesEndpoint.ts +62 -0
  69. package/src/endpoints/organization/dashboard/email-templates/PatchEmailTemplatesEndpoint.ts +85 -0
  70. package/src/endpoints/organization/dashboard/mollie/CheckMollieEndpoint.ts +80 -0
  71. package/src/endpoints/organization/dashboard/mollie/ConnectMollieEndpoint.ts +54 -0
  72. package/src/endpoints/organization/dashboard/mollie/DisconnectMollieEndpoint.ts +49 -0
  73. package/src/endpoints/organization/dashboard/mollie/GetMollieDashboardEndpoint.ts +63 -0
  74. package/src/endpoints/organization/dashboard/nolt/CreateNoltTokenEndpoint.ts +61 -0
  75. package/src/endpoints/organization/dashboard/organization/ApplyRegisterCodeEndpoint.test.ts +64 -0
  76. package/src/endpoints/organization/dashboard/organization/ApplyRegisterCodeEndpoint.ts +84 -0
  77. package/src/endpoints/organization/dashboard/organization/GetOrganizationArchivedGroups.ts +43 -0
  78. package/src/endpoints/organization/dashboard/organization/GetOrganizationDeletedGroups.ts +42 -0
  79. package/src/endpoints/organization/dashboard/organization/GetOrganizationSSOEndpoint.ts +43 -0
  80. package/src/endpoints/organization/dashboard/organization/GetRegisterCodeEndpoint.ts +65 -0
  81. package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.test.ts +281 -0
  82. package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.ts +338 -0
  83. package/src/endpoints/organization/dashboard/organization/SetOrganizationDomainEndpoint.ts +196 -0
  84. package/src/endpoints/organization/dashboard/organization/SetOrganizationSSOEndpoint.ts +50 -0
  85. package/src/endpoints/organization/dashboard/payments/GetMemberBalanceEndpoint.ts +48 -0
  86. package/src/endpoints/organization/dashboard/payments/GetPaymentsEndpoint.ts +207 -0
  87. package/src/endpoints/organization/dashboard/payments/PatchBalanceItemsEndpoint.ts +202 -0
  88. package/src/endpoints/organization/dashboard/payments/PatchPaymentsEndpoint.ts +233 -0
  89. package/src/endpoints/organization/dashboard/registration-periods/GetOrganizationRegistrationPeriodsEndpoint.ts +66 -0
  90. package/src/endpoints/organization/dashboard/registration-periods/PatchOrganizationRegistrationPeriodsEndpoint.ts +210 -0
  91. package/src/endpoints/organization/dashboard/stripe/ConnectStripeEndpoint.ts +93 -0
  92. package/src/endpoints/organization/dashboard/stripe/DeleteStripeAccountEndpoint.ts +59 -0
  93. package/src/endpoints/organization/dashboard/stripe/GetStripeAccountLinkEndpoint.ts +78 -0
  94. package/src/endpoints/organization/dashboard/stripe/GetStripeAccountsEndpoint.ts +40 -0
  95. package/src/endpoints/organization/dashboard/stripe/GetStripeLoginLinkEndpoint.ts +69 -0
  96. package/src/endpoints/organization/dashboard/stripe/UpdateStripeAccountEndpoint.ts +52 -0
  97. package/src/endpoints/organization/dashboard/users/CreateApiUserEndpoint.ts +73 -0
  98. package/src/endpoints/organization/dashboard/users/DeleteUserEndpoint.ts +60 -0
  99. package/src/endpoints/organization/dashboard/users/GetApiUsersEndpoint.ts +47 -0
  100. package/src/endpoints/organization/dashboard/users/GetOrganizationAdminsEndpoint.ts +41 -0
  101. package/src/endpoints/organization/dashboard/webshops/CreateWebshopEndpoint.ts +217 -0
  102. package/src/endpoints/organization/dashboard/webshops/DeleteWebshopEndpoint.ts +51 -0
  103. package/src/endpoints/organization/dashboard/webshops/GetDiscountCodesEndpoint.ts +47 -0
  104. package/src/endpoints/organization/dashboard/webshops/GetWebshopOrdersEndpoint.ts +83 -0
  105. package/src/endpoints/organization/dashboard/webshops/GetWebshopTicketsEndpoint.ts +68 -0
  106. package/src/endpoints/organization/dashboard/webshops/GetWebshopUriAvailabilityEndpoint.ts +69 -0
  107. package/src/endpoints/organization/dashboard/webshops/PatchDiscountCodesEndpoint.ts +125 -0
  108. package/src/endpoints/organization/dashboard/webshops/PatchWebshopEndpoint.ts +204 -0
  109. package/src/endpoints/organization/dashboard/webshops/PatchWebshopOrdersEndpoint.ts +278 -0
  110. package/src/endpoints/organization/dashboard/webshops/PatchWebshopTicketsEndpoint.ts +80 -0
  111. package/src/endpoints/organization/dashboard/webshops/VerifyWebshopDomainEndpoint.ts +60 -0
  112. package/src/endpoints/organization/shared/ExchangePaymentEndpoint.ts +379 -0
  113. package/src/endpoints/organization/shared/GetDocumentHtml.ts +54 -0
  114. package/src/endpoints/organization/shared/GetPaymentEndpoint.ts +45 -0
  115. package/src/endpoints/organization/shared/auth/GetOrganizationEndpoint.test.ts +78 -0
  116. package/src/endpoints/organization/shared/auth/GetOrganizationEndpoint.ts +34 -0
  117. package/src/endpoints/organization/shared/auth/OpenIDConnectCallbackEndpoint.ts +44 -0
  118. package/src/endpoints/organization/shared/auth/OpenIDConnectStartEndpoint.ts +82 -0
  119. package/src/endpoints/organization/webshops/CheckWebshopDiscountCodesEndpoint.ts +59 -0
  120. package/src/endpoints/organization/webshops/GetOrderByPaymentEndpoint.ts +51 -0
  121. package/src/endpoints/organization/webshops/GetOrderEndpoint.ts +40 -0
  122. package/src/endpoints/organization/webshops/GetTicketsEndpoint.ts +124 -0
  123. package/src/endpoints/organization/webshops/GetWebshopEndpoint.test.ts +130 -0
  124. package/src/endpoints/organization/webshops/GetWebshopEndpoint.ts +50 -0
  125. package/src/endpoints/organization/webshops/PlaceOrderEndpoint.test.ts +450 -0
  126. package/src/endpoints/organization/webshops/PlaceOrderEndpoint.ts +335 -0
  127. package/src/helpers/AddressValidator.test.ts +40 -0
  128. package/src/helpers/AddressValidator.ts +256 -0
  129. package/src/helpers/AdminPermissionChecker.ts +1031 -0
  130. package/src/helpers/AuthenticatedStructures.ts +158 -0
  131. package/src/helpers/BuckarooHelper.ts +279 -0
  132. package/src/helpers/CheckSettlements.ts +215 -0
  133. package/src/helpers/Context.ts +202 -0
  134. package/src/helpers/CookieHelper.ts +45 -0
  135. package/src/helpers/ForwardHandler.test.ts +216 -0
  136. package/src/helpers/ForwardHandler.ts +140 -0
  137. package/src/helpers/OpenIDConnectHelper.ts +284 -0
  138. package/src/helpers/StripeHelper.ts +293 -0
  139. package/src/helpers/StripePayoutChecker.ts +188 -0
  140. package/src/middleware/ContextMiddleware.ts +16 -0
  141. package/src/migrations/1646578856-validate-addresses.ts +60 -0
  142. package/src/seeds/0000000000-example.ts +13 -0
  143. package/src/seeds/1715028563-user-permissions.ts +52 -0
  144. package/tests/e2e/stock.test.ts +2120 -0
  145. package/tests/e2e/tickets.test.ts +926 -0
  146. package/tests/helpers/StripeMocker.ts +362 -0
  147. package/tests/helpers/TestServer.ts +21 -0
  148. package/tests/jest.global.setup.ts +29 -0
  149. package/tests/jest.setup.ts +59 -0
  150. package/tsconfig.json +42 -0
@@ -0,0 +1,63 @@
1
+ {
2
+ "environment": "development",
3
+ "domains": {
4
+ "dashboard": "dashboard.stamhoofd",
5
+ "registration": {
6
+ "": "be.stamhoofd",
7
+ "BE": "be.stamhoofd",
8
+ "NL": "nl.stamhoofd"
9
+ },
10
+ "marketing": {
11
+ "": "www.be.stamhoofd",
12
+ "BE": "www.be.stamhoofd",
13
+ "NL": "www.nl.stamhoofd"
14
+ },
15
+ "webshop": {
16
+ "": "shop.be.stamhoofd",
17
+ "BE": "shop.be.stamhoofd",
18
+ "NL": "shop.nl.stamhoofd"
19
+ },
20
+ "legacyWebshop": "shop.stamhoofd",
21
+ "api": "api.stamhoofd",
22
+ "rendererApi": "renderer.stamhoofd"
23
+ },
24
+ "translationNamespace": "stamhoofd",
25
+ "userMode": "organization",
26
+
27
+ "PORT": 9091,
28
+ "DB_HOST": "127.0.0.1",
29
+ "DB_USER": "",
30
+ "DB_PASS": "",
31
+ "DB_DATABASE": "",
32
+
33
+ "SMTP_HOST": "0.0.0.0",
34
+ "SMTP_USERNAME": "username",
35
+ "SMTP_PASSWORD": "password",
36
+ "SMTP_PORT": 1025,
37
+
38
+ "TRANSACTIONAL_SMTP_HOST": "0.0.0.0",
39
+ "TRANSACTIONAL_SMTP_USERNAME": "username",
40
+ "TRANSACTIONAL_SMTP_PASSWORD": "password",
41
+ "TRANSACTIONAL_SMTP_PORT": 1025,
42
+
43
+ "AWS_ACCESS_KEY_ID": "",
44
+ "AWS_SECRET_ACCESS_KEY": "",
45
+ "AWS_REGION": "",
46
+
47
+ "SPACES_ENDPOINT": "",
48
+ "SPACES_BUCKET": "",
49
+ "SPACES_KEY": "",
50
+ "SPACES_SECRET": "",
51
+
52
+ "MOLLIE_CLIENT_ID": "",
53
+ "MOLLIE_SECRET": "",
54
+ "MOLLIE_API_KEY": "",
55
+ "MOLLIE_ORGANIZATION_TOKEN": "",
56
+
57
+ "LATEST_IOS_VERSION": 0,
58
+ "LATEST_ANDROID_VERSION": 0,
59
+
60
+ "NOLT_SSO_SECRET_KEY": "",
61
+ "INTERNAL_SECRET_KEY": "",
62
+ "CRONS_DISABLED": false
63
+ }
package/.eslintrc.js ADDED
@@ -0,0 +1,61 @@
1
+ module.exports = {
2
+ root: true,
3
+ ignorePatterns: ["dist/", "node_modules/"],
4
+ parserOptions: {
5
+ "ecmaVersion": 2017
6
+ },
7
+ env: {
8
+ "es6": true,
9
+ "node": true,
10
+ },
11
+ extends: [
12
+ "eslint:recommended",
13
+ ],
14
+ plugins: [],
15
+ rules: {
16
+ "no-console": "off",
17
+ "no-debugger": process.env.NODE_ENV === "production" ? "error" : "off",
18
+ "sort-imports": "off",
19
+ "import/order": "off"
20
+ },
21
+ overrides: [
22
+ {
23
+ // Rules for TypeScript and vue
24
+ files: ["*.ts"],
25
+ parser: "@typescript-eslint/parser",
26
+ parserOptions: {
27
+ project: ["./tsconfig.json"]
28
+ },
29
+ plugins: ["@typescript-eslint", "jest"],
30
+ extends: [
31
+ "eslint:recommended",
32
+ "plugin:@typescript-eslint/eslint-recommended",
33
+ "plugin:@typescript-eslint/recommended",
34
+ "plugin:@typescript-eslint/recommended-requiring-type-checking",
35
+ "plugin:jest/recommended",
36
+ ],
37
+ rules: {
38
+ "no-console": "off",
39
+ "no-debugger": process.env.NODE_ENV === "production" ? "error" : "off",
40
+ "sort-imports": "off",
41
+ "import/order": "off",
42
+ "@typescript-eslint/explicit-function-return-type": "off",
43
+ "@typescript-eslint/no-explicit-any": "off",
44
+ "@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_" }],
45
+ "@typescript-eslint/no-namespace": "off",
46
+ "@typescript-eslint/no-floating-promises": "error",
47
+ "@typescript-eslint/no-misused-promises": "error",
48
+ "@typescript-eslint/prefer-for-of": "warn",
49
+ "@typescript-eslint/no-empty-interface": "off", // It is convenient to have placeholder interfaces
50
+ "@typescript-eslint/no-this-alias": "off", // No idea why we need this. This breaks code that is just fine. Prohibit the use of function() instead of this rule
51
+ "@typescript-eslint/unbound-method": "off", // Methods are automatically bound in vue, it would break removeEventListeners if we bound it every time unless we save every method in variables again...
52
+ "@typescript-eslint/no-unsafe-assignment": "off", // This is impossible to use with dependencies that don't have types yet, such as tiptap
53
+ "@typescript-eslint/no-unsafe-return": "off", // This is impossible to use with dependencies that don't have types yet, such as tiptap
54
+ "@typescript-eslint/no-unsafe-call": "off", // This is impossible to use with dependencies that don't have types yet, such as tiptap
55
+ "@typescript-eslint/no-unsafe-member-access": "off", // This is impossible to use with dependencies that don't have types yet, such as tiptap
56
+ "@typescript-eslint/restrict-plus-operands": "off", // bullshit one
57
+ "@typescript-eslint/explicit-module-boundary-types": "off",
58
+ },
59
+ }
60
+ ]
61
+ };
package/README.md ADDED
@@ -0,0 +1,40 @@
1
+ # Stamhoofd backend application
2
+
3
+ To run, make sure you set your environment variables.
4
+
5
+ You can create a `.env` file:
6
+
7
+ ```
8
+ # Database
9
+ DB_HOST=localhost
10
+ DB_USER=root
11
+ DB_PASS=root
12
+ DB_DATABASE=stamhoofd
13
+
14
+ # SMTP server (for sending emails)
15
+ SMTP_HOST=email-smtp.eu-west-1.amazonaws.com
16
+ SMTP_USERNAME=xxxx
17
+ SMTP_PASSWORD=xxxx
18
+ SMTP_PORT=xxxx
19
+ ```
20
+
21
+ ## Setup
22
+
23
+ Install dependencies and run the migrations to setup the database.
24
+
25
+ ```
26
+ yarn install
27
+ yarn migrations
28
+ ```
29
+
30
+ ## Running
31
+
32
+ ```
33
+ yarn start
34
+ ```
35
+
36
+ ## Testing
37
+
38
+ ```
39
+ yarn test
40
+ ```
package/index.ts ADDED
@@ -0,0 +1,172 @@
1
+ require('@stamhoofd/backend-env').load()
2
+ import { Column, Database, Migration } from "@simonbackx/simple-database";
3
+ import { CORSPreflightEndpoint, Router, RouterServer } from "@simonbackx/simple-endpoints";
4
+ import { I18n } from "@stamhoofd/backend-i18n";
5
+ import { CORSMiddleware, LogMiddleware, VersionMiddleware } from "@stamhoofd/backend-middleware";
6
+ import { Email } from "@stamhoofd/email";
7
+ import { loadLogger } from "@stamhoofd/logging";
8
+ import { Version } from '@stamhoofd/structures';
9
+ import { sleep } from "@stamhoofd/utility";
10
+
11
+ import { areCronsRunning, crons, stopCronScheduling } from './src/crons';
12
+ import { ContextMiddleware } from "./src/middleware/ContextMiddleware";
13
+
14
+ process.on("unhandledRejection", (error: Error) => {
15
+ console.error("unhandledRejection");
16
+ console.error(error.message, error.stack);
17
+ process.exit(1);
18
+ });
19
+
20
+ // Set version of saved structures
21
+ Column.setJSONVersion(Version);
22
+
23
+ // Set timezone!
24
+ process.env.TZ = "UTC";
25
+
26
+ // Quick check
27
+ if (new Date().getTimezoneOffset() != 0) {
28
+ throw new Error("Process should always run in UTC timezone");
29
+ }
30
+
31
+ const seeds = async () => {
32
+ try {
33
+ // Internal
34
+ await Migration.runAll(__dirname + "/src/seeds");
35
+ } catch (e) {
36
+ console.error("Failed to run seeds:")
37
+ console.error(e)
38
+ }
39
+ };
40
+
41
+ const start = async () => {
42
+ console.log('Running server at v' + Version)
43
+ loadLogger();
44
+ await I18n.load()
45
+ const router = new Router();
46
+ await router.loadAllEndpoints(__dirname + "/src/endpoints/global/*");
47
+ await router.loadAllEndpoints(__dirname + "/src/endpoints/admin/*");
48
+ await router.loadAllEndpoints(__dirname + "/src/endpoints/auth");
49
+ await router.loadAllEndpoints(__dirname + "/src/endpoints/organization/dashboard/*");
50
+ await router.loadAllEndpoints(__dirname + "/src/endpoints/organization/registration");
51
+ await router.loadAllEndpoints(__dirname + "/src/endpoints/organization/webshops");
52
+ await router.loadAllEndpoints(__dirname + "/src/endpoints/organization/shared");
53
+ await router.loadAllEndpoints(__dirname + "/src/endpoints/organization/shared/*");
54
+
55
+ router.endpoints.push(new CORSPreflightEndpoint())
56
+
57
+ const routerServer = new RouterServer(router);
58
+ routerServer.verbose = false
59
+
60
+ // Log requests and errors
61
+ routerServer.addRequestMiddleware(LogMiddleware)
62
+ routerServer.addResponseMiddleware(LogMiddleware)
63
+
64
+ // Contexts
65
+ routerServer.addRequestMiddleware(ContextMiddleware)
66
+
67
+ // Add version headers and minimum version
68
+ const versionMiddleware = new VersionMiddleware({
69
+ latestVersions: {
70
+ android: STAMHOOFD.LATEST_ANDROID_VERSION,
71
+ ios: STAMHOOFD.LATEST_IOS_VERSION,
72
+ web: Version
73
+ },
74
+ minimumVersion: 168
75
+ })
76
+ routerServer.addRequestMiddleware(versionMiddleware)
77
+ routerServer.addResponseMiddleware(versionMiddleware)
78
+
79
+ // Add CORS headers
80
+ routerServer.addResponseMiddleware(CORSMiddleware)
81
+
82
+ routerServer.listen(STAMHOOFD.PORT ?? 9090);
83
+
84
+ if (routerServer.server) {
85
+ // Default timeout is a bit too short
86
+ routerServer.server.timeout = 61000;
87
+ }
88
+
89
+ let shuttingDown = false;
90
+ const shutdown = async () => {
91
+ if (shuttingDown) {
92
+ return
93
+ }
94
+ shuttingDown = true
95
+ console.log("Shutting down...")
96
+ // Disable keep alive
97
+ routerServer.defaultHeaders = Object.assign(routerServer.defaultHeaders, { 'Connection': 'close' })
98
+ if (routerServer.server) {
99
+ routerServer.server.headersTimeout = 5000;
100
+ routerServer.server.keepAliveTimeout = 1;
101
+ }
102
+
103
+ stopCronScheduling();
104
+ clearInterval(cronInterval)
105
+
106
+ try {
107
+ await routerServer.close()
108
+ console.log("HTTP server stopped");
109
+ } catch (err) {
110
+ console.error("Failed to stop HTTP server:");
111
+ console.error(err);
112
+ }
113
+
114
+ try {
115
+ while (areCronsRunning()) {
116
+ console.log("Crons are still running. Waiting 2 seconds...")
117
+ await sleep(2000)
118
+ }
119
+ } catch (err) {
120
+ console.error("Failed to wait for crons to finish:");
121
+ console.error(err);
122
+ }
123
+
124
+ try {
125
+ while (Email.currentQueue.length > 0) {
126
+ console.log("Emails still in queue. Waiting 2 seconds...")
127
+ await sleep(2000)
128
+ }
129
+ } catch (err) {
130
+ console.error("Failed to wait for emails to finish:");
131
+ console.error(err);
132
+ }
133
+
134
+ try {
135
+ await Database.end()
136
+ console.log("MySQL connections closed");
137
+ } catch (err) {
138
+ console.error("Failed to close MySQL connection:")
139
+ console.error(err);
140
+ }
141
+
142
+ // Should not be needed, but added for security as sometimes a promise hangs somewhere
143
+ process.exit(0);
144
+ };
145
+
146
+ process.on("SIGTERM", () => {
147
+ console.info("SIGTERM signal received.");
148
+ shutdown().catch((e) => {
149
+ console.error(e)
150
+ process.exit(1);
151
+ });
152
+ });
153
+
154
+ process.on("SIGINT", () => {
155
+ console.info("SIGINT signal received.");
156
+ shutdown().catch((e) => {
157
+ console.error(e)
158
+ process.exit(1);
159
+ });
160
+ });
161
+
162
+ const cronInterval = setInterval(() => {
163
+ crons().catch(console.error)
164
+ }, 5 * 60 * 1000);
165
+ crons().catch(console.error)
166
+ seeds().catch(console.error);
167
+ };
168
+
169
+ start().catch(error => {
170
+ console.error("unhandledRejection", error);
171
+ process.exit(1);
172
+ });
package/jest.config.js ADDED
@@ -0,0 +1,11 @@
1
+
2
+ module.exports = {
3
+ roots: ["<rootDir>/dist"],
4
+ testEnvironment: "node",
5
+ setupFilesAfterEnv: [
6
+ "jest-extended/all",
7
+ "./dist/tests/jest.setup.js",
8
+ ],
9
+ globalSetup: "./dist/tests/jest.global.setup.js"
10
+ //verbose: true,
11
+ };
package/migrations.ts ADDED
@@ -0,0 +1,33 @@
1
+ require('@stamhoofd/backend-env').load()
2
+ import { Column, Migration } from "@simonbackx/simple-database";
3
+ import { Version } from "@stamhoofd/structures";
4
+ import path from "path";
5
+
6
+ Column.setJSONVersion(Version);
7
+ process.env.TZ = "UTC";
8
+
9
+ const emailPath = require.resolve("@stamhoofd/email")
10
+ const modelsPath = require.resolve("@stamhoofd/models")
11
+
12
+ // Validate UTC timezone
13
+ if (new Date().getTimezoneOffset() != 0) {
14
+ throw new Error("Process should always run in UTC timezone");
15
+ }
16
+
17
+ const start = async () => {
18
+ // External migrations
19
+ await Migration.runAll(path.dirname(modelsPath) + "/migrations");
20
+ await Migration.runAll(path.dirname(emailPath) + "/migrations");
21
+
22
+ // Internal
23
+ await Migration.runAll(__dirname + "/src/migrations");
24
+ };
25
+
26
+ start()
27
+ .catch(error => {
28
+ console.error("unhandledRejection", error);
29
+ process.exit(1);
30
+ })
31
+ .finally(() => {
32
+ process.exit();
33
+ });
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@stamhoofd/backend",
3
+ "version": "1.0.0",
4
+ "main": "index.ts",
5
+ "license": "UNLICENCED",
6
+ "scripts": {
7
+ "dev": "concurrently -r \"rm -rf ./dist && wait-on ./dist/index.js && nodemon --quiet --inspect=5858 --watch dist --delay 200ms --exec node --enable-source-maps ./dist/index.js --signal SIGTERM\" 'yarn build --watch --preserveWatchOutput'",
8
+ "dev:backend": "yarn dev",
9
+ "build": "rm -rf ./dist/src/migrations && rm -rf ./dist/src/seeds && tsc -b",
10
+ "build:full": "yarn clear && yarn build",
11
+ "clear": "rm -rf ./dist",
12
+ "start": "yarn build && node --enable-source-maps ./dist/index.js",
13
+ "test": "jest --runInBand",
14
+ "test:reset": "yarn build:full && jest --runInBand",
15
+ "migrations": "yarn build:full && node ./dist/migrations.js",
16
+ "lint": "eslint . --ext .js,.jsx,.ts,.tsx"
17
+ },
18
+ "devDependencies": {
19
+ "@types/cookie": "^0.5.1",
20
+ "@types/luxon": "^2.0.8",
21
+ "@types/mailparser": "3.4.4",
22
+ "@types/mysql": "^2.15.20",
23
+ "@types/node": "^18.11.17",
24
+ "nock": "^13.5.1",
25
+ "qs": "^6.11.2",
26
+ "sinon": "^17.0.1"
27
+ },
28
+ "dependencies": {
29
+ "@mollie/api-client": "3.7.0",
30
+ "@simonbackx/simple-database": "1.24.0",
31
+ "@simonbackx/simple-endpoints": "1.13.0",
32
+ "@simonbackx/simple-logging": "^1.0.1",
33
+ "aws-sdk": "^2.885.0",
34
+ "axios": "1.6.8",
35
+ "cookie": "^0.5.0",
36
+ "formidable": "3.5.1",
37
+ "handlebars": "^4.7.7",
38
+ "jsonwebtoken": "9.0.0",
39
+ "luxon": "^2.2.0",
40
+ "mailparser": "3.7.0",
41
+ "mockdate": "^3.0.2",
42
+ "mysql": "^2.18.1",
43
+ "node-rsa": "1.1.1",
44
+ "openid-client": "^5.4.0",
45
+ "postmark": "4.0.2",
46
+ "stripe": "^11.5.0"
47
+ }
48
+ }