jit_request.go 3.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. package email
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/gravitl/netmaker/logger"
  6. "github.com/gravitl/netmaker/models"
  7. proLogic "github.com/gravitl/netmaker/pro/logic"
  8. "github.com/gravitl/netmaker/schema"
  9. "github.com/gravitl/netmaker/servercfg"
  10. )
  11. // JITRequestMail - mail for notifying admins of JIT access requests
  12. type JITRequestMail struct {
  13. BodyBuilder EmailBodyBuilder
  14. Request *schema.JITRequest
  15. Network models.Network
  16. }
  17. // SendJITRequestEmails - sends email notifications to network admins about JIT requests
  18. func SendJITRequestEmails(request *schema.JITRequest, network models.Network) error {
  19. admins, err := proLogic.GetNetworkAdmins(request.NetworkID)
  20. if err != nil {
  21. return err
  22. }
  23. for _, admin := range admins {
  24. if admin.UserName == "" {
  25. continue
  26. }
  27. // Skip sending email if username is not a valid email address
  28. if !IsValid(admin.UserName) {
  29. logger.Log(2, "skipping JIT request email for admin with non-email username", "admin", admin.UserName)
  30. continue
  31. }
  32. // Create a fresh mail struct per admin to avoid BodyBuilder state accumulation
  33. // (EmailBodyBuilderWithH1HeadlineAndImage mutates internal state on each GetBody call)
  34. mail := JITRequestMail{
  35. BodyBuilder: &EmailBodyBuilderWithH1HeadlineAndImage{},
  36. Request: request,
  37. Network: network,
  38. }
  39. notification := Notification{
  40. RecipientMail: admin.UserName, // Assuming username is email
  41. RecipientName: admin.UserName,
  42. }
  43. if err := GetClient().SendEmail(context.Background(), notification, mail); err != nil {
  44. logger.Log(0, "failed to send JIT request email", "admin", admin.UserName, "error", err.Error())
  45. continue
  46. }
  47. }
  48. return nil
  49. }
  50. // GetSubject - gets the subject of the email
  51. func (mail JITRequestMail) GetSubject(info Notification) string {
  52. return fmt.Sprintf("JIT Access Request: %s requests access to %s", mail.Request.UserName, mail.Network.NetID)
  53. }
  54. // GetBody - gets the body of the email
  55. func (mail JITRequestMail) GetBody(info Notification) string {
  56. dashboardURL := fmt.Sprintf("https://dashboard.%s/networks/%s/jit-requests?jit_req_id=%s", servercfg.GetNmBaseDomain(),
  57. mail.Network.NetID, mail.Request.ID)
  58. if servercfg.DeployedByOperator() {
  59. dashboardURL = fmt.Sprintf("%s/dashboard?tenant_id=%s&network=%s&jit_req_id=%s",
  60. proLogic.GetAccountsUIHost(), servercfg.GetNetmakerTenantID(), mail.Network.NetID, mail.Request.ID)
  61. }
  62. reasonText := mail.Request.Reason
  63. if reasonText == "" {
  64. reasonText = "No reason provided"
  65. }
  66. content := mail.BodyBuilder.
  67. WithHeadline("New JIT Access Request").
  68. WithParagraph(fmt.Sprintf("User <strong>%s</strong> has requested Just-In-Time access to network <strong>%s</strong>.",
  69. mail.Request.UserName, mail.Network.NetID)).
  70. WithParagraph("Request Details:").
  71. WithHtml("<ul>").
  72. WithHtml(fmt.Sprintf("<li><strong>User:</strong> %s</li>", mail.Request.UserName)).
  73. WithHtml(fmt.Sprintf("<li><strong>Network:</strong> %s</li>", mail.Network.NetID)).
  74. WithHtml(fmt.Sprintf("<li><strong>Requested At:</strong> %s</li>", formatUTCTime(mail.Request.RequestedAt))).
  75. WithHtml(fmt.Sprintf("<li><strong>Reason:</strong> %s</li>", reasonText)).
  76. WithHtml("</ul>").
  77. WithParagraph(fmt.Sprintf("<a href=\"%s\" style=\"display: inline-block; padding: 12px 24px; background-color: #007bff; color: #ffffff; text-decoration: none; border-radius: 4px;\">Review Request</a>", dashboardURL)).
  78. WithParagraph("You can approve or deny this request from the network JIT page.").
  79. WithParagraph("Best Regards,").
  80. WithParagraph("The Netmaker Team").
  81. Build()
  82. return content
  83. }