11use crate :: coaching_sessions:: Model ;
2- use crate :: error:: { DomainErrorKind , Error , ExternalErrorKind , InternalErrorKind } ;
3- use crate :: gateway:: tiptap:: client as tiptap_client ;
2+ use crate :: error:: { DomainErrorKind , Error , InternalErrorKind } ;
3+ use crate :: gateway:: tiptap:: TiptapDocument ;
44use crate :: Id ;
5- use chrono:: { DurationRound , TimeDelta } ;
5+ use chrono:: { DurationRound , NaiveDateTime , TimeDelta } ;
66use entity_api:: {
77 coaching_relationship, coaching_session, coaching_sessions, mutate, organization, query,
88 query:: IntoQueryFilterMap ,
99} ;
1010use log:: * ;
1111use sea_orm:: { DatabaseConnection , IntoActiveModel } ;
12- use serde_json:: json;
1312use service:: config:: Config ;
1413
1514pub use entity_api:: coaching_session:: { find_by_id, find_by_id_with_coaching_relationship} ;
1615
16+ #[ derive( Debug , Clone ) ]
17+ struct SessionDate ( NaiveDateTime ) ;
18+
19+ impl SessionDate {
20+ fn new ( date : NaiveDateTime ) -> Result < Self , Error > {
21+ let truncated = date. duration_trunc ( TimeDelta :: minutes ( 1 ) ) . map_err ( |err| {
22+ warn ! ( "Failed to truncate date_time: {:?}" , err) ;
23+ Error {
24+ source : Some ( Box :: new ( err) ) ,
25+ error_kind : DomainErrorKind :: Internal ( InternalErrorKind :: Other ) ,
26+ }
27+ } ) ?;
28+ Ok ( Self ( truncated) )
29+ }
30+
31+ fn into_inner ( self ) -> NaiveDateTime {
32+ self . 0
33+ }
34+ }
35+
1736pub async fn create (
1837 db : & DatabaseConnection ,
1938 config : & Config ,
@@ -23,68 +42,20 @@ pub async fn create(
2342 coaching_relationship:: find_by_id ( db, coaching_session_model. coaching_relationship_id )
2443 . await ?;
2544 let organization = organization:: find_by_id ( db, coaching_relationship. organization_id ) . await ?;
26- // Remove seconds because all coaching_sessions will be scheduled by the minute
27- // TODO: we might consider codifying this in the type system at some point.
28- let date_time = coaching_session_model
29- . date
30- . duration_trunc ( TimeDelta :: minutes ( 1 ) )
31- . map_err ( |err| {
32- warn ! ( "Failed to truncate date_time: {:?}" , err) ;
33- Error {
34- source : Some ( Box :: new ( err) ) ,
35- error_kind : DomainErrorKind :: Internal ( InternalErrorKind :: Other ) ,
36- }
37- } ) ?;
38- coaching_session_model. date = date_time;
39- let document_name = format ! (
40- "{}.{}.{}-v0" ,
41- organization. slug,
42- coaching_relationship. slug,
43- Id :: new_v4( )
44- ) ;
45+
46+ coaching_session_model. date = SessionDate :: new ( coaching_session_model. date ) ?. into_inner ( ) ;
47+
48+ let document_name = generate_document_name ( & organization. slug , & coaching_relationship. slug ) ;
4549 info ! (
4650 "Attempting to create Tiptap document with name: {}" ,
4751 document_name
4852 ) ;
4953 coaching_session_model. collab_document_name = Some ( document_name. clone ( ) ) ;
50- let tiptap_url = config. tiptap_url ( ) . ok_or_else ( || {
51- warn ! ( "Failed to get Tiptap URL from config" ) ;
52- Error {
53- source : None ,
54- error_kind : DomainErrorKind :: Internal ( InternalErrorKind :: Other ) ,
55- }
56- } ) ?;
57- let full_url = format ! ( "{}/api/documents/{}?format=json" , tiptap_url, document_name) ;
58- let client = tiptap_client ( config) . await ?;
59-
60- let request = client
61- . post ( full_url)
62- . json ( & json ! ( { "type" : "doc" , "content" : [ ] } ) ) ;
63- let response = match request. send ( ) . await {
64- Ok ( response) => {
65- info ! ( "Tiptap response: {:?}" , response) ;
66- response
67- }
68- Err ( e) => {
69- warn ! ( "Failed to send request: {:?}" , e) ;
70- return Err ( e. into ( ) ) ;
71- }
72- } ;
73-
74- // Tiptap's API will return a 200 for successful creation of a new document
75- // and will return a 409 if the document already exists. We consider both "successful".
76- if response. status ( ) . is_success ( ) || response. status ( ) . as_u16 ( ) == 409 {
77- Ok ( coaching_session:: create ( db, coaching_session_model) . await ?)
78- } else {
79- warn ! (
80- "Failed to create Tiptap document: {}" ,
81- response. text( ) . await ?
82- ) ;
83- Err ( Error {
84- source : None ,
85- error_kind : DomainErrorKind :: External ( ExternalErrorKind :: Network ) ,
86- } )
87- }
54+
55+ let tiptap = TiptapDocument :: new ( config) . await ?;
56+ tiptap. create ( & document_name) . await ?;
57+
58+ Ok ( coaching_session:: create ( db, coaching_session_model) . await ?)
8859}
8960
9061pub async fn find_by (
@@ -127,41 +98,18 @@ pub async fn delete(db: &DatabaseConnection, config: &Config, id: Id) -> Result<
12798 }
12899 } ) ?;
129100
130- let tiptap_url = config. tiptap_url ( ) . ok_or_else ( || {
131- warn ! ( "Failed to get Tiptap URL from config" ) ;
132- Error {
133- source : None ,
134- error_kind : DomainErrorKind :: Internal ( InternalErrorKind :: Other ) ,
135- }
136- } ) ?;
137- let full_url = format ! ( "{}/api/documents/{}?format=json" , tiptap_url, document_name) ;
138- let client = tiptap_client ( config) . await ?;
139-
140- let request = client. delete ( full_url) ;
141- let response = match request. send ( ) . await {
142- Ok ( response) => {
143- info ! ( "Tiptap response: {:?}" , response) ;
144- response
145- }
146- Err ( e) => {
147- warn ! ( "Failed to send request: {:?}" , e) ;
148- return Err ( e. into ( ) ) ;
149- }
150- } ;
151-
152- // Tiptap's API will return a 204 for successful deletion of a document
153- // and will return a 404 if the document does not exist.
154- let status = response. status ( ) ;
155- if status. is_success ( ) {
156- Ok ( coaching_session:: delete ( db, id) . await ?)
157- } else {
158- warn ! (
159- "Failed to delete Tiptap document: {}, with status: {}" ,
160- document_name, status
161- ) ;
162- Err ( Error {
163- source : None ,
164- error_kind : DomainErrorKind :: External ( ExternalErrorKind :: Network ) ,
165- } )
166- }
101+ let tiptap = TiptapDocument :: new ( config) . await ?;
102+ tiptap. delete ( & document_name) . await ?;
103+
104+ coaching_session:: delete ( db, id) . await ?;
105+ Ok ( ( ) )
106+ }
107+
108+ fn generate_document_name ( organization_slug : & str , relationship_slug : & str ) -> String {
109+ format ! (
110+ "{}.{}.{}-v0" ,
111+ organization_slug,
112+ relationship_slug,
113+ Id :: new_v4( )
114+ )
167115}
0 commit comments