diff --git a/src/api/ecdar_api.rs b/src/api/ecdar_api.rs index a4e58d1..61553d0 100644 --- a/src/api/ecdar_api.rs +++ b/src/api/ecdar_api.rs @@ -117,10 +117,6 @@ impl EcdarApi for ConcreteEcdarApi { todo!() } - async fn delete_session(&self, _request: Request<()>) -> Result, Status> { - todo!() - } - /// Gets a Model and its queries from the database. /// /// If the Model is not in use, it will now be in use by the requestees session, @@ -1022,6 +1018,25 @@ impl EcdarApi for ConcreteEcdarApi { response: Some(query_result.into_inner()), })) } + + /// Deletes the requester's session, found by their access token. + /// + /// Returns the response that is received from Reveaal. + async fn delete_session(&self, request: Request<()>) -> Result, Status> { + let access_token = request + .token_string() + .ok_or(Status::unauthenticated("No access token provided"))?; + + match self + .contexts + .session_context + .delete_by_token(TokenType::AccessToken, access_token) + .await + { + Ok(_) => Ok(Response::new(())), + Err(error) => Err(Status::new(Code::Internal, error.to_string())), + } + } } async fn check_editor_role_helper( diff --git a/src/database/session_context.rs b/src/database/session_context.rs index 4709fc2..28d111c 100644 --- a/src/database/session_context.rs +++ b/src/database/session_context.rs @@ -2,6 +2,7 @@ use crate::api::auth::TokenType; use crate::database::database_context::DatabaseContextTrait; use crate::database::entity_context::EntityContextTrait; use crate::entities::session; +use crate::entities::session::Model; use chrono::Local; use sea_orm::prelude::async_trait::async_trait; use sea_orm::ActiveValue::{Set, Unchanged}; @@ -19,6 +20,12 @@ pub trait SessionContextTrait: EntityContextTrait { token_type: TokenType, token: String, ) -> Result, DbErr>; + + async fn delete_by_token( + &self, + token_type: TokenType, + token: String, + ) -> Result; } #[async_trait] @@ -43,6 +50,21 @@ impl SessionContextTrait for SessionContext { } } } + + async fn delete_by_token(&self, token_type: TokenType, token: String) -> Result { + let session = self + .get_by_token(token_type, token) + .await? + .ok_or(DbErr::RecordNotFound( + "No session found with the provided access token".into(), + ))?; + + session::Entity::delete_by_id(session.id) + .exec(&self.db_context.get_connection()) + .await?; + + Ok(session) + } } impl SessionContext { diff --git a/src/tests/api/helpers.rs b/src/tests/api/helpers.rs index 3afe765..89c1709 100644 --- a/src/tests/api/helpers.rs +++ b/src/tests/api/helpers.rs @@ -162,6 +162,7 @@ mock! { #[async_trait] impl SessionContextTrait for SessionContext { async fn get_by_token(&self, token_type: TokenType, token: String) -> Result, DbErr>; + async fn delete_by_token(&self, token_type: TokenType, token: String) -> Result; } } diff --git a/src/tests/api/session_logic.rs b/src/tests/api/session_logic.rs index 4513531..774dab2 100644 --- a/src/tests/api/session_logic.rs +++ b/src/tests/api/session_logic.rs @@ -1,7 +1,8 @@ +use crate::api::server::server::ecdar_api_server::EcdarApi; use crate::api::server::server::GetAuthTokenRequest; use crate::api::{auth::TokenType, ecdar_api::handle_session}; use crate::entities::session; -use crate::tests::api::helpers::get_mock_services; +use crate::tests::api::helpers::{get_mock_concrete_ecdar_api, get_mock_services}; use mockall::predicate; use sea_orm::DbErr; use std::str::FromStr; @@ -134,3 +135,67 @@ async fn handle_session_no_session_exists_creates_session_returns_err() { assert_eq!(res.unwrap_err().code(), Code::Internal); } + +#[tokio::test] +async fn delete_session_returns_ok() { + let mut mock_services = get_mock_services(); + + mock_services + .session_context_mock + .expect_delete_by_token() + .with( + predicate::eq(TokenType::AccessToken), + predicate::eq("test_token".to_string()), + ) + .returning(move |_, _| { + Ok(session::Model { + id: 1, + refresh_token: Default::default(), + access_token: "test_token".to_string(), + updated_at: Default::default(), + user_id: Default::default(), + }) + }); + + let api = get_mock_concrete_ecdar_api(mock_services); + + let mut request = Request::new(()); + request.metadata_mut().insert( + "authorization", + metadata::MetadataValue::from_str("Bearer test_token").unwrap(), + ); + + let res = api.delete_session(request).await; + + assert!(res.is_ok()); +} + +#[tokio::test] +async fn delete_session_no_session_returns_err() { + let mut mock_services = get_mock_services(); + + mock_services + .session_context_mock + .expect_delete_by_token() + .with( + predicate::eq(TokenType::AccessToken), + predicate::eq("test_token".to_string()), + ) + .returning(move |_, _| { + Err(DbErr::RecordNotFound( + "No session found with the provided access token".to_string(), + )) + }); + + let api = get_mock_concrete_ecdar_api(mock_services); + + let mut request = Request::new(()); + request.metadata_mut().insert( + "authorization", + metadata::MetadataValue::from_str("Bearer test_token").unwrap(), + ); + + let res = api.delete_session(request).await; + + assert_eq!(res.unwrap_err().code(), Code::Internal); +}