prow-authority 3.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (168) hide show
  1. package/.claude/settings.local.json +11 -0
  2. package/.dockerignore +11 -0
  3. package/.github/workflows/_deploy.yml +191 -0
  4. package/.github/workflows/deploy-dev.yml +30 -0
  5. package/.github/workflows/deploy-prod.yml +34 -0
  6. package/CLAUDE.md +114 -0
  7. package/Dockerfile +61 -0
  8. package/Dockerfile.dev +24 -0
  9. package/README.md +1 -0
  10. package/package.json +61 -0
  11. package/src/App.ts +40 -0
  12. package/src/helpers/api-error.ts +21 -0
  13. package/src/helpers/authority.ts +216 -0
  14. package/src/helpers/config.ts +4 -0
  15. package/src/helpers/holded.ts +105 -0
  16. package/src/helpers/mysql.ts +15 -0
  17. package/src/helpers/notifications.ts +55 -0
  18. package/src/helpers/random.ts +18 -0
  19. package/src/helpers/s3.ts +43 -0
  20. package/src/helpers/stripe.ts +8 -0
  21. package/src/index.ts +47 -0
  22. package/src/v1/common-types.ts +12 -0
  23. package/src/v1/controllers/admin/accounting-seat-controller.ts +148 -0
  24. package/src/v1/controllers/admin/billing-cycle-controller.ts +171 -0
  25. package/src/v1/controllers/admin/invoice-controller.ts +222 -0
  26. package/src/v1/controllers/admin/license-controller.ts +190 -0
  27. package/src/v1/controllers/admin/license-limit-controller.ts +160 -0
  28. package/src/v1/controllers/admin/notification-controller.ts +115 -0
  29. package/src/v1/controllers/admin/organization-controller.ts +210 -0
  30. package/src/v1/controllers/admin/organization-license-controller.ts +224 -0
  31. package/src/v1/controllers/admin/organization-license-limit-controller.ts +196 -0
  32. package/src/v1/controllers/admin/organization-usage-controller.ts +167 -0
  33. package/src/v1/controllers/admin/payment-method-controller.ts +173 -0
  34. package/src/v1/controllers/admin/policy-controller.ts +138 -0
  35. package/src/v1/controllers/admin/policy-version-controller.ts +143 -0
  36. package/src/v1/controllers/admin/schedule-controller.ts +181 -0
  37. package/src/v1/controllers/admin/service-controller.ts +206 -0
  38. package/src/v1/controllers/admin/service-notification-controller.ts +166 -0
  39. package/src/v1/controllers/admin/user-controller.ts +282 -0
  40. package/src/v1/controllers/admin/user-organization-controller.ts +172 -0
  41. package/src/v1/controllers/admin/user-policy-controller.ts +164 -0
  42. package/src/v1/controllers/auth/@deprecated oauth-controller.ts +191 -0
  43. package/src/v1/controllers/auth/identity-token-controller.ts +286 -0
  44. package/src/v1/controllers/auth/organization-token-controller.ts +277 -0
  45. package/src/v1/controllers/auth/temp-code-controller.ts +60 -0
  46. package/src/v1/controllers/billing/billing-controller.ts +805 -0
  47. package/src/v1/controllers/organizations/public-organization-controller.ts +1796 -0
  48. package/src/v1/controllers/policies/public-policy-controller.ts +68 -0
  49. package/src/v1/controllers/services/public-service-controller.ts +177 -0
  50. package/src/v1/controllers/services/service-controller.ts +474 -0
  51. package/src/v1/controllers/users/public-user-controller.ts +471 -0
  52. package/src/v1/daos/@deprecated auth-dao.ts +173 -0
  53. package/src/v1/daos/accounting-seat-dao.ts +111 -0
  54. package/src/v1/daos/billing-cycle-dao.ts +107 -0
  55. package/src/v1/daos/invoice-dao.ts +131 -0
  56. package/src/v1/daos/license-dao.ts +152 -0
  57. package/src/v1/daos/license-limit-dao.ts +120 -0
  58. package/src/v1/daos/organization-dao.ts +109 -0
  59. package/src/v1/daos/organization-license-dao.ts +117 -0
  60. package/src/v1/daos/organization-license-limit-dao.ts +157 -0
  61. package/src/v1/daos/organization-usage-dao.ts +115 -0
  62. package/src/v1/daos/payment-method-dao.ts +110 -0
  63. package/src/v1/daos/policy-dao.ts +105 -0
  64. package/src/v1/daos/policy-version-dao.ts +112 -0
  65. package/src/v1/daos/redis-dao.ts +38 -0
  66. package/src/v1/daos/schema.sql +462 -0
  67. package/src/v1/daos/service-dao.ts +118 -0
  68. package/src/v1/daos/service-notification-dao.ts +120 -0
  69. package/src/v1/daos/user-dao.ts +127 -0
  70. package/src/v1/daos/user-organization-dao.ts +123 -0
  71. package/src/v1/daos/user-policy-dao.ts +109 -0
  72. package/src/v1/middlewares/auth/identity-token-middleware.ts +51 -0
  73. package/src/v1/middlewares/auth/organization-token-middleware.ts +73 -0
  74. package/src/v1/middlewares/auth/service-token-middleware.ts +167 -0
  75. package/src/v1/middlewares/authority-middleware.ts +97 -0
  76. package/src/v1/middlewares/organizations/organization-middleware.ts +94 -0
  77. package/src/v1/middlewares/static/static-middleware.ts +41 -0
  78. package/src/v1/middlewares/users/user-middleware.ts +41 -0
  79. package/src/v1/routes/admin/accounting-seat-router.ts +89 -0
  80. package/src/v1/routes/admin/admin-router.ts +61 -0
  81. package/src/v1/routes/admin/billing-cycle-router.ts +89 -0
  82. package/src/v1/routes/admin/invoice-router.ts +89 -0
  83. package/src/v1/routes/admin/license-limit-router.ts +89 -0
  84. package/src/v1/routes/admin/license-router.ts +89 -0
  85. package/src/v1/routes/admin/notification-router.ts +61 -0
  86. package/src/v1/routes/admin/organization-license-limit-router.ts +89 -0
  87. package/src/v1/routes/admin/organization-license-router.ts +89 -0
  88. package/src/v1/routes/admin/organization-router.ts +89 -0
  89. package/src/v1/routes/admin/payment-method-router.ts +89 -0
  90. package/src/v1/routes/admin/policy-router.ts +89 -0
  91. package/src/v1/routes/admin/policy-version-router.ts +89 -0
  92. package/src/v1/routes/admin/schedule-router.ts +75 -0
  93. package/src/v1/routes/admin/service-notification-router.ts +98 -0
  94. package/src/v1/routes/admin/service-router.ts +89 -0
  95. package/src/v1/routes/admin/user-organization-router.ts +89 -0
  96. package/src/v1/routes/admin/user-policy-router.ts +89 -0
  97. package/src/v1/routes/admin/user-router.ts +89 -0
  98. package/src/v1/routes/auth/@deprecated auth-router.ts +199 -0
  99. package/src/v1/routes/auth/identity-token-router.ts +147 -0
  100. package/src/v1/routes/auth/organization-token-router.ts +70 -0
  101. package/src/v1/routes/billing/billing-router.ts +227 -0
  102. package/src/v1/routes/organizations/invoices-router.ts +48 -0
  103. package/src/v1/routes/organizations/payments-router.ts +104 -0
  104. package/src/v1/routes/organizations/public-organization-router.ts +319 -0
  105. package/src/v1/routes/organizations/users-router.ts +139 -0
  106. package/src/v1/routes/policies/public-policy-router.ts +50 -0
  107. package/src/v1/routes/services/public-service-router.ts +89 -0
  108. package/src/v1/routes/services/service-router.ts +197 -0
  109. package/src/v1/routes/users/public-user-router.ts +230 -0
  110. package/src/v1/routes/v1-router.ts +50 -0
  111. package/src/v1/schemas/admin/accounting-seat-schemas.ts +22 -0
  112. package/src/v1/schemas/admin/billing-cycle-schemas.ts +20 -0
  113. package/src/v1/schemas/admin/invoice-schemas.ts +41 -0
  114. package/src/v1/schemas/admin/license-limit-schemas.ts +25 -0
  115. package/src/v1/schemas/admin/license-schemas.ts +30 -0
  116. package/src/v1/schemas/admin/organization-license-limit-schemas.ts +29 -0
  117. package/src/v1/schemas/admin/organization-license-schemas.ts +43 -0
  118. package/src/v1/schemas/admin/organization-schemas.ts +67 -0
  119. package/src/v1/schemas/admin/organization-usage-schemas.ts +15 -0
  120. package/src/v1/schemas/admin/payment-method-schemas.ts +40 -0
  121. package/src/v1/schemas/admin/policy-schemas.ts +31 -0
  122. package/src/v1/schemas/admin/service-notification-schemas.ts +23 -0
  123. package/src/v1/schemas/admin/service-schemas.ts +56 -0
  124. package/src/v1/schemas/admin/user-organization-schemas.ts +24 -0
  125. package/src/v1/schemas/admin/user-policy-schemas.ts +17 -0
  126. package/src/v1/schemas/admin/user-schemas.ts +52 -0
  127. package/src/v1/schemas/auth/auth-schemas.ts +55 -0
  128. package/src/v1/schemas/billing/billing-schemas.ts +32 -0
  129. package/src/v1/schemas/organizations/public-organization-schemas.ts +77 -0
  130. package/src/v1/schemas/payments/payment-method-schemas.ts +0 -0
  131. package/src/v1/schemas/services/public-service-schemas.ts +5 -0
  132. package/src/v1/schemas/services/service-schemas.ts +27 -0
  133. package/src/v1/schemas/users/public-user-schemas.ts +73 -0
  134. package/src/v1/types/admin/accounting-seat-types.ts +16 -0
  135. package/src/v1/types/admin/billing-cycle-types.ts +14 -0
  136. package/src/v1/types/admin/invoice-types.ts +39 -0
  137. package/src/v1/types/admin/license-limit-types.ts +16 -0
  138. package/src/v1/types/admin/license-types.ts +29 -0
  139. package/src/v1/types/admin/organization-license-limit-types.ts +13 -0
  140. package/src/v1/types/admin/organization-license-types.ts +21 -0
  141. package/src/v1/types/admin/organization-types.ts +60 -0
  142. package/src/v1/types/admin/organization-usage-types.ts +17 -0
  143. package/src/v1/types/admin/payment-method-types.ts +30 -0
  144. package/src/v1/types/admin/policy-types.ts +9 -0
  145. package/src/v1/types/admin/policy-version-types.ts +12 -0
  146. package/src/v1/types/admin/service-notification-types.ts +20 -0
  147. package/src/v1/types/admin/service-types.ts +36 -0
  148. package/src/v1/types/admin/user-organization-types.ts +31 -0
  149. package/src/v1/types/admin/user-types.ts +44 -0
  150. package/src/v1/types/auth/@deprecated auth-types.ts +26 -0
  151. package/src/v1/types/auth/common-types.ts +7 -0
  152. package/src/v1/types/auth/confirmation-types.ts +5 -0
  153. package/src/v1/types/auth/identity-token-types.ts +8 -0
  154. package/src/v1/types/auth/organization-token-types.ts +23 -0
  155. package/src/v1/types/auth/otp-types.ts +12 -0
  156. package/src/v1/types/billing/billing-types.ts +37 -0
  157. package/src/v1/types/billing/ue-types.ts +29 -0
  158. package/src/v1/types/organizations/public-organization-types.ts +76 -0
  159. package/src/v1/types/policies/public-policy-types.ts +7 -0
  160. package/src/v1/types/services/public-service-types.ts +20 -0
  161. package/src/v1/types/services/service-types.ts +43 -0
  162. package/src/v1/types/users/public-user-types.ts +15 -0
  163. package/src/v1/types/users/user-policy-types.ts +11 -0
  164. package/static/error.html +55 -0
  165. package/static/grant.html +117 -0
  166. package/static/login.html +54 -0
  167. package/static/oauth-client-logo.webp +0 -0
  168. package/tsconfig.json +20 -0
