33use anyhow:: Result ;
44use askama:: Template ;
55use axum:: {
6+ Json ,
67 extract:: { Path , State } ,
78 http:: StatusCode ,
89 response:: { Html , IntoResponse } ,
@@ -102,6 +103,21 @@ pub(crate) async fn update_page(
102103 Ok ( Html ( template. render ( ) ?) )
103104}
104105
106+ // JSON handlers.
107+
108+ /// Returns full event details in JSON format.
109+ #[ instrument( skip_all, err) ]
110+ pub ( crate ) async fn details (
111+ CommunityId ( community_id) : CommunityId ,
112+ SelectedGroupId ( group_id) : SelectedGroupId ,
113+ State ( db) : State < DynDB > ,
114+ Path ( event_id) : Path < Uuid > ,
115+ ) -> Result < impl IntoResponse , HandlerError > {
116+ let event = db. get_event_full ( community_id, group_id, event_id) . await ?;
117+
118+ Ok ( Json ( event) . into_response ( ) )
119+ }
120+
105121// Actions handlers.
106122
107123/// Adds a new event to the database.
@@ -343,7 +359,7 @@ mod tests {
343359 } ,
344360 } ;
345361 use axum_login:: tower_sessions:: session;
346- use serde_json:: from_value;
362+ use serde_json:: { from_slice , from_value, to_value } ;
347363 use tower:: ServiceExt ;
348364 use uuid:: Uuid ;
349365
@@ -353,7 +369,7 @@ mod tests {
353369 router:: CACHE_CONTROL_NO_CACHE ,
354370 services:: notifications:: { MockNotificationsManager , NotificationKind } ,
355371 templates:: notifications:: { EventCanceled , EventPublished , EventRescheduled } ,
356- types:: event:: EventSummary ,
372+ types:: event:: { EventFull , EventSummary } ,
357373 } ;
358374
359375 #[ tokio:: test]
@@ -500,6 +516,7 @@ mod tests {
500516 let auth_hash = "hash" . to_string ( ) ;
501517 let session_record = sample_session_record ( session_id, user_id, & auth_hash, Some ( group_id) ) ;
502518 let event_full = sample_event_full ( event_id, group_id) ;
519+ let event_full_db = event_full. clone ( ) ;
503520 let category = sample_event_category ( ) ;
504521 let kind = sample_event_kind_summary ( ) ;
505522 let session_kind = sample_session_kind_summary ( ) ;
@@ -523,7 +540,7 @@ mod tests {
523540 db. expect_get_event_full ( )
524541 . times ( 1 )
525542 . withf ( move |cid, gid, eid| * cid == community_id && * gid == group_id && * eid == event_id)
526- . returning ( move |_, _, _| Ok ( event_full . clone ( ) ) ) ;
543+ . returning ( move |_, _, _| Ok ( event_full_db . clone ( ) ) ) ;
527544 db. expect_list_event_categories ( )
528545 . times ( 1 )
529546 . withf ( move |cid| * cid == community_id)
@@ -571,6 +588,64 @@ mod tests {
571588 assert ! ( !bytes. is_empty( ) ) ;
572589 }
573590
591+ #[ tokio:: test]
592+ async fn test_details_success ( ) {
593+ // Setup identifiers and data structures
594+ let community_id = Uuid :: new_v4 ( ) ;
595+ let event_id = Uuid :: new_v4 ( ) ;
596+ let group_id = Uuid :: new_v4 ( ) ;
597+ let session_id = session:: Id :: default ( ) ;
598+ let user_id = Uuid :: new_v4 ( ) ;
599+ let auth_hash = "hash" . to_string ( ) ;
600+ let session_record = sample_session_record ( session_id, user_id, & auth_hash, Some ( group_id) ) ;
601+ let event_full = sample_event_full ( event_id, group_id) ;
602+ let event_full_db = event_full. clone ( ) ;
603+
604+ // Setup database mock
605+ let mut db = MockDB :: new ( ) ;
606+ db. expect_get_session ( )
607+ . times ( 1 )
608+ . withf ( move |id| * id == session_id)
609+ . returning ( move |_| Ok ( Some ( session_record. clone ( ) ) ) ) ;
610+ db. expect_get_user_by_id ( )
611+ . times ( 1 )
612+ . withf ( move |id| * id == user_id)
613+ . returning ( move |_| Ok ( Some ( sample_auth_user ( user_id, & auth_hash) ) ) ) ;
614+ db. expect_get_community_id ( )
615+ . times ( 1 )
616+ . withf ( |host| host == "example.test" )
617+ . returning ( move |_| Ok ( Some ( community_id) ) ) ;
618+ db. expect_get_event_full ( )
619+ . times ( 1 )
620+ . withf ( move |cid, gid, eid| * cid == community_id && * gid == group_id && * eid == event_id)
621+ . returning ( move |_, _, _| Ok ( event_full_db. clone ( ) ) ) ;
622+
623+ // Setup notifications manager mock
624+ let nm = MockNotificationsManager :: new ( ) ;
625+
626+ // Setup router and send request
627+ let router = setup_test_router ( db, nm) . await ;
628+ let request = Request :: builder ( )
629+ . method ( "GET" )
630+ . uri ( format ! ( "/dashboard/group/events/{event_id}/details" ) )
631+ . header ( HOST , "example.test" )
632+ . header ( COOKIE , format ! ( "id={session_id}" ) )
633+ . body ( Body :: empty ( ) )
634+ . unwrap ( ) ;
635+ let response = router. oneshot ( request) . await . unwrap ( ) ;
636+ let ( parts, body) = response. into_parts ( ) ;
637+ let bytes = to_bytes ( body, usize:: MAX ) . await . unwrap ( ) ;
638+ let payload: EventFull = from_slice ( & bytes) . unwrap ( ) ;
639+
640+ // Check response matches expectations
641+ assert_eq ! ( parts. status, StatusCode :: OK ) ;
642+ assert_eq ! (
643+ parts. headers. get( CONTENT_TYPE ) . unwrap( ) ,
644+ & HeaderValue :: from_static( "application/json" ) ,
645+ ) ;
646+ assert_eq ! ( to_value( payload) . unwrap( ) , to_value( event_full) . unwrap( ) ) ;
647+ }
648+
574649 #[ tokio:: test]
575650 async fn test_add_success ( ) {
576651 // Setup identifiers and data structures
0 commit comments