@byline/admin 2.4.0 → 2.4.2
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/dist/abilities.js +5 -24
- package/dist/index.js +8 -30
- package/dist/lib/assert-admin-actor.js +13 -74
- package/dist/lib/create-command.js +6 -16
- package/dist/modules/admin-account/commands.js +35 -24
- package/dist/modules/admin-account/components/change-password.d.ts +8 -0
- package/dist/modules/admin-account/components/change-password.js +192 -0
- package/dist/modules/admin-account/components/change-password.module.js +8 -0
- package/dist/modules/admin-account/components/change-password_module.css +27 -0
- package/dist/modules/admin-account/components/container.d.ts +29 -0
- package/dist/modules/admin-account/components/container.js +298 -0
- package/dist/modules/admin-account/components/container.module.js +28 -0
- package/dist/modules/admin-account/components/container_module.css +106 -0
- package/dist/modules/admin-account/components/update.d.ts +8 -0
- package/dist/modules/admin-account/components/update.js +207 -0
- package/dist/modules/admin-account/components/update.module.js +8 -0
- package/dist/modules/admin-account/components/update_module.css +27 -0
- package/dist/modules/admin-account/errors.js +14 -45
- package/dist/modules/admin-account/index.js +4 -34
- package/dist/modules/admin-account/schemas.js +25 -59
- package/dist/modules/admin-account/service.js +56 -61
- package/dist/modules/admin-permissions/abilities.js +6 -24
- package/dist/modules/admin-permissions/commands.js +42 -28
- package/dist/modules/admin-permissions/components/inspector.d.ts +4 -0
- package/dist/modules/admin-permissions/components/inspector.js +284 -0
- package/dist/modules/admin-permissions/components/inspector.module.js +56 -0
- package/dist/modules/admin-permissions/components/inspector_module.css +238 -0
- package/dist/modules/admin-permissions/dto.js +3 -16
- package/dist/modules/admin-permissions/errors.js +14 -27
- package/dist/modules/admin-permissions/index.js +6 -26
- package/dist/modules/admin-permissions/repository.js +1 -8
- package/dist/modules/admin-permissions/schemas.js +33 -70
- package/dist/modules/admin-permissions/service.js +88 -92
- package/dist/modules/admin-roles/abilities.js +8 -30
- package/dist/modules/admin-roles/commands.js +89 -55
- package/dist/modules/admin-roles/components/create.d.ts +7 -0
- package/dist/modules/admin-roles/components/create.js +177 -0
- package/dist/modules/admin-roles/components/create.module.js +8 -0
- package/dist/modules/admin-roles/components/create_module.css +27 -0
- package/dist/modules/admin-roles/components/permissions.d.ts +10 -0
- package/dist/modules/admin-roles/components/permissions.js +303 -0
- package/dist/modules/admin-roles/components/permissions.module.js +44 -0
- package/dist/modules/admin-roles/components/permissions_module.css +192 -0
- package/dist/modules/admin-roles/components/update.d.ts +8 -0
- package/dist/modules/admin-roles/components/update.js +166 -0
- package/dist/modules/admin-roles/components/update.module.js +8 -0
- package/dist/modules/admin-roles/components/update_module.css +27 -0
- package/dist/modules/admin-roles/dto.js +3 -16
- package/dist/modules/admin-roles/errors.js +16 -40
- package/dist/modules/admin-roles/index.js +6 -26
- package/dist/modules/admin-roles/repository.js +1 -8
- package/dist/modules/admin-roles/schemas.js +41 -71
- package/dist/modules/admin-roles/service.js +79 -82
- package/dist/modules/admin-users/abilities.js +9 -38
- package/dist/modules/admin-users/commands.js +92 -50
- package/dist/modules/admin-users/components/create.d.ts +8 -0
- package/dist/modules/admin-users/components/create.js +268 -0
- package/dist/modules/admin-users/components/create.module.js +10 -0
- package/dist/modules/admin-users/components/create_module.css +45 -0
- package/dist/modules/admin-users/components/roles.d.ts +11 -0
- package/dist/modules/admin-users/components/roles.js +148 -0
- package/dist/modules/admin-users/components/roles.module.js +18 -0
- package/dist/modules/admin-users/components/roles_module.css +75 -0
- package/dist/modules/admin-users/components/set-password.d.ts +8 -0
- package/dist/modules/admin-users/components/set-password.js +170 -0
- package/dist/modules/admin-users/components/set-password.module.js +9 -0
- package/dist/modules/admin-users/components/set-password_module.css +31 -0
- package/dist/modules/admin-users/components/update.d.ts +8 -0
- package/dist/modules/admin-users/components/update.js +254 -0
- package/dist/modules/admin-users/components/update.module.js +9 -0
- package/dist/modules/admin-users/components/update_module.css +34 -0
- package/dist/modules/admin-users/dto.js +3 -18
- package/dist/modules/admin-users/errors.js +17 -43
- package/dist/modules/admin-users/index.js +7 -27
- package/dist/modules/admin-users/repository.js +1 -8
- package/dist/modules/admin-users/schemas.js +44 -75
- package/dist/modules/admin-users/seed-super-admin.js +9 -34
- package/dist/modules/admin-users/service.js +76 -91
- package/dist/modules/auth/components/sign-in-form.d.ts +12 -0
- package/dist/modules/auth/components/sign-in-form.js +115 -0
- package/dist/modules/auth/components/sign-in-form.module.js +12 -0
- package/dist/modules/auth/components/sign-in-form_module.css +41 -0
- package/dist/modules/auth/index.js +3 -24
- package/dist/modules/auth/jwt-session-provider.js +179 -149
- package/dist/modules/auth/password.js +11 -53
- package/dist/modules/auth/phc.js +21 -54
- package/dist/modules/auth/refresh-tokens-repository.js +1 -8
- package/dist/modules/auth/resolve-actor.js +6 -28
- package/dist/services/admin-services-context.d.ts +16 -0
- package/dist/services/admin-services-context.js +13 -0
- package/dist/services/admin-services-types.d.ts +129 -0
- package/dist/services/admin-services-types.js +1 -0
- package/dist/store.js +1 -8
- package/dist/vendor/noble-argon2/_blake.js +277 -45
- package/dist/vendor/noble-argon2/_md.js +81 -136
- package/dist/vendor/noble-argon2/_u64.js +65 -67
- package/dist/vendor/noble-argon2/argon2.js +181 -342
- package/dist/vendor/noble-argon2/blake2.js +252 -327
- package/dist/vendor/noble-argon2/utils.js +110 -490
- package/dist/vendor/noble-argon2/utils.js.LICENSE.txt +1 -0
- package/package.json +89 -10
- package/src/abilities.ts +32 -0
- package/src/declarations.d.ts +4 -0
- package/src/index.ts +39 -0
- package/src/lib/assert-admin-actor.ts +90 -0
- package/src/lib/create-command.ts +109 -0
- package/src/modules/admin-account/commands.ts +76 -0
- package/src/modules/admin-account/components/change-password.module.css +40 -0
- package/src/modules/admin-account/components/change-password.tsx +232 -0
- package/src/modules/admin-account/components/container.module.css +158 -0
- package/src/modules/admin-account/components/container.tsx +229 -0
- package/src/modules/admin-account/components/update.module.css +40 -0
- package/src/modules/admin-account/components/update.tsx +263 -0
- package/src/modules/admin-account/errors.ts +75 -0
- package/src/modules/admin-account/index.ts +60 -0
- package/src/modules/admin-account/schemas.ts +84 -0
- package/src/modules/admin-account/service.ts +92 -0
- package/src/modules/admin-permissions/abilities.ts +46 -0
- package/src/modules/admin-permissions/commands.ts +103 -0
- package/src/modules/admin-permissions/components/inspector.module.css +326 -0
- package/src/modules/admin-permissions/components/inspector.tsx +298 -0
- package/src/modules/admin-permissions/dto.ts +28 -0
- package/src/modules/admin-permissions/errors.ts +57 -0
- package/src/modules/admin-permissions/index.ts +72 -0
- package/src/modules/admin-permissions/repository.ts +49 -0
- package/src/modules/admin-permissions/schemas.ts +128 -0
- package/src/modules/admin-permissions/service.ts +137 -0
- package/src/modules/admin-roles/abilities.ts +62 -0
- package/src/modules/admin-roles/commands.ts +161 -0
- package/src/modules/admin-roles/components/create.module.css +40 -0
- package/src/modules/admin-roles/components/create.tsx +218 -0
- package/src/modules/admin-roles/components/permissions.module.css +279 -0
- package/src/modules/admin-roles/components/permissions.tsx +396 -0
- package/src/modules/admin-roles/components/update.module.css +40 -0
- package/src/modules/admin-roles/components/update.tsx +218 -0
- package/src/modules/admin-roles/dto.ts +30 -0
- package/src/modules/admin-roles/errors.ts +76 -0
- package/src/modules/admin-roles/index.ts +81 -0
- package/src/modules/admin-roles/repository.ts +96 -0
- package/src/modules/admin-roles/schemas.ts +139 -0
- package/src/modules/admin-roles/service.ts +136 -0
- package/src/modules/admin-users/abilities.ts +76 -0
- package/src/modules/admin-users/commands.ts +157 -0
- package/src/modules/admin-users/components/create.module.css +63 -0
- package/src/modules/admin-users/components/create.tsx +323 -0
- package/src/modules/admin-users/components/roles.module.css +119 -0
- package/src/modules/admin-users/components/roles.tsx +172 -0
- package/src/modules/admin-users/components/set-password.module.css +46 -0
- package/src/modules/admin-users/components/set-password.tsx +199 -0
- package/src/modules/admin-users/components/update.module.css +49 -0
- package/src/modules/admin-users/components/update.tsx +328 -0
- package/src/modules/admin-users/dto.ts +39 -0
- package/src/modules/admin-users/errors.ts +84 -0
- package/src/modules/admin-users/index.ts +91 -0
- package/src/modules/admin-users/repository.ts +161 -0
- package/src/modules/admin-users/schemas.ts +168 -0
- package/src/modules/admin-users/seed-super-admin.ts +102 -0
- package/src/modules/admin-users/service.ts +166 -0
- package/src/modules/auth/components/sign-in-form.module.css +62 -0
- package/src/modules/auth/components/sign-in-form.tsx +132 -0
- package/src/modules/auth/index.ts +31 -0
- package/src/modules/auth/jwt-session-provider.ts +301 -0
- package/src/modules/auth/password.ts +94 -0
- package/src/modules/auth/phc.ts +121 -0
- package/src/modules/auth/refresh-tokens-repository.ts +74 -0
- package/src/modules/auth/resolve-actor.ts +42 -0
- package/src/services/admin-services-context.tsx +52 -0
- package/src/services/admin-services-types.ts +177 -0
- package/src/store.ts +32 -0
- package/src/vendor/noble-argon2/LICENSE +21 -0
- package/src/vendor/noble-argon2/README.md +87 -0
- package/src/vendor/noble-argon2/_blake.ts +58 -0
- package/src/vendor/noble-argon2/_md.ts +223 -0
- package/src/vendor/noble-argon2/_u64.ts +118 -0
- package/src/vendor/noble-argon2/argon2.ts +668 -0
- package/src/vendor/noble-argon2/blake2.ts +583 -0
- package/src/vendor/noble-argon2/utils.ts +849 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Infonomic Company Limited
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { toAdminRole } from './dto.js'
|
|
10
|
+
import {
|
|
11
|
+
ERR_ADMIN_ROLE_MACHINE_NAME_IN_USE,
|
|
12
|
+
ERR_ADMIN_ROLE_NOT_FOUND,
|
|
13
|
+
ERR_ADMIN_ROLE_USER_NOT_FOUND,
|
|
14
|
+
} from './errors.js'
|
|
15
|
+
import type { AdminStore } from '../../store.js'
|
|
16
|
+
import type {
|
|
17
|
+
AdminRoleListResponse,
|
|
18
|
+
AdminRoleResponse,
|
|
19
|
+
CreateAdminRoleRequest,
|
|
20
|
+
DeleteAdminRoleRequest,
|
|
21
|
+
GetAdminRoleRequest,
|
|
22
|
+
GetRolesForUserRequest,
|
|
23
|
+
ReorderAdminRolesRequest,
|
|
24
|
+
SetRolesForUserRequest,
|
|
25
|
+
UpdateAdminRoleRequest,
|
|
26
|
+
UserRolesResponse,
|
|
27
|
+
} from './schemas.js'
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Business logic for administering admin roles.
|
|
31
|
+
*
|
|
32
|
+
* Owns four concerns the repository deliberately avoids:
|
|
33
|
+
*
|
|
34
|
+
* 1. **Domain invariants.** `machine_name` uniqueness pre-check on
|
|
35
|
+
* create — the unique index is the ultimate backstop, but the
|
|
36
|
+
* pre-check produces a clean domain error rather than a raw
|
|
37
|
+
* Postgres code.
|
|
38
|
+
* 2. **DTO shaping.** Raw rows are shaped through `toAdminRole` so
|
|
39
|
+
* the response contract is owned in one place.
|
|
40
|
+
* 3. **Optimistic-concurrency plumbing.** The repo gates writes on
|
|
41
|
+
* `expectedVid`; the service threads it from the validated request
|
|
42
|
+
* shape. Version conflicts surface as
|
|
43
|
+
* `AdminRolesError(VERSION_CONFLICT)` from the adapter; the service
|
|
44
|
+
* does not catch them.
|
|
45
|
+
* 4. **Cross-table validation.** The user-roles editor validates the
|
|
46
|
+
* user and every referenced role exists before mutating the join
|
|
47
|
+
* table — clean errors over raw FK violations.
|
|
48
|
+
*
|
|
49
|
+
* Roles do not need a self-target invariant the way users do
|
|
50
|
+
* (no "self-delete" concept), so role-CRUD service methods are
|
|
51
|
+
* actor-agnostic and the ability check at the command boundary is the
|
|
52
|
+
* only authorisation.
|
|
53
|
+
*/
|
|
54
|
+
export class AdminRolesService {
|
|
55
|
+
readonly #store: AdminStore
|
|
56
|
+
|
|
57
|
+
constructor(deps: { store: AdminStore }) {
|
|
58
|
+
this.#store = deps.store
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async listRoles(): Promise<AdminRoleListResponse> {
|
|
62
|
+
const rows = await this.#store.adminRoles.list()
|
|
63
|
+
return { roles: rows.map(toAdminRole) }
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async getRole(request: GetAdminRoleRequest): Promise<AdminRoleResponse> {
|
|
67
|
+
const row = await this.#store.adminRoles.getById(request.id)
|
|
68
|
+
if (!row) throw ERR_ADMIN_ROLE_NOT_FOUND()
|
|
69
|
+
return toAdminRole(row)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async createRole(request: CreateAdminRoleRequest): Promise<AdminRoleResponse> {
|
|
73
|
+
// Pre-check for machine_name conflict so the common case returns a
|
|
74
|
+
// domain-specific error rather than the raw unique-violation code.
|
|
75
|
+
const existing = await this.#store.adminRoles.getByMachineName(request.machine_name)
|
|
76
|
+
if (existing) throw ERR_ADMIN_ROLE_MACHINE_NAME_IN_USE()
|
|
77
|
+
|
|
78
|
+
const row = await this.#store.adminRoles.create({
|
|
79
|
+
name: request.name,
|
|
80
|
+
machine_name: request.machine_name,
|
|
81
|
+
description: request.description ?? null,
|
|
82
|
+
order: request.order,
|
|
83
|
+
})
|
|
84
|
+
return toAdminRole(row)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async updateRole(request: UpdateAdminRoleRequest): Promise<AdminRoleResponse> {
|
|
88
|
+
const current = await this.#store.adminRoles.getById(request.id)
|
|
89
|
+
if (!current) throw ERR_ADMIN_ROLE_NOT_FOUND()
|
|
90
|
+
const row = await this.#store.adminRoles.update(request.id, request.vid, request.patch)
|
|
91
|
+
return toAdminRole(row)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async deleteRole(request: DeleteAdminRoleRequest): Promise<void> {
|
|
95
|
+
const exists = await this.#store.adminRoles.getById(request.id)
|
|
96
|
+
if (!exists) throw ERR_ADMIN_ROLE_NOT_FOUND()
|
|
97
|
+
await this.#store.adminRoles.delete(request.id, request.vid)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async reorderRoles(request: ReorderAdminRolesRequest): Promise<void> {
|
|
101
|
+
await this.#store.adminRoles.reorder(request.ids)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async getRolesForUser(request: GetRolesForUserRequest): Promise<UserRolesResponse> {
|
|
105
|
+
const user = await this.#store.adminUsers.getById(request.userId)
|
|
106
|
+
if (!user) throw ERR_ADMIN_ROLE_USER_NOT_FOUND()
|
|
107
|
+
const rows = await this.#store.adminRoles.listRolesForUser(request.userId)
|
|
108
|
+
return { userId: request.userId, roles: rows.map(toAdminRole) }
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async setRolesForUser(request: SetRolesForUserRequest): Promise<UserRolesResponse> {
|
|
112
|
+
const user = await this.#store.adminUsers.getById(request.userId)
|
|
113
|
+
if (!user) throw ERR_ADMIN_ROLE_USER_NOT_FOUND()
|
|
114
|
+
|
|
115
|
+
// Validate every referenced role exists. N round-trips, but role
|
|
116
|
+
// assignment payloads are small by design (typically < 10 roles)
|
|
117
|
+
// and surfacing a clean `notFound` beats a raw FK violation.
|
|
118
|
+
if (request.roleIds.length > 0) {
|
|
119
|
+
const found = await Promise.all(
|
|
120
|
+
request.roleIds.map((id) => this.#store.adminRoles.getById(id))
|
|
121
|
+
)
|
|
122
|
+
const missing = request.roleIds.filter((_, i) => found[i] == null)
|
|
123
|
+
if (missing.length > 0) {
|
|
124
|
+
throw ERR_ADMIN_ROLE_NOT_FOUND({
|
|
125
|
+
message: `One or more referenced roles do not exist: ${missing.join(', ')}`,
|
|
126
|
+
})
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
await this.#store.adminRoles.setRolesForUser(request.userId, request.roleIds)
|
|
131
|
+
// Return the freshly stored set, shaped — saves the editor a second
|
|
132
|
+
// round-trip and guards against any normalisation the repo might apply.
|
|
133
|
+
const stored = await this.#store.adminRoles.listRolesForUser(request.userId)
|
|
134
|
+
return { userId: request.userId, roles: stored.map(toAdminRole) }
|
|
135
|
+
}
|
|
136
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Infonomic Company Limited
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { AbilityRegistry } from '@byline/auth'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Ability keys for the admin-users module.
|
|
13
|
+
*
|
|
14
|
+
* Dot-notation rather than Modulus' colon-notation — keeps one consistent
|
|
15
|
+
* hierarchy across the whole platform alongside `collections.<path>.<verb>`
|
|
16
|
+
* from core.
|
|
17
|
+
*
|
|
18
|
+
* `changePassword` is split out from `update` deliberately: setting
|
|
19
|
+
* someone else's password is a higher-trust operation than editing their
|
|
20
|
+
* profile fields, and the role editor UI benefits from naming it
|
|
21
|
+
* explicitly. A role can grant `update` without implicitly granting
|
|
22
|
+
* `changePassword`.
|
|
23
|
+
*
|
|
24
|
+
* Self-service (changing *own* password, email, etc.) does **not** use
|
|
25
|
+
* any of these keys. That flow lives in the separate `account` module
|
|
26
|
+
* where the actor is the target by definition; the `admin.users.*` keys
|
|
27
|
+
* are strictly for administering other admin users.
|
|
28
|
+
*/
|
|
29
|
+
export const ADMIN_USERS_ABILITIES = {
|
|
30
|
+
read: 'admin.users.read',
|
|
31
|
+
create: 'admin.users.create',
|
|
32
|
+
update: 'admin.users.update',
|
|
33
|
+
delete: 'admin.users.delete',
|
|
34
|
+
changePassword: 'admin.users.changePassword',
|
|
35
|
+
} as const
|
|
36
|
+
|
|
37
|
+
export type AdminUsersAbilityKey =
|
|
38
|
+
(typeof ADMIN_USERS_ABILITIES)[keyof typeof ADMIN_USERS_ABILITIES]
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Register every admin-users ability with the framework's `AbilityRegistry`.
|
|
42
|
+
* Called from `registerAdminAbilities(registry)` at package level, which
|
|
43
|
+
* the webapp wires into `initBylineCore()`.
|
|
44
|
+
*/
|
|
45
|
+
export function registerAdminUsersAbilities(registry: AbilityRegistry): void {
|
|
46
|
+
registry.register({
|
|
47
|
+
key: ADMIN_USERS_ABILITIES.read,
|
|
48
|
+
label: 'Read admin users',
|
|
49
|
+
group: 'admin.users',
|
|
50
|
+
source: 'admin',
|
|
51
|
+
})
|
|
52
|
+
registry.register({
|
|
53
|
+
key: ADMIN_USERS_ABILITIES.create,
|
|
54
|
+
label: 'Create admin users',
|
|
55
|
+
group: 'admin.users',
|
|
56
|
+
source: 'admin',
|
|
57
|
+
})
|
|
58
|
+
registry.register({
|
|
59
|
+
key: ADMIN_USERS_ABILITIES.update,
|
|
60
|
+
label: 'Update admin users',
|
|
61
|
+
group: 'admin.users',
|
|
62
|
+
source: 'admin',
|
|
63
|
+
})
|
|
64
|
+
registry.register({
|
|
65
|
+
key: ADMIN_USERS_ABILITIES.delete,
|
|
66
|
+
label: 'Delete admin users',
|
|
67
|
+
group: 'admin.users',
|
|
68
|
+
source: 'admin',
|
|
69
|
+
})
|
|
70
|
+
registry.register({
|
|
71
|
+
key: ADMIN_USERS_ABILITIES.changePassword,
|
|
72
|
+
label: "Change an admin user's password",
|
|
73
|
+
group: 'admin.users',
|
|
74
|
+
source: 'admin',
|
|
75
|
+
})
|
|
76
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Infonomic Company Limited
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { type Command, createCommand } from '../../lib/create-command.js'
|
|
10
|
+
import { ADMIN_USERS_ABILITIES } from './abilities.js'
|
|
11
|
+
import {
|
|
12
|
+
adminUserListResponseSchema,
|
|
13
|
+
adminUserResponseSchema,
|
|
14
|
+
createAdminUserRequestSchema,
|
|
15
|
+
deleteAdminUserRequestSchema,
|
|
16
|
+
disableAdminUserRequestSchema,
|
|
17
|
+
enableAdminUserRequestSchema,
|
|
18
|
+
getAdminUserRequestSchema,
|
|
19
|
+
listAdminUsersRequestSchema,
|
|
20
|
+
okResponseSchema,
|
|
21
|
+
setAdminUserPasswordRequestSchema,
|
|
22
|
+
updateAdminUserRequestSchema,
|
|
23
|
+
} from './schemas.js'
|
|
24
|
+
import { AdminUsersService } from './service.js'
|
|
25
|
+
import type { AdminStore } from '../../store.js'
|
|
26
|
+
import type {
|
|
27
|
+
AdminUserListResponse,
|
|
28
|
+
AdminUserResponse,
|
|
29
|
+
CreateAdminUserRequest,
|
|
30
|
+
DeleteAdminUserRequest,
|
|
31
|
+
DisableAdminUserRequest,
|
|
32
|
+
EnableAdminUserRequest,
|
|
33
|
+
GetAdminUserRequest,
|
|
34
|
+
ListAdminUsersRequest,
|
|
35
|
+
OkResponse,
|
|
36
|
+
SetAdminUserPasswordRequest,
|
|
37
|
+
UpdateAdminUserRequest,
|
|
38
|
+
} from './schemas.js'
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Transport-agnostic commands for the admin-users module.
|
|
42
|
+
*
|
|
43
|
+
* Each command is built through `createCommand`, which folds the four
|
|
44
|
+
* standard steps (Zod-validate input → assert admin actor + ability →
|
|
45
|
+
* call the service → Zod-validate output) into a single declaration.
|
|
46
|
+
* The wrapper preserves the historical `(context, input, deps)` call
|
|
47
|
+
* signature so server fns keep working without change.
|
|
48
|
+
*
|
|
49
|
+
* The `deps` argument holds the `AdminStore`. The webapp wraps these in
|
|
50
|
+
* server fns that supply `deps` from the application's singleton store;
|
|
51
|
+
* scripts and tests construct their own store and pass it in directly.
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
export interface AdminUsersCommandDeps {
|
|
55
|
+
store: AdminStore
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function serviceOf(deps: AdminUsersCommandDeps): AdminUsersService {
|
|
59
|
+
return new AdminUsersService({ repo: deps.store.adminUsers })
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export const listAdminUsersCommand: Command<
|
|
63
|
+
ListAdminUsersRequest,
|
|
64
|
+
AdminUserListResponse,
|
|
65
|
+
AdminUsersCommandDeps
|
|
66
|
+
> = createCommand({
|
|
67
|
+
method: 'listAdminUsers',
|
|
68
|
+
auth: { ability: ADMIN_USERS_ABILITIES.read },
|
|
69
|
+
schemas: { input: listAdminUsersRequestSchema, output: adminUserListResponseSchema },
|
|
70
|
+
handler: ({ input, deps }) => serviceOf(deps).listUsers(input),
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
export const getAdminUserCommand: Command<
|
|
74
|
+
GetAdminUserRequest,
|
|
75
|
+
AdminUserResponse,
|
|
76
|
+
AdminUsersCommandDeps
|
|
77
|
+
> = createCommand({
|
|
78
|
+
method: 'getAdminUser',
|
|
79
|
+
auth: { ability: ADMIN_USERS_ABILITIES.read },
|
|
80
|
+
schemas: { input: getAdminUserRequestSchema, output: adminUserResponseSchema },
|
|
81
|
+
handler: ({ input, deps }) => serviceOf(deps).getUser(input),
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
export const createAdminUserCommand: Command<
|
|
85
|
+
CreateAdminUserRequest,
|
|
86
|
+
AdminUserResponse,
|
|
87
|
+
AdminUsersCommandDeps
|
|
88
|
+
> = createCommand({
|
|
89
|
+
method: 'createAdminUser',
|
|
90
|
+
auth: { ability: ADMIN_USERS_ABILITIES.create },
|
|
91
|
+
schemas: { input: createAdminUserRequestSchema, output: adminUserResponseSchema },
|
|
92
|
+
handler: ({ input, deps }) => serviceOf(deps).createUser(input),
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
export const updateAdminUserCommand: Command<
|
|
96
|
+
UpdateAdminUserRequest,
|
|
97
|
+
AdminUserResponse,
|
|
98
|
+
AdminUsersCommandDeps
|
|
99
|
+
> = createCommand({
|
|
100
|
+
method: 'updateAdminUser',
|
|
101
|
+
auth: { ability: ADMIN_USERS_ABILITIES.update },
|
|
102
|
+
schemas: { input: updateAdminUserRequestSchema, output: adminUserResponseSchema },
|
|
103
|
+
handler: ({ input, deps }) => serviceOf(deps).updateUser(input),
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
export const setAdminUserPasswordCommand: Command<
|
|
107
|
+
SetAdminUserPasswordRequest,
|
|
108
|
+
AdminUserResponse,
|
|
109
|
+
AdminUsersCommandDeps
|
|
110
|
+
> = createCommand({
|
|
111
|
+
method: 'setAdminUserPassword',
|
|
112
|
+
auth: { ability: ADMIN_USERS_ABILITIES.changePassword },
|
|
113
|
+
schemas: { input: setAdminUserPasswordRequestSchema, output: adminUserResponseSchema },
|
|
114
|
+
handler: ({ input, deps }) => serviceOf(deps).setPassword(input),
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
export const enableAdminUserCommand: Command<
|
|
118
|
+
EnableAdminUserRequest,
|
|
119
|
+
OkResponse,
|
|
120
|
+
AdminUsersCommandDeps
|
|
121
|
+
> = createCommand({
|
|
122
|
+
method: 'enableAdminUser',
|
|
123
|
+
auth: { ability: ADMIN_USERS_ABILITIES.update },
|
|
124
|
+
schemas: { input: enableAdminUserRequestSchema, output: okResponseSchema },
|
|
125
|
+
handler: async ({ input, deps }) => {
|
|
126
|
+
await serviceOf(deps).enableUser(input)
|
|
127
|
+
return { ok: true } as const
|
|
128
|
+
},
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
export const disableAdminUserCommand: Command<
|
|
132
|
+
DisableAdminUserRequest,
|
|
133
|
+
OkResponse,
|
|
134
|
+
AdminUsersCommandDeps
|
|
135
|
+
> = createCommand({
|
|
136
|
+
method: 'disableAdminUser',
|
|
137
|
+
auth: { ability: ADMIN_USERS_ABILITIES.update },
|
|
138
|
+
schemas: { input: disableAdminUserRequestSchema, output: okResponseSchema },
|
|
139
|
+
handler: async ({ input, deps, actor }) => {
|
|
140
|
+
await serviceOf(deps).disableUser(actor, input)
|
|
141
|
+
return { ok: true } as const
|
|
142
|
+
},
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
export const deleteAdminUserCommand: Command<
|
|
146
|
+
DeleteAdminUserRequest,
|
|
147
|
+
OkResponse,
|
|
148
|
+
AdminUsersCommandDeps
|
|
149
|
+
> = createCommand({
|
|
150
|
+
method: 'deleteAdminUser',
|
|
151
|
+
auth: { ability: ADMIN_USERS_ABILITIES.delete },
|
|
152
|
+
schemas: { input: deleteAdminUserRequestSchema, output: okResponseSchema },
|
|
153
|
+
handler: async ({ input, deps, actor }) => {
|
|
154
|
+
await serviceOf(deps).deleteUser(actor, input)
|
|
155
|
+
return { ok: true } as const
|
|
156
|
+
},
|
|
157
|
+
})
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CreateAdminUser — drawer form for creating a new admin user.
|
|
3
|
+
*
|
|
4
|
+
* Override handles:
|
|
5
|
+
* .byline-user-create-wrap — outer container
|
|
6
|
+
* .byline-user-create-form — vertical-stack form element
|
|
7
|
+
* .byline-user-create-grid — two-column name grid (collapses on mobile)
|
|
8
|
+
* .byline-user-create-flags — checkbox stack (enabled / verified / super)
|
|
9
|
+
* .byline-user-create-actions — Cancel/Save row
|
|
10
|
+
* .byline-user-create-action — buttons in the actions row
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
.wrap,
|
|
14
|
+
:global(.byline-user-create-wrap) {
|
|
15
|
+
display: flex;
|
|
16
|
+
flex-direction: column;
|
|
17
|
+
gap: var(--spacing-8);
|
|
18
|
+
padding: var(--spacing-4);
|
|
19
|
+
margin-top: var(--spacing-4);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.form,
|
|
23
|
+
:global(.byline-user-create-form) {
|
|
24
|
+
display: flex;
|
|
25
|
+
flex-direction: column;
|
|
26
|
+
gap: var(--spacing-16);
|
|
27
|
+
padding-top: var(--spacing-8);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.grid,
|
|
31
|
+
:global(.byline-user-create-grid) {
|
|
32
|
+
display: grid;
|
|
33
|
+
grid-template-columns: 1fr;
|
|
34
|
+
gap: var(--spacing-16);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@media (min-width: 40rem) {
|
|
38
|
+
.grid,
|
|
39
|
+
:global(.byline-user-create-grid) {
|
|
40
|
+
grid-template-columns: 1fr 1fr;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.flags,
|
|
45
|
+
:global(.byline-user-create-flags) {
|
|
46
|
+
display: flex;
|
|
47
|
+
flex-direction: column;
|
|
48
|
+
gap: var(--spacing-8);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.actions,
|
|
52
|
+
:global(.byline-user-create-actions) {
|
|
53
|
+
display: flex;
|
|
54
|
+
align-items: center;
|
|
55
|
+
justify-content: flex-end;
|
|
56
|
+
gap: var(--spacing-8);
|
|
57
|
+
margin-top: var(--spacing-16);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.action,
|
|
61
|
+
:global(.byline-user-create-action) {
|
|
62
|
+
min-width: 4rem;
|
|
63
|
+
}
|