Initial commit
This commit is contained in:
1
.dockerignore
Normal file
1
.dockerignore
Normal file
@@ -0,0 +1 @@
|
||||
.env
|
||||
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.env
|
||||
40
.gitlab-ci.yml
Normal file
40
.gitlab-ci.yml
Normal file
@@ -0,0 +1,40 @@
|
||||
# tahapan
|
||||
stages:
|
||||
- cleaning
|
||||
- build_image
|
||||
- deploy
|
||||
|
||||
# build image on development server
|
||||
build_image:
|
||||
stage: build_image
|
||||
script:
|
||||
- docker build -t 36.66.3.44:7007/$PROJECT_NAME:$CI_PIPELINE_ID .
|
||||
- docker push 36.66.3.44:7007/$PROJECT_NAME:$CI_PIPELINE_ID
|
||||
environment:
|
||||
only:
|
||||
- main
|
||||
tags:
|
||||
- runner-internal-his
|
||||
|
||||
# deploy to development server
|
||||
deploy_development:
|
||||
stage: deploy
|
||||
script:
|
||||
- docker stack deploy --compose-file compose.yml email-notification
|
||||
environment:
|
||||
only:
|
||||
- main
|
||||
tags:
|
||||
- runner-internal-his
|
||||
|
||||
# deploy to development server
|
||||
cleaning_image_and_container:
|
||||
stage: cleaning
|
||||
script:
|
||||
- echo y | docker container prune
|
||||
- echo y | docker image prune -a
|
||||
environment:
|
||||
only:
|
||||
- main
|
||||
tags:
|
||||
- runner-internal-his
|
||||
14
Dockerfile
Normal file
14
Dockerfile
Normal file
@@ -0,0 +1,14 @@
|
||||
FROM golang:latest
|
||||
ENV TZ="Asia/Jakarta"
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN go mod download
|
||||
|
||||
RUN go build -o email-notification
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
CMD [ "./email-notification" ]
|
||||
1
app/app.go
Normal file
1
app/app.go
Normal file
@@ -0,0 +1 @@
|
||||
package app
|
||||
72
app/mail-config.go
Normal file
72
app/mail-config.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/smtp"
|
||||
"os"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
const CONFIG_SMTP_HOST = "smtp.gmail.com"
|
||||
const CONFIG_SMTP_PORT = 587
|
||||
const CONFIG_SENDER_NAME = "HIS <hats.nutech@gmail.com>"
|
||||
const CONFIG_AUTH_EMAIL = "hats.nutech@gmail.com"
|
||||
const CONFIG_AUTH_PASSWORD = "lbfjfuywqktkexij"
|
||||
|
||||
func Mail() {
|
||||
// dialer := gomail.NewDialer(
|
||||
// CONFIG_SMTP_HOST,
|
||||
// CONFIG_SMTP_PORT,
|
||||
// CONFIG_AUTH_EMAIL,
|
||||
// CONFIG_AUTH_PASSWORD,
|
||||
// )
|
||||
|
||||
// return dialer
|
||||
}
|
||||
|
||||
func SendEmail(to []string, cc []string, subject, message string) error {
|
||||
tmpl, err := template.ParseFiles("template/test.html")
|
||||
if err != nil {
|
||||
log.Fatalf("Error parsing template: %v", err)
|
||||
}
|
||||
|
||||
fmt.Println("qwqwqw", os.Getenv("PORT"))
|
||||
|
||||
type Data struct {
|
||||
Name string
|
||||
Company string
|
||||
}
|
||||
|
||||
data := Data{Name: "Salwa Balqis Sulaeman", Company: "HIS"}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := tmpl.Execute(&buf, data); err != nil {
|
||||
log.Fatalf("Error executing template: %v", err)
|
||||
}
|
||||
|
||||
// content, err := os.ReadFile("template/test.html")
|
||||
// if err != nil {
|
||||
// fmt.Println("Error reading file:", err)
|
||||
// return err
|
||||
// }
|
||||
|
||||
htmlString := buf.String()
|
||||
|
||||
sender := "From: " + CONFIG_SENDER_NAME + "\n"
|
||||
subjectt := "Subject: 👋 Hello from Go\n"
|
||||
mime := "MIME-version: 1.0;\nContent-Type: text/html; charset=\"UTF-8\";\n\n"
|
||||
body := htmlString
|
||||
messages := []byte(sender + subjectt + mime + body)
|
||||
|
||||
auth := smtp.PlainAuth("", CONFIG_AUTH_EMAIL, CONFIG_AUTH_PASSWORD, CONFIG_SMTP_HOST)
|
||||
smtpAddr := fmt.Sprintf("%s:%d", CONFIG_SMTP_HOST, CONFIG_SMTP_PORT)
|
||||
|
||||
err = smtp.SendMail(smtpAddr, auth, CONFIG_AUTH_EMAIL, append(to, cc...), messages)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
16
compose.yml
Normal file
16
compose.yml
Normal file
@@ -0,0 +1,16 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
app:
|
||||
image: 36.66.3.44:7007/$PROJECT_NAME:$CI_PIPELINE_ID
|
||||
deploy:
|
||||
replicas : 1
|
||||
restart_policy :
|
||||
condition: on-failure
|
||||
resources:
|
||||
limits:
|
||||
cpus: "0.1"
|
||||
memory: "300m"
|
||||
restart: always
|
||||
ports:
|
||||
- "7010:3000"
|
||||
51
config/db.go
Normal file
51
config/db.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"gorm.io/driver/postgres"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func NewDatabase() *gorm.DB {
|
||||
username := os.Getenv("DB_USERNAME")
|
||||
password := "123$Nt1"
|
||||
port, err := strconv.Atoi(os.Getenv("DB_PORT"))
|
||||
if err != nil {
|
||||
fmt.Println("error ", err.Error())
|
||||
}
|
||||
host := os.Getenv("DB_HOST")
|
||||
database := os.Getenv("DB_NAME")
|
||||
idleConnection := 10
|
||||
maxConnection := 100
|
||||
maxLifeTimeConnection := 300
|
||||
|
||||
dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%d sslmode=disable TimeZone=Asia/Jakarta", host, username, password, database, port)
|
||||
|
||||
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{
|
||||
// Logger: logger.New(&logrusWriter{Logger: log}, logger.Config{
|
||||
// SlowThreshold: time.Second * 5,
|
||||
// Colorful: false,
|
||||
// IgnoreRecordNotFoundError: true,
|
||||
// ParameterizedQueries: true,
|
||||
// LogLevel: logger.Info,
|
||||
// }),
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Println("failed to connect database: ", err)
|
||||
}
|
||||
|
||||
connection, err := db.DB()
|
||||
if err != nil {
|
||||
fmt.Println("failed to connect database: ", err)
|
||||
}
|
||||
|
||||
connection.SetMaxIdleConns(idleConnection)
|
||||
connection.SetMaxOpenConns(maxConnection)
|
||||
connection.SetConnMaxLifetime(time.Second * time.Duration(maxLifeTimeConnection))
|
||||
|
||||
return db
|
||||
}
|
||||
22
go.mod
Normal file
22
go.mod
Normal file
@@ -0,0 +1,22 @@
|
||||
module email-notification
|
||||
|
||||
go 1.21.1
|
||||
|
||||
require (
|
||||
github.com/joho/godotenv v1.5.1
|
||||
gorm.io/driver/postgres v1.5.11
|
||||
gorm.io/gorm v1.25.12
|
||||
)
|
||||
|
||||
require (
|
||||
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/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
|
||||
)
|
||||
38
go.sum
Normal file
38
go.sum
Normal file
@@ -0,0 +1,38 @@
|
||||
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/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw=
|
||||
github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
|
||||
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
|
||||
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
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/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=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
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=
|
||||
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=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gorm.io/driver/postgres v1.5.11 h1:ubBVAfbKEUld/twyKZ0IYn9rSQh448EdelLYk9Mv314=
|
||||
gorm.io/driver/postgres v1.5.11/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI=
|
||||
gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
|
||||
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
|
||||
98
main.go
Normal file
98
main.go
Normal file
@@ -0,0 +1,98 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"email-notification/app"
|
||||
"email-notification/config"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/joho/godotenv"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("Test")
|
||||
err := godotenv.Load()
|
||||
if err != nil {
|
||||
log.Fatal("Error loading .env file")
|
||||
}
|
||||
|
||||
config.NewDatabase()
|
||||
|
||||
to := []string{"teddy.nutech@gmail.com"}
|
||||
cc := []string{"teddy.nutech@gmail.com"}
|
||||
subject := "test"
|
||||
message := "test"
|
||||
|
||||
// conn, err := amqp091.Dial("amqp://guest:guest@36.66.3.44:7012/")
|
||||
// if err != nil {
|
||||
// fmt.Println("Failed to connect to RabbitMQ: ", err)
|
||||
// }
|
||||
// defer conn.Close()
|
||||
|
||||
// ch, err := conn.Channel()
|
||||
// if err != nil {
|
||||
// fmt.Println("Failed to open a channel: ", err)
|
||||
// }
|
||||
// defer ch.Close()
|
||||
|
||||
http.HandleFunc("/notif-email", func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// ch.Publish("notification", "email", false, false, amqp091.Publishing{
|
||||
// ContentType: "application/json",
|
||||
// Body: []byte("test-email"),
|
||||
// })
|
||||
|
||||
go func() {
|
||||
fmt.Println("sending email...")
|
||||
err := app.SendEmail(to, cc, subject, message)
|
||||
if err != nil {
|
||||
fmt.Println("error", err.Error())
|
||||
}
|
||||
fmt.Println("email sent")
|
||||
}()
|
||||
|
||||
w.Write([]byte{})
|
||||
})
|
||||
|
||||
port := os.Getenv("PORT")
|
||||
|
||||
http.ListenAndServe(":"+port, nil)
|
||||
|
||||
// q, err := ch.QueueDeclare(
|
||||
// "email", // name
|
||||
// false,
|
||||
// false,
|
||||
// false,
|
||||
// false,
|
||||
// nil,
|
||||
// )
|
||||
// if err != nil {
|
||||
// fmt.Println("Failed to declare a queue:", err)
|
||||
// }
|
||||
|
||||
// msgs, err := ch.Consume(
|
||||
// "email",
|
||||
// "", // consumer
|
||||
// true, // auto-ack
|
||||
// false, // exclusive
|
||||
// false, // no-local
|
||||
// false, // no-wait
|
||||
// nil,
|
||||
// )
|
||||
// if err != nil {
|
||||
// fmt.Println("Failed to register a consumer: ", err)
|
||||
// }
|
||||
|
||||
// forever := make(chan bool)
|
||||
|
||||
// go func() {
|
||||
// for d := range msgs {
|
||||
// log.Printf("Received a message: %s", d.Body)
|
||||
// }
|
||||
// }()
|
||||
|
||||
// fmt.Println(" [*] Waiting for messages. To exit press CTRL+C")
|
||||
// <-forever
|
||||
}
|
||||
56
template/test.html
Normal file
56
template/test.html
Normal file
@@ -0,0 +1,56 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Selamat Ulang Tahun!</title>
|
||||
<style>
|
||||
.container {
|
||||
max-width: 600px;
|
||||
margin: auto;
|
||||
padding: 30px;
|
||||
background-color: #fef9f4;
|
||||
font-family: Arial, sans-serif;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
text-align: center;
|
||||
}
|
||||
.title {
|
||||
font-size: 28px;
|
||||
color: #d35400;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.message {
|
||||
font-size: 18px;
|
||||
color: #333;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.footer {
|
||||
font-size: 14px;
|
||||
/* color: #aaa; */
|
||||
}
|
||||
.cake-emoji {
|
||||
font-size: 50px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="cake-emoji">🎉🎂🥳</div>
|
||||
<h1 class="title">Selamat Ulang Tahun, {{.Name}}!</h1>
|
||||
<p class="message">
|
||||
Semoga hari spesialmu dipenuhi dengan kebahagiaan, cinta, dan tawa yang
|
||||
tak berakhir.<br />
|
||||
Terima kasih telah menjadi bagian dari perjalanan kami. 🎈
|
||||
</p>
|
||||
<p class="footer">
|
||||
Salam hangat dari kami,<br />
|
||||
<b>Tim {{.Company}}</b>
|
||||
</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>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user