1+ use crate :: email:: EmailMessage ;
12use crate :: models:: ApiToken ;
23use crate :: schema:: api_tokens;
34use crate :: views:: EncodableApiTokenWithToken ;
5+ use anyhow:: Context ;
46
57use crate :: app:: AppState ;
68use crate :: auth:: AuthCheck ;
@@ -20,7 +22,9 @@ use diesel::sql_types::Timestamptz;
2022use diesel_async:: RunQueryDsl ;
2123use http:: StatusCode ;
2224use http:: request:: Parts ;
25+ use minijinja:: context;
2326use secrecy:: ExposeSecret ;
27+ use serde:: Serialize ;
2428
2529#[ derive( Deserialize ) ]
2630pub struct GetParams {
@@ -171,17 +175,16 @@ pub async fn create_api_token(
171175 . build ( ) ;
172176
173177 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,
178182 } ;
179183
180184 // At this point the token has been created so failing to send the
181185 // email should not cause an error response to be returned to the
182186 // 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 {
185188 error ! ( "Failed to send token creation email: {e}" )
186189 }
187190 }
@@ -286,28 +289,13 @@ pub async fn revoke_current_api_token(app: AppState, req: Parts) -> AppResult<Re
286289 Ok ( StatusCode :: NO_CONTENT . into_response ( ) )
287290}
288291
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" )
313301}
0 commit comments