1
1
use 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 ;
4
4
use crate :: Id ;
5
- use chrono:: { DurationRound , TimeDelta } ;
5
+ use chrono:: { DurationRound , NaiveDateTime , TimeDelta } ;
6
6
use entity_api:: {
7
7
coaching_relationship, coaching_session, coaching_sessions, mutate, organization, query,
8
8
query:: IntoQueryFilterMap ,
9
9
} ;
10
10
use log:: * ;
11
11
use sea_orm:: { DatabaseConnection , IntoActiveModel } ;
12
- use serde_json:: json;
13
12
use service:: config:: Config ;
14
13
15
14
pub use entity_api:: coaching_session:: { find_by_id, find_by_id_with_coaching_relationship} ;
16
15
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
+
17
36
pub async fn create (
18
37
db : & DatabaseConnection ,
19
38
config : & Config ,
@@ -23,69 +42,20 @@ pub async fn create(
23
42
coaching_relationship:: find_by_id ( db, coaching_session_model. coaching_relationship_id )
24
43
. await ?;
25
44
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 ) ;
45
49
info ! (
46
50
"Attempting to create Tiptap document with name: {}" ,
47
51
document_name
48
52
) ;
49
53
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
- // TODO: Save document_name to record
78
- Ok ( coaching_session:: create ( db, coaching_session_model) . await ?)
79
- } else {
80
- warn ! (
81
- "Failed to create Tiptap document: {}" ,
82
- response. text( ) . await ?
83
- ) ;
84
- Err ( Error {
85
- source : None ,
86
- error_kind : DomainErrorKind :: External ( ExternalErrorKind :: Network ) ,
87
- } )
88
- }
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 ?)
89
59
}
90
60
91
61
pub async fn find_by (
@@ -117,3 +87,29 @@ pub async fn update(
117
87
. await ?,
118
88
)
119
89
}
90
+
91
+ pub async fn delete ( db : & DatabaseConnection , config : & Config , id : Id ) -> Result < ( ) , Error > {
92
+ let coaching_session = find_by_id ( db, id) . await ?;
93
+ let document_name = coaching_session. collab_document_name . ok_or_else ( || {
94
+ warn ! ( "Failed to get document name from coaching session" ) ;
95
+ Error {
96
+ source : None ,
97
+ error_kind : DomainErrorKind :: Internal ( InternalErrorKind :: Other ) ,
98
+ }
99
+ } ) ?;
100
+
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
+ )
115
+ }
0 commit comments