update
This commit is contained in:
9
config/validator.go
Normal file
9
config/validator.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"github.com/go-playground/validator/v10"
|
||||
)
|
||||
|
||||
func NewValidator() *validator.Validate {
|
||||
return validator.New()
|
||||
}
|
||||
13
go.mod
13
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
|
||||
)
|
||||
|
||||
28
go.sum
28
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=
|
||||
|
||||
@@ -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 <hats.nutech@gmail.com>\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
|
||||
}
|
||||
|
||||
@@ -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"`
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
55
template/general.html
Normal file
55
template/general.html
Normal file
@@ -0,0 +1,55 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="id">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Email</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
background-color: #f2f4f6;
|
||||
padding: 20px;
|
||||
}
|
||||
.container {
|
||||
background-color: #ffffff;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
max-width: 100%;
|
||||
margin: auto;
|
||||
border: 1px solid #e0e0e0;
|
||||
}
|
||||
.header {
|
||||
color: #d62828;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.info {
|
||||
font-size: 14px;
|
||||
color: #333333;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.footer {
|
||||
font-size: 12px;
|
||||
color: #888;
|
||||
margin-top: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="info">
|
||||
<p>{{.Message}}</p>
|
||||
<br />
|
||||
</div>
|
||||
<div class="footer">
|
||||
<p>Email ini dikirim oleh sistem.</p>
|
||||
<img
|
||||
src="http://36.66.3.44:9000/create-bucket-test/test-folder/LOGO_HIS_NI_New_Contrasted-removebg-preview.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=BDYv2npRYZw5fcXzd80c%2F20250417%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20250417T045323Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=c399ff0031b0d8bc9b7073171bca8ad3a9c2b82a374e25e60dbd35bd5bd5775e"
|
||||
alt="logo"
|
||||
width="100px"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user