1
+ use crate :: email:: EmailMessage ;
1
2
use crate :: models:: ApiToken ;
2
3
use crate :: schema:: api_tokens;
3
4
use crate :: views:: EncodableApiTokenWithToken ;
5
+ use anyhow:: Context ;
4
6
5
7
use crate :: app:: AppState ;
6
8
use crate :: auth:: AuthCheck ;
@@ -20,7 +22,9 @@ use diesel::sql_types::Timestamptz;
20
22
use diesel_async:: RunQueryDsl ;
21
23
use http:: StatusCode ;
22
24
use http:: request:: Parts ;
25
+ use minijinja:: context;
23
26
use secrecy:: ExposeSecret ;
27
+ use serde:: Serialize ;
24
28
25
29
#[ derive( Deserialize ) ]
26
30
pub struct GetParams {
@@ -171,17 +175,16 @@ pub async fn create_api_token(
171
175
. build ( ) ;
172
176
173
177
if let Some ( recipient) = recipient {
174
- let email = NewTokenEmail {
175
- token_name : & new. api_token . name ,
176
- user_name : & user. gh_login ,
177
- domain : & app. emails . domain ,
178
+ let context = context ! {
179
+ token_name => & new. api_token. name,
180
+ user_name => & user. gh_login,
181
+ domain => app. emails. domain,
178
182
} ;
179
183
180
184
// At this point the token has been created so failing to send the
181
185
// email should not cause an error response to be returned to the
182
186
// caller.
183
- let email_ret = app. emails . send ( & recipient, email) . await ;
184
- if let Err ( e) = email_ret {
187
+ if let Err ( e) = send_creation_email ( & app. emails , & recipient, context) . await {
185
188
error ! ( "Failed to send token creation email: {e}" )
186
189
}
187
190
}
@@ -286,28 +289,13 @@ pub async fn revoke_current_api_token(app: AppState, req: Parts) -> AppResult<Re
286
289
Ok ( StatusCode :: NO_CONTENT . into_response ( ) )
287
290
}
288
291
289
- struct NewTokenEmail < ' a > {
290
- token_name : & ' a str ,
291
- user_name : & ' a str ,
292
- domain : & ' a str ,
293
- }
294
-
295
- impl crate :: email:: Email for NewTokenEmail < ' _ > {
296
- fn subject ( & self ) -> String {
297
- format ! ( "crates.io: New API token \" {}\" created" , self . token_name)
298
- }
299
-
300
- fn body ( & self ) -> String {
301
- format ! (
302
- "\
303
- Hello {user_name}!
304
-
305
- A new API token with the name \" {token_name}\" was recently added to your {domain} account.
306
-
307
- If this wasn't you, you should revoke the token immediately: https://{domain}/settings/tokens" ,
308
- token_name = self . token_name,
309
- user_name = self . user_name,
310
- domain = self . domain,
311
- )
312
- }
292
+ async fn send_creation_email (
293
+ emails : & crate :: Emails ,
294
+ recipient : & str ,
295
+ context : impl Serialize ,
296
+ ) -> anyhow:: Result < ( ) > {
297
+ let email = EmailMessage :: from_template ( "new_token" , context) ;
298
+ let email = email. context ( "Failed to render email template" ) ?;
299
+ let result = emails. send ( recipient, email) . await ;
300
+ result. context ( "Failed to send email" )
313
301
}
0 commit comments