1
1
use crate :: authentication:: UserId ;
2
2
use crate :: domain:: SubscriberEmail ;
3
3
use crate :: email_client:: EmailClient ;
4
- use crate :: utils:: { e500, see_other} ;
4
+ use crate :: idempotency:: { get_saved_response, save_response} ;
5
+ use crate :: idempotency:: IdempotencyKey ;
6
+ use crate :: utils:: { e400, e500, see_other} ;
5
7
use actix_web:: web:: ReqData ;
6
8
use actix_web:: { web, HttpResponse } ;
7
9
use actix_web_flash_messages:: FlashMessage ;
8
10
use anyhow:: Context ;
9
11
use sqlx:: PgPool ;
10
12
11
13
#[ derive( serde:: Deserialize ) ]
12
- pub struct BodyData {
14
+ pub struct FormData {
13
15
title : String ,
14
16
text_content : String ,
15
17
html_content : String ,
18
+ idempotency_key : String ,
16
19
}
17
20
18
21
#[ tracing:: instrument(
19
22
name = "Publish a newsletter issue" ,
20
- skip( body , pool, email_client, user_id) ,
23
+ skip( form , pool, email_client, user_id) ,
21
24
fields( user_id = %* user_id)
22
25
) ]
23
26
pub async fn publish_newsletter (
24
- body : web:: Form < BodyData > ,
27
+ form : web:: Form < FormData > ,
25
28
pool : web:: Data < PgPool > ,
26
29
email_client : web:: Data < EmailClient > ,
27
30
user_id : ReqData < UserId > ,
28
31
) -> Result < HttpResponse , actix_web:: Error > {
32
+ let user_id = user_id. into_inner ( ) ;
33
+ let FormData {
34
+ title,
35
+ text_content,
36
+ html_content,
37
+ idempotency_key,
38
+ } = form. 0 ;
39
+ let idempotency_key: IdempotencyKey = idempotency_key. try_into ( ) . map_err ( e400) ?;
40
+ if let Some ( save_response) = get_saved_response ( & pool, & idempotency_key, * user_id)
41
+ . await
42
+ . map_err ( e500) ?
43
+ {
44
+ return Ok ( save_response) ;
45
+ }
29
46
let subscribers = get_confirmed_subscribers ( & pool) . await . map_err ( e500) ?;
30
47
for subscriber in subscribers {
31
48
match subscriber {
32
49
Ok ( subscriber) => {
33
50
email_client
34
- . send_email (
35
- & subscriber. email ,
36
- & body. title ,
37
- & body. html_content ,
38
- & body. text_content ,
39
- )
51
+ . send_email ( & subscriber. email , & title, & html_content, & text_content)
40
52
. await
41
53
. with_context ( || {
42
54
format ! ( "Failed to send newsletter issue to {}" , subscriber. email)
@@ -55,7 +67,11 @@ pub async fn publish_newsletter(
55
67
}
56
68
}
57
69
FlashMessage :: info ( "The newsletter issue has been published!" ) . send ( ) ;
58
- Ok ( see_other ( "/admin/newsletters" ) )
70
+ let response = see_other ( "/admin/newsletters" ) ;
71
+ let response = save_response ( & pool, & idempotency_key, * user_id, response)
72
+ . await
73
+ . map_err ( e500) ?;
74
+ Ok ( response)
59
75
}
60
76
61
77
struct ConfirmedSubscriber {
0 commit comments