@@ -0,0 +1,471 @@
1
+ import { Date2, Formats } from "@beseif-solutions/utility-functions/dist/utils/date-utils";
2
+ import { Requester } from "@beseif-solutions/utility-functions/dist/utils/http-utils";
3
+ import { DeepPartial } from "@beseif-solutions/utility-functions/dist/utils/typing-utils";
4
+ import { Schema, Validator } from "@beseif-solutions/utility-functions/dist/utils/validation-utils";
5
+ import _ from "lodash";
6
+ import APIError, { StatusCodes } from "../../../helpers/api-error";
7
+ import { informationResponseSchema } from "../../schemas/admin/service-schemas";
8
+ import { confirmSchema } from "../../schemas/auth/auth-schemas";
9
+ import { acceptPoliciesSchema, registerUserSchema, updateUserSchema } from "../../schemas/users/public-user-schemas";
10
+ import { OrganizationStatus } from "../../types/admin/organization-types";
11
+ import { Policy } from "../../types/admin/policy-types";
12
+ import { UserOrganization, UserOrganizationRole } from "../../types/admin/user-organization-types";
13
+ import { CommunicationType, User, UTM } from "../../types/admin/user-types";
14
+ import { Environment } from "../../types/auth/organization-token-types";
15
+ import { TempCodeType } from "../../types/auth/otp-types";
16
+ import { AcceptPolicies, PublicPolicy } from "../../types/policies/public-policy-types";
17
+ import { PublicServiceInformation } from "../../types/services/public-service-types";
18
+ import { PublicAccess, PublicUser, PublicUserOrganization } from "../../types/users/public-user-types";
19
+ import notificationController from "../admin/notification-controller";
20
+ import organizationController from "../admin/organization-controller";
21
+ import policyController from "../admin/policy-controller";
22
+ import serviceController from "../admin/service-controller";
23
+ import userController from "../admin/user-controller";
24
+ import userOrganizationController from "../admin/user-organization-controller";
25
+ import userPolicyController from "../admin/user-policy-controller";
26
+ import tempCodeController from "../auth/temp-code-controller";
27
+ import publicOrganizationController from "../organizations/public-organization-controller";
28
+ import publicPolicyController from "../policies/public-policy-controller";
29
+ import publicServiceController from "../services/public-service-controller";
30
+ import { Resource } from "@beseif-solutions/prow-authority-for-services";
31
+ import authority, { MemberAdded, NotificationEventNames, ResourceModelName, omnipotentAccess } from "../../../helpers/authority";
32
+ import nconf from "../../../helpers/config";
33
+
34
+ type Register = Omit<PublicUser, `uuid` | `status` | `created_date` | `modified_date` | `password`> & { password: string, utm?: UTM, referrer?: string };
35
+ type Update = DeepPartial<Register>;
36
+
37
+ class PublicUserCtrl {
38
+
39
+ public readonly register = async (data: Register, confirmation: boolean): Promise<PublicUser> => {
40
+ try {
41
+ Validator.validate(registerUserSchema, data);
42
+ let user = (await userController.list({ email: data.email }, { password: true, timestamp: true }))[0];
43
+
44
+ if (!user) {
45
+ // create user
46
+ user = (await userController.add(data, { password: false, timestamp: true }))[0];
47
+ } else if (user.status === `pending` || !user.password) {
48
+ // "create" when status is pending
49
+ // - Social Sign Up
50
+ // - Invitation from organization
51
+ user = (await userController.update(user.id, data, { password: false, timestamp: true }))[0];
52
+ } else {
53
+ // user already exists
54
+ throw new APIError({
55
+ code: StatusCodes.CONFLICT,
56
+ detail: `User with email ${data.email} already exists.`,
57
+ });
58
+ }
59
+
60
+ // accept all current policies on registration
61
+ await this.acceptPolicies(user);
62
+
63
+ if (confirmation) {
64
+ // send confirmation
65
+ await this.requestConfirmation(user);
66
+ }
67
+
68
+ const [response] = await this.parseUser([user]);
69
+ return response;
70
+ } catch (e) { throw e; }
71
+ };
72
+
73
+ public readonly get = async (user: User): Promise<PublicUser> => {
74
+ try {
75
+ const [response] = await this.parseUser([user]);
76
+ return response;
77
+ } catch (e) { throw e; }
78
+ };
79
+
80
+ public readonly update = async (user: User, data: Update): Promise<PublicUser> => {
81
+ try {
82
+ Validator.validate(updateUserSchema, data);
83
+ const updated = await userController.update(user.id, data, { password: false, timestamp: true });
84
+ const [response] = await this.parseUser(updated);
85
+ return response;
86
+ } catch (e) { throw e; }
87
+
88
+ };
89
+
90
+ public readonly delete = async (user: User): Promise<void> => {
91
+ try {
92
+ // check user organization accesses
93
+ const accesses = await userOrganizationController.list({ user: user.id, enabled: true });
94
+
95
+ const owner = accesses.filter((access) => access.role === UserOrganizationRole.Owner);
96
+ if (owner.length > 0) {
97
+ throw new APIError({
98
+ code: StatusCodes.BAD_REQUEST,
99
+ detail: `This user is the owner of ${owner.length} organization${owner.length === 1 ? `` : `s`}. Please remove ${owner.length === 1 ? `it` : `them`} or change the ownership before deleting the user.`,
100
+ });
101
+ }
102
+
103
+ const organizations = await organizationController.list({ id: { in: accesses.map((a) => a.organization) } });
104
+ for (const organization of organizations) {
105
+ // delete user access
106
+ const access = accesses.find((a) => a.organization === organization.id);
107
+ if (!access) { continue; }
108
+
109
+ const env = {
110
+ organization: organization,
111
+ user: user,
112
+ access: access,
113
+ license: null,
114
+ };
115
+
116
+ // delete user from organization
117
+ await publicOrganizationController.deleteUser(env, user.uuid);
118
+ }
119
+
120
+ await userController.delete(user.id);
121
+
122
+ await this.deleteInformation(user);
123
+ } catch (e) { throw e; }
124
+ };
125
+
126
+ // authority endpoint: user resources
127
+ public readonly authority = async (userUUID: string): Promise<Resource<ResourceModelName>[]> => {
128
+ try {
129
+ const user = (await userController.list({ uuid: userUUID }, { password: false }))[0];
130
+ if (!user) {
131
+ throw new APIError({
132
+ code: StatusCodes.NOT_FOUND,
133
+ detail: `No user ${userUUID} found.`,
134
+ });
135
+ }
136
+
137
+ const access = await userOrganizationController.count({ user: user.id, enabled: true });
138
+ const response: Resource<ResourceModelName>[] = [
139
+ {
140
+ type: `shared`,
141
+ model: `organization.organization`,
142
+ count: access.count,
143
+ },
144
+ ];
145
+
146
+ return response;
147
+ } catch (e) { throw e; }
148
+ };
149
+
150
+ // information over services
151
+ public readonly getInformation = async (user: User): Promise<PublicServiceInformation[]> => {
152
+ try {
153
+ const services = await serviceController.list({ enabled: true });
154
+
155
+ const response: PublicServiceInformation[] = _.compact(await Promise.all(services.map(async (service) => {
156
+ try {
157
+ let information: any[] = [];
158
+ if (service.internal.host && service.internal.user?.information) {
159
+ information = await Requester.get(`${service.internal.user?.information}/${user.uuid}`, {
160
+ baseURL: service.internal.host,
161
+ headers: {
162
+ "x-service-uuid": service.uuid,
163
+ "x-service-token": service.token,
164
+ },
165
+ });
166
+ Validator.validate(informationResponseSchema, information);
167
+ }
168
+
169
+ return {
170
+ service: (await publicServiceController.parseServices([service]))[0],
171
+ information: information,
172
+ };
173
+ } catch (e) { return null; }
174
+ })));
175
+ return response;
176
+ } catch (e) { throw e; }
177
+ };
178
+
179
+ private readonly deleteInformation = async (user: User): Promise<void> => {
180
+ try {
181
+ const services = await serviceController.list({ enabled: true });
182
+
183
+ await Promise.all(services.map(async (service) => {
184
+ try {
185
+ if (service.internal.host && service.internal.user?.deleted) {
186
+ await Requester.delete(`${service.internal.user?.deleted}/${user.uuid}`, {
187
+ baseURL: service.internal.host,
188
+ headers: {
189
+ "x-service-uuid": service.uuid,
190
+ "x-service-token": service.token,
191
+ },
192
+ });
193
+ }
194
+ } catch (e) {
195
+ // TODO: what to do when error?
196
+ }
197
+ }));
198
+ } catch (e) { throw e; }
199
+ };
200
+
201
+ // confirmation process
202
+ public readonly requestConfirmation = async (user: User): Promise<void> => {
203
+ try {
204
+ await notificationController.confirmation(user.id);
205
+ } catch (e) { throw e; }
206
+ };
207
+
208
+ public readonly confirm = async (user: User, data: { code: string }): Promise<PublicUser> => {
209
+ try {
210
+ Validator.validate(confirmSchema, data);
211
+ await tempCodeController.validate(TempCodeType.Confirmation, user, data.code);
212
+
213
+ await userController.activate(user.id, { password: false });
214
+
215
+ const updated = await userController.get(user.id, { password: false, timestamp: true });
216
+ const [response] = await this.parseUser(updated);
217
+ return response;
218
+ } catch (e) { throw e; }
219
+ };
220
+
221
+ // organizations
222
+ public readonly organizations = async (user: User): Promise<PublicUserOrganization[]> => {
223
+ try {
224
+ const accesses = await userOrganizationController.list({ user: user.id, enabled: true });
225
+ const organizations = await organizationController.list(
226
+ user.omnipotent ? {} : { id: { in: accesses.map((a) => a.organization) } },
227
+ { timestamp: true },
228
+ );
229
+
230
+ const response: PublicUserOrganization[] = [];
231
+ for (const o of organizations) {
232
+ const access = accesses.find((a) => a.organization === o.id) || (user.omnipotent ? omnipotentAccess(user, o) : null);
233
+ if (!access) { continue; }
234
+
235
+ const env: Environment = {
236
+ user: user,
237
+ access: access,
238
+ organization: o,
239
+ license: null,
240
+ };
241
+
242
+ response.push({
243
+ organization: (await publicOrganizationController.parse(env, [o]))[0],
244
+ access: (await this.parseAccess([access], { userCache: [user] }))[0],
245
+ });
246
+ }
247
+ return response;
248
+ } catch (e) { throw e; }
249
+ };
250
+
251
+ public readonly invite = async (user: User, organizationUUID: string, data: { code: string, accept: boolean }): Promise<void> => {
252
+ try {
253
+ Validator.validate(Schema.object({ code: Schema.requiredString(), accept: Schema.requiredBool() }), data);
254
+
255
+ const organization = (await organizationController.list({ uuid: organizationUUID, status: { is: OrganizationStatus.Blocked, inverse: true } }))[0];
256
+ if (!organization) {
257
+ throw new APIError({
258
+ code: StatusCodes.NOT_FOUND,
259
+ detail: `No organization ${organizationUUID} found.`,
260
+ });
261
+ }
262
+
263
+ const access = (await userOrganizationController.list({
264
+ user: user.id,
265
+ organization: organization.id,
266
+ invite: data.code,
267
+ enabled: true,
268
+ }))[0];
269
+ if (!access) {
270
+ throw new APIError({
271
+ code: StatusCodes.BAD_REQUEST,
272
+ detail: `Invalid invite code for organization ${organizationUUID}.`,
273
+ });
274
+ }
275
+
276
+ if (data.accept) {
277
+ await userOrganizationController.update(access.id, { invite: null });
278
+
279
+ await authority.notify<MemberAdded>(organization.uuid, {
280
+ event: NotificationEventNames.MemberAdded,
281
+ data: {
282
+ user: user,
283
+ role: access.role,
284
+ organization: organization,
285
+ cta: {
286
+ members: nconf.get(`SERVICES:NOTIFICATIONS:CTAS:ORG_MEMBERS`),
287
+ preferences: nconf.get(`SERVICES:NOTIFICATIONS:CTAS:USER_PREF_LIST`),
288
+ },
289
+ },
290
+ });
291
+ } else {
292
+ await publicOrganizationController.deleteUser({
293
+ organization: organization,
294
+ user: user,
295
+ access: access,
296
+ license: null,
297
+ }, user.uuid);
298
+ }
299
+ } catch (e) { throw e; }
300
+ };
301
+
302
+ public readonly leave = async (user: User, organizationUUID: string): Promise<void> => {
303
+ try {
304
+ const organization = (await organizationController.list({ uuid: organizationUUID, status: { is: OrganizationStatus.Blocked, inverse: true } }))[0];
305
+ if (!organization) {
306
+ throw new APIError({
307
+ code: StatusCodes.NOT_FOUND,
308
+ detail: `No organization ${organizationUUID} found.`,
309
+ });
310
+ }
311
+
312
+ const access = (await userOrganizationController.list({
313
+ user: user.id,
314
+ organization: organization.id,
315
+ enabled: true,
316
+ }))[0];
317
+ if (!access) {
318
+ throw new APIError({
319
+ code: StatusCodes.BAD_REQUEST,
320
+ detail: `Invalid invite code for organization ${organizationUUID}.`,
321
+ });
322
+ }
323
+
324
+ await publicOrganizationController.deleteUser({
325
+ organization: organization,
326
+ user: user,
327
+ access: access,
328
+ license: null,
329
+ }, user.uuid);
330
+ } catch (e) { throw e; }
331
+ };
332
+
333
+ // policy-related methods
334
+ public readonly getPendingUserPolicies = async (user: User): Promise<PublicPolicy[]> => {
335
+ try {
336
+ const policies = await policyController.list({});
337
+
338
+ const pendingPolicies: Policy[] = [];
339
+ for (const policy of policies) {
340
+ const latestVersion = await publicPolicyController.getLatestVersion(policy.id);
341
+ if (!latestVersion) { continue; }
342
+
343
+ const userAcceptance = (await userPolicyController.list({
344
+ user: user.id,
345
+ policy: policy.id,
346
+ version: latestVersion.id,
347
+ }))[0];
348
+
349
+ if (!userAcceptance) { pendingPolicies.push(policy); }
350
+ }
351
+
352
+ return publicPolicyController.parsePolicies(pendingPolicies);
353
+ } catch (e) { throw e; }
354
+ };
355
+
356
+ public readonly acceptPolicies = async (user: User, data: AcceptPolicies = {}): Promise<void> => {
357
+ try {
358
+ Validator.validate(acceptPoliciesSchema, data);
359
+
360
+ const policies = await policyController.list({
361
+ ...data.uuids ? { uuid: { in: data.uuids } } : {},
362
+ });
363
+
364
+ for (const policy of policies) {
365
+ const version = await publicPolicyController.getLatestVersion(policy.id);
366
+ if (!version) { continue; }
367
+
368
+ // check if user already has this policy version accepted
369
+ const existing = (await userPolicyController.list({
370
+ user: user.id,
371
+ policy: policy.id,
372
+ version: version.id,
373
+ }))[0];
374
+
375
+ if (!existing) {
376
+ await userPolicyController.add({
377
+ user: user.id,
378
+ policy: policy.id,
379
+ version: version.id,
380
+ metadata: {},
381
+ internal: {},
382
+ });
383
+ }
384
+ }
385
+ } catch (e) { throw e; }
386
+ };
387
+
388
+ public readonly parseUser = async (records: User[]): Promise<PublicUser[]> => {
389
+ try {
390
+ const response: PublicUser[] = [];
391
+
392
+ for (const record of records) {
393
+ const p: PublicUser = {
394
+ uuid: record.uuid,
395
+ email: record.email,
396
+ password: record.password ? true : false,
397
+ properties: record.properties,
398
+ preferences: record.preferences,
399
+ omnipotent: record.omnipotent ? true : undefined, // don't expose omnipotent flag if false
400
+ created_date: new Date2(record.created_date).format(Formats.ISO),
401
+ modified_date: new Date2(record.modified_date).format(Formats.ISO),
402
+ status: record.status,
403
+ metadata: record.metadata,
404
+ };
405
+ response.push(p);
406
+ }
407
+ return response;
408
+ } catch (e) { throw e; }
409
+ };
410
+
411
+ public readonly parseAccess = async (records: UserOrganization[], options: { userCache?: User[], preferences?: boolean } = {}): Promise<PublicAccess[]> => {
412
+ try {
413
+ const missingUserIDs = _.compact(
414
+ _.uniq(records.map((r) => r.invited_by)
415
+ .filter((id) => !(options.userCache || []).some((u) => u.id === id))));
416
+ const users = [
417
+ ...options.userCache || [],
418
+ ...missingUserIDs.length ? await userController.list({ id: { in: missingUserIDs } }, { password: false, timestamp: true }) : [],
419
+ ];
420
+
421
+ const response: PublicAccess[] = [];
422
+ for (const record of records) {
423
+ const invitedBy = users.find((u) => u.id === record.invited_by);
424
+ const p: PublicAccess = {
425
+ invite: record.invite,
426
+ invited_by: invitedBy ? (await this.parseUser([invitedBy]))[0] : null,
427
+ role: record.role,
428
+ created_date: new Date2(record.created_date).format(Formats.ISO),
429
+ modified_date: new Date2(record.modified_date).format(Formats.ISO),
430
+ enabled: record.enabled ? true : false,
431
+ ...(options.preferences ? { preferences: record.preferences } : {}),
432
+ metadata: record.metadata,
433
+ };
434
+ response.push(p);
435
+ }
436
+ return response;
437
+ } catch (e) { throw e; }
438
+ };
439
+
440
+ // communications
441
+ public readonly unsubscribeByUuid = async (uuid: string, type: CommunicationType): Promise<void> => {
442
+ try {
443
+ const validTypes: CommunicationType[] = [CommunicationType.Commercial, CommunicationType.Newsletter];
444
+ if (!validTypes.includes(type)) {
445
+ throw new APIError({
446
+ code: StatusCodes.BAD_REQUEST,
447
+ detail: `Invalid communication type. Valid types are: ${validTypes.join(`, `)}`,
448
+ });
449
+ }
450
+
451
+ const user = (await userController.list({ uuid: uuid }, { password: false }))[0];
452
+ if (!user) {
453
+ throw new APIError({
454
+ code: StatusCodes.NOT_FOUND,
455
+ detail: `User not found`,
456
+ });
457
+ }
458
+
459
+ await userController.update(user.id, {
460
+ preferences: {
461
+ communications: {
462
+ [type]: false,
463
+ },
464
+ },
465
+ }, { password: false });
466
+ } catch (e) { throw e; }
467
+ };
468
+ }
469
+
470
+ const publicUserController = new PublicUserCtrl();
471
+ export default publicUserController;
@@ -0,0 +1,173 @@
1
+ // import { newUUIDv4 } from "@beseif-solutions/utility-functions/dist/utils/string-utils";
2
+
3
+ // // session
4
+ // export type UserLogin = {
5
+ // id: number,
6
+ // username: string,
7
+ // password: string,
8
+ // sign: string,
9
+ // webhook: string,
10
+ // };
11
+
12
+
13
+ // const userLogins: UserLogin[] = [];
14
+
15
+ // // static
16
+ // export type AppLogin = {
17
+ // id: number,
18
+ // token: string,
19
+ // user: number,
20
+ // };
21
+
22
+ // const appLogins: AppLogin[] = [
23
+
24
+ // ];
25
+
26
+ // // oauth
27
+ // export type OAuthClient = {
28
+ // id: string,
29
+ // secret: string,
30
+ // name: string,
31
+ // image: string,
32
+ // redirects: string[],
33
+ // };
34
+
35
+ // const oauthClients: OAuthClient[] = [
36
+
37
+ // ];
38
+
39
+ // export const SCOPES = [`*`, `user`, `crm:orders`, `crm:clients`];
40
+
41
+ // export type OAuthSession = {
42
+ // token: string,
43
+ // client_id: OAuthClient[`id`],
44
+ // redirect_uri: string,
45
+ // scope: string,
46
+ // user?: UserLogin[`id`],
47
+ // };
48
+
49
+ // let oauthSessions: OAuthSession[] = [];
50
+
51
+ // export type OAuthCode = {
52
+ // code: string,
53
+ // session: OAuthSession[`token`],
54
+ // };
55
+
56
+ // let oauthCodes: OAuthCode[] = [];
57
+
58
+ // export type OAuthLogin = {
59
+ // id: string,
60
+ // };
61
+
62
+ // let oauthLogins: OAuthLogin[] = [];
63
+
64
+ // class AuthDao {
65
+ // // session
66
+ // public readonly findUserLoginByUsername = async (username: string): Promise<UserLogin> =>
67
+ // userLogins.find(user => user.username === username);
68
+
69
+ // public readonly findUserLoginById = async (id: number): Promise<UserLogin> =>
70
+ // userLogins.find(user => user.id === id);
71
+
72
+ // // static
73
+ // public readonly findAppLoginById = async (id: number): Promise<AppLogin> =>
74
+ // appLogins.find(app => app.id === id);
75
+
76
+ // // oauth
77
+ // public readonly findOAuthClientById = async (id: string): Promise<OAuthClient> =>
78
+ // oauthClients.find(client => client.id === id);
79
+
80
+ // public readonly findOAuthSessionByToken = async (token: string): Promise<OAuthSession> =>
81
+ // oauthSessions.find(session => session.token === token);
82
+
83
+ // public readonly addOAuthSession = async (data: Omit<OAuthSession, `token`>): Promise<OAuthSession> => {
84
+ // try {
85
+ // const token = newUUIDv4();
86
+
87
+ // const session: OAuthSession = {
88
+ // ...data,
89
+ // token: token,
90
+ // };
91
+
92
+ // oauthSessions.push(session);
93
+ // return session;
94
+ // } catch (e) { throw e; }
95
+ // };
96
+
97
+ // public readonly updateOAuthSession = async (token: string, data: Partial<Omit<OAuthSession, `token`>>): Promise<OAuthSession> => {
98
+ // try {
99
+ // const id = oauthSessions.findIndex(session => session.token === token);
100
+ // if (id < 0) { throw new Error(`No OAuth session found`); }
101
+
102
+ // const updated = {
103
+ // ...oauthSessions[id],
104
+ // ...data,
105
+ // };
106
+
107
+ // oauthSessions[id] = updated;
108
+ // return updated;
109
+ // } catch (e) { throw e; }
110
+ // };
111
+
112
+ // public readonly deleteOAuthSessionByToken = async (token: string): Promise<void> => {
113
+ // oauthSessions = oauthSessions.filter(session => session.token !== token);
114
+ // };
115
+
116
+ // public readonly findOAuthCodeByCode = async (code: string): Promise<OAuthCode> =>
117
+ // oauthCodes.find(codes => codes.code === code);
118
+
119
+ // public readonly addOAuthCode = async (data: Omit<OAuthCode, `code`>): Promise<OAuthCode> => {
120
+ // try {
121
+ // const code = newUUIDv4();
122
+
123
+ // const session: OAuthCode = {
124
+ // ...data,
125
+ // code: code,
126
+ // };
127
+
128
+ // oauthCodes.push(session);
129
+ // return session;
130
+ // } catch (e) { throw e; }
131
+ // };
132
+
133
+ // public readonly updateOAuthCode = async (code: string, data: Partial<Omit<OAuthCode, `code`>>): Promise<OAuthCode> => {
134
+ // try {
135
+ // const id = oauthCodes.findIndex(session => session.code === code);
136
+ // if (id < 0) { throw new Error(`No OAuth session found`); }
137
+
138
+ // const updated = {
139
+ // ...oauthCodes[id],
140
+ // ...data,
141
+ // };
142
+
143
+ // oauthCodes[id] = updated;
144
+ // return updated;
145
+ // } catch (e) { throw e; }
146
+ // };
147
+
148
+ // public readonly deleteOAuthCodeByCode = async (code: string): Promise<void> => {
149
+ // oauthCodes = oauthCodes.filter(codes => codes.code !== code);
150
+ // };
151
+
152
+ // public readonly findOAuthLoginById = async (id: string): Promise<OAuthLogin> =>
153
+ // oauthLogins.find(logins => logins.id === id);
154
+
155
+ // public readonly addOAuthLogin = async (data: OAuthLogin): Promise<OAuthLogin> => {
156
+ // try {
157
+ // const session: OAuthLogin = {
158
+ // ...data,
159
+ // };
160
+
161
+ // oauthLogins.push(session);
162
+ // return session;
163
+ // } catch (e) { throw e; }
164
+ // };
165
+
166
+ // public readonly deleteOAuthLoginById = async (id: string): Promise<void> => {
167
+ // oauthLogins = oauthLogins.filter(logins => logins.id !== id);
168
+ // };
169
+
170
+ // }
171
+
172
+ // const authDao = new AuthDao();
173
+ // export default authDao;