Skip to content

Commit 3ce4d4b

Browse files
committed
feat(email): send registration status emails for events
Add email notifications for event registration and payment status using HTML templates. Introduce new email templates for pending payment and successful registration. Refactor event usecase to support sending emails with dynamic data and templates. Improve error handling and logging for email operations.
1 parent aac50b6 commit 3ce4d4b

File tree

9 files changed

+523
-11
lines changed

9 files changed

+523
-11
lines changed

app/app.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func InitApp(
4949
// usecase
5050
userUsecase := users.InitUsecase(cfg, userRepo, dbTx, jwtInstance)
5151
newsletterUC := newsletters.InitUsecase(cfg, newsletterRepo, dbTx, jwt.NewJwt(cfg.JWT_SECRET_KEY))
52-
eventUC := events.InitUsecase(eventRepo, imgRepo, dbTx)
52+
eventUC := events.InitUsecase(cfg, eventRepo, imgRepo, dbTx)
5353
imgUc := images.InitUsecase(imgRepo, dbTx)
5454
blogPostUc := blogPost.InitUseCase(blogPostRepo, jwtInstance)
5555

app/events/events.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import (
44
handler_http "github.com/hammer-code/lms-be/app/events/delivery/http"
55
repository "github.com/hammer-code/lms-be/app/events/repository"
66
usecase "github.com/hammer-code/lms-be/app/events/usecase"
7+
8+
"github.com/hammer-code/lms-be/config"
79
"github.com/hammer-code/lms-be/domain"
810
"github.com/hammer-code/lms-be/pkg/db"
911
)
@@ -12,8 +14,8 @@ func InitRepository(db db.DatabaseTransaction) domain.EventRepository {
1214
return repository.NewRepository(db)
1315
}
1416

15-
func InitUsecase(repository domain.EventRepository, imageRepository domain.ImageRepository, dbTX db.DatabaseTransaction) domain.EventUsecase {
16-
return usecase.NewUsecase(repository, imageRepository, dbTX)
17+
func InitUsecase(cfg config.Config, repository domain.EventRepository, imageRepository domain.ImageRepository, dbTX db.DatabaseTransaction) domain.EventUsecase {
18+
return usecase.NewUsecase(cfg, repository, imageRepository, dbTX)
1719
}
1820

1921
func InitHandler(uc domain.EventUsecase) domain.EventHandler {

app/events/usecase/create_register_event.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@ import (
44
"context"
55
"errors"
66
"fmt"
7+
"html/template"
8+
"os"
79
"time"
810

911
"github.com/hammer-code/lms-be/domain"
12+
"github.com/hammer-code/lms-be/pkg/email"
1013
"github.com/hammer-code/lms-be/pkg/hash"
1114
"github.com/sirupsen/logrus"
1215
)
@@ -38,12 +41,86 @@ func (uc usecase) CreateRegisterEvent(ctx context.Context, payload domain.Regist
3841

3942
orderNo := fmt.Sprintf("TXE-%d-%s%s%s%s", event.ID, time.Now().Format("06"), time.Now().Format("01"), time.Now().Format("02"), hash[0:4])
4043

44+
// Read HTML template for email
45+
htmlTmpl, err := os.ReadFile("./assets/event_status_registration_template.html")
46+
if err != nil {
47+
return domain.RegisterEventResponse{}, fmt.Errorf("failed to read file template: %w", err)
48+
}
49+
50+
// Parse the HTML template
51+
tmpl, err := template.New("register_event_status").Parse(string(htmlTmpl))
52+
if err != nil {
53+
return domain.RegisterEventResponse{}, fmt.Errorf("failed to parse template: %w", err)
54+
}
55+
56+
// Prepare data for the email template
57+
smtpConfig := email.SMTP{
58+
Email: uc.cfg.SMTP_EMAIL,
59+
Password: uc.cfg.SMTP_PASSWORD,
60+
Host: uc.cfg.SMTP_HOST,
61+
Port: uc.cfg.SMTP_PORT,
62+
}
63+
64+
// Prepare the receiver data
65+
emailPayload := email.NewSendEmail(
66+
ctx,
67+
smtpConfig,
68+
"MIME-Version: 1.0\r\nContent-Type: text/html; charset=UTF-8",
69+
"Welcome to Our Platform - Event Registration Status",
70+
tmpl,
71+
)
72+
var formattedDate string
73+
if event.Date.Valid {
74+
formattedDate = event.Date.Time.Format("Monday, 02 January 2006")
75+
} else {
76+
formattedDate = "Date to be announced"
77+
}
78+
79+
// Add the receiver's email and data to the payload
80+
if err := emailPayload.AddReceiver(
81+
ctx,
82+
email.Receiver{
83+
Email: payload.Email,
84+
Data: map[string]interface{}{
85+
"name": payload.Name,
86+
"title": event.Title,
87+
"price": event.Price,
88+
"email": payload.Email,
89+
"order_no": orderNo,
90+
"year": time.Now().Format("2006"),
91+
"date": formattedDate,
92+
"duration": event.Duration,
93+
"location": event.Location,
94+
},
95+
}); err != nil {
96+
return domain.RegisterEventResponse{}, fmt.Errorf("failed to add receiver: %w", err)
97+
}
98+
4199
// is free event or not
42100
status := "SUCCESS"
43101
upToYou := "registration success"
44102
if event.Price != 0.0 {
45103
status = "PENDING"
46104
upToYou = "new register"
105+
emailPayload.SendEmail(ctx)
106+
} else {
107+
logrus.Info("free event, send email registration success")
108+
// Read HTML template for email
109+
htmlTmpl, err := os.ReadFile("./assets/event_status_registration_sucess_template.html")
110+
if err != nil {
111+
return domain.RegisterEventResponse{}, fmt.Errorf("failed to read file template: %w", err)
112+
}
113+
114+
// Parse the HTML template
115+
tmpl, err := template.New("register_event_status").Parse(string(htmlTmpl))
116+
if err != nil {
117+
return domain.RegisterEventResponse{}, fmt.Errorf("failed to parse template: %w", err)
118+
}
119+
120+
if err := emailPayload.ChangeTemplate(ctx, tmpl); err != nil {
121+
return domain.RegisterEventResponse{}, fmt.Errorf("failed to change template: %w", err)
122+
}
123+
emailPayload.SendEmail(ctx)
47124
}
48125

49126
err = uc.dbTX.StartTransaction(ctx, func(txCtx context.Context) error {

app/events/usecase/pay_process.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,13 @@ package usecase
33
import (
44
"context"
55
"errors"
6+
"fmt"
7+
"html/template"
8+
"os"
9+
"time"
610

711
"github.com/hammer-code/lms-be/domain"
12+
"github.com/hammer-code/lms-be/pkg/email"
813
"github.com/sirupsen/logrus"
914
)
1015

@@ -15,6 +20,7 @@ func (uc usecase) PayProcess(ctx context.Context, payload domain.PayProcessPaylo
1520
return err
1621
}
1722

23+
logrus.Info("registration event: ", rEvent)
1824
if rEvent.ID == 0 {
1925
return errors.New("registration order not found")
2026
}
@@ -55,6 +61,79 @@ func (uc usecase) PayProcess(ctx context.Context, payload domain.PayProcessPaylo
5561
return err
5662
}
5763

64+
// Get the complete event details
65+
event, err := uc.repository.GetEvent(txCtx, rEvent.EventID)
66+
if err != nil {
67+
logrus.Error("failed to get event details")
68+
return err
69+
}
70+
71+
// Format the date in a readable format
72+
var formattedDate string
73+
if event.Date.Valid {
74+
formattedDate = event.Date.Time.Format("Monday, 02 January 2006")
75+
} else {
76+
formattedDate = "Date to be announced"
77+
}
78+
79+
// Read HTML template for email
80+
var htmlTmpl []byte
81+
if payload.Status == "SUCCESS" {
82+
htmlTmpl, err = os.ReadFile("./assets/event_status_registration_sucess_template.html")
83+
} else {
84+
htmlTmpl, err = os.ReadFile("./assets/event_status_registration_template.html")
85+
}
86+
if err != nil {
87+
return fmt.Errorf("failed to read file template: %w", err)
88+
}
89+
90+
// Parse the HTML template
91+
tmpl, err := template.New("register_event_status").Parse(string(htmlTmpl))
92+
if err != nil {
93+
return fmt.Errorf("failed to parse template: %w", err)
94+
}
95+
96+
// Prepare data for the email template
97+
smtpConfig := email.SMTP{
98+
Email: uc.cfg.SMTP_EMAIL,
99+
Password: uc.cfg.SMTP_PASSWORD,
100+
Host: uc.cfg.SMTP_HOST,
101+
Port: uc.cfg.SMTP_PORT,
102+
}
103+
104+
// Prepare the receiver data
105+
emailPayload := email.NewSendEmail(
106+
ctx,
107+
smtpConfig,
108+
"MIME-Version: 1.0\r\nContent-Type: text/html; charset=UTF-8",
109+
"Update: Your Event Registration Status",
110+
tmpl,
111+
)
112+
113+
// Add the receiver's email and data to the payload
114+
if err := emailPayload.AddReceiver(
115+
ctx,
116+
email.Receiver{
117+
Email: rEvent.Email,
118+
Data: map[string]interface{}{
119+
"name": rEvent.Name,
120+
"title": event.Title,
121+
"price": event.Price,
122+
"email": rEvent.Email,
123+
"order_no": rEvent.OrderNo,
124+
"status": payload.Status,
125+
"note": payload.Note,
126+
"year": time.Now().Format("2006"),
127+
"date": formattedDate,
128+
"duration": event.Duration,
129+
"location": event.Location,
130+
},
131+
}); err != nil {
132+
return fmt.Errorf("failed to add receiver: %w", err)
133+
}
134+
135+
// Send the email
136+
emailPayload.SendEmail(ctx)
58137
return nil
59138
})
60139

app/events/usecase/usecase.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,29 @@
11
package usecase
22

33
import (
4+
"github.com/hammer-code/lms-be/config"
45
"github.com/hammer-code/lms-be/domain"
56
"github.com/hammer-code/lms-be/pkg/db"
67
)
78

89
type usecase struct {
910
repository domain.EventRepository
1011
imageRepository domain.ImageRepository
12+
cfg config.Config
1113
dbTX db.DatabaseTransaction
1214
}
1315

1416
var (
1517
uc *usecase
1618
)
1719

18-
func NewUsecase(repository domain.EventRepository, imageRepository domain.ImageRepository, dbTX db.DatabaseTransaction) domain.EventUsecase {
20+
func NewUsecase(cfg config.Config, repository domain.EventRepository, imageRepository domain.ImageRepository, dbTX db.DatabaseTransaction) domain.EventUsecase {
1921
if uc == nil {
2022
uc = &usecase{
2123
repository: repository,
2224
imageRepository: imageRepository,
2325
dbTX: dbTX,
26+
cfg: cfg,
2427
}
2528
}
2629

app/images/delivery/http/upload_image.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package http
22

33
import (
4+
"fmt"
45
_ "image/gif"
56
_ "image/jpeg"
67
_ "image/png"
@@ -19,7 +20,7 @@ func (h Handler) UploadImage(w http.ResponseWriter, r *http.Request) {
1920
// Retrieve the file from the form-data
2021
file, header, err := r.FormFile("image")
2122
if err != nil {
22-
http.Error(w, "Error Retrieving the File", http.StatusInternalServerError)
23+
http.Error(w, fmt.Sprintf("Error retrieving file: %v", err), http.StatusBadRequest)
2324
return
2425
}
2526
defer file.Close()

0 commit comments

Comments
 (0)