init commit
This commit is contained in:
commit
3ccb7519ef
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
*.log
|
||||
2
Makefile
Normal file
2
Makefile
Normal file
@ -0,0 +1,2 @@
|
||||
run_usersUpdateLoginMethod:
|
||||
go run cmd/main.go -c usersUpdateLoginMethod
|
||||
49
cmd/main.go
Normal file
49
cmd/main.go
Normal file
@ -0,0 +1,49 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
|
||||
"scripts/internal/command"
|
||||
"scripts/internal/config"
|
||||
e "scripts/pkg/errors"
|
||||
"scripts/pkg/logger"
|
||||
l "scripts/pkg/logger"
|
||||
)
|
||||
|
||||
const defaultConfigPath = "config.json"
|
||||
|
||||
func main() {
|
||||
var (
|
||||
commandName string
|
||||
confPath string
|
||||
)
|
||||
|
||||
flag.StringVar(&confPath, "config", defaultConfigPath, "path to config file")
|
||||
flag.StringVar(&commandName, "c", "", "command name")
|
||||
flag.Parse()
|
||||
|
||||
config.MustLoad(confPath)
|
||||
|
||||
if commandName == "" {
|
||||
l.Log.Fatal().Msg("flag '-c' required")
|
||||
}
|
||||
|
||||
logger.MustInit()
|
||||
command.InitSripts()
|
||||
|
||||
cmd, exists := command.Scripts[commandName]
|
||||
if !exists {
|
||||
l.Log.Warn().Err(e.ErrCommandNotFound).Str("command", commandName).Send()
|
||||
l.Log.Info().Msg("selected command - 'help'")
|
||||
if err := command.Scripts["help"].Exec(); err != nil {
|
||||
l.Log.Fatal().Err(err).Str("command", commandName).Msg("failed to use help command")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
l.Log.Info().Msgf("selected command - %s", commandName)
|
||||
if err := cmd.Exec(); err != nil {
|
||||
l.Log.Error().Err(err).Str("command", commandName).Msg("failed to execude command")
|
||||
return
|
||||
}
|
||||
}
|
||||
43
config.json
Normal file
43
config.json
Normal file
@ -0,0 +1,43 @@
|
||||
{
|
||||
"SqlSettings": {
|
||||
"DriverName": "postgres",
|
||||
"DataSource": "postgres://mmuser:mostest@localhost/mattermost_test?sslmode=disable\u0026connect_timeout=10\u0026binary_parameters=yes",
|
||||
"DataSourceReplicas": [],
|
||||
"DataSourceSearchReplicas": [],
|
||||
"MaxIdleConns": 20,
|
||||
"ConnMaxLifetimeMilliseconds": 3600000,
|
||||
"ConnMaxIdleTimeMilliseconds": 300000,
|
||||
"MaxOpenConns": 300,
|
||||
"Trace": false,
|
||||
"AtRestEncryptKey": "cirgp8x5eydrr9sjmwawb5zsefhbditq",
|
||||
"QueryTimeout": 30,
|
||||
"DisableDatabaseSearch": false,
|
||||
"MigrationsStatementTimeoutSeconds": 100000,
|
||||
"ReplicaLagSettings": [],
|
||||
"ReplicaMonitorIntervalSeconds": 5
|
||||
},
|
||||
"LogSettings": {
|
||||
"EnableConsole": true,
|
||||
"ConsoleLevel": "DEBUG",
|
||||
"ConsoleJson": true,
|
||||
"EnableColor": false,
|
||||
"EnableFile": true,
|
||||
"FileLevel": "INFO",
|
||||
"FileJson": true,
|
||||
"FileLocation": "./pkg/logger/logs.log",
|
||||
"EnableWebhookDebugging": true,
|
||||
"EnableDiagnostics": true,
|
||||
"VerboseDiagnostics": false,
|
||||
"EnableSentry": true,
|
||||
"EnableCaller": true,
|
||||
"AdvancedLoggingJSON": {},
|
||||
"AdvancedLoggingConfig": "",
|
||||
"MaxFieldSize": 2048
|
||||
},
|
||||
"KeycloakSettings": {
|
||||
"address": "http://localhost:8282",
|
||||
"realm_name": "loop",
|
||||
"admin_name": "admin",
|
||||
"admin_pass": "admin"
|
||||
}
|
||||
}
|
||||
15
go.mod
Normal file
15
go.mod
Normal file
@ -0,0 +1,15 @@
|
||||
module scripts
|
||||
|
||||
go 1.26.0
|
||||
|
||||
require (
|
||||
github.com/jmoiron/sqlx v1.4.0
|
||||
github.com/lib/pq v1.10.9
|
||||
github.com/rs/zerolog v1.34.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
golang.org/x/sys v0.12.0 // indirect
|
||||
)
|
||||
25
go.sum
Normal file
25
go.sum
Normal file
@ -0,0 +1,25 @@
|
||||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
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/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
|
||||
github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
|
||||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
|
||||
github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
|
||||
github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
48
internal/command/common.go
Normal file
48
internal/command/common.go
Normal file
@ -0,0 +1,48 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
commandEmailPassToOidc "scripts/internal/command/email_pass_to_oidc"
|
||||
)
|
||||
|
||||
func InitSripts() {
|
||||
scripts := map[string]*Commands{
|
||||
commandEmailPassToOidc.Name: {
|
||||
Exec: commandEmailPassToOidc.UsersUpdateLoginMethod,
|
||||
Requirements: commandEmailPassToOidc.Requirement,
|
||||
Description: "переводит авторизацию пользователей с ролью 'system_user' c почта/пароль на keycloak",
|
||||
},
|
||||
"help": {
|
||||
Exec: Help,
|
||||
Requirements: Requirement,
|
||||
Description: "вывод всех доступных скриптов",
|
||||
},
|
||||
}
|
||||
|
||||
Scripts = scripts
|
||||
}
|
||||
|
||||
var Scripts map[string]*Commands
|
||||
|
||||
type Commands struct {
|
||||
Exec Execute
|
||||
Requirements Requirements
|
||||
Description string
|
||||
}
|
||||
|
||||
type Execute func() error
|
||||
type Requirements func() string
|
||||
|
||||
func Help() error {
|
||||
fmt.Printf("All commands:\n\n")
|
||||
for k, v := range Scripts {
|
||||
fmt.Printf("name: %s\n", k)
|
||||
fmt.Printf("description: %s\n", v.Description)
|
||||
fmt.Printf("requirements: %s\n\n", v.Requirements())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Requirement() string {
|
||||
return "none"
|
||||
}
|
||||
32
internal/command/email_pass_to_oidc/dto.go
Normal file
32
internal/command/email_pass_to_oidc/dto.go
Normal file
@ -0,0 +1,32 @@
|
||||
package commandEmailPassToOidc
|
||||
|
||||
type KeycloakUser struct {
|
||||
ID string `json:"id"`
|
||||
Username string `json:"username"`
|
||||
FirstName string `json:"firstName"`
|
||||
LastName string `json:"lastName"`
|
||||
Email string `json:"email"`
|
||||
EmailVerified bool `json:"emailVerified"`
|
||||
Attributes map[string][]string `json:"attributes"`
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
|
||||
type KeycloakTokenResponse struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
TokenType string `json:"token_type"`
|
||||
ExpiresIn int `json:"expires_in"`
|
||||
}
|
||||
|
||||
type LoopUser struct {
|
||||
Id string `json:"id" db:"id"`
|
||||
Username string `json:"username" db:"username"`
|
||||
Password string `json:"password,omitempty" db:"password"`
|
||||
AuthData *string `json:"auth_data,omitempty" db:"authdata"`
|
||||
AuthService *string `json:"auth_service" db:"authservice"`
|
||||
Email string `json:"email" db:"email"`
|
||||
EmailVerified bool `json:"email_verified,omitempty" db:"emailverified"`
|
||||
Nickname string `json:"nickname" db:"nickname"`
|
||||
FirstName string `json:"first_name" db:"firstname"`
|
||||
LastName string `json:"last_name" db:"lastname"`
|
||||
Roles string `json:"roles" db:"roles"`
|
||||
}
|
||||
154
internal/command/email_pass_to_oidc/exec.go
Normal file
154
internal/command/email_pass_to_oidc/exec.go
Normal file
@ -0,0 +1,154 @@
|
||||
package commandEmailPassToOidc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
c "scripts/internal/config"
|
||||
l "scripts/pkg/logger"
|
||||
"scripts/pkg/postgres"
|
||||
)
|
||||
|
||||
const Name = "usersUpdateLoginMethod"
|
||||
|
||||
func UsersUpdateLoginMethod() error {
|
||||
postgres.InitDB()
|
||||
defer postgres.DB.Close()
|
||||
|
||||
tokenData, err := keycloakAccessToken()
|
||||
if err != nil {
|
||||
l.Log.Error().Err(err).Msg("failed to get access token from keycloak")
|
||||
return err
|
||||
}
|
||||
|
||||
loopUsers, err := allLoopUsers()
|
||||
if err != nil {
|
||||
l.Log.Error().Err(err).Msg("failed to get users from loop db")
|
||||
return err
|
||||
}
|
||||
|
||||
if len(loopUsers) == 0 {
|
||||
l.Log.Info().Msg("no users in loop db for change login")
|
||||
return nil
|
||||
}
|
||||
|
||||
keycloakUsers, err := allKeycloakUsers(tokenData.AccessToken)
|
||||
if err != nil {
|
||||
l.Log.Error().Err(err).Msg("failed to get users from kecloak")
|
||||
return err
|
||||
}
|
||||
|
||||
if err := changeLogin(loopUsers, keycloakUsers); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
l.Log.Info().Str("name", Name).Msg("command successfully")
|
||||
return nil
|
||||
}
|
||||
|
||||
func keycloakAccessToken() (*KeycloakTokenResponse, error) {
|
||||
url := fmt.Sprintf("%s/realms/%s/protocol/openid-connect/token", c.Conf.KeycloakSettings.Address, "master")
|
||||
|
||||
var data bytes.Buffer
|
||||
fmt.Fprintf(&data, "grant_type=password&client_id=admin-cli&username=%s&password=%s", c.Conf.KeycloakSettings.AdminName, c.Conf.KeycloakSettings.AdminPass)
|
||||
|
||||
req, err := http.NewRequest("POST", url, &data)
|
||||
if err != nil {
|
||||
l.Log.Error().Err(err).Msg("failed to create http request")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
|
||||
client := http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
l.Log.Error().Err(err).Msg("failed to exec http request")
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("failed to get access token, status %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
var tokenResp KeycloakTokenResponse
|
||||
if err := json.NewDecoder(resp.Body).Decode(&tokenResp); err != nil {
|
||||
l.Log.Error().Err(err).Msg("failed to decode body response")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &tokenResp, nil
|
||||
}
|
||||
|
||||
func allLoopUsers() (map[string]LoopUser, error) {
|
||||
ctx := postgres.DB.Context()
|
||||
var users []LoopUser
|
||||
|
||||
if err := postgres.DB.Conn().SelectContext(ctx, &users, allUsersQuery); err != nil {
|
||||
l.Log.Error().Err(err).Msg("failed to select query")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make(map[string]LoopUser, len(users))
|
||||
for _, el := range users {
|
||||
result[el.Email] = el
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func allKeycloakUsers(accessToken string) ([]KeycloakUser, error) {
|
||||
url := fmt.Sprintf("%s/admin/realms/%s/users", c.Conf.KeycloakSettings.Address, c.Conf.KeycloakSettings.RealmName)
|
||||
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
l.Log.Error().Err(err).Msg("failed to create http request")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Set("Authorization", "Bearer "+accessToken)
|
||||
|
||||
client := http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
l.Log.Error().Err(err).Msg("failed to exec http request")
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("failed to get users: status %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
var users []KeycloakUser
|
||||
if err := json.NewDecoder(resp.Body).Decode(&users); err != nil {
|
||||
l.Log.Error().Err(err).Msg("failed to decode body response")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func changeLogin(loopUsers map[string]LoopUser, keycloakUsers []KeycloakUser) error {
|
||||
|
||||
for _, el := range keycloakUsers {
|
||||
|
||||
user, exists := loopUsers[el.Email]
|
||||
if !exists {
|
||||
l.Log.Warn().Str("email", el.Email).Msg("user not found")
|
||||
continue
|
||||
}
|
||||
|
||||
// NOTE: если в keycloak не были указаны firstname и lastname - при первои входе сам keycloak спросит их и ЗАМЕНИТ данные в БД loop
|
||||
if _, err := postgres.DB.Conn().ExecContext(postgres.DB.Context(), changeLoginQuery, user.Id, el.ID, el.EmailVerified); err != nil {
|
||||
l.Log.Error().Err(err).Msg("failed to exec update query")
|
||||
return err
|
||||
}
|
||||
|
||||
l.Log.Info().Str("email", el.Email).Msg("successfully update")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
34
internal/command/email_pass_to_oidc/query.go
Normal file
34
internal/command/email_pass_to_oidc/query.go
Normal file
@ -0,0 +1,34 @@
|
||||
package commandEmailPassToOidc
|
||||
|
||||
const (
|
||||
allUsersQuery = `
|
||||
SELECT
|
||||
users.id,
|
||||
users.username,
|
||||
users.password,
|
||||
users.authdata,
|
||||
users.authservice,
|
||||
users.email,
|
||||
users.emailverified,
|
||||
users.nickname,
|
||||
users.firstname,
|
||||
users.lastname,
|
||||
users.roles
|
||||
FROM users
|
||||
LEFT JOIN bots ON users.id = bots.userid
|
||||
WHERE users.deleteat = 0
|
||||
AND bots.userid IS NULL
|
||||
AND roles LIKE '%system_user%'
|
||||
AND roles NOT LIKE '%system_admin%'
|
||||
AND (users.authservice != 'openid' OR users.authservice IS NULL)
|
||||
`
|
||||
|
||||
changeLoginQuery = `
|
||||
UPDATE users
|
||||
SET password = '',
|
||||
authdata = $2,
|
||||
emailverified = $3,
|
||||
authservice = 'openid'
|
||||
WHERE id = $1
|
||||
`
|
||||
)
|
||||
20
internal/command/email_pass_to_oidc/requirement.go
Normal file
20
internal/command/email_pass_to_oidc/requirement.go
Normal file
@ -0,0 +1,20 @@
|
||||
package commandEmailPassToOidc
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
c "scripts/internal/config"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func Requirement() string {
|
||||
var required []string
|
||||
|
||||
t := reflect.TypeFor[c.KeycloakSettings]()
|
||||
|
||||
for field := range t.Fields() {
|
||||
jsonTag := field.Tag.Get("json")
|
||||
required = append(required, jsonTag)
|
||||
}
|
||||
|
||||
return "необходимо задать в конфигурации ключ KeycloakSettings с ключами в объекте: " + strings.Join(required, "; ")
|
||||
}
|
||||
67
internal/config/config.go
Normal file
67
internal/config/config.go
Normal file
@ -0,0 +1,67 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
type SqlSettings struct {
|
||||
DriverName string `json:"DriverName"`
|
||||
DataSource string `json:"DataSource"`
|
||||
DataSourceReplicas []string `json:"DataSourceReplicas"`
|
||||
DataSourceSearchReplicas []string `json:"DataSourceSearchReplicas"`
|
||||
MaxIdleConns int `json:"MaxIdleConns"`
|
||||
ConnMaxLifetimeMilliseconds int64 `json:"ConnMaxLifetimeMilliseconds"`
|
||||
ConnMaxIdleTimeMilliseconds int64 `json:"ConnMaxIdleTimeMilliseconds"`
|
||||
MaxOpenConns int `json:"MaxOpenConns"`
|
||||
Trace bool `json:"Trace"`
|
||||
AtRestEncryptKey string `json:"AtRestEncryptKey"`
|
||||
QueryTimeout int `json:"QueryTimeout"`
|
||||
DisableDatabaseSearch bool `json:"DisableDatabaseSearch"`
|
||||
MigrationsStatementTimeoutSeconds int `json:"MigrationsStatementTimeoutSeconds"`
|
||||
ReplicaMonitorIntervalSeconds int `json:"ReplicaMonitorIntervalSeconds"`
|
||||
// ReplicaLagSettings []ReplicaLagSetting `json:"ReplicaLagSettings"`
|
||||
}
|
||||
|
||||
type LogSettings struct {
|
||||
EnableConsole bool `json:"EnableConsole"`
|
||||
ConsoleLevel string `json:"ConsoleLevel"`
|
||||
ConsoleJson bool `json:"ConsoleJson"`
|
||||
EnableColor bool `json:"EnableColor"`
|
||||
EnableFile bool `json:"EnableFile"`
|
||||
FileLevel string `json:"FileLevel"`
|
||||
FileJson bool `json:"FileJson"`
|
||||
FileLocation string `json:"FileLocation"`
|
||||
EnableWebhookDebugging bool `json:"EnableWebhookDebugging"`
|
||||
EnableDiagnostics bool `json:"EnableDiagnostics"`
|
||||
VerboseDiagnostics bool `json:"VerboseDiagnostics"`
|
||||
EnableSentry bool `json:"EnableSentry"`
|
||||
EnableCaller bool `json:"EnableCaller"`
|
||||
AdvancedLoggingConfig string `json:"AdvancedLoggingConfig"`
|
||||
MaxFieldSize int `json:"MaxFieldSize"`
|
||||
// AdvancedLoggingJSON map[string]interface{} `json:"AdvancedLoggingJSON"`
|
||||
}
|
||||
|
||||
var Conf Config
|
||||
|
||||
type Config struct {
|
||||
SqlSettings SqlSettings `json:"SqlSettings"`
|
||||
LogSettings LogSettings `json:"LogSettings"`
|
||||
KeycloakSettings KeycloakSettings `json:"KeycloakSettings"`
|
||||
}
|
||||
|
||||
func MustLoad(confPath string) {
|
||||
file, err := os.Open(confPath)
|
||||
if err != nil {
|
||||
log.Fatal("err", "failed to open file")
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
decoder := json.NewDecoder(file)
|
||||
if err := decoder.Decode(&Conf); err != nil {
|
||||
log.Fatal(err, "failed to decode")
|
||||
}
|
||||
|
||||
log.Println("init config successfully")
|
||||
}
|
||||
8
internal/config/email_pass_to_oidc.go
Normal file
8
internal/config/email_pass_to_oidc.go
Normal file
@ -0,0 +1,8 @@
|
||||
package config
|
||||
|
||||
type KeycloakSettings struct {
|
||||
Address string `json:"address"`
|
||||
RealmName string `json:"realm_name"`
|
||||
AdminName string `json:"admin_name"`
|
||||
AdminPass string `json:"admin_pass"`
|
||||
}
|
||||
7
pkg/errors/errors.go
Normal file
7
pkg/errors/errors.go
Normal file
@ -0,0 +1,7 @@
|
||||
package errors
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
ErrCommandNotFound = errors.New("command not found")
|
||||
)
|
||||
54
pkg/logger/logger.go
Normal file
54
pkg/logger/logger.go
Normal file
@ -0,0 +1,54 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
c "scripts/internal/config"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
const timeFormat = "2006-01-02 15:04:05"
|
||||
|
||||
var Log zerolog.Logger
|
||||
|
||||
func MustInit() {
|
||||
writers := make([]io.Writer, 0, 2)
|
||||
|
||||
zerolog.TimeFieldFormat = timeFormat
|
||||
|
||||
consoleWriter := zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: timeFormat}
|
||||
writers = append(writers, consoleWriter)
|
||||
|
||||
if c.Conf.LogSettings.EnableFile {
|
||||
logFile, err := os.OpenFile(c.Conf.LogSettings.FileLocation, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
writers = append(writers, logFile)
|
||||
}
|
||||
|
||||
multi := zerolog.MultiLevelWriter(writers...)
|
||||
zCtx := zerolog.New(multi).Level(detectedLogLevel(c.Conf.LogSettings.ConsoleLevel)).With().Timestamp()
|
||||
if c.Conf.LogSettings.EnableCaller {
|
||||
zCtx = zCtx.Caller()
|
||||
}
|
||||
|
||||
Log = zCtx.Logger()
|
||||
}
|
||||
|
||||
func detectedLogLevel(level string) zerolog.Level {
|
||||
switch level {
|
||||
case "TRACE":
|
||||
return zerolog.TraceLevel
|
||||
case "DEBUG":
|
||||
return zerolog.DebugLevel
|
||||
case "WARN":
|
||||
return zerolog.WarnLevel
|
||||
case "INFO":
|
||||
return zerolog.InfoLevel
|
||||
default:
|
||||
return zerolog.InfoLevel
|
||||
}
|
||||
}
|
||||
68
pkg/postgres/connect.go
Normal file
68
pkg/postgres/connect.go
Normal file
@ -0,0 +1,68 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"context"
|
||||
c "scripts/internal/config"
|
||||
l "scripts/pkg/logger"
|
||||
"time"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
_ "github.com/lib/pq"
|
||||
)
|
||||
|
||||
var DB *Postgres
|
||||
|
||||
type Option func(*Postgres)
|
||||
|
||||
type Postgres struct {
|
||||
ctx context.Context
|
||||
conn *sqlx.DB
|
||||
}
|
||||
|
||||
func (p *Postgres) Conn() *sqlx.DB {
|
||||
return p.conn
|
||||
}
|
||||
|
||||
func (p *Postgres) Context() context.Context {
|
||||
return p.ctx
|
||||
}
|
||||
|
||||
func WithContext(ctx context.Context) Option {
|
||||
return func(p *Postgres) {
|
||||
p.ctx = ctx
|
||||
}
|
||||
}
|
||||
|
||||
func InitDB(opts ...Option) {
|
||||
p := &Postgres{
|
||||
ctx: context.Background(),
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(p)
|
||||
}
|
||||
|
||||
db, err := sqlx.ConnectContext(p.ctx, c.Conf.SqlSettings.DriverName, c.Conf.SqlSettings.DataSource)
|
||||
if err != nil {
|
||||
l.Log.Fatal().Err(err).Msg("failed to connect DB")
|
||||
}
|
||||
|
||||
db.SetMaxIdleConns(c.Conf.SqlSettings.MaxIdleConns)
|
||||
db.SetMaxOpenConns(c.Conf.SqlSettings.MaxOpenConns)
|
||||
db.SetConnMaxLifetime(time.Duration(c.Conf.SqlSettings.ConnMaxLifetimeMilliseconds) * time.Millisecond)
|
||||
db.SetConnMaxIdleTime(time.Duration(c.Conf.SqlSettings.ConnMaxIdleTimeMilliseconds) * time.Millisecond)
|
||||
|
||||
if err := db.Ping(); err != nil {
|
||||
l.Log.Fatal().Err(err).Msg("failed to ping DB")
|
||||
}
|
||||
|
||||
p.conn = db
|
||||
DB = p
|
||||
l.Log.Info().Msg("connect to postgres successfully ")
|
||||
}
|
||||
|
||||
func (p *Postgres) Close() {
|
||||
if err := p.Conn().Close(); err != nil {
|
||||
l.Log.Error().Err(err).Msg("failed to close connect DB")
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user