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,224 @@
1
+ import { Date2, Formats } from "@beseif-solutions/utility-functions/dist/utils/date-utils";
2
+ import { JSON2 } from "@beseif-solutions/utility-functions/dist/utils/json-utils";
3
+ import { Where } from "@beseif-solutions/utility-functions/dist/utils/sql-utils";
4
+ import { newUUIDv4 } from "@beseif-solutions/utility-functions/dist/utils/string-utils";
5
+ import { DeepPartial } from "@beseif-solutions/utility-functions/dist/utils/typing-utils";
6
+ import { Validator } from "@beseif-solutions/utility-functions/dist/utils/validation-utils";
7
+ import APIError, { StatusCodes } from "../../../helpers/api-error";
8
+ import organizationLicenseDao from "../../daos/organization-license-dao";
9
+ import { addOrganizationLicenseSchema, updateOrganizationLicenseSchema } from "../../schemas/admin/organization-license-schemas";
10
+ import { DBRecord, OrganizationLicense } from "../../types/admin/organization-license-types";
11
+ import { OrganizationStatus } from "../../types/admin/organization-types";
12
+ import licenseController from "./license-controller";
13
+ import organizationController from "./organization-controller";
14
+ import serviceController from "./service-controller";
15
+ import { Modifiers } from "../../common-types";
16
+
17
+ type Add = Omit<OrganizationLicense, `id` | `uuid` | `annual_price` | `monthly_price` | `enabled`>;
18
+ type Update = DeepPartial<Omit<OrganizationLicense, `id` | `uuid` | `annual_price` | `monthly_price` | `enabled`>>;
19
+
20
+ class OrganizationLicenseCtrl {
21
+
22
+ public readonly get = async (id: number): Promise<OrganizationLicense[]> => {
23
+ try {
24
+ const db = await organizationLicenseDao.get({ id: id });
25
+ const response = await this.parse(db);
26
+ return response;
27
+ } catch (e) { throw e; }
28
+ };
29
+
30
+ public readonly list = async (params: Where<OrganizationLicense>, options: Modifiers = {}): Promise<OrganizationLicense[]> => {
31
+ try {
32
+ const db = await organizationLicenseDao.list({ ...params } as any, options);
33
+ const response = await this.parse(db);
34
+ return response;
35
+ } catch (e) {
36
+ throw e;
37
+ }
38
+ };
39
+
40
+ public readonly add = async (data: Add): Promise<OrganizationLicense[]> => {
41
+ try {
42
+ await Validator.validateAsync(addOrganizationLicenseSchema, data);
43
+ await this.check(data);
44
+
45
+ const uuid = await this.getFreeUUID();
46
+
47
+ const { insertId } = await organizationLicenseDao.add({
48
+ uuid: uuid,
49
+ service: data.service,
50
+ organization: data.organization,
51
+ type: data.type,
52
+ associated: data.associated,
53
+ original: data.original,
54
+ billing: data.billing,
55
+ properties: data.properties,
56
+ data: data.data,
57
+ start_date: data.start_date,
58
+ end_date: data.end_date,
59
+ metadata: data.metadata,
60
+ internal: data.internal,
61
+ });
62
+
63
+ return await this.get(insertId);
64
+ } catch (e) { throw e; }
65
+ };
66
+
67
+ public readonly update = async (id: number, data: Update): Promise<OrganizationLicense[]> => {
68
+ try {
69
+ await Validator.validateAsync(updateOrganizationLicenseSchema, data);
70
+
71
+ const old = (await this.get(id))[0];
72
+ if (!old) {
73
+ throw new APIError({
74
+ code: StatusCodes.NOT_FOUND,
75
+ detail: `OrganizationLicense with id ${id} not found.`,
76
+ });
77
+ }
78
+
79
+ const merged = JSON2.deepClean(JSON2.deepMerge({}, old, data)) as OrganizationLicense;
80
+
81
+ await this.check(merged, old);
82
+
83
+ const { affectedRows } = await organizationLicenseDao.update({ id: id }, {
84
+ uuid: merged.uuid,
85
+ service: merged.service,
86
+ organization: merged.organization,
87
+ type: merged.type,
88
+ associated: merged.associated,
89
+ original: merged.original,
90
+ billing: merged.billing,
91
+ properties: merged.properties,
92
+ data: merged.data,
93
+ start_date: merged.start_date,
94
+ end_date: merged.end_date,
95
+ metadata: merged.metadata,
96
+ internal: merged.internal,
97
+ });
98
+
99
+ if (affectedRows <= 0) {
100
+ throw new APIError({
101
+ code: StatusCodes.INTERNAL_SERVER_ERROR,
102
+ detail: `Could not update license with id ${id}`,
103
+ });
104
+ }
105
+
106
+ return await this.get(id);
107
+ } catch (e) { throw e; }
108
+
109
+ };
110
+
111
+ public readonly delete = async (id: number): Promise<{ deleted: boolean }> => {
112
+ try {
113
+ const license = (await this.get(id))[0];
114
+ if (!license) {
115
+ throw new APIError({
116
+ code: StatusCodes.NOT_FOUND,
117
+ detail: `OrganizationLicense with id ${id} not found.`,
118
+ });
119
+ }
120
+
121
+ const { affectedRows } = await organizationLicenseDao.delete({ id: license.id });
122
+
123
+ if (affectedRows <= 0) {
124
+ throw new APIError({
125
+ code: StatusCodes.INTERNAL_SERVER_ERROR,
126
+ detail: `Could not delete license with id ${id}`,
127
+ });
128
+ }
129
+
130
+ return { deleted: affectedRows > 0 };
131
+ } catch (e) { throw e; }
132
+ };
133
+
134
+ private readonly check = async (data: Add | OrganizationLicense, old?: OrganizationLicense): Promise<void> => {
135
+ try {
136
+ if (!old || data.service !== old.service) {
137
+ const service = (await serviceController.list({ id: data.service, enabled: true }))[0];
138
+ if (!service) {
139
+ throw new APIError({
140
+ code: StatusCodes.BAD_REQUEST,
141
+ detail: `No enabled service ${data.service} found.`,
142
+ });
143
+ }
144
+ }
145
+
146
+ if (!old || data.organization !== old.organization) {
147
+ const organization = (await organizationController.list({ id: data.organization, status: { is: OrganizationStatus.Blocked, inverse: true } }))[0];
148
+ if (!organization) {
149
+ throw new APIError({
150
+ code: StatusCodes.BAD_REQUEST,
151
+ detail: `No active organization ${data.organization} found.`,
152
+ });
153
+ }
154
+ }
155
+
156
+ if (!old || data.original !== old.original) {
157
+ const originalLicense = (await licenseController.list({ id: data.original }))[0];
158
+ if (!originalLicense) {
159
+ throw new APIError({
160
+ code: StatusCodes.BAD_REQUEST,
161
+ detail: `No enabled original license with id ${data.original} found.`,
162
+ });
163
+ }
164
+ }
165
+
166
+ if (!old || (data.associated && data.associated !== old.associated)) {
167
+ const associatedLicense = (await organizationLicenseDao.list({ id: data.associated }))[0];
168
+ if (!associatedLicense) {
169
+ throw new APIError({
170
+ code: StatusCodes.BAD_REQUEST,
171
+ detail: `No enabled associated license with id ${data.associated} found.`,
172
+ });
173
+ }
174
+ }
175
+ } catch (e) { throw e; }
176
+ };
177
+
178
+ private readonly getFreeUUID = async (): Promise<string> => {
179
+ try {
180
+ let uuid: string;
181
+ do {
182
+ uuid = newUUIDv4({ case: `lower` });
183
+ const exists = (await organizationLicenseDao.list({ uuid: uuid }))[0];
184
+ if (!exists) { break; }
185
+ } while (true);
186
+ return uuid;
187
+ } catch (e) { throw e; }
188
+ };
189
+
190
+ private readonly parse = async (records: DBRecord[]): Promise<OrganizationLicense[]> => {
191
+ try {
192
+ const response: OrganizationLicense[] = [];
193
+
194
+ for (const record of records) {
195
+ const p: OrganizationLicense = {
196
+ id: record.id,
197
+ uuid: record.uuid,
198
+ service: record.service,
199
+ organization: record.organization,
200
+ associated: record.associated,
201
+ original: record.original,
202
+ type: record.type,
203
+ billing: record.billing,
204
+ properties: record.properties,
205
+ data: record.data,
206
+ start_date: new Date2(record.start_date).format(Formats.ISO),
207
+ end_date: record.end_date ? new Date2(record.end_date).format(Formats.ISO) : null,
208
+ annual_price: parseFloat(record.annual_price || `0`),
209
+ monthly_price: parseFloat(record.monthly_price || `0`),
210
+ enabled: record.enabled ? true : false,
211
+ metadata: record.metadata,
212
+ internal: record.internal,
213
+ };
214
+
215
+ response.push(p);
216
+ }
217
+
218
+ return response;
219
+ } catch (e) { throw e; }
220
+ };
221
+ }
222
+
223
+ const organizationLicenseController = new OrganizationLicenseCtrl();
224
+ export default organizationLicenseController;
@@ -0,0 +1,196 @@
1
+ import { JSON2 } from "@beseif-solutions/utility-functions/dist/utils/json-utils";
2
+ import { Where } from "@beseif-solutions/utility-functions/dist/utils/sql-utils";
3
+ import { DeepPartial } from "@beseif-solutions/utility-functions/dist/utils/typing-utils";
4
+ import { Validator } from "@beseif-solutions/utility-functions/dist/utils/validation-utils";
5
+ import APIError, { StatusCodes } from "../../../helpers/api-error";
6
+ import organizationOrganizationLicenseLimitDao from "../../daos/organization-license-limit-dao";
7
+ import { addOrganizationLicenseLimitSchema, updateOrganizationLicenseLimitSchema } from "../../schemas/admin/organization-license-limit-schemas";
8
+ import { DBRecord, OrganizationLicenseLimit } from "../../types/admin/organization-license-limit-types";
9
+ import { OrganizationStatus } from "../../types/admin/organization-types";
10
+ import organizationController from "./organization-controller";
11
+ import organizationLicenseController from "./organization-license-controller";
12
+ import { Modifiers } from "../../common-types";
13
+
14
+ type Add = Omit<OrganizationLicenseLimit, `id`>;
15
+ type Update = DeepPartial<Omit<OrganizationLicenseLimit, `id`>>;
16
+
17
+ class OrganizationLicenseLimitCtrl {
18
+
19
+ public readonly get = async (id: number): Promise<OrganizationLicenseLimit[]> => {
20
+ try {
21
+ const db = await organizationOrganizationLicenseLimitDao.get({ id: id });
22
+ const response = await this.parse(db);
23
+ return response;
24
+ } catch (e) { throw e; }
25
+ };
26
+
27
+ public readonly list = async (params: Where<OrganizationLicenseLimit>, options: Modifiers = {}): Promise<OrganizationLicenseLimit[]> => {
28
+ try {
29
+ const db = await organizationOrganizationLicenseLimitDao.list({ ...params }, options);
30
+ const response = await this.parse(db);
31
+ return response;
32
+ } catch (e) {
33
+ throw e;
34
+ }
35
+ };
36
+
37
+ public readonly sum = async (sum: string, params: Where<OrganizationLicenseLimit>, group: string[] = []) => {
38
+ try {
39
+ const response = await organizationOrganizationLicenseLimitDao.sum(sum, { ...params }, group);
40
+ return response;
41
+ } catch (e) {
42
+ throw e;
43
+ }
44
+ };
45
+
46
+ public readonly count = async (params: Where<OrganizationLicenseLimit>, group: string[] = []) => {
47
+ try {
48
+ const response = await organizationOrganizationLicenseLimitDao.count({ ...params }, group);
49
+ return response;
50
+ } catch (e) {
51
+ throw e;
52
+ }
53
+ };
54
+
55
+ public readonly add = async (data: Add): Promise<OrganizationLicenseLimit[]> => {
56
+ try {
57
+ await Validator.validateAsync(addOrganizationLicenseLimitSchema, data);
58
+ await this.check(data);
59
+
60
+ const { insertId } = await organizationOrganizationLicenseLimitDao.add({
61
+ organization: data.organization,
62
+ license: data.license,
63
+ name: data.name,
64
+ limit: data.limit,
65
+ period: data.period,
66
+ monthly_price_abs: data.monthly_price_abs,
67
+ annual_price_abs: data.annual_price_abs,
68
+ overconsume: data.overconsume,
69
+ overconsume_monthly_price_per_unit: data.overconsume_monthly_price_per_unit,
70
+ overconsume_annual_price_per_unit: data.overconsume_annual_price_per_unit,
71
+ metadata: data.metadata,
72
+ });
73
+
74
+ return await this.get(insertId);
75
+ } catch (e) { throw e; }
76
+ };
77
+
78
+ public readonly update = async (id: number, data: Update): Promise<OrganizationLicenseLimit[]> => {
79
+ try {
80
+ await Validator.validateAsync(updateOrganizationLicenseLimitSchema, data);
81
+
82
+ const old = (await this.get(id))[0];
83
+ if (!old) {
84
+ throw new APIError({
85
+ code: StatusCodes.NOT_FOUND,
86
+ detail: `OrganizationLicenseLimit with id ${id} not found.`,
87
+ });
88
+ }
89
+
90
+ const merged = JSON2.deepClean(JSON2.deepMerge({}, old, data)) as OrganizationLicenseLimit;
91
+
92
+ await this.check(merged, old);
93
+
94
+ const { affectedRows } = await organizationOrganizationLicenseLimitDao.update({ id: id }, {
95
+ organization: merged.organization,
96
+ license: merged.license,
97
+ name: merged.name,
98
+ limit: merged.limit,
99
+ period: merged.period,
100
+ monthly_price_abs: merged.monthly_price_abs,
101
+ annual_price_abs: merged.annual_price_abs,
102
+ overconsume: merged.overconsume,
103
+ overconsume_monthly_price_per_unit: merged.overconsume_monthly_price_per_unit,
104
+ overconsume_annual_price_per_unit: merged.overconsume_annual_price_per_unit,
105
+ metadata: merged.metadata,
106
+ });
107
+
108
+ if (affectedRows <= 0) {
109
+ throw new APIError({
110
+ code: StatusCodes.INTERNAL_SERVER_ERROR,
111
+ detail: `Could not update license with id ${id}`,
112
+ });
113
+ }
114
+
115
+ return await this.get(id);
116
+ } catch (e) { throw e; }
117
+
118
+ };
119
+
120
+ public readonly delete = async (id: number): Promise<{ deleted: boolean }> => {
121
+ try {
122
+ const license = (await this.get(id))[0];
123
+ if (!license) {
124
+ throw new APIError({
125
+ code: StatusCodes.NOT_FOUND,
126
+ detail: `OrganizationLicenseLimit with id ${id} not found.`,
127
+ });
128
+ }
129
+
130
+ const { affectedRows } = await organizationOrganizationLicenseLimitDao.delete({ id: license.id });
131
+
132
+ if (affectedRows <= 0) {
133
+ throw new APIError({
134
+ code: StatusCodes.INTERNAL_SERVER_ERROR,
135
+ detail: `Could not delete license with id ${id}`,
136
+ });
137
+ }
138
+
139
+ return { deleted: affectedRows > 0 };
140
+ } catch (e) { throw e; }
141
+ };
142
+
143
+ private readonly check = async (data: Add | OrganizationLicenseLimit, old?: OrganizationLicenseLimit): Promise<void> => {
144
+ try {
145
+ if (!old || data.license !== old.license) {
146
+ const license = (await organizationLicenseController.list({ id: data.license }))[0];
147
+ if (!license) {
148
+ throw new APIError({
149
+ code: StatusCodes.BAD_REQUEST,
150
+ detail: `No enabled license ${data.license} found.`,
151
+ });
152
+ }
153
+ }
154
+
155
+ if (!old || data.organization !== old.organization) {
156
+ const organization = (await organizationController.list({ id: data.organization, status: { is: OrganizationStatus.Blocked, inverse: true } }))[0];
157
+ if (!organization) {
158
+ throw new APIError({
159
+ code: StatusCodes.BAD_REQUEST,
160
+ detail: `No active organization ${data.organization} found.`,
161
+ });
162
+ }
163
+ }
164
+ } catch (e) { throw e; }
165
+ };
166
+
167
+ private readonly parse = async (records: DBRecord[]): Promise<OrganizationLicenseLimit[]> => {
168
+ try {
169
+ const response: OrganizationLicenseLimit[] = [];
170
+
171
+ for (const record of records) {
172
+ const p: OrganizationLicenseLimit = {
173
+ id: record.id,
174
+ organization: record.organization,
175
+ license: record.license,
176
+ name: record.name,
177
+ limit: record.limit,
178
+ period: record.period,
179
+ monthly_price_abs: parseFloat(record.monthly_price_abs as any),
180
+ annual_price_abs: parseFloat(record.annual_price_abs as any),
181
+ overconsume: record.overconsume ? true : false,
182
+ overconsume_monthly_price_per_unit: record.overconsume_monthly_price_per_unit ? parseFloat(record.overconsume_monthly_price_per_unit as any) : null,
183
+ overconsume_annual_price_per_unit: record.overconsume_annual_price_per_unit ? parseFloat(record.overconsume_annual_price_per_unit as any) : null,
184
+ metadata: record.metadata,
185
+ };
186
+
187
+ response.push(p);
188
+ }
189
+
190
+ return response;
191
+ } catch (e) { throw e; }
192
+ };
193
+ }
194
+
195
+ const organizationLicenseLimitController = new OrganizationLicenseLimitCtrl();
196
+ export default organizationLicenseLimitController;
@@ -0,0 +1,167 @@
1
+ import { Date2, Formats } from "@beseif-solutions/utility-functions/dist/utils/date-utils";
2
+ import { JSON2 } from "@beseif-solutions/utility-functions/dist/utils/json-utils";
3
+ import { Where } from "@beseif-solutions/utility-functions/dist/utils/sql-utils";
4
+ import { DeepPartial } from "@beseif-solutions/utility-functions/dist/utils/typing-utils";
5
+ import { Validator } from "@beseif-solutions/utility-functions/dist/utils/validation-utils";
6
+ import APIError, { StatusCodes } from "../../../helpers/api-error";
7
+ import organizationUsageDao from "../../daos/organization-usage-dao";
8
+ import { addOrganizationUsageSchema, updateOrganizationUsageSchema } from "../../schemas/admin/organization-usage-schemas";
9
+ import { OrganizationStatus } from "../../types/admin/organization-types";
10
+ import { DBRecord, OrganizationUsage, Sum } from "../../types/admin/organization-usage-types";
11
+ import organizationController from "./organization-controller";
12
+ import serviceController from "./service-controller";
13
+ import { Modifiers } from "../../common-types";
14
+
15
+ type Add = Omit<OrganizationUsage, `id` | `date`>;
16
+ type Update = DeepPartial<Omit<OrganizationUsage, `id` | `date`>>;
17
+
18
+ class OrganizationUsageCtrl {
19
+
20
+ public readonly get = async (id: number): Promise<OrganizationUsage[]> => {
21
+ try {
22
+ const db = await organizationUsageDao.get({ id: id });
23
+ const response = await this.parse(db);
24
+ return response;
25
+ } catch (e) { throw e; }
26
+ };
27
+
28
+ public readonly list = async (params: Where<OrganizationUsage> | Where<OrganizationUsage>[], options: Modifiers = {}): Promise<OrganizationUsage[]> => {
29
+ try {
30
+ const db = await organizationUsageDao.list(params, options);
31
+ const response = await this.parse(db);
32
+ return response;
33
+ } catch (e) {
34
+ throw e;
35
+ }
36
+ };
37
+
38
+ public readonly add = async (data: Add): Promise<OrganizationUsage[]> => {
39
+ try {
40
+ await Validator.validateAsync(addOrganizationUsageSchema, data);
41
+ await this.check(data);
42
+
43
+ const { insertId } = await organizationUsageDao.add({
44
+ service: data.service,
45
+ organization: data.organization,
46
+ name: data.name,
47
+ count: data.count,
48
+ });
49
+
50
+ return await this.get(insertId);
51
+ } catch (e) { throw e; }
52
+ };
53
+
54
+ public readonly update = async (id: number, data: Update): Promise<OrganizationUsage[]> => {
55
+ try {
56
+ await Validator.validateAsync(updateOrganizationUsageSchema, data);
57
+
58
+ const old = (await this.get(id))[0];
59
+ if (!old) {
60
+ throw new APIError({
61
+ code: StatusCodes.NOT_FOUND,
62
+ detail: `OrganizationUsage with id ${id} not found.`,
63
+ });
64
+ }
65
+
66
+ const merged = JSON2.deepClean(JSON2.deepMerge({}, old, data)) as OrganizationUsage;
67
+
68
+ await this.check(merged, old);
69
+
70
+ const { affectedRows } = await organizationUsageDao.update({ id: id }, {
71
+ service: merged.service,
72
+ organization: merged.organization,
73
+ name: merged.name,
74
+ count: merged.count,
75
+ });
76
+
77
+ if (affectedRows <= 0) {
78
+ throw new APIError({
79
+ code: StatusCodes.INTERNAL_SERVER_ERROR,
80
+ detail: `Could not update license with id ${id}`,
81
+ });
82
+ }
83
+
84
+ return await this.get(id);
85
+ } catch (e) { throw e; }
86
+
87
+ };
88
+
89
+ public readonly delete = async (id: number): Promise<{ deleted: boolean }> => {
90
+ try {
91
+ const license = (await this.get(id))[0];
92
+ if (!license) {
93
+ throw new APIError({
94
+ code: StatusCodes.NOT_FOUND,
95
+ detail: `Organization usage with id ${id} not found.`,
96
+ });
97
+ }
98
+
99
+ const { affectedRows } = await organizationUsageDao.delete({ id: license.id });
100
+
101
+ if (affectedRows <= 0) {
102
+ throw new APIError({
103
+ code: StatusCodes.INTERNAL_SERVER_ERROR,
104
+ detail: `Could not delete license with id ${id}`,
105
+ });
106
+ }
107
+
108
+ return { deleted: affectedRows > 0 };
109
+ } catch (e) { throw e; }
110
+ };
111
+
112
+ public readonly sum = async (params: Where<OrganizationUsage>): Promise<Sum[]> => {
113
+ try {
114
+ const db = await organizationUsageDao.sum(params);
115
+ const response = db.map((d): Sum => ({ total: parseFloat(d.total as any) }));
116
+ return response;
117
+ } catch (e) { throw e; }
118
+ };
119
+
120
+ private readonly check = async (data: Add | OrganizationUsage, old?: OrganizationUsage): Promise<void> => {
121
+ try {
122
+ if (!old || data.service !== old.service) {
123
+ const service = (await serviceController.list({ id: data.service, enabled: true }))[0];
124
+ if (!service) {
125
+ throw new APIError({
126
+ code: StatusCodes.BAD_REQUEST,
127
+ detail: `No enabled service ${data.service} found.`,
128
+ });
129
+ }
130
+ }
131
+
132
+ if (!old || data.organization !== old.organization) {
133
+ const organization = (await organizationController.list({ id: data.organization, status: { is: OrganizationStatus.Blocked, inverse: true } }))[0];
134
+ if (!organization) {
135
+ throw new APIError({
136
+ code: StatusCodes.BAD_REQUEST,
137
+ detail: `No active organization ${data.organization} found.`,
138
+ });
139
+ }
140
+ }
141
+ } catch (e) { throw e; }
142
+ };
143
+
144
+ private readonly parse = async (records: DBRecord[]): Promise<OrganizationUsage[]> => {
145
+ try {
146
+ const response: OrganizationUsage[] = [];
147
+
148
+ for (const record of records) {
149
+ const p: OrganizationUsage = {
150
+ id: record.id,
151
+ service: record.service,
152
+ organization: record.organization,
153
+ name: record.name,
154
+ count: parseFloat(record.count as any),
155
+ date: new Date2(record.date).format(Formats.ISO),
156
+ };
157
+
158
+ response.push(p);
159
+ }
160
+
161
+ return response;
162
+ } catch (e) { throw e; }
163
+ };
164
+ }
165
+
166
+ const organizationUsageController = new OrganizationUsageCtrl();
167
+ export default organizationUsageController;