registry: add sqlx checks for user profile reads

This commit is contained in:
a.tolmachev
2026-04-12 21:25:03 +00:00
parent 247440a793
commit 075c1762e2
4 changed files with 166 additions and 17 deletions
+17 -11
View File
@@ -138,7 +138,7 @@ impl PostgresRegistry {
email: &str,
display_name: &str,
) -> Result<User, RegistryError> {
let row = sqlx::query(
let row = sqlx::query!(
"update users
set email = $2,
display_name = $3
@@ -148,16 +148,22 @@ impl PostgresRegistry {
email,
display_name,
status,
to_char(created_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as created_at",
to_char(created_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as \"created_at!\"",
user_id.as_str(),
email,
display_name,
)
.bind(user_id.as_str())
.bind(email)
.bind(display_name)
.fetch_one(&self.pool)
.await
.map_err(|error| map_user_update_error(error, user_id, email))?;
map_user(&row)
build_user(
row.id,
row.email,
row.display_name,
row.status,
row.created_at,
)
}
pub async fn update_user_password(
@@ -340,20 +346,20 @@ impl PostgresRegistry {
user_id: &UserId,
workspace_id: &WorkspaceId,
) -> Result<bool, RegistryError> {
let row = sqlx::query(
let row = sqlx::query!(
"select exists(
select 1
from memberships
where user_id = $1
and workspace_id = $2
) as allowed",
) as \"allowed!\"",
user_id.as_str(),
workspace_id.as_str(),
)
.bind(user_id.as_str())
.bind(workspace_id.as_str())
.fetch_one(&self.pool)
.await?;
Ok(row.try_get("allowed")?)
Ok(row.allowed)
}
pub async fn save_auth_profile(
+78 -6
View File
@@ -484,13 +484,19 @@ fn assert_immutable_fields(
Ok(())
}
fn map_user(row: &PgRow) -> Result<User, RegistryError> {
fn build_user(
id: String,
email: String,
display_name: String,
status: String,
created_at: String,
) -> Result<User, RegistryError> {
Ok(User {
id: UserId::new(row.try_get::<String, _>("id")?),
email: row.try_get("email")?,
display_name: row.try_get("display_name")?,
status: deserialize_enum_text(&row.try_get::<String, _>("status")?, "status")?,
created_at: row.try_get("created_at")?,
id: UserId::new(id),
email,
display_name,
status: deserialize_enum_text(&status, "status")?,
created_at,
})
}
@@ -1503,6 +1509,72 @@ mod tests {
database.cleanup().await;
}
#[tokio::test]
async fn manages_user_profile_and_workspace_access_reads() {
let database = TestDatabase::new().await;
let registry = database.registry().await;
let workspace = Workspace {
id: WorkspaceId::new("ws_profile_01"),
slug: "profile".to_owned(),
display_name: "Profile Workspace".to_owned(),
status: crank_core::WorkspaceStatus::Active,
settings: json!({}),
created_at: "2026-03-25T12:00:00Z".to_owned(),
updated_at: "2026-03-25T12:00:00Z".to_owned(),
};
let other_workspace = Workspace {
id: WorkspaceId::new("ws_profile_02"),
slug: "profile-other".to_owned(),
display_name: "Other Workspace".to_owned(),
status: crank_core::WorkspaceStatus::Active,
settings: json!({}),
created_at: "2026-03-25T12:01:00Z".to_owned(),
updated_at: "2026-03-25T12:01:00Z".to_owned(),
};
let user_id = registry
.upsert_bootstrap_user("profile@example.com", "Owner", "hashed-password")
.await
.unwrap();
registry
.create_workspace(CreateWorkspaceRequest {
workspace: &workspace,
})
.await
.unwrap();
registry
.create_workspace(CreateWorkspaceRequest {
workspace: &other_workspace,
})
.await
.unwrap();
registry
.ensure_membership(&workspace.id, &user_id, MembershipRole::Owner)
.await
.unwrap();
let updated = registry
.update_user_profile(&user_id, "updated@example.com", "Updated Owner")
.await
.unwrap();
let has_access = registry
.user_has_workspace_access(&user_id, &workspace.id)
.await
.unwrap();
let lacks_access = registry
.user_has_workspace_access(&user_id, &other_workspace.id)
.await
.unwrap();
assert_eq!(updated.id, user_id);
assert_eq!(updated.email, "updated@example.com");
assert_eq!(updated.display_name, "Updated Owner");
assert!(has_access);
assert!(!lacks_access);
database.cleanup().await;
}
#[tokio::test]
async fn manages_platform_api_key_read_paths() {
let database = TestDatabase::new().await;