feat(v1.1.8): per-app roles + roles in user record (migration 0031)
migration 0031: app_user_roles table — composite PK (app_id, user_id,
role) so add is idempotent (ON CONFLICT DO NOTHING). v1.1.8 stores
strings only; permission matrices / hierarchies / role registry are
explicitly v1.2 work per the brief.
UsersServiceImpl wires roles: Arc<dyn AppUserRoleRepo>:
* fetch_roles() now actually queries the repo (replacing the empty
Vec stub from commit 4). Every AppUser returned from get /
find_by_email / list / update / verify / login now carries its
role list.
* users::add_role gated on AppUsersAdmin; first checks the user
exists in this app so a FK violation can't leak "no such user".
* users::remove_role gated on AppUsersAdmin; idempotent.
* users::has_role gated on AppUsersRead.
* accept_invite now applies pre-staged roles atomically with the
user creation; malformed role strings are skipped with a warn
rather than aborting the whole accept (the invitation was an
admin's promise — we honor as much of it as we can).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -22,7 +22,7 @@ use picloud_manager_core::{
|
||||
OutboxRepo, PostgresAbandonedRepo, PostgresAdminSessionRepository, PostgresAdminUserRepository,
|
||||
PostgresApiKeyRepository, PostgresAppDomainRepository, PostgresAppMembersRepository,
|
||||
PostgresAppRepository, PostgresAppSecretsRepo, PostgresAppUserInvitationRepo,
|
||||
PostgresAppUserPasswordResetRepo, PostgresAppUserRepository,
|
||||
PostgresAppUserPasswordResetRepo, PostgresAppUserRepository, PostgresAppUserRoleRepo,
|
||||
PostgresAppUserSessionRepository, PostgresAppUserVerificationRepo, PostgresDeadLetterRepo,
|
||||
PostgresDeadLetterService,
|
||||
PostgresDocsRepo, PostgresExecutionLogRepository, PostgresExecutionLogSink, PostgresKvRepo,
|
||||
@@ -258,12 +258,14 @@ pub async fn build_app(
|
||||
Arc::new(PostgresAppUserPasswordResetRepo::new(pool.clone()));
|
||||
let app_user_invitations_repo =
|
||||
Arc::new(PostgresAppUserInvitationRepo::new(pool.clone()));
|
||||
let app_user_roles_repo = Arc::new(PostgresAppUserRoleRepo::new(pool.clone()));
|
||||
let users: Arc<dyn UsersService> = Arc::new(UsersServiceImpl::new(
|
||||
app_users_repo.clone(),
|
||||
app_user_sessions_repo.clone(),
|
||||
app_user_verifications_repo.clone(),
|
||||
app_user_password_resets_repo.clone(),
|
||||
app_user_invitations_repo.clone(),
|
||||
app_user_roles_repo.clone(),
|
||||
email.clone(),
|
||||
authz.clone(),
|
||||
events.clone(),
|
||||
|
||||
Reference in New Issue
Block a user