2026-03-16 18:06:59 +03:00

155 lines
4.0 KiB
Go

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
}