1use headless_lms_models::{
2 email_templates::{EmailTemplateNew, EmailTemplateType, insert_email_template},
3 user_passwords::insert_password_reset_token,
4};
5use serde_json::json;
6use sqlx::{Pool, Postgres};
7use uuid::Uuid;
8
9use super::seed_users::SeedUsersResult;
10
11pub async fn seed_generic_emails(
12 db_pool: Pool<Postgres>,
13 seed_users_result: SeedUsersResult,
14) -> anyhow::Result<()> {
15 info!("inserting password reset emails");
16
17 let mut conn = db_pool.acquire().await?;
18
19 let english_subject = Some("Reset password request");
20 let english_body = json!([
21 {
22 "name": "core/paragraph",
23 "isValid": true,
24 "clientId": "95acea49-1c92-4d54-9854-707e1bfee010",
25 "attributes": {
26 "content": "Hello, it seems you requested a password reset.",
27 "dropCap": false
28 },
29 "innerBlocks": []
30 },
31 {
32 "name": "core/paragraph",
33 "isValid": true,
34 "clientId": "ceac591d-b291-40b2-8da7-6f437a6a8fce",
35 "attributes": {
36 "content": "Click the button below to choose a new password.",
37 "dropCap": false
38 },
39 "innerBlocks": []
40 },
41 {
42 "name": "core/buttons",
43 "isValid": true,
44 "clientId": "e1000000-0000-0000-0000-000000000001",
45 "attributes": {},
46 "innerBlocks": [
47 {
48 "name": "core/button",
49 "isValid": true,
50 "clientId": "e1000000-0000-0000-0000-000000000002",
51 "attributes": {
52 "text": "Reset password",
53 "url": "{{RESET_LINK}}"
54 },
55 "innerBlocks": []
56 }
57 ]
58 },
59 {
60 "name": "core/paragraph",
61 "isValid": true,
62 "clientId": "6a4165a1-38e1-4a17-b364-5f265afc7d23",
63 "attributes": {
64 "content": "If you did not request a password reset, please ignore this message.",
65 "dropCap": false
66 },
67 "innerBlocks": []
68 }
69 ]);
70
71 let english_template = EmailTemplateNew {
72 template_type: EmailTemplateType::ResetPasswordEmail,
73 language: Some("en".to_string()),
74 content: Some(english_body),
75 subject: english_subject.map(|s| s.to_string()),
76 };
77
78 insert_email_template(&mut conn, None, english_template, english_subject).await?;
79
80 let finnish_subject = Some("Salasanan palautuspyyntö");
81 let finnish_body = json!([
82 {
83 "name": "core/paragraph",
84 "isValid": true,
85 "clientId": "a9de49ff-919f-44b4-a085-9210ce0da94b",
86 "attributes": {
87 "content": "Hei, olet pyytänyt salasanan palautusta.",
88 "dropCap": false
89 },
90 "innerBlocks": []
91 },
92 {
93 "name": "core/paragraph",
94 "isValid": true,
95 "clientId": "c145bae4-9ff5-4194-8913-50f8900c20c8",
96 "attributes": {
97 "content": "Valitse uusi salasana alla olevasta painikkeesta.",
98 "dropCap": false
99 },
100 "innerBlocks": []
101 },
102 {
103 "name": "core/buttons",
104 "isValid": true,
105 "clientId": "e2000000-0000-0000-0000-000000000001",
106 "attributes": {},
107 "innerBlocks": [
108 {
109 "name": "core/button",
110 "isValid": true,
111 "clientId": "e2000000-0000-0000-0000-000000000002",
112 "attributes": {
113 "text": "Palauta salasana",
114 "url": "{{RESET_LINK}}"
115 },
116 "innerBlocks": []
117 }
118 ]
119 },
120 {
121 "name": "core/paragraph",
122 "isValid": true,
123 "clientId": "ebd0d430-0ae3-4b85-9e8e-96481660ded4",
124 "attributes": {
125 "content": "Jos et pyytänyt salasanan palautusta, voit jättää tämän viestin huomiotta.",
126 "dropCap": false
127 },
128 "innerBlocks": []
129 }
130 ]);
131
132 let finnish_template = EmailTemplateNew {
133 template_type: EmailTemplateType::ResetPasswordEmail,
134 language: Some("fi".to_string()),
135 content: Some(finnish_body),
136 subject: finnish_subject.map(|s| s.to_string()),
137 };
138
139 insert_email_template(&mut conn, None, finnish_template, finnish_subject).await?;
140
141 info!("inserting password reset token for user");
142 let SeedUsersResult { sign_up_user, .. } = seed_users_result;
143 insert_password_reset_token(
144 &mut conn,
145 sign_up_user,
146 Uuid::parse_str("5a831370-6b7e-4ece-b962-6bc31c28fe53")?,
147 )
148 .await?;
149
150 info!("inserting delete account email");
151
152 let delete_subject = Some("Account deletion code");
153 let delete_body = json!([
154 {
155 "name": "core/paragraph",
156 "isValid": true,
157 "clientId": "11111111-1111-1111-1111-111111111111",
158 "attributes": {
159 "content": "Hello, it seems you requested a code for deleting your account",
160 "dropCap": false
161 },
162 "innerBlocks": []
163 },
164 {
165 "name": "core/paragraph",
166 "isValid": true,
167 "clientId": "22222222-2222-2222-2222-222222222222",
168 "attributes": {
169 "content": "Use this verification code to delete your account:",
170 "dropCap": false
171 },
172 "innerBlocks": []
173 },
174 {
175 "name": "moocfi/email-one-time-code",
176 "isValid": true,
177 "clientId": "e3000000-0000-0000-0000-000000000001",
178 "attributes": {
179 "code": "{{CODE}}"
180 },
181 "innerBlocks": []
182 },
183 {
184 "name": "core/paragraph",
185 "isValid": true,
186 "clientId": "33333333-3333-3333-3333-333333333333",
187 "attributes": {
188 "content": "If you did not request a code, please ignore this message.",
189 "dropCap": false
190 },
191 "innerBlocks": []
192 }
193 ]);
194
195 let delete_template = EmailTemplateNew {
196 template_type: EmailTemplateType::DeleteUserEmail,
197 language: Some("en".to_string()),
198 content: Some(delete_body),
199 subject: delete_subject.map(|s| s.to_string()),
200 };
201
202 insert_email_template(&mut conn, None, delete_template, delete_subject).await?;
203
204 info!("inserting confirm email code email");
205
206 let confirm_subject = Some("Email verification code");
207 let confirm_body = json!([
208 {
209 "name": "core/paragraph",
210 "isValid": true,
211 "clientId": "44444444-4444-4444-4444-444444444444",
212 "attributes": {
213 "content": "Hello, please use this code to verify your email address",
214 "dropCap": false
215 },
216 "innerBlocks": []
217 },
218 {
219 "name": "core/paragraph",
220 "isValid": true,
221 "clientId": "55555555-5555-5555-5555-555555555555",
222 "attributes": {
223 "content": "Your verification code is:",
224 "dropCap": false
225 },
226 "innerBlocks": []
227 },
228 {
229 "name": "moocfi/email-one-time-code",
230 "isValid": true,
231 "clientId": "e3000000-0000-0000-0000-000000000002",
232 "attributes": {
233 "code": "{{CODE}}"
234 },
235 "innerBlocks": []
236 },
237 {
238 "name": "core/paragraph",
239 "isValid": true,
240 "clientId": "66666666-6666-6666-6666-666666666666",
241 "attributes": {
242 "content": "If you did not request this code, please ignore this message.",
243 "dropCap": false
244 },
245 "innerBlocks": []
246 }
247 ]);
248
249 let confirm_template = EmailTemplateNew {
250 template_type: EmailTemplateType::ConfirmEmailCode,
251 language: Some("en".to_string()),
252 content: Some(confirm_body),
253 subject: confirm_subject.map(|s| s.to_string()),
254 };
255
256 insert_email_template(&mut conn, None, confirm_template, confirm_subject).await?;
257
258 seed_email_ownership_verification_templates(&mut conn).await?;
259 seed_account_linking_templates(&mut conn).await?;
260 seed_credit_registration_status_templates(&mut conn).await?;
261
262 Ok(())
263}
264
265async fn seed_account_linking_templates(conn: &mut sqlx::PgConnection) -> anyhow::Result<()> {
270 info!("inserting credit registration account linking emails");
271
272 let english_subject =
273 Some("Link your University of Helsinki student number to register your credits");
274 let english_body = json!([
275 {
276 "name": "core/paragraph",
277 "isValid": true,
278 "clientId": "d1000000-0000-0000-0000-000000000001",
279 "attributes": {
280 "content": "Hello, we can see your enrolment on {{COURSE_NAME}}. To register your completion in Sisu, we need to link your University of Helsinki student number {{STUDENT_NUMBER}} to your account on courses.mooc.fi.",
281 "dropCap": false
282 },
283 "innerBlocks": []
284 },
285 {
286 "name": "core/paragraph",
287 "isValid": true,
288 "clientId": "d1000000-0000-0000-0000-000000000002",
289 "attributes": {
290 "content": "Log in to courses.mooc.fi with the account you use for the course, then press the button below.",
291 "dropCap": false
292 },
293 "innerBlocks": []
294 },
295 {
296 "name": "core/buttons",
297 "isValid": true,
298 "clientId": "e4000000-0000-0000-0000-000000000001",
299 "attributes": {},
300 "innerBlocks": [
301 {
302 "name": "core/button",
303 "isValid": true,
304 "clientId": "e4000000-0000-0000-0000-000000000002",
305 "attributes": {
306 "text": "Link student number",
307 "url": "{{LINK}}"
308 },
309 "innerBlocks": []
310 }
311 ]
312 },
313 {
314 "name": "core/paragraph",
315 "isValid": true,
316 "clientId": "d1000000-0000-0000-0000-000000000003",
317 "attributes": {
318 "content": "The link works once, for 14 days. It is fine if this email address is different from the one you use on courses.mooc.fi.",
319 "dropCap": false
320 },
321 "innerBlocks": []
322 },
323 {
324 "name": "core/paragraph",
325 "isValid": true,
326 "clientId": "d1000000-0000-0000-0000-000000000004",
327 "attributes": {
328 "content": "You got this email because you are enrolled on {{COURSE_NAME}} at the University of Helsinki. If that is not you, ignore this email.",
329 "dropCap": false
330 },
331 "innerBlocks": []
332 },
333 {
334 "name": "core/paragraph",
335 "isValid": true,
336 "clientId": "d1000000-0000-0000-0000-000000000005",
337 "attributes": {
338 "content": "Best regards,<br>MOOC.fi",
339 "dropCap": false
340 },
341 "innerBlocks": []
342 }
343 ]);
344
345 insert_email_template(
346 conn,
347 None,
348 EmailTemplateNew {
349 template_type: EmailTemplateType::CreditRegistrationAccountLinking,
350 language: Some("en".to_string()),
351 content: Some(english_body),
352 subject: english_subject.map(|s| s.to_string()),
353 },
354 english_subject,
355 )
356 .await?;
357
358 let finnish_subject =
359 Some("Liitä Helsingin yliopiston opiskelijanumerosi, jotta voimme kirjata opintopisteesi");
360 let finnish_body = json!([
361 {
362 "name": "core/paragraph",
363 "isValid": true,
364 "clientId": "d2000000-0000-0000-0000-000000000001",
365 "attributes": {
366 "content": "Hei, näemme ilmoittautumisesi kurssille {{COURSE_NAME}}. Jotta voimme kirjata suorituksesi Sisuun, meidän pitää liittää Helsingin yliopiston opiskelijanumerosi {{STUDENT_NUMBER}} courses.mooc.fi-tiliisi.",
367 "dropCap": false
368 },
369 "innerBlocks": []
370 },
371 {
372 "name": "core/paragraph",
373 "isValid": true,
374 "clientId": "d2000000-0000-0000-0000-000000000002",
375 "attributes": {
376 "content": "Kirjaudu courses.mooc.fi-palveluun sillä tilillä, jolla teet kurssia, ja paina sitten alla olevaa painiketta.",
377 "dropCap": false
378 },
379 "innerBlocks": []
380 },
381 {
382 "name": "core/buttons",
383 "isValid": true,
384 "clientId": "e5000000-0000-0000-0000-000000000001",
385 "attributes": {},
386 "innerBlocks": [
387 {
388 "name": "core/button",
389 "isValid": true,
390 "clientId": "e5000000-0000-0000-0000-000000000002",
391 "attributes": {
392 "text": "Liitä opiskelijanumero",
393 "url": "{{LINK}}"
394 },
395 "innerBlocks": []
396 }
397 ]
398 },
399 {
400 "name": "core/paragraph",
401 "isValid": true,
402 "clientId": "d2000000-0000-0000-0000-000000000003",
403 "attributes": {
404 "content": "Linkki toimii kerran, 14 päivän ajan. Ei haittaa, jos tämä sähköpostiosoite on eri kuin courses.mooc.fi:ssä käyttämäsi.",
405 "dropCap": false
406 },
407 "innerBlocks": []
408 },
409 {
410 "name": "core/paragraph",
411 "isValid": true,
412 "clientId": "d2000000-0000-0000-0000-000000000004",
413 "attributes": {
414 "content": "Sait tämän viestin, koska olet ilmoittautunut Helsingin yliopiston kurssille {{COURSE_NAME}}. Jos viesti ei ole sinulle, voit jättää sen huomiotta.",
415 "dropCap": false
416 },
417 "innerBlocks": []
418 },
419 {
420 "name": "core/paragraph",
421 "isValid": true,
422 "clientId": "d2000000-0000-0000-0000-000000000005",
423 "attributes": {
424 "content": "Terveisin,<br>MOOC.fi",
425 "dropCap": false
426 },
427 "innerBlocks": []
428 }
429 ]);
430
431 insert_email_template(
432 conn,
433 None,
434 EmailTemplateNew {
435 template_type: EmailTemplateType::CreditRegistrationAccountLinking,
436 language: Some("fi".to_string()),
437 content: Some(finnish_body),
438 subject: finnish_subject.map(|s| s.to_string()),
439 },
440 finnish_subject,
441 )
442 .await?;
443
444 Ok(())
445}
446
447async fn seed_email_ownership_verification_templates(
453 conn: &mut sqlx::PgConnection,
454) -> anyhow::Result<()> {
455 info!("inserting email address verification emails");
456
457 let english_subject = Some("Confirm your email address");
458 let english_body = json!([
459 {
460 "name": "core/paragraph",
461 "isValid": true,
462 "clientId": "77777777-7777-7777-7777-777777777777",
463 "attributes": {
464 "content": "Hello, please use this code to confirm the email address on your account.",
465 "dropCap": false
466 },
467 "innerBlocks": []
468 },
469 {
470 "name": "core/paragraph",
471 "isValid": true,
472 "clientId": "88888888-8888-8888-8888-888888888888",
473 "attributes": {
474 "content": "Your confirmation code is:",
475 "dropCap": false
476 },
477 "innerBlocks": []
478 },
479 {
480 "name": "moocfi/email-one-time-code",
481 "isValid": true,
482 "clientId": "e3000000-0000-0000-0000-000000000003",
483 "attributes": {
484 "code": "{{CODE}}"
485 },
486 "innerBlocks": []
487 },
488 {
489 "name": "core/paragraph",
490 "isValid": true,
491 "clientId": "99999999-9999-9999-9999-999999999999",
492 "attributes": {
493 "content": "If you did not request this, you can ignore this message. Nothing changes until the code is entered.",
494 "dropCap": false
495 },
496 "innerBlocks": []
497 }
498 ]);
499
500 insert_email_template(
501 conn,
502 None,
503 EmailTemplateNew {
504 template_type: EmailTemplateType::VerifyEmailAddress,
505 language: Some("en".to_string()),
506 content: Some(english_body),
507 subject: english_subject.map(|s| s.to_string()),
508 },
509 english_subject,
510 )
511 .await?;
512
513 let finnish_subject = Some("Vahvista sähköpostiosoitteesi");
514 let finnish_body = json!([
515 {
516 "name": "core/paragraph",
517 "isValid": true,
518 "clientId": "aaaaaaaa-7777-7777-7777-777777777777",
519 "attributes": {
520 "content": "Hei, vahvista tilisi sähköpostiosoite tällä koodilla.",
521 "dropCap": false
522 },
523 "innerBlocks": []
524 },
525 {
526 "name": "core/paragraph",
527 "isValid": true,
528 "clientId": "bbbbbbbb-8888-8888-8888-888888888888",
529 "attributes": {
530 "content": "Vahvistuskoodisi on:",
531 "dropCap": false
532 },
533 "innerBlocks": []
534 },
535 {
536 "name": "moocfi/email-one-time-code",
537 "isValid": true,
538 "clientId": "e3000000-0000-0000-0000-000000000004",
539 "attributes": {
540 "code": "{{CODE}}"
541 },
542 "innerBlocks": []
543 },
544 {
545 "name": "core/paragraph",
546 "isValid": true,
547 "clientId": "cccccccc-9999-9999-9999-999999999999",
548 "attributes": {
549 "content": "Jos et pyytänyt tätä, voit jättää viestin huomiotta. Mikään ei muutu ennen kuin koodi syötetään.",
550 "dropCap": false
551 },
552 "innerBlocks": []
553 }
554 ]);
555
556 insert_email_template(
557 conn,
558 None,
559 EmailTemplateNew {
560 template_type: EmailTemplateType::VerifyEmailAddress,
561 language: Some("fi".to_string()),
562 content: Some(finnish_body),
563 subject: finnish_subject.map(|s| s.to_string()),
564 },
565 finnish_subject,
566 )
567 .await?;
568
569 Ok(())
570}
571
572async fn seed_credit_registration_status_templates(
575 conn: &mut sqlx::PgConnection,
576) -> anyhow::Result<()> {
577 info!("inserting credit registration status emails");
578
579 const BUTTON_AFTER_PARAGRAPH: usize = 2;
580
581 let templates: [(EmailTemplateType, &str, &str, &str, &[&str]); 4] = [
582 (
583 EmailTemplateType::CreditRegistrationActionNeeded,
584 "en",
585 "One more step to get your credits registered",
586 "See how to enrol",
587 &[
588 "Hello, congratulations on completing {{COURSE_NAME}}! You have earned {{CREDITS}} credits.",
589 "To get your completion registered in Sisu, enrol on the course. The button below shows how. If you have already enrolled, you do not need to enrol again.",
590 "After you enrol, we register your completion automatically. If your University of Helsinki student number is not linked yet, we first send a linking email to your email address in Sisu.",
591 "Best regards,<br>MOOC.fi",
592 ],
593 ),
594 (
595 EmailTemplateType::CreditRegistrationActionNeeded,
596 "fi",
597 "Vielä yksi vaihe opintopisteiden kirjaamiseen",
598 "Katso ilmoittautumisohjeet",
599 &[
600 "Hei, onnittelut kurssin {{COURSE_NAME}} suorittamisesta! Olet ansainnut {{CREDITS}} op.",
601 "Jotta suorituksesi voidaan kirjata Sisuun, ilmoittaudu kurssille. Alla olevasta painikkeesta näet, miten. Jos olet jo ilmoittautunut, sinun ei tarvitse ilmoittautua uudelleen.",
602 "Ilmoittautumisen jälkeen kirjaamme suorituksesi automaattisesti. Jos Helsingin yliopiston opiskelijanumeroasi ei ole vielä liitetty, lähetämme ensin liitosviestin Sisussa olevaan sähköpostiosoitteeseesi.",
603 "Terveisin,<br>MOOC.fi",
604 ],
605 ),
606 (
607 EmailTemplateType::CreditRegistrationRegistered,
608 "en",
609 "Your credits have been registered",
610 "See the details",
611 &[
612 "Hello, your completion of {{COURSE_NAME}} ({{CREDITS}} credits) is now registered in Sisu.",
613 "You do not need to do anything else.",
614 "Best regards,<br>MOOC.fi",
615 ],
616 ),
617 (
618 EmailTemplateType::CreditRegistrationRegistered,
619 "fi",
620 "Opintopisteesi on kirjattu",
621 "Katso tiedot",
622 &[
623 "Hei, suorituksesi kurssilta {{COURSE_NAME}} ({{CREDITS}} op) on nyt kirjattu Sisuun.",
624 "Sinun ei tarvitse tehdä muuta.",
625 "Terveisin,<br>MOOC.fi",
626 ],
627 ),
628 ];
629
630 for (template_index, (template_type, language, subject, button_label, paragraphs)) in
631 templates.into_iter().enumerate()
632 {
633 let mut blocks: Vec<_> = paragraphs
634 .iter()
635 .enumerate()
636 .map(|(paragraph_index, content)| {
637 json!({
638 "name": "core/paragraph",
639 "isValid": true,
640 "clientId": format!(
641 "d{}000000-0000-0000-0000-{:012}",
642 template_index + 3,
643 paragraph_index + 1
644 ),
645 "attributes": {
646 "content": content,
647 "dropCap": false
648 },
649 "innerBlocks": []
650 })
651 })
652 .collect();
653 blocks.insert(
654 BUTTON_AFTER_PARAGRAPH,
655 json!({
656 "name": "core/buttons",
657 "isValid": true,
658 "clientId": format!("d{}000000-0000-0000-0000-{:012}", template_index + 3, 100),
659 "attributes": {},
660 "innerBlocks": [{
661 "name": "core/button",
662 "isValid": true,
663 "clientId": format!("d{}000000-0000-0000-0000-{:012}", template_index + 3, 101),
664 "attributes": { "text": button_label, "url": "{{STATUS_LINK}}" },
665 "innerBlocks": []
666 }]
667 }),
668 );
669
670 insert_email_template(
671 conn,
672 None,
673 EmailTemplateNew {
674 template_type,
675 language: Some(language.to_string()),
676 content: Some(json!(blocks)),
677 subject: Some(subject.to_string()),
678 },
679 Some(subject),
680 )
681 .await?;
682 }
683
684 Ok(())
685}