@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,37 @@
1
+ import { DecodedRequest, Endpoint, Request, Response } from "@simonbackx/simple-endpoints";
2
+ import { RegistrationPeriod as RegistrationPeriodStruct } from "@stamhoofd/structures";
3
+
4
+ import { RegistrationPeriod } from '@stamhoofd/models';
5
+
6
+ type Params = Record<string, never>;
7
+ type Query = undefined;
8
+ type Body = undefined
9
+ type ResponseBody = RegistrationPeriodStruct[]
10
+
11
+ /**
12
+ * One endpoint to create, patch and delete members and their registrations and payments
13
+ */
14
+
15
+ export class PatchRegistrationPeriodsEndpoint extends Endpoint<Params, Query, Body, ResponseBody> {
16
+ protected doesMatch(request: Request): [true, Params] | [false] {
17
+ if (request.method != "GET") {
18
+ return [false];
19
+ }
20
+
21
+ const params = Endpoint.parseParameters(request.url, "/registration-periods", {});
22
+
23
+ if (params) {
24
+ return [true, params as Params];
25
+ }
26
+ return [false];
27
+ }
28
+
29
+ async handle(request: DecodedRequest<Params, Query, Body>) {
30
+ const periods = await RegistrationPeriod.all()
31
+
32
+ return new Response(
33
+ periods.map(p => p.getStructure())
34
+ );
35
+ }
36
+
37
+ }
@@ -0,0 +1,115 @@
1
+ import { ConvertArrayToPatchableArray, Decoder, PatchableArrayAutoEncoder, PatchableArrayDecoder, StringDecoder, patchObject } from '@simonbackx/simple-encoding';
2
+ import { DecodedRequest, Endpoint, Request, Response } from "@simonbackx/simple-endpoints";
3
+ import { RegistrationPeriod as RegistrationPeriodStruct } from "@stamhoofd/structures";
4
+
5
+ import { AuthenticatedStructures } from '../../../helpers/AuthenticatedStructures';
6
+ import { Context } from '../../../helpers/Context';
7
+ import { RegistrationPeriod } from '@stamhoofd/models';
8
+ import { SimpleError } from '@simonbackx/simple-errors';
9
+
10
+ type Params = Record<string, never>;
11
+ type Query = undefined;
12
+ type Body = PatchableArrayAutoEncoder<RegistrationPeriodStruct>
13
+ type ResponseBody = RegistrationPeriodStruct[]
14
+
15
+ /**
16
+ * One endpoint to create, patch and delete members and their registrations and payments
17
+ */
18
+
19
+ export class PatchRegistrationPeriodsEndpoint extends Endpoint<Params, Query, Body, ResponseBody> {
20
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
21
+ bodyDecoder = new PatchableArrayDecoder(RegistrationPeriodStruct as any, RegistrationPeriodStruct.patchType(), StringDecoder) as any as Decoder<ConvertArrayToPatchableArray<RegistrationPeriodStruct[]>>
22
+
23
+ protected doesMatch(request: Request): [true, Params] | [false] {
24
+ if (request.method != "PATCH") {
25
+ return [false];
26
+ }
27
+
28
+ const params = Endpoint.parseParameters(request.url, "/registration-periods", {});
29
+
30
+ if (params) {
31
+ return [true, params as Params];
32
+ }
33
+ return [false];
34
+ }
35
+
36
+ async handle(request: DecodedRequest<Params, Query, Body>) {
37
+ const organization = await Context.setUserOrganizationScope();
38
+ await Context.authenticate()
39
+
40
+ // Fast throw first (more in depth checking for patches later)
41
+ if (organization) {
42
+ if (!await Context.auth.hasFullAccess(organization.id)) {
43
+ throw Context.auth.error()
44
+ }
45
+ } else {
46
+ if (!Context.auth.hasPlatformFullAccess()) {
47
+ throw Context.auth.error()
48
+ }
49
+ }
50
+
51
+ const periods: RegistrationPeriod[] = [];
52
+
53
+ for (const {put} of request.body.getPuts()) {
54
+ const period = new RegistrationPeriod();
55
+ period.id = put.id;
56
+ period.startDate = put.startDate;
57
+ period.endDate = put.endDate;
58
+ period.locked = put.locked;
59
+ period.settings = put.settings;
60
+ period.organizationId = organization?.id ?? null;
61
+
62
+ await period.save();
63
+ periods.push(period);
64
+ }
65
+
66
+ for (const patch of request.body.getPatches()) {
67
+ const model = await RegistrationPeriod.getByID(patch.id);
68
+
69
+ if (!model || model.organizationId !== (organization?.id ?? null)) {
70
+ throw new SimpleError({
71
+ code: "not_found",
72
+ statusCode: 404,
73
+ message: "Registration period not found",
74
+ });
75
+ }
76
+
77
+ if (patch.startDate !== undefined) {
78
+ model.startDate = patch.startDate;
79
+ }
80
+
81
+ if (patch.endDate !== undefined) {
82
+ model.endDate = patch.endDate;
83
+ }
84
+
85
+ if (patch.locked !== undefined) {
86
+ model.locked = patch.locked;
87
+ }
88
+
89
+ if (patch.settings !== undefined) {
90
+ model.settings = patchObject(model.settings, patch.settings);
91
+ }
92
+
93
+ await model.save();
94
+ }
95
+
96
+ for (const id of request.body.getDeletes()) {
97
+ const model = await RegistrationPeriod.getByID(id);
98
+
99
+ if (!model || model.organizationId !== (organization?.id ?? null)) {
100
+ throw new SimpleError({
101
+ code: "not_found",
102
+ statusCode: 404,
103
+ message: "Registration period not found",
104
+ });
105
+ }
106
+
107
+ await model.delete();
108
+ }
109
+
110
+ return new Response(
111
+ periods.map(p => p.getStructure())
112
+ );
113
+ }
114
+
115
+ }
@@ -0,0 +1,187 @@
1
+ import { AutoEncoder, Decoder,field, StringDecoder } from "@simonbackx/simple-encoding";
2
+ import { DecodedRequest, Endpoint, Request, Response } from "@simonbackx/simple-endpoints";
3
+ import { SimpleError } from '@simonbackx/simple-errors';
4
+ import { Organization } from '@stamhoofd/models';
5
+ import { Webshop } from '@stamhoofd/models';
6
+ import { GetWebshopFromDomainResult, Webshop as WebshopStruct, WebshopPreview } from "@stamhoofd/structures";
7
+ import { GoogleTranslateHelper, Sorter } from "@stamhoofd/utility";
8
+ type Params = Record<string, never>;
9
+
10
+ class Query extends AutoEncoder {
11
+ @field({ decoder: StringDecoder })
12
+ domain: string;
13
+
14
+ @field({ decoder: StringDecoder, nullable: true })
15
+ uri: string | null;
16
+ }
17
+
18
+ type Body = undefined
19
+ type ResponseBody = GetWebshopFromDomainResult;
20
+
21
+ /**
22
+ * One endpoint to create, patch and delete groups. Usefull because on organization setup, we need to create multiple groups at once. Also, sometimes we need to link values and update multiple groups at once
23
+ */
24
+
25
+ export class GetWebshopFromDomainEndpoint extends Endpoint<Params, Query, Body, ResponseBody> {
26
+ queryDecoder = Query as Decoder<Query>
27
+ webshopDomains = [
28
+ ...new Set([
29
+ ...Object.values(STAMHOOFD.domains.webshop),
30
+ ...Object.values(STAMHOOFD.domains.marketing)
31
+ ])
32
+ ]
33
+
34
+ protected doesMatch(request: Request): [true, Params] | [false] {
35
+ if (request.method != "GET") {
36
+ return [false];
37
+ }
38
+
39
+ const params = Endpoint.parseParameters(request.url, "/webshop-from-domain", {});
40
+
41
+ if (params) {
42
+ return [true, params as Params];
43
+ }
44
+ return [false];
45
+ }
46
+
47
+ async handle(request: DecodedRequest<Params, Query, Body>) {
48
+ // check if the domain ends on .stamhoofd.be
49
+ if (!STAMHOOFD.domains.webshop) {
50
+ throw new Error("Expected environment variable HOSTNAME_WEBSHOP")
51
+ }
52
+
53
+ // Clean up google translate domains -> make sure we can translate register pages
54
+ request.query.domain = GoogleTranslateHelper.getDomainFromTranslateDomain(request.query.domain)
55
+
56
+ if (request.query.uri) {
57
+ for (const domain of this.webshopDomains) {
58
+ if (request.query.domain === domain) {
59
+ // Search webshop
60
+ const webshop = await Webshop.getByURI(request.query.uri)
61
+
62
+ if (!webshop) {
63
+ throw new SimpleError({
64
+ code: "unknown_webshop",
65
+ message: "No webshop registered with this name",
66
+ statusCode: 404
67
+ })
68
+ }
69
+
70
+ const organization = await Organization.getByID(webshop.organizationId)
71
+
72
+ if (!organization) {
73
+ throw new SimpleError({
74
+ code: "unknown_organization",
75
+ message: "No organization registered with this domain name",
76
+ statusCode: 404
77
+ })
78
+ }
79
+
80
+ return new Response(GetWebshopFromDomainResult.create({
81
+ organization: await organization.getStructure({emptyGroups: true}),
82
+ webshop: WebshopStruct.create(webshop)
83
+ }));
84
+ }
85
+ }
86
+ }
87
+
88
+ // If ends with the legacy webshop domain
89
+ if (STAMHOOFD.domains.legacyWebshop && request.query.domain.endsWith("." + STAMHOOFD.domains.legacyWebshop)) {
90
+ const strippped = request.query.domain.substr(0, request.query.domain.length - ("." + STAMHOOFD.domains.legacyWebshop).length )
91
+ if (strippped.includes(".")) {
92
+ throw new SimpleError({
93
+ code: "invalid_domain",
94
+ message: "This domain format is not supported",
95
+ statusCode: 404
96
+ })
97
+ }
98
+
99
+ // Search for the URI
100
+ const organization = await Organization.getByURI(strippped)
101
+
102
+ if (!organization) {
103
+ throw new SimpleError({
104
+ code: "unknown_organization",
105
+ message: "No organization registered with this domain name",
106
+ statusCode: 404
107
+ })
108
+ }
109
+
110
+ // Search webshop
111
+ const webshop = await Webshop.getByLegacyURI(organization.id, request.query.uri ?? "")
112
+
113
+ if (!webshop) {
114
+ // Return organization, so we know the locale + can do some custom logic
115
+ return new Response(GetWebshopFromDomainResult.create({
116
+ organization: await organization.getStructure({emptyGroups: true}),
117
+ webshop: null,
118
+ webshops: []
119
+ }));
120
+ }
121
+
122
+ return new Response(GetWebshopFromDomainResult.create({
123
+ organization: await organization.getStructure({emptyGroups: true}),
124
+ webshop: WebshopStruct.create(webshop)
125
+ }));
126
+ }
127
+
128
+ // Check if we have an organization with a custom domain name
129
+
130
+ const webshop = await Webshop.getByDomain(request.query.domain, request.query.uri)
131
+
132
+ if (!webshop) {
133
+ // If uri is empty, check if we have multiple webshops with the same domain
134
+ // Check organization
135
+ if (!request.query.uri) {
136
+ const webshops = await Webshop.getByDomainOnly(request.query.domain)
137
+ const organizationId = Sorter.getMostOccuringElement(webshops.map(w => w.organizationId))
138
+
139
+ if (webshops.length == 0 || !organizationId) {
140
+ throw new SimpleError({
141
+ code: "unknown_webshop",
142
+ message: "No webshop registered with this domain name",
143
+ statusCode: 404
144
+ })
145
+ }
146
+
147
+ const organization = await Organization.getByID(organizationId)
148
+
149
+ if (!organization) {
150
+ throw new SimpleError({
151
+ code: "unknown_webshop",
152
+ message: "No webshop registered with this domain name",
153
+ statusCode: 404
154
+ })
155
+ }
156
+
157
+ // Return organization, and the known webshops on this domain
158
+ return new Response(GetWebshopFromDomainResult.create({
159
+ organization: await organization.getStructure({emptyGroups: true}),
160
+ webshop: null,
161
+ webshops: webshops.map(w => WebshopPreview.create(w)).filter(w => w.isClosed(0) === false).sort((a, b) => Sorter.byStringValue(a.meta.name, b.meta.name))
162
+ }));
163
+ }
164
+
165
+ throw new SimpleError({
166
+ code: "unknown_webshop",
167
+ message: "No webshop registered with this domain name",
168
+ statusCode: 404
169
+ })
170
+ }
171
+
172
+ const organization = await Organization.getByID(webshop.organizationId)
173
+
174
+ if (!organization) {
175
+ throw new SimpleError({
176
+ code: "unknown_organization",
177
+ message: "No organization registered with this domain name",
178
+ statusCode: 404
179
+ })
180
+ }
181
+
182
+ return new Response(GetWebshopFromDomainResult.create({
183
+ organization: await organization.getStructure({emptyGroups: true}),
184
+ webshop: WebshopStruct.create(webshop)
185
+ }));
186
+ }
187
+ }