diff --git a/schema.graphql b/schema.graphql index 7a96ac8..7f9eb58 100644 --- a/schema.graphql +++ b/schema.graphql @@ -6,6 +6,7 @@ input EqualityConstraint { type Mutation { createUser(user: CreateUserInput!): User! updateUser(user: UpdateUserInput!): Success! + updateGroup(group: UpdateGroupInput!): Success! addUserToGroup(userId: String!, groupId: Int!): Success! removeUserFromGroup(userId: String!, groupId: Int!): Success! deleteUser(userId: String!): Success! @@ -33,6 +34,12 @@ input RequestFilter { "DateTime" scalar DateTimeUtc +"The fields that can be updated for a group." +input UpdateGroupInput { + id: Int! + displayName: String +} + type Query { apiVersion: String! user(userId: String!): User! diff --git a/server/src/domain/handler.rs b/server/src/domain/handler.rs index e53d141..1eff98f 100644 --- a/server/src/domain/handler.rs +++ b/server/src/domain/handler.rs @@ -70,6 +70,12 @@ pub struct UpdateUserRequest { pub last_name: Option, } +#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Clone)] +pub struct UpdateGroupRequest { + pub group_id: GroupId, + pub display_name: Option, +} + #[async_trait] pub trait LoginHandler: Clone + Send { async fn bind(&self, request: BindRequest) -> Result<()>; @@ -88,6 +94,7 @@ pub trait BackendHandler: Clone + Send { async fn get_user_details(&self, user_id: &str) -> Result; async fn create_user(&self, request: CreateUserRequest) -> Result<()>; async fn update_user(&self, request: UpdateUserRequest) -> Result<()>; + async fn update_group(&self, request: UpdateGroupRequest) -> Result<()>; async fn delete_user(&self, user_id: &str) -> Result<()>; async fn create_group(&self, group_name: &str) -> Result; async fn delete_group(&self, group_id: GroupId) -> Result<()>; @@ -109,6 +116,7 @@ mockall::mock! { async fn get_user_details(&self, user_id: &str) -> Result; async fn create_user(&self, request: CreateUserRequest) -> Result<()>; async fn update_user(&self, request: UpdateUserRequest) -> Result<()>; + async fn update_group(&self, request: UpdateGroupRequest) -> Result<()>; async fn delete_user(&self, user_id: &str) -> Result<()>; async fn create_group(&self, group_name: &str) -> Result; async fn delete_group(&self, group_id: GroupId) -> Result<()>; diff --git a/server/src/domain/sql_backend_handler.rs b/server/src/domain/sql_backend_handler.rs index 2d33ab4..a73998a 100644 --- a/server/src/domain/sql_backend_handler.rs +++ b/server/src/domain/sql_backend_handler.rs @@ -226,6 +226,23 @@ impl BackendHandler for SqlBackendHandler { Ok(()) } + async fn update_group(&self, request: UpdateGroupRequest) -> Result<()> { + let mut values = Vec::new(); + if let Some(display_name) = request.display_name { + values.push((Groups::DisplayName, display_name.into())); + } + if values.is_empty() { + return Ok(()); + } + let query = Query::update() + .table(Groups::Table) + .values(values) + .and_where(Expr::col(Groups::GroupId).eq(request.group_id)) + .to_string(DbQueryBuilder {}); + sqlx::query(&query).execute(&self.sql_pool).await?; + Ok(()) + } + async fn delete_user(&self, user_id: &str) -> Result<()> { let delete_query = Query::delete() .from_table(Users::Table) diff --git a/server/src/infra/graphql/mutation.rs b/server/src/infra/graphql/mutation.rs index 20068c5..c8cabb4 100644 --- a/server/src/infra/graphql/mutation.rs +++ b/server/src/infra/graphql/mutation.rs @@ -1,4 +1,6 @@ -use crate::domain::handler::{BackendHandler, CreateUserRequest, GroupId, UpdateUserRequest}; +use crate::domain::handler::{ + BackendHandler, CreateUserRequest, GroupId, UpdateGroupRequest, UpdateUserRequest, +}; use juniper::{graphql_object, FieldResult, GraphQLInputObject, GraphQLObject}; use super::api::Context; @@ -37,6 +39,13 @@ pub struct UpdateUserInput { last_name: Option, } +#[derive(PartialEq, Eq, Debug, GraphQLInputObject)] +/// The fields that can be updated for a group. +pub struct UpdateGroupInput { + id: i32, + display_name: Option, +} + #[derive(PartialEq, Eq, Debug, GraphQLObject)] pub struct Success { ok: bool, @@ -94,6 +103,23 @@ impl Mutation { Ok(Success::new()) } + async fn update_group( + context: &Context, + group: UpdateGroupInput, + ) -> FieldResult { + if !context.validation_result.is_admin { + return Err("Unauthorized group update".into()); + } + context + .handler + .update_group(UpdateGroupRequest { + group_id: GroupId(group.id), + display_name: group.display_name, + }) + .await?; + Ok(Success::new()) + } + async fn add_user_to_group( context: &Context, user_id: String, diff --git a/server/src/infra/tcp_backend_handler.rs b/server/src/infra/tcp_backend_handler.rs index 4e29463..4025d1b 100644 --- a/server/src/infra/tcp_backend_handler.rs +++ b/server/src/infra/tcp_backend_handler.rs @@ -32,6 +32,7 @@ mockall::mock! { async fn get_user_groups(&self, user: &str) -> DomainResult>; async fn create_user(&self, request: CreateUserRequest) -> DomainResult<()>; async fn update_user(&self, request: UpdateUserRequest) -> DomainResult<()>; + async fn update_group(&self, request: UpdateGroupRequest) -> DomainResult<()>; async fn delete_user(&self, user_id: &str) -> DomainResult<()>; async fn create_group(&self, group_name: &str) -> DomainResult; async fn delete_group(&self, group_id: GroupId) -> DomainResult<()>;