feat; add notify by email script

This commit is contained in:
urko 2025-02-19 18:47:11 +01:00
parent 95bdcd0203
commit f480ce4ee3
13 changed files with 308 additions and 19 deletions

View File

@ -17,8 +17,8 @@ import (
"slices" "slices"
"syscall" "syscall"
"gitea.urkob.com/mcr-swiss/gogstea/config"
"gitea.urkob.com/mcr-swiss/gogstea/internal/domain" "gitea.urkob.com/mcr-swiss/gogstea/internal/domain"
"gitea.urkob.com/mcr-swiss/gogstea/kit/config"
) )
var okStatuses = []int{ var okStatuses = []int{

View File

@ -16,8 +16,8 @@ import (
"runtime" "runtime"
"syscall" "syscall"
"gitea.urkob.com/mcr-swiss/gogstea/config"
"gitea.urkob.com/mcr-swiss/gogstea/internal/domain" "gitea.urkob.com/mcr-swiss/gogstea/internal/domain"
"gitea.urkob.com/mcr-swiss/gogstea/kit/config"
) )
func main() { func main() {

View File

@ -11,7 +11,7 @@ import (
"syscall" "syscall"
"time" "time"
"gitea.urkob.com/mcr-swiss/gogstea/kit/config" "gitea.urkob.com/mcr-swiss/gogstea/config"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
) )

View File

@ -18,8 +18,8 @@ import (
"syscall" "syscall"
"time" "time"
"gitea.urkob.com/mcr-swiss/gogstea/config"
"gitea.urkob.com/mcr-swiss/gogstea/internal/domain" "gitea.urkob.com/mcr-swiss/gogstea/internal/domain"
"gitea.urkob.com/mcr-swiss/gogstea/kit/config"
) )
func main() { func main() {

151
cmd/notify/main.go Normal file
View File

@ -0,0 +1,151 @@
package main
import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"net/smtp"
"net/url"
"os"
"os/signal"
"path"
"runtime"
"syscall"
"time"
"gitea.urkob.com/mcr-swiss/gogstea/config"
"gitea.urkob.com/mcr-swiss/gogstea/internal/mail"
emailsender "gitea.urkob.com/urko/emailsender/pkg/email"
)
func main() {
ctx, cancel := context.WithCancel(signalContext(context.Background()))
defer cancel()
cfgFile := os.Getenv("CONFIG_FILE")
if cfgFile == "" {
// Get root path
_, filename, _, _ := runtime.Caller(0)
cfgFile = path.Join(path.Dir(filename), "configs", "app.yml")
}
cfg, err := config.LoadConfig(cfgFile)
if err != nil {
panic(err)
}
ms := mail.NewMailService(
cfg.Email.From,
emailsender.NewSecure(emailsender.MailServiceConfig{
Auth: smtp.PlainAuth("", cfg.Email.User, cfg.Email.Password, cfg.Email.Host),
Host: cfg.Email.Host,
Port: fmt.Sprint(cfg.Email.Port),
From: cfg.Email.From,
}),
)
wd, err := os.Getwd()
if err != nil {
panic(err)
}
outputFile, err := os.Create(wd + "/notification-results.txt")
if err != nil {
panic(err)
}
defer outputFile.Close()
// http req
cli := http.DefaultClient
parsedURL, err := url.Parse(cfg.Gitea.URL + "/admin/users")
if err != nil {
panic(err)
}
req, err := http.NewRequestWithContext(ctx, http.MethodGet, parsedURL.String(), http.NoBody)
if err != nil {
panic(err)
}
req.Header.Add("Authorization", "token "+cfg.Gitea.ApiKey)
req.Header.Add("Content-Type", "application/json")
resp, err := cli.Do(req)
if err != nil {
panic(err)
}
if resp.StatusCode != http.StatusOK {
bts, _ := io.ReadAll(resp.Body)
if _, err := outputFile.WriteString(fmt.Sprintf("couln't get users | %d: %s\n", resp.StatusCode, string(bts))); err != nil {
panic(err)
}
}
bts, err := io.ReadAll(resp.Body)
if err != nil {
panic(err)
}
var users []struct {
ID int `json:"id"`
Login string `json:"login"`
LoginName string `json:"login_name"`
FullName string `json:"full_name"`
Email string `json:"email"`
AvatarURL string `json:"avatar_url"`
Language string `json:"language"`
IsAdmin bool `json:"is_admin"`
LastLogin time.Time `json:"last_login"`
Created time.Time `json:"created"`
Restricted bool `json:"restricted"`
Active bool `json:"active"`
ProhibitLogin bool `json:"prohibit_login"`
Location string `json:"location"`
Website string `json:"website"`
Description string `json:"description"`
Visibility string `json:"visibility"`
FollowersCount int `json:"followers_count"`
FollowingCount int `json:"following_count"`
StarredReposCount int `json:"starred_repos_count"`
Username string `json:"username"`
}
if err := json.Unmarshal(bts, &users); err != nil {
panic(err)
}
// Loop over users and notify
for _, u := range users {
emailBody := "HTML MESSAGE"
// Send the new password via email.
// if err := ms.SendMsg(email, []byte(fmt.Sprintf("Esta esta es tu nueva contraseña: %s", newPassword))); err != nil {
if err := ms.Send(
u.Email,
"Password changed",
emailBody,
); err != nil {
if _, err := outputFile.WriteString(fmt.Sprintf("Error sending email for user %s: %v", u.Email, err)); err != nil {
panic(err)
}
continue
}
}
}
func signalContext(ctx context.Context) context.Context {
ctx, cancel := context.WithCancel(ctx)
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
go func() {
<-sigs
signal.Stop(sigs)
close(sigs)
cancel()
}()
return ctx
}

View File

@ -16,8 +16,8 @@ import (
"runtime" "runtime"
"syscall" "syscall"
"gitea.urkob.com/mcr-swiss/gogstea/config"
"gitea.urkob.com/mcr-swiss/gogstea/internal/domain" "gitea.urkob.com/mcr-swiss/gogstea/internal/domain"
"gitea.urkob.com/mcr-swiss/gogstea/kit/config"
) )
func main() { func main() {

View File

@ -16,8 +16,8 @@ import (
"runtime" "runtime"
"syscall" "syscall"
"gitea.urkob.com/mcr-swiss/gogstea/config"
"gitea.urkob.com/mcr-swiss/gogstea/internal/domain" "gitea.urkob.com/mcr-swiss/gogstea/internal/domain"
"gitea.urkob.com/mcr-swiss/gogstea/kit/config"
) )
func main() { func main() {
@ -70,7 +70,7 @@ func main() {
cli := http.DefaultClient cli := http.DefaultClient
parsedURL, err := url.Parse(fmt.Sprintf(cfg.Gitea.URL + "/admin/users")) parsedURL, err := url.Parse(cfg.Gitea.URL + "/admin/users")
if err != nil { if err != nil {
panic(err) panic(err)
} }

19
config/app.test.yml Normal file
View File

@ -0,0 +1,19 @@
gitea:
url: "https://gitea.imep.net/api/v1"
api_key: "257e1a0a9616d665b473999aad0b36cce995ea61"
users:
default_password: "D3f4ultCh4ng3Plz#"
csv_path: "/projects/work/mcr/code/gogstea/.notes/user.csv"
organizations:
csv_path: "/projects/work/mcr/code/gogstea/.notes/organizations.csv"
issues:
csv_path: "/projects/work/mcr/code/gogstea/.notes/issues.csv"
collaborators:
csv_path: "/projects/work/mcr/code/gogstea/.notes/collaborators.csv"
email:
from: no-reply@mcr-solutions.com
user: d0fb307c46b467f0532a49a1d91b1117
host: in-v3.mailjet.com
password: "87fe4c4118f66969f681382df04cd54e"
port: 587

View File

@ -1,10 +1,13 @@
package config package config
import ( import (
"os" "flag"
"path"
"runtime"
"github.com/go-playground/validator/v10"
"github.com/jinzhu/configor"
"go.uber.org/zap" "go.uber.org/zap"
"gopkg.in/yaml.v3"
) )
type Config struct { type Config struct {
@ -28,20 +31,41 @@ type Config struct {
Collaborators struct { Collaborators struct {
CSVPath string `yaml:"csv_path"` CSVPath string `yaml:"csv_path"`
} `yaml:"collaborators"` } `yaml:"collaborators"`
Email struct {
Host string
From string
User string
Password string
Port uint
}
} }
func LoadConfig(path string) (*Config, error) { // LoadConfig
data, err := os.ReadFile(path) func LoadConfig(c ...string) (Config, error) {
if err != nil { cfg := "app.yml"
return nil, err test := flag.Lookup("test.v") != nil
if test {
cfg = "app.test.yml"
} }
if len(c) > 0 {
cfg = c[0]
}
// Get root path
_, filename, _, _ := runtime.Caller(0)
var config Config var config Config
if err := yaml.Unmarshal(data, &config); err != nil { if err := configor.Load(&config, path.Join(path.Dir(filename), cfg)); err != nil {
return nil, err return config, err
} }
return &config, nil v := validator.New()
if err := v.Struct(config); err != nil {
return config, err
}
return config, nil
} }
func NewZapCfg(dev bool) zap.Config { func NewZapCfg(dev bool) zap.Config {

17
go.mod
View File

@ -3,12 +3,27 @@ module gitea.urkob.com/mcr-swiss/gogstea
go 1.23.0 go 1.23.0
require ( require (
gitea.urkob.com/urko/emailsender v0.0.0-20240822131142-dca0236b06af
github.com/go-playground/validator/v10 v10.25.0
github.com/go-sql-driver/mysql v1.8.1 github.com/go-sql-driver/mysql v1.8.1
github.com/jinzhu/configor v1.2.2
github.com/stretchr/testify v1.8.4
go.uber.org/zap v1.27.0 go.uber.org/zap v1.27.0
gopkg.in/yaml.v3 v3.0.1
) )
require ( require (
filippo.io/edwards25519 v1.1.0 // indirect filippo.io/edwards25519 v1.1.0 // indirect
github.com/BurntSushi/toml v1.2.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
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/leodido/go-urn v1.4.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
go.uber.org/multierr v1.10.0 // indirect go.uber.org/multierr v1.10.0 // indirect
golang.org/x/crypto v0.32.0 // indirect
golang.org/x/net v0.34.0 // indirect
golang.org/x/sys v0.29.0 // indirect
golang.org/x/text v0.21.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
) )

34
go.sum
View File

@ -1,19 +1,49 @@
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
gitea.urkob.com/urko/emailsender v0.0.0-20240822131142-dca0236b06af h1:eb6YvnvawZ824BCAhD281Rwobx0+z5pEIAclsw8nrQc=
gitea.urkob.com/urko/emailsender v0.0.0-20240822131142-dca0236b06af/go.mod h1:E8lpo+yp+634C25vMCfz14bslbfkJyfzlgFsXimUu1g=
github.com/BurntSushi/toml v1.2.0 h1:Rt8g24XnyGTyglgET/PRUNlrUeu9F5L+7FilkXfZgs0=
github.com/BurntSushi/toml v1.2.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 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/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.25.0 h1:5Dh7cjvzR7BRZadnsVOzPhWsrwUr0nmsZJxEAnFLNO8=
github.com/go-playground/validator/v10 v10.25.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus=
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/jinzhu/configor v1.2.2 h1:sLgh6KMzpCmaQB4e+9Fu/29VErtBUqsS2t8C9BNIVsA=
github.com/jinzhu/configor v1.2.2/go.mod h1:iFFSfOBKP3kC2Dku0ZGB3t3aulfQgTGJknodhFavsU8=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
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/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
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 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

22
internal/mail/mail.go Executable file
View File

@ -0,0 +1,22 @@
package mail
import (
"gitea.urkob.com/urko/emailsender/pkg/email"
)
type EmailService struct {
emailService *email.EmailService
from string
}
func NewMailService(from string, emailService *email.EmailService) EmailService {
return EmailService{from: from, emailService: emailService}
}
func (srv EmailService) Send(to, subject, body string) error {
return srv.emailService.SendEmail(email.EmailMessage{
To: to,
Subject: subject,
Body: body,
})
}

View File

@ -0,0 +1,28 @@
package mail
import (
"fmt"
"net/smtp"
"testing"
"gitea.urkob.com/mcr-swiss/gogstea/config"
emailsender "gitea.urkob.com/urko/emailsender/pkg/email"
"github.com/stretchr/testify/require"
)
func TestSend(t *testing.T) {
cfg, err := config.LoadConfig()
require.NoError(t, err)
ms := NewMailService(
cfg.Email.From,
emailsender.NewSecure(emailsender.MailServiceConfig{
Auth: smtp.PlainAuth("", cfg.Email.User, cfg.Email.Password, cfg.Email.Host),
Host: cfg.Email.Host,
Port: fmt.Sprint(cfg.Email.Port),
From: cfg.Email.From,
}),
)
require.NoError(t, ms.Send("urko@fungimail.com", "ss", "asdfsd"))
}