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,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;
|