From a69b44625e7e3e36356c24064010a69f647c8b6d Mon Sep 17 00:00:00 2001 From: teddy Date: Mon, 21 Apr 2025 11:58:12 +0700 Subject: [PATCH] update --- config/validator.go | 9 +++++++ go.mod | 13 +++++++--- go.sum | 28 +++++++++++++++++----- helper/helper.go | 33 +++++++++++++++++++++++++- model/model.go | 7 ++++++ route/route.go | 50 +++++++++++++++++++++++++++++++++++++++ template/general.html | 55 +++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 185 insertions(+), 10 deletions(-) create mode 100644 config/validator.go create mode 100644 template/general.html diff --git a/config/validator.go b/config/validator.go new file mode 100644 index 0000000..3a1e9db --- /dev/null +++ b/config/validator.go @@ -0,0 +1,9 @@ +package config + +import ( + "github.com/go-playground/validator/v10" +) + +func NewValidator() *validator.Validate { + return validator.New() +} diff --git a/go.mod b/go.mod index 420ef36..edb0f5f 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module email-notification go 1.21.1 require ( + github.com/go-playground/validator/v10 v10.26.0 github.com/google/uuid v1.6.0 github.com/joho/godotenv v1.5.1 gorm.io/driver/postgres v1.5.11 @@ -10,14 +11,20 @@ require ( ) require ( + github.com/gabriel-vasile/mimetype v1.4.8 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackc/pgx/v5 v5.5.5 // indirect github.com/jackc/puddle/v2 v2.2.1 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect + github.com/leodido/go-urn v1.4.0 // indirect github.com/stretchr/testify v1.10.0 // indirect - golang.org/x/crypto v0.32.0 // indirect - golang.org/x/sync v0.10.0 // indirect - golang.org/x/text v0.21.0 // indirect + golang.org/x/crypto v0.33.0 // indirect + golang.org/x/net v0.34.0 // indirect + golang.org/x/sync v0.11.0 // indirect + golang.org/x/sys v0.30.0 // indirect + golang.org/x/text v0.22.0 // indirect ) diff --git a/go.sum b/go.sum index 0d139dd..14ae9f4 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,16 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= +github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k= +github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= @@ -17,6 +27,8 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -24,12 +36,16 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= -golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= -golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= +golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= +golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= +golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= +golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/helper/helper.go b/helper/helper.go index 43f9567..9f5a850 100644 --- a/helper/helper.go +++ b/helper/helper.go @@ -3,12 +3,17 @@ package helper import ( "bytes" "email-notification/config" + "encoding/json" + "errors" "fmt" "html/template" "log" + "net/http" "net/smtp" + "reflect" "time" + "github.com/go-playground/validator/v10" "github.com/google/uuid" ) @@ -69,7 +74,7 @@ func FormatSince(t time.Time) string { } func SendEmail(to []string, cc []string, name, subject, message, htmlString string) error { - sender := "From: " + config.Mail().SMTPSenderName + "\n" + sender := "From: HIS \n" subjectt := "Subject: " + subject + "\n" mime := "MIME-version: 1.0;\nContent-Type: text/html; charset=\"UTF-8\";\n\n" body := htmlString @@ -85,3 +90,29 @@ func SendEmail(to []string, cc []string, name, subject, message, htmlString stri return nil } + +func ParseRequest(r *http.Request, v any) error { + err := json.NewDecoder(r.Body).Decode(&v) + if err != nil { + return err + } + return nil +} + +func ValidateRequest(request any) error { + c := config.NewValidator() + if err := c.Struct(request); err != nil { + var errMessage string + for _, err := range err.(validator.ValidationErrors) { + fmt.Println(err) + fieldName := err.Field() + field, _ := reflect.TypeOf(request).Elem().FieldByName(fieldName) + jsonField, _ := field.Tag.Lookup("json") + errMessage = jsonField + " is " + err.ActualTag() + } + fmt.Println(errMessage) + return errors.New(errMessage) + } + + return nil +} diff --git a/model/model.go b/model/model.go index 07649f3..3dd939b 100644 --- a/model/model.go +++ b/model/model.go @@ -13,3 +13,10 @@ type Workanniversary struct { Fullname string `json:"fullname"` HireDate time.Time `json:"hire_date"` } + +type SendEmailRequest struct { + Subject string `json:"subject" validate:"required"` + To []string `json:"to" validate:"required"` + CC []string `json:"cc"` + Message string `json:"message"` +} diff --git a/route/route.go b/route/route.go index d8965c8..2c1f212 100644 --- a/route/route.go +++ b/route/route.go @@ -199,6 +199,56 @@ func Route(db *gorm.DB) { w.Write([]byte("success")) })) + http.HandleFunc("/send-email", middleware.ResponseTimeMiddleware(func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) + return + } + + sessionID := helper.GenerateSessionID() + module := "SEND EMAIL" + request := new(model.SendEmailRequest) + + err := helper.ParseRequest(r, request) + if err != nil { + w.WriteHeader(500) + w.Write([]byte("system error")) + return + } + + err = helper.ValidateRequest(request) + if err != nil { + w.WriteHeader(400) + w.Write([]byte(err.Error())) + return + } + + subject := request.Subject + + sendTo := request.To + + type Data struct { + Message string + } + + data := Data{Message: request.Message} + + htmlString := helper.ParseHTML("template/general.html", data) + + go func() { + log.Printf("%+v %+v SENDING EMAIL TO %+v", sessionID, module, sendTo) + err := helper.SendEmail(sendTo, request.CC, "", subject, "", htmlString) + if err != nil { + log.Printf("%+v %+v response %+v", sessionID, module, err.Error()) + } else { + log.Printf("%+v %+v EMAIL SENT TO %+v", sessionID, module, sendTo) + } + }() + + log.Printf("%+v %+v response %+v", sessionID, module, "success") + w.Write([]byte("success")) + })) + http.Handle("/", middleware.ResponseTimeMiddleware(func(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) diff --git a/template/general.html b/template/general.html new file mode 100644 index 0000000..64e2cb6 --- /dev/null +++ b/template/general.html @@ -0,0 +1,55 @@ + + + + + Email + + + +
+
+

{{.Message}}

+
+
+ +
+ +