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.
- package/.claude/settings.local.json +11 -0
- package/.dockerignore +11 -0
- package/.github/workflows/_deploy.yml +191 -0
- package/.github/workflows/deploy-dev.yml +30 -0
- package/.github/workflows/deploy-prod.yml +34 -0
- package/CLAUDE.md +114 -0
- package/Dockerfile +61 -0
- package/Dockerfile.dev +24 -0
- package/README.md +1 -0
- package/package.json +61 -0
- package/src/App.ts +40 -0
- package/src/helpers/api-error.ts +21 -0
- package/src/helpers/authority.ts +216 -0
- package/src/helpers/config.ts +4 -0
- package/src/helpers/holded.ts +105 -0
- package/src/helpers/mysql.ts +15 -0
- package/src/helpers/notifications.ts +55 -0
- package/src/helpers/random.ts +18 -0
- package/src/helpers/s3.ts +43 -0
- package/src/helpers/stripe.ts +8 -0
- package/src/index.ts +47 -0
- package/src/v1/common-types.ts +12 -0
- package/src/v1/controllers/admin/accounting-seat-controller.ts +148 -0
- package/src/v1/controllers/admin/billing-cycle-controller.ts +171 -0
- package/src/v1/controllers/admin/invoice-controller.ts +222 -0
- package/src/v1/controllers/admin/license-controller.ts +190 -0
- package/src/v1/controllers/admin/license-limit-controller.ts +160 -0
- package/src/v1/controllers/admin/notification-controller.ts +115 -0
- package/src/v1/controllers/admin/organization-controller.ts +210 -0
- package/src/v1/controllers/admin/organization-license-controller.ts +224 -0
- package/src/v1/controllers/admin/organization-license-limit-controller.ts +196 -0
- package/src/v1/controllers/admin/organization-usage-controller.ts +167 -0
- package/src/v1/controllers/admin/payment-method-controller.ts +173 -0
- package/src/v1/controllers/admin/policy-controller.ts +138 -0
- package/src/v1/controllers/admin/policy-version-controller.ts +143 -0
- package/src/v1/controllers/admin/schedule-controller.ts +181 -0
- package/src/v1/controllers/admin/service-controller.ts +206 -0
- package/src/v1/controllers/admin/service-notification-controller.ts +166 -0
- package/src/v1/controllers/admin/user-controller.ts +282 -0
- package/src/v1/controllers/admin/user-organization-controller.ts +172 -0
- package/src/v1/controllers/admin/user-policy-controller.ts +164 -0
- package/src/v1/controllers/auth/@deprecated oauth-controller.ts +191 -0
- package/src/v1/controllers/auth/identity-token-controller.ts +286 -0
- package/src/v1/controllers/auth/organization-token-controller.ts +277 -0
- package/src/v1/controllers/auth/temp-code-controller.ts +60 -0
- package/src/v1/controllers/billing/billing-controller.ts +805 -0
- package/src/v1/controllers/organizations/public-organization-controller.ts +1796 -0
- package/src/v1/controllers/policies/public-policy-controller.ts +68 -0
- package/src/v1/controllers/services/public-service-controller.ts +177 -0
- package/src/v1/controllers/services/service-controller.ts +474 -0
- package/src/v1/controllers/users/public-user-controller.ts +471 -0
- package/src/v1/daos/@deprecated auth-dao.ts +173 -0
- package/src/v1/daos/accounting-seat-dao.ts +111 -0
- package/src/v1/daos/billing-cycle-dao.ts +107 -0
- package/src/v1/daos/invoice-dao.ts +131 -0
- package/src/v1/daos/license-dao.ts +152 -0
- package/src/v1/daos/license-limit-dao.ts +120 -0
- package/src/v1/daos/organization-dao.ts +109 -0
- package/src/v1/daos/organization-license-dao.ts +117 -0
- package/src/v1/daos/organization-license-limit-dao.ts +157 -0
- package/src/v1/daos/organization-usage-dao.ts +115 -0
- package/src/v1/daos/payment-method-dao.ts +110 -0
- package/src/v1/daos/policy-dao.ts +105 -0
- package/src/v1/daos/policy-version-dao.ts +112 -0
- package/src/v1/daos/redis-dao.ts +38 -0
- package/src/v1/daos/schema.sql +462 -0
- package/src/v1/daos/service-dao.ts +118 -0
- package/src/v1/daos/service-notification-dao.ts +120 -0
- package/src/v1/daos/user-dao.ts +127 -0
- package/src/v1/daos/user-organization-dao.ts +123 -0
- package/src/v1/daos/user-policy-dao.ts +109 -0
- package/src/v1/middlewares/auth/identity-token-middleware.ts +51 -0
- package/src/v1/middlewares/auth/organization-token-middleware.ts +73 -0
- package/src/v1/middlewares/auth/service-token-middleware.ts +167 -0
- package/src/v1/middlewares/authority-middleware.ts +97 -0
- package/src/v1/middlewares/organizations/organization-middleware.ts +94 -0
- package/src/v1/middlewares/static/static-middleware.ts +41 -0
- package/src/v1/middlewares/users/user-middleware.ts +41 -0
- package/src/v1/routes/admin/accounting-seat-router.ts +89 -0
- package/src/v1/routes/admin/admin-router.ts +61 -0
- package/src/v1/routes/admin/billing-cycle-router.ts +89 -0
- package/src/v1/routes/admin/invoice-router.ts +89 -0
- package/src/v1/routes/admin/license-limit-router.ts +89 -0
- package/src/v1/routes/admin/license-router.ts +89 -0
- package/src/v1/routes/admin/notification-router.ts +61 -0
- package/src/v1/routes/admin/organization-license-limit-router.ts +89 -0
- package/src/v1/routes/admin/organization-license-router.ts +89 -0
- package/src/v1/routes/admin/organization-router.ts +89 -0
- package/src/v1/routes/admin/payment-method-router.ts +89 -0
- package/src/v1/routes/admin/policy-router.ts +89 -0
- package/src/v1/routes/admin/policy-version-router.ts +89 -0
- package/src/v1/routes/admin/schedule-router.ts +75 -0
- package/src/v1/routes/admin/service-notification-router.ts +98 -0
- package/src/v1/routes/admin/service-router.ts +89 -0
- package/src/v1/routes/admin/user-organization-router.ts +89 -0
- package/src/v1/routes/admin/user-policy-router.ts +89 -0
- package/src/v1/routes/admin/user-router.ts +89 -0
- package/src/v1/routes/auth/@deprecated auth-router.ts +199 -0
- package/src/v1/routes/auth/identity-token-router.ts +147 -0
- package/src/v1/routes/auth/organization-token-router.ts +70 -0
- package/src/v1/routes/billing/billing-router.ts +227 -0
- package/src/v1/routes/organizations/invoices-router.ts +48 -0
- package/src/v1/routes/organizations/payments-router.ts +104 -0
- package/src/v1/routes/organizations/public-organization-router.ts +319 -0
- package/src/v1/routes/organizations/users-router.ts +139 -0
- package/src/v1/routes/policies/public-policy-router.ts +50 -0
- package/src/v1/routes/services/public-service-router.ts +89 -0
- package/src/v1/routes/services/service-router.ts +197 -0
- package/src/v1/routes/users/public-user-router.ts +230 -0
- package/src/v1/routes/v1-router.ts +50 -0
- package/src/v1/schemas/admin/accounting-seat-schemas.ts +22 -0
- package/src/v1/schemas/admin/billing-cycle-schemas.ts +20 -0
- package/src/v1/schemas/admin/invoice-schemas.ts +41 -0
- package/src/v1/schemas/admin/license-limit-schemas.ts +25 -0
- package/src/v1/schemas/admin/license-schemas.ts +30 -0
- package/src/v1/schemas/admin/organization-license-limit-schemas.ts +29 -0
- package/src/v1/schemas/admin/organization-license-schemas.ts +43 -0
- package/src/v1/schemas/admin/organization-schemas.ts +67 -0
- package/src/v1/schemas/admin/organization-usage-schemas.ts +15 -0
- package/src/v1/schemas/admin/payment-method-schemas.ts +40 -0
- package/src/v1/schemas/admin/policy-schemas.ts +31 -0
- package/src/v1/schemas/admin/service-notification-schemas.ts +23 -0
- package/src/v1/schemas/admin/service-schemas.ts +56 -0
- package/src/v1/schemas/admin/user-organization-schemas.ts +24 -0
- package/src/v1/schemas/admin/user-policy-schemas.ts +17 -0
- package/src/v1/schemas/admin/user-schemas.ts +52 -0
- package/src/v1/schemas/auth/auth-schemas.ts +55 -0
- package/src/v1/schemas/billing/billing-schemas.ts +32 -0
- package/src/v1/schemas/organizations/public-organization-schemas.ts +77 -0
- package/src/v1/schemas/payments/payment-method-schemas.ts +0 -0
- package/src/v1/schemas/services/public-service-schemas.ts +5 -0
- package/src/v1/schemas/services/service-schemas.ts +27 -0
- package/src/v1/schemas/users/public-user-schemas.ts +73 -0
- package/src/v1/types/admin/accounting-seat-types.ts +16 -0
- package/src/v1/types/admin/billing-cycle-types.ts +14 -0
- package/src/v1/types/admin/invoice-types.ts +39 -0
- package/src/v1/types/admin/license-limit-types.ts +16 -0
- package/src/v1/types/admin/license-types.ts +29 -0
- package/src/v1/types/admin/organization-license-limit-types.ts +13 -0
- package/src/v1/types/admin/organization-license-types.ts +21 -0
- package/src/v1/types/admin/organization-types.ts +60 -0
- package/src/v1/types/admin/organization-usage-types.ts +17 -0
- package/src/v1/types/admin/payment-method-types.ts +30 -0
- package/src/v1/types/admin/policy-types.ts +9 -0
- package/src/v1/types/admin/policy-version-types.ts +12 -0
- package/src/v1/types/admin/service-notification-types.ts +20 -0
- package/src/v1/types/admin/service-types.ts +36 -0
- package/src/v1/types/admin/user-organization-types.ts +31 -0
- package/src/v1/types/admin/user-types.ts +44 -0
- package/src/v1/types/auth/@deprecated auth-types.ts +26 -0
- package/src/v1/types/auth/common-types.ts +7 -0
- package/src/v1/types/auth/confirmation-types.ts +5 -0
- package/src/v1/types/auth/identity-token-types.ts +8 -0
- package/src/v1/types/auth/organization-token-types.ts +23 -0
- package/src/v1/types/auth/otp-types.ts +12 -0
- package/src/v1/types/billing/billing-types.ts +37 -0
- package/src/v1/types/billing/ue-types.ts +29 -0
- package/src/v1/types/organizations/public-organization-types.ts +76 -0
- package/src/v1/types/policies/public-policy-types.ts +7 -0
- package/src/v1/types/services/public-service-types.ts +20 -0
- package/src/v1/types/services/service-types.ts +43 -0
- package/src/v1/types/users/public-user-types.ts +15 -0
- package/src/v1/types/users/user-policy-types.ts +11 -0
- package/static/error.html +55 -0
- package/static/grant.html +117 -0
- package/static/login.html +54 -0
- package/static/oauth-client-logo.webp +0 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,173 @@
|
|
|
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 paymentMethodDao from "../../daos/payment-method-dao";
|
|
9
|
+
import { addPaymentMethodSchema, updatePaymentMethodSchema } from "../../schemas/admin/payment-method-schemas";
|
|
10
|
+
import { DBRecord, PaymentMethod } from "../../types/admin/payment-method-types";
|
|
11
|
+
import organizationController from "./organization-controller";
|
|
12
|
+
import { OrganizationStatus } from "../../types/admin/organization-types";
|
|
13
|
+
import { Modifiers } from "../../common-types";
|
|
14
|
+
|
|
15
|
+
type Add = Omit<PaymentMethod, `id` | `uuid` | `created_date` | `modified_date`>;
|
|
16
|
+
type Update = DeepPartial<Omit<PaymentMethod, `id` | `uuid` | `created_date` | `modified_date`>>;
|
|
17
|
+
|
|
18
|
+
class PaymentMethodCtrl {
|
|
19
|
+
|
|
20
|
+
public readonly get = async (id: number): Promise<PaymentMethod[]> => {
|
|
21
|
+
try {
|
|
22
|
+
const db = await paymentMethodDao.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<PaymentMethod>, options: Modifiers = {}): Promise<PaymentMethod[]> => {
|
|
29
|
+
try {
|
|
30
|
+
const db = await paymentMethodDao.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<PaymentMethod[]> => {
|
|
39
|
+
try {
|
|
40
|
+
await Validator.validateAsync(addPaymentMethodSchema, data);
|
|
41
|
+
await this.check(data);
|
|
42
|
+
|
|
43
|
+
const uuid = await this.getFreeUUID();
|
|
44
|
+
|
|
45
|
+
const { insertId } = await paymentMethodDao.add({
|
|
46
|
+
uuid: uuid,
|
|
47
|
+
organization: data.organization,
|
|
48
|
+
type: data.type,
|
|
49
|
+
properties: data.properties,
|
|
50
|
+
enabled: data.enabled,
|
|
51
|
+
metadata: data.metadata,
|
|
52
|
+
internal: data.internal,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
return await this.get(insertId);
|
|
56
|
+
} catch (e) { throw e; }
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
public readonly update = async (id: number, data: Update): Promise<PaymentMethod[]> => {
|
|
60
|
+
try {
|
|
61
|
+
await Validator.validateAsync(updatePaymentMethodSchema, data);
|
|
62
|
+
|
|
63
|
+
const old = (await this.get(id))[0];
|
|
64
|
+
if (!old) {
|
|
65
|
+
throw new APIError({
|
|
66
|
+
code: StatusCodes.NOT_FOUND,
|
|
67
|
+
detail: `PaymentMethod with id ${id} not found.`,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const merged = JSON2.deepClean(JSON2.deepMerge({}, old, data)) as PaymentMethod;
|
|
72
|
+
|
|
73
|
+
await this.check(merged, old);
|
|
74
|
+
|
|
75
|
+
const { affectedRows } = await paymentMethodDao.update({ id: id }, {
|
|
76
|
+
uuid: merged.uuid,
|
|
77
|
+
organization: merged.organization,
|
|
78
|
+
type: merged.type,
|
|
79
|
+
properties: merged.properties,
|
|
80
|
+
enabled: merged.enabled,
|
|
81
|
+
metadata: merged.metadata,
|
|
82
|
+
internal: merged.internal,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
if (affectedRows <= 0) {
|
|
86
|
+
throw new APIError({
|
|
87
|
+
code: StatusCodes.INTERNAL_SERVER_ERROR,
|
|
88
|
+
detail: `Could not update paymentMethod with id ${id}`,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return await this.get(id);
|
|
93
|
+
} catch (e) { throw e; }
|
|
94
|
+
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
public readonly delete = async (id: number): Promise<{ deleted: boolean }> => {
|
|
98
|
+
try {
|
|
99
|
+
const paymentMethod = (await this.get(id))[0];
|
|
100
|
+
if (!paymentMethod) {
|
|
101
|
+
throw new APIError({
|
|
102
|
+
code: StatusCodes.NOT_FOUND,
|
|
103
|
+
detail: `PaymentMethod with id ${id} not found.`,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const { affectedRows } = await paymentMethodDao.delete({ id: paymentMethod.id });
|
|
108
|
+
|
|
109
|
+
if (affectedRows <= 0) {
|
|
110
|
+
throw new APIError({
|
|
111
|
+
code: StatusCodes.INTERNAL_SERVER_ERROR,
|
|
112
|
+
detail: `Could not delete paymentMethod with id ${id}`,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return { deleted: affectedRows > 0 };
|
|
117
|
+
} catch (e) { throw e; }
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
private readonly getFreeUUID = async (): Promise<string> => {
|
|
121
|
+
try {
|
|
122
|
+
let uuid: string;
|
|
123
|
+
do {
|
|
124
|
+
uuid = newUUIDv4({ case: `lower` });
|
|
125
|
+
const exists = (await paymentMethodDao.list({ uuid: uuid }))[0];
|
|
126
|
+
if (!exists) { break; }
|
|
127
|
+
} while (true);
|
|
128
|
+
return uuid;
|
|
129
|
+
} catch (e) { throw e; }
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
private readonly check = async (data: Add | PaymentMethod, old?: PaymentMethod): Promise<void> => {
|
|
133
|
+
try {
|
|
134
|
+
if (!old || data.organization !== old.organization) {
|
|
135
|
+
const organization = (await organizationController.list({ id: data.organization, status: { is: OrganizationStatus.Blocked, inverse: true } }))[0];
|
|
136
|
+
if (!organization) {
|
|
137
|
+
throw new APIError({
|
|
138
|
+
code: StatusCodes.BAD_REQUEST,
|
|
139
|
+
detail: `No active organization ${data.organization} found.`,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
} catch (e) { throw e; }
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
private readonly parse = async (records: DBRecord[]): Promise<PaymentMethod[]> => {
|
|
147
|
+
try {
|
|
148
|
+
const response: PaymentMethod[] = [];
|
|
149
|
+
|
|
150
|
+
for (const record of records) {
|
|
151
|
+
const p: PaymentMethod = {
|
|
152
|
+
id: record.id,
|
|
153
|
+
uuid: record.uuid,
|
|
154
|
+
organization: record.organization,
|
|
155
|
+
type: record.type,
|
|
156
|
+
properties: record.properties,
|
|
157
|
+
created_date: new Date2(record.created_date).format(Formats.ISO),
|
|
158
|
+
modified_date: new Date2(record.modified_date).format(Formats.ISO),
|
|
159
|
+
enabled: record.enabled ? true : false,
|
|
160
|
+
metadata: record.metadata,
|
|
161
|
+
internal: record.internal,
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
response.push(p);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return response;
|
|
168
|
+
} catch (e) { throw e; }
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const paymentMethodController = new PaymentMethodCtrl();
|
|
173
|
+
export default paymentMethodController;
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { Where } from "@beseif-solutions/utility-functions/dist/utils/sql-utils";
|
|
2
|
+
import { newUUIDv4 } from "@beseif-solutions/utility-functions/dist/utils/string-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 policyDao from '../../daos/policy-dao';
|
|
7
|
+
import { addPolicySchema, updatePolicySchema } from '../../schemas/admin/policy-schemas';
|
|
8
|
+
import { DBRecord, Policy } from '../../types/admin/policy-types';
|
|
9
|
+
import { Modifiers } from '../../common-types';
|
|
10
|
+
import { JSON2 } from "@beseif-solutions/utility-functions/dist/utils/json-utils";
|
|
11
|
+
|
|
12
|
+
type Add = Omit<Policy, 'id' | 'uuid'>;
|
|
13
|
+
type Update = DeepPartial<Omit<Policy, 'id' | 'uuid'>>;
|
|
14
|
+
|
|
15
|
+
class PolicyController {
|
|
16
|
+
public readonly get = async (id: number): Promise<Policy[]> => {
|
|
17
|
+
try {
|
|
18
|
+
const db = await policyDao.get({ id: id });
|
|
19
|
+
const response = await this.parse(db);
|
|
20
|
+
return response;
|
|
21
|
+
} catch (e) { throw e; }
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
public readonly list = async (params: Where<Policy>, options: Modifiers = {}): Promise<Policy[]> => {
|
|
25
|
+
try {
|
|
26
|
+
const db = await policyDao.list(params, options);
|
|
27
|
+
const response = await this.parse(db);
|
|
28
|
+
return response;
|
|
29
|
+
} catch (e) { throw e; }
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
public readonly add = async (data: Add): Promise<Policy[]> => {
|
|
33
|
+
try {
|
|
34
|
+
await Validator.validateAsync(addPolicySchema, data);
|
|
35
|
+
await this.check(data);
|
|
36
|
+
|
|
37
|
+
const uuid = await this.getFreeUUID();
|
|
38
|
+
|
|
39
|
+
const { insertId } = await policyDao.add({
|
|
40
|
+
uuid: uuid,
|
|
41
|
+
name: data.name,
|
|
42
|
+
metadata: data.metadata || {},
|
|
43
|
+
internal: data.internal || {},
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
return await this.get(insertId);
|
|
47
|
+
} catch (e) { throw e; }
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
public readonly update = async (id: number, data: Update): Promise<Policy[]> => {
|
|
51
|
+
try {
|
|
52
|
+
await Validator.validateAsync(updatePolicySchema, data);
|
|
53
|
+
|
|
54
|
+
const old = (await this.get(id))[0];
|
|
55
|
+
if (!old) {
|
|
56
|
+
throw new APIError({
|
|
57
|
+
code: StatusCodes.NOT_FOUND,
|
|
58
|
+
detail: `Policy with id ${id} not found.`,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const merged = JSON2.deepClean(JSON2.deepMerge({}, old, data)) as Policy;
|
|
63
|
+
await this.check(merged, old);
|
|
64
|
+
|
|
65
|
+
const { affectedRows } = await policyDao.update({ id: id }, {
|
|
66
|
+
uuid: merged.uuid,
|
|
67
|
+
name: merged.name,
|
|
68
|
+
metadata: merged.metadata,
|
|
69
|
+
internal: merged.internal,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
if (affectedRows <= 0) {
|
|
73
|
+
throw new APIError({
|
|
74
|
+
code: StatusCodes.INTERNAL_SERVER_ERROR,
|
|
75
|
+
detail: `Could not update policy with id ${id}`,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return await this.get(id);
|
|
80
|
+
} catch (e) { throw e; }
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
public readonly delete = async (id: number): Promise<{ deleted: boolean }> => {
|
|
84
|
+
try {
|
|
85
|
+
const policy = (await this.get(id))[0];
|
|
86
|
+
if (!policy) {
|
|
87
|
+
throw new APIError({
|
|
88
|
+
code: StatusCodes.NOT_FOUND,
|
|
89
|
+
detail: `Policy with id ${id} not found.`,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const { affectedRows } = await policyDao.delete({ id: id });
|
|
94
|
+
return { deleted: affectedRows > 0 };
|
|
95
|
+
} catch (e) { throw e; }
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
private readonly getFreeUUID = async (): Promise<string> => {
|
|
99
|
+
try {
|
|
100
|
+
const uuid = newUUIDv4();
|
|
101
|
+
const db = await policyDao.list({ uuid: uuid });
|
|
102
|
+
if (db.length > 0) {
|
|
103
|
+
return await this.getFreeUUID();
|
|
104
|
+
}
|
|
105
|
+
return uuid;
|
|
106
|
+
} catch (e) { throw e; }
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
private readonly check = async (data: Add | Policy, old?: Policy): Promise<void> => {
|
|
110
|
+
try {
|
|
111
|
+
if (!old || data.name !== old.name) {
|
|
112
|
+
const exists = (await this.list({ name: data.name }))[0];
|
|
113
|
+
if (exists && (!old || exists.id !== old.id)) {
|
|
114
|
+
throw new APIError({
|
|
115
|
+
code: StatusCodes.CONFLICT,
|
|
116
|
+
detail: `Policy with name '${data.name}' already exists.`,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
} catch (e) { throw e; }
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
private readonly parse = async (data: DBRecord[]): Promise<Policy[]> => {
|
|
124
|
+
try {
|
|
125
|
+
const response: Policy[] = data.map((record) => ({
|
|
126
|
+
id: record.id,
|
|
127
|
+
uuid: record.uuid,
|
|
128
|
+
name: record.name,
|
|
129
|
+
metadata: record.metadata,
|
|
130
|
+
internal: record.internal,
|
|
131
|
+
}));
|
|
132
|
+
return response;
|
|
133
|
+
} catch (e) { throw e; }
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const policyController = new PolicyController();
|
|
138
|
+
export default policyController;
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { Date2, Formats } from "@beseif-solutions/utility-functions/dist/utils/date-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 policyVersionDao from '../../daos/policy-version-dao';
|
|
7
|
+
import { addPolicyVersionSchema, updatePolicyVersionSchema } from '../../schemas/admin/policy-schemas';
|
|
8
|
+
import { DBRecord, PolicyVersion } from '../../types/admin/policy-version-types';
|
|
9
|
+
import { Modifiers } from '../../common-types';
|
|
10
|
+
import policyController from './policy-controller';
|
|
11
|
+
import { JSON2 } from "@beseif-solutions/utility-functions/dist/utils/json-utils";
|
|
12
|
+
|
|
13
|
+
type Add = Omit<PolicyVersion, 'id' | 'uuid' | 'created_date'>;
|
|
14
|
+
type Update = DeepPartial<Omit<PolicyVersion, 'id' | 'uuid' | 'created_date'>>;
|
|
15
|
+
|
|
16
|
+
class PolicyVersionController {
|
|
17
|
+
public readonly get = async (id: number): Promise<PolicyVersion[]> => {
|
|
18
|
+
try {
|
|
19
|
+
const db = await policyVersionDao.get({ id: id });
|
|
20
|
+
const response = await this.parse(db);
|
|
21
|
+
return response;
|
|
22
|
+
} catch (e) { throw e; }
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
public readonly list = async (params: Where<PolicyVersion>, options: Modifiers = {}): Promise<PolicyVersion[]> => {
|
|
26
|
+
try {
|
|
27
|
+
const db = await policyVersionDao.list(params, options);
|
|
28
|
+
const response = await this.parse(db);
|
|
29
|
+
return response;
|
|
30
|
+
} catch (e) { throw e; }
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
public readonly add = async (data: Add): Promise<PolicyVersion[]> => {
|
|
34
|
+
try {
|
|
35
|
+
await Validator.validateAsync(addPolicyVersionSchema, data);
|
|
36
|
+
await this.check(data);
|
|
37
|
+
|
|
38
|
+
const { insertId } = await policyVersionDao.add({
|
|
39
|
+
policy: data.policy,
|
|
40
|
+
version: data.version,
|
|
41
|
+
url: data.url,
|
|
42
|
+
metadata: data.metadata || {},
|
|
43
|
+
internal: data.internal || {},
|
|
44
|
+
effective_date: data.effective_date,
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
return await this.get(insertId);
|
|
48
|
+
} catch (e) { throw e; }
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
public readonly update = async (id: number, data: Update): Promise<PolicyVersion[]> => {
|
|
52
|
+
try {
|
|
53
|
+
await Validator.validateAsync(updatePolicyVersionSchema, data);
|
|
54
|
+
|
|
55
|
+
const old = (await this.get(id))[0];
|
|
56
|
+
if (!old) {
|
|
57
|
+
throw new APIError({
|
|
58
|
+
code: StatusCodes.NOT_FOUND,
|
|
59
|
+
detail: `Policy version with id ${id} not found.`,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const merged = JSON2.deepClean(JSON2.deepMerge({}, old, data)) as PolicyVersion;
|
|
64
|
+
await this.check(merged, old);
|
|
65
|
+
|
|
66
|
+
const { affectedRows } = await policyVersionDao.update({ id: id }, {
|
|
67
|
+
policy: merged.policy,
|
|
68
|
+
version: merged.version,
|
|
69
|
+
url: merged.url,
|
|
70
|
+
metadata: merged.metadata,
|
|
71
|
+
internal: merged.internal,
|
|
72
|
+
effective_date: merged.effective_date,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
if (affectedRows <= 0) {
|
|
76
|
+
throw new APIError({
|
|
77
|
+
code: StatusCodes.INTERNAL_SERVER_ERROR,
|
|
78
|
+
detail: `Could not update policy version with id ${id}`,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return await this.get(id);
|
|
83
|
+
} catch (e) { throw e; }
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
public readonly delete = async (id: number): Promise<{ deleted: boolean }> => {
|
|
87
|
+
try {
|
|
88
|
+
const version = (await this.get(id))[0];
|
|
89
|
+
if (!version) {
|
|
90
|
+
throw new APIError({
|
|
91
|
+
code: StatusCodes.NOT_FOUND,
|
|
92
|
+
detail: `Policy version with id ${id} not found.`,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const { affectedRows } = await policyVersionDao.delete({ id: id });
|
|
97
|
+
return { deleted: affectedRows > 0 };
|
|
98
|
+
} catch (e) { throw e; }
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
private readonly check = async (data: Add | PolicyVersion, old?: PolicyVersion): Promise<void> => {
|
|
102
|
+
try {
|
|
103
|
+
// verify policy exists
|
|
104
|
+
const policy = (await policyController.get(data.policy))[0];
|
|
105
|
+
if (!policy) {
|
|
106
|
+
throw new APIError({
|
|
107
|
+
code: StatusCodes.BAD_REQUEST,
|
|
108
|
+
detail: `Policy with id ${data.policy} not found.`,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// check for duplicate version for the same policy
|
|
113
|
+
if (!old || data.policy !== old.policy || data.version !== old.version) {
|
|
114
|
+
const exists = (await this.list({ policy: data.policy, version: data.version }))[0];
|
|
115
|
+
if (exists && (!old || exists.id !== old.id)) {
|
|
116
|
+
throw new APIError({
|
|
117
|
+
code: StatusCodes.CONFLICT,
|
|
118
|
+
detail: `Policy version '${data.version}' already exists for policy ${data.policy}.`,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
} catch (e) { throw e; }
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
private readonly parse = async (data: DBRecord[]): Promise<PolicyVersion[]> => {
|
|
126
|
+
try {
|
|
127
|
+
const response: PolicyVersion[] = data.map((record) => ({
|
|
128
|
+
id: record.id,
|
|
129
|
+
policy: record.policy,
|
|
130
|
+
version: record.version,
|
|
131
|
+
url: record.url,
|
|
132
|
+
created_date: new Date2(record.created_date).format(Formats.ISO),
|
|
133
|
+
effective_date: record.effective_date ? new Date2(record.effective_date).format(Formats.ISO) : null,
|
|
134
|
+
metadata: record.metadata,
|
|
135
|
+
internal: record.internal,
|
|
136
|
+
}));
|
|
137
|
+
return response;
|
|
138
|
+
} catch (e) { throw e; }
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const policyVersionController = new PolicyVersionController();
|
|
143
|
+
export default policyVersionController;
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { Scheduler } from "@beseif-solutions/utility-functions/dist/utils/scheduling-utils";
|
|
2
|
+
import nconf from "../../../helpers/config";
|
|
3
|
+
import { OrganizationStatus } from "../../types/admin/organization-types";
|
|
4
|
+
import { ServiceEnvironment } from "../../types/services/service-types";
|
|
5
|
+
import serviceController from "../services/service-controller";
|
|
6
|
+
import organizationController from "./organization-controller";
|
|
7
|
+
import organizationLicenseController from "./organization-license-controller";
|
|
8
|
+
import adminServiceController from "./service-controller";
|
|
9
|
+
import { Requester } from "@beseif-solutions/utility-functions/dist/utils/http-utils";
|
|
10
|
+
import _ from "lodash";
|
|
11
|
+
import billingController from "../billing/billing-controller";
|
|
12
|
+
import { LicenseType } from "../../types/admin/license-types";
|
|
13
|
+
import authority from "../../../helpers/authority";
|
|
14
|
+
|
|
15
|
+
class ScheduleController {
|
|
16
|
+
|
|
17
|
+
constructor() {
|
|
18
|
+
Scheduler.schedule({
|
|
19
|
+
expression: nconf.get(`SERVICES:SCHEDULE:LIMITS:EXPRESSION`),
|
|
20
|
+
name: `Organization limits check`,
|
|
21
|
+
description: `Check limits for all organizations`,
|
|
22
|
+
task: this.limits,
|
|
23
|
+
})
|
|
24
|
+
.then((task) => { console.log(`[*] Scheduled: ${task.name}`.green); })
|
|
25
|
+
.catch((e) => { console.log(`[!] Could not schedule`.red, e); });
|
|
26
|
+
|
|
27
|
+
Scheduler.schedule({
|
|
28
|
+
expression: nconf.get(`SERVICES:SCHEDULE:LICENSES:EXPRESSION`),
|
|
29
|
+
name: `Organization license change (fallback)`,
|
|
30
|
+
task: this.licenseChangeFallback,
|
|
31
|
+
})
|
|
32
|
+
.then((task) => { console.log(`[*] Scheduled: ${task.name}`.green); })
|
|
33
|
+
.catch((e) => { console.log(`[!] Could not schedule`.red, e); });
|
|
34
|
+
|
|
35
|
+
Scheduler.schedule({
|
|
36
|
+
expression: nconf.get(`SERVICES:SCHEDULE:BILLING:CYCLES:EXPRESSION`),
|
|
37
|
+
name: `Organization billing cycle (fallback)`,
|
|
38
|
+
task: this.billingCycles,
|
|
39
|
+
})
|
|
40
|
+
.then((task) => { console.log(`[*] Scheduled: ${task.name}`.green); })
|
|
41
|
+
.catch((e) => { console.log(`[!] Could not schedule`.red, e); });
|
|
42
|
+
|
|
43
|
+
Scheduler.schedule({
|
|
44
|
+
expression: nconf.get(`SERVICES:SCHEDULE:BILLING:INVOICES:EXPRESSION`),
|
|
45
|
+
name: `Organization invoices (fallback)`,
|
|
46
|
+
task: this.invoices,
|
|
47
|
+
})
|
|
48
|
+
.then((task) => { console.log(`[*] Scheduled: ${task.name}`.green); })
|
|
49
|
+
.catch((e) => { console.log(`[!] Could not schedule`.red, e); });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
public readonly limits = async (): Promise<void> => {
|
|
53
|
+
try {
|
|
54
|
+
console.log(`[>] Checking limits for all organizations`.yellow);
|
|
55
|
+
|
|
56
|
+
const [organizations, services] = await Promise.all([
|
|
57
|
+
organizationController.list({ status: OrganizationStatus.Active }),
|
|
58
|
+
adminServiceController.list({ enabled: true }),
|
|
59
|
+
]);
|
|
60
|
+
|
|
61
|
+
const orgService = services.find((s) => s.uuid === authority.configuration.uuid);
|
|
62
|
+
if (!orgService) { throw new Error(`Root service not found.`); }
|
|
63
|
+
|
|
64
|
+
for (const organization of organizations) {
|
|
65
|
+
try {
|
|
66
|
+
console.log(`Checking limits for organization ${organization.id}`.blue);
|
|
67
|
+
|
|
68
|
+
const licenses = await organizationLicenseController.list({
|
|
69
|
+
organization: organization.id,
|
|
70
|
+
service: { in: services.map((s) => s.id) },
|
|
71
|
+
enabled: true,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const noLifetimeLicenses = licenses.filter((l) => l.type === LicenseType.Base && l.service !== orgService.id);
|
|
75
|
+
|
|
76
|
+
if (noLifetimeLicenses.length === 0) {
|
|
77
|
+
console.log(` > No active licenses for organization ${organization.id}, skipping limits check`.blue);
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const byService = _.groupBy(noLifetimeLicenses, (l) => l.service);
|
|
82
|
+
|
|
83
|
+
for (const service of services) {
|
|
84
|
+
try {
|
|
85
|
+
const serviceLicenses = byService[service.id] || [];
|
|
86
|
+
if (serviceLicenses.length === 0) {
|
|
87
|
+
console.log(` > No active licenses for organization ${organization.id} on service ${service.id}, skipping limits check`.blue);
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const env: ServiceEnvironment = {
|
|
92
|
+
organization: organization,
|
|
93
|
+
service: service,
|
|
94
|
+
licenses: serviceLicenses,
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
console.log(` > Checking limits for organization ${organization.id} on service ${service.id}`.blue);
|
|
98
|
+
|
|
99
|
+
await serviceController.checkQuota(env);
|
|
100
|
+
} catch (e) { console.log(e); }
|
|
101
|
+
}
|
|
102
|
+
} catch (e) { console.log(e); }
|
|
103
|
+
}
|
|
104
|
+
} catch (e) { throw e; }
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
public readonly licenseChangeFallback = async (): Promise<void> => {
|
|
108
|
+
try {
|
|
109
|
+
const licenses = await organizationLicenseController.list({
|
|
110
|
+
enabled: true,
|
|
111
|
+
internal: { notified: false },
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
const [organizations, services] = await Promise.all([
|
|
115
|
+
organizationController.list({ id: { in: _.uniq(licenses.map((l) => l.organization)) } }),
|
|
116
|
+
adminServiceController.list({ id: { in: _.uniq(licenses.map((l) => l.service)) }, enabled: true }),
|
|
117
|
+
]);
|
|
118
|
+
|
|
119
|
+
for (const l of licenses) {
|
|
120
|
+
try {
|
|
121
|
+
const organization = organizations.find((o) => o.id === l.organization);
|
|
122
|
+
if (!organization) { throw new Error(`Organization with id ${l.organization} not found.`); }
|
|
123
|
+
|
|
124
|
+
const service = services.find((s) => s.id === l.service);
|
|
125
|
+
if (!service) { throw new Error(`Service with id ${l.service} not found.`); }
|
|
126
|
+
|
|
127
|
+
if (service.internal.host && service.internal.organization?.modified) {
|
|
128
|
+
console.log(`[>] Notifying organization ${l.organization} license change`.yellow);
|
|
129
|
+
|
|
130
|
+
await Requester.patch(`${service.internal.organization?.modified}/${organization.uuid}`,
|
|
131
|
+
null,
|
|
132
|
+
{
|
|
133
|
+
baseURL: service.internal.host,
|
|
134
|
+
headers: {
|
|
135
|
+
"x-service-uuid": service.uuid,
|
|
136
|
+
"x-service-token": service.token,
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
await organizationLicenseController.update(l.id, { internal: { notified: null } });
|
|
142
|
+
} catch (e) { console.error(`Failed to notify organization license ${l.id}`, e); }
|
|
143
|
+
}
|
|
144
|
+
} catch (e) { throw e; }
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
public readonly billingCycles = async (): Promise<void> => {
|
|
148
|
+
try {
|
|
149
|
+
const organizations = await organizationController.list({
|
|
150
|
+
status: { is: OrganizationStatus.Blocked, inverse: true },
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
for (const organization of organizations) {
|
|
154
|
+
try {
|
|
155
|
+
await billingController.cycleContext(organization);
|
|
156
|
+
} catch (e) { console.log(`Could not generate organization ${organization.id} cycle`, e); }
|
|
157
|
+
|
|
158
|
+
try {
|
|
159
|
+
await billingController.trialWarningCheck(organization);
|
|
160
|
+
} catch (e) { console.log(`Could not check trial warning for organization ${organization.id}`, e); }
|
|
161
|
+
}
|
|
162
|
+
} catch (e) { throw e; }
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
public readonly invoices = async (): Promise<void> => {
|
|
166
|
+
try {
|
|
167
|
+
const organizations = await organizationController.list({
|
|
168
|
+
status: { is: OrganizationStatus.Blocked, inverse: true },
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
for (const organization of organizations) {
|
|
172
|
+
try {
|
|
173
|
+
await billingController.generateLicensesInvoice(organization);
|
|
174
|
+
} catch (e) { console.log(`Could not generate organization ${organization.id} invoice`, e); }
|
|
175
|
+
}
|
|
176
|
+
} catch (e) { throw e; }
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const scheduleController = new ScheduleController();
|
|
181
|
+
export default scheduleController;
|