mirror of
https://github.com/emo2007/block-accounting.git
synced 2025-04-12 08:56:28 +00:00
login and tokens implemented
This commit is contained in:
parent
eeb2ad30f4
commit
86bd1107ce
2
backend/.vscode/launch.json
vendored
2
backend/.vscode/launch.json
vendored
@ -16,7 +16,7 @@
|
|||||||
"-log-add-source=true",
|
"-log-add-source=true",
|
||||||
"-jwt-secret=local_jwt_secret",
|
"-jwt-secret=local_jwt_secret",
|
||||||
|
|
||||||
"-rest-address=localhost:8080",
|
"-rest-address=localhost:8081",
|
||||||
"-db-host=localhost:8432",
|
"-db-host=localhost:8432",
|
||||||
"-db-database=blockd",
|
"-db-database=blockd",
|
||||||
"-db-user=blockd",
|
"-db-user=blockd",
|
||||||
|
@ -25,7 +25,7 @@ run.local: bin.build
|
|||||||
-log-level=debug \
|
-log-level=debug \
|
||||||
-log-local=true \
|
-log-local=true \
|
||||||
-log-add-source=true \
|
-log-add-source=true \
|
||||||
-rest-address=localhost:8080 \
|
-rest-address=localhost:8081 \
|
||||||
-db-host=localhost:8432 \
|
-db-host=localhost:8432 \
|
||||||
-db-database=blockd \
|
-db-database=blockd \
|
||||||
-db-user=blockd \
|
-db-user=blockd \
|
||||||
@ -39,7 +39,7 @@ run.debug: bin.build
|
|||||||
-log-level=debug \
|
-log-level=debug \
|
||||||
-log-local=false \
|
-log-local=false \
|
||||||
-log-add-source=true \
|
-log-add-source=true \
|
||||||
-rest-address=localhost:8080 \
|
-rest-address=localhost:8081 \
|
||||||
-db-host=localhost:8432 \
|
-db-host=localhost:8432 \
|
||||||
-db-database=blockd \
|
-db-database=blockd \
|
||||||
-db-user=blockd \
|
-db-user=blockd \
|
||||||
|
@ -8,8 +8,10 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/emochka2007/block-accounting/internal/interface/rest/domain"
|
||||||
"github.com/emochka2007/block-accounting/internal/interface/rest/presenters"
|
"github.com/emochka2007/block-accounting/internal/interface/rest/presenters"
|
||||||
"github.com/emochka2007/block-accounting/internal/pkg/bip32"
|
"github.com/emochka2007/block-accounting/internal/pkg/bip32"
|
||||||
|
"github.com/emochka2007/block-accounting/internal/pkg/hdwallet"
|
||||||
"github.com/emochka2007/block-accounting/internal/usecase/interactors/jwt"
|
"github.com/emochka2007/block-accounting/internal/usecase/interactors/jwt"
|
||||||
"github.com/emochka2007/block-accounting/internal/usecase/interactors/users"
|
"github.com/emochka2007/block-accounting/internal/usecase/interactors/users"
|
||||||
)
|
)
|
||||||
@ -45,19 +47,15 @@ func NewAuthController(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *authController) Join(w http.ResponseWriter, req *http.Request) error {
|
func (c *authController) Join(w http.ResponseWriter, req *http.Request) error {
|
||||||
request, err := c.presenter.CreateJoinRequest(req)
|
request, err := presenters.CreateRequest[domain.JoinRequest](req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.presenter.ResponseJoin(
|
return fmt.Errorf("error create join request. %w", err)
|
||||||
w, nil, fmt.Errorf("error create join request. %w", err),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
c.log.Debug("join request", slog.String("mnemonic", request.Mnemonic))
|
c.log.Debug("join request", slog.String("mnemonic", request.Mnemonic))
|
||||||
|
|
||||||
if !bip32.IsMnemonicValid(request.Mnemonic) {
|
if !bip32.IsMnemonicValid(request.Mnemonic) {
|
||||||
return c.presenter.ResponseJoin(
|
return fmt.Errorf("error invalid mnemonic. %w", ErrorAuthInvalidMnemonic)
|
||||||
w, nil, fmt.Errorf("error invalid mnemonic. %w", ErrorAuthInvalidMnemonic),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(req.Context(), 5*time.Second)
|
ctx, cancel := context.WithTimeout(req.Context(), 5*time.Second)
|
||||||
@ -69,22 +67,53 @@ func (c *authController) Join(w http.ResponseWriter, req *http.Request) error {
|
|||||||
Activate: true,
|
Activate: true,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.presenter.ResponseJoin(w, nil, fmt.Errorf("error create new user. %w", err))
|
return fmt.Errorf("error create new user. %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.presenter.ResponseJoin(w, user, nil)
|
c.log.Debug("join request", slog.String("user id", user.ID.String()))
|
||||||
|
|
||||||
|
return c.presenter.ResponseJoin(w, user)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NIT: wrap with idempotent action handler
|
||||||
|
func (c *authController) Login(w http.ResponseWriter, req *http.Request) error {
|
||||||
|
request, err := presenters.CreateRequest[domain.LoginRequest](req)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error create login request. %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.log.Debug("login request", slog.String("mnemonic", request.Mnemonic))
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(req.Context(), 5*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
seed, err := hdwallet.NewSeedFromMnemonic(request.Mnemonic)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error create seed from mnemonic. %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
users, err := c.usersInteractor.Get(ctx, users.GetParams{
|
||||||
|
Seed: seed,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error fetch user by seed. %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(users) == 0 {
|
||||||
|
return fmt.Errorf("error empty users set")
|
||||||
|
}
|
||||||
|
|
||||||
|
c.log.Debug("login request", slog.String("user id", users[0].ID.String()))
|
||||||
|
|
||||||
|
return c.presenter.ResponseLogin(w, users[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
// const mnemonicEntropyBitSize int = 256
|
||||||
|
|
||||||
|
func (c *authController) Invite(w http.ResponseWriter, req *http.Request) error {
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *authController) JoinWithInvite(w http.ResponseWriter, req *http.Request) error {
|
func (c *authController) JoinWithInvite(w http.ResponseWriter, req *http.Request) error {
|
||||||
return nil // implement
|
return nil // implement
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *authController) Login(w http.ResponseWriter, req *http.Request) error {
|
|
||||||
return nil // implement
|
|
||||||
}
|
|
||||||
|
|
||||||
const mnemonicEntropyBitSize int = 256
|
|
||||||
|
|
||||||
func (c *authController) Invite(w http.ResponseWriter, req *http.Request) error {
|
|
||||||
return nil // implement
|
|
||||||
}
|
|
||||||
|
10
backend/internal/interface/rest/controllers/organization.go
Normal file
10
backend/internal/interface/rest/controllers/organization.go
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package controllers
|
||||||
|
|
||||||
|
import "log/slog"
|
||||||
|
|
||||||
|
type OrganizationsController interface {
|
||||||
|
}
|
||||||
|
|
||||||
|
type organizationsController struct {
|
||||||
|
log *slog.Logger
|
||||||
|
}
|
@ -10,24 +10,15 @@ type JoinRequest struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type JoinResponse struct {
|
type JoinResponse struct {
|
||||||
Ok bool `json:"ok"`
|
Token string `json:"token"`
|
||||||
Token string `json:"token,omitempty"`
|
|
||||||
Error *Error `json:"error,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type LoginRequest struct {
|
type LoginRequest struct {
|
||||||
Mnemonc string `json:"mnemonic"`
|
Mnemonic string `json:"mnemonic"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type LoginResponse struct {
|
type LoginResponse struct {
|
||||||
Ok bool `json:"ok"`
|
Token string `json:"token"`
|
||||||
Token string `json:"token,omitempty"`
|
|
||||||
Error *Error `json:"error,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Error struct {
|
|
||||||
Code int `json:"code"`
|
|
||||||
Message string `json:"message"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func BuildRequest[T any](data []byte) (*T, error) {
|
func BuildRequest[T any](data []byte) (*T, error) {
|
||||||
|
@ -1,22 +1,28 @@
|
|||||||
package rest
|
package rest
|
||||||
|
|
||||||
import "net/http"
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/emochka2007/block-accounting/internal/interface/rest/controllers"
|
||||||
|
)
|
||||||
|
|
||||||
type apiError struct {
|
type apiError struct {
|
||||||
Code int `json:"code"`
|
Code int `json:"code"`
|
||||||
Error string `json:"error"`
|
Message string `json:"message"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildApiError(code int, message string) apiError {
|
func buildApiError(code int, message string) apiError {
|
||||||
return apiError{
|
return apiError{
|
||||||
Code: code,
|
Code: code,
|
||||||
Error: message,
|
Message: message,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func mapError(_ error) apiError {
|
func mapError(err error) apiError {
|
||||||
// todo map typed errors
|
|
||||||
switch {
|
switch {
|
||||||
|
case errors.Is(err, controllers.ErrorAuthInvalidMnemonic):
|
||||||
|
return buildApiError(http.StatusBadRequest, "Invalid Mnemonic")
|
||||||
default:
|
default:
|
||||||
return buildApiError(http.StatusInternalServerError, "Internal Server Error")
|
return buildApiError(http.StatusInternalServerError, "Internal Server Error")
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package presenters
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -13,8 +12,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type AuthPresenter interface {
|
type AuthPresenter interface {
|
||||||
CreateJoinRequest(r *http.Request) (*domain.JoinRequest, error)
|
ResponseJoin(w http.ResponseWriter, user *models.User) error
|
||||||
ResponseJoin(w http.ResponseWriter, user *models.User, err error) error
|
ResponseLogin(w http.ResponseWriter, user *models.User) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type authPresenter struct {
|
type authPresenter struct {
|
||||||
@ -29,38 +28,16 @@ func NewAuthPresenter(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *authPresenter) CreateJoinRequest(r *http.Request) (*domain.JoinRequest, error) {
|
func (p *authPresenter) ResponseJoin(w http.ResponseWriter, user *models.User) error {
|
||||||
defer r.Body.Close()
|
|
||||||
|
|
||||||
data, err := io.ReadAll(r.Body)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error read request body. %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var request domain.JoinRequest
|
|
||||||
|
|
||||||
if err := json.Unmarshal(data, &request); err != nil {
|
|
||||||
return nil, fmt.Errorf("error unmarshal join request. %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &request, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *authPresenter) ResponseJoin(w http.ResponseWriter, user *models.User, err error) error {
|
|
||||||
resp := new(domain.JoinResponse)
|
resp := new(domain.JoinResponse)
|
||||||
|
|
||||||
|
token, err := p.jwtInteractor.NewToken(user, 24*time.Hour)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// todo map error
|
return fmt.Errorf("error create access token. %w", err)
|
||||||
} else {
|
|
||||||
token, err := p.jwtInteractor.NewToken(user, 24*time.Hour)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error create access token. %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.Ok = true
|
|
||||||
resp.Token = token
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resp.Token = token
|
||||||
|
|
||||||
out, err := json.Marshal(resp)
|
out, err := json.Marshal(resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error marshal join response. %w", err)
|
return fmt.Errorf("error marshal join response. %w", err)
|
||||||
@ -72,3 +49,25 @@ func (p *authPresenter) ResponseJoin(w http.ResponseWriter, user *models.User, e
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *authPresenter) ResponseLogin(w http.ResponseWriter, user *models.User) error {
|
||||||
|
resp := new(domain.LoginResponse)
|
||||||
|
|
||||||
|
token, err := p.jwtInteractor.NewToken(user, 24*time.Hour)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error create access token. %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.Token = token
|
||||||
|
|
||||||
|
out, err := json.Marshal(resp)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error marshal login response. %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = w.Write(out); err != nil {
|
||||||
|
return fmt.Errorf("error write response. %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
25
backend/internal/interface/rest/presenters/request.go
Normal file
25
backend/internal/interface/rest/presenters/request.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package presenters
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CreateRequest[T any](r *http.Request) (*T, error) {
|
||||||
|
defer r.Body.Close()
|
||||||
|
|
||||||
|
data, err := io.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error read request body. %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var request T
|
||||||
|
|
||||||
|
if err := json.Unmarshal(data, &request); err != nil {
|
||||||
|
return nil, fmt.Errorf("error unmarshal join request. %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &request, nil
|
||||||
|
}
|
@ -84,11 +84,11 @@ func (s *Server) buildRouter() {
|
|||||||
s.Use(s.handleMw)
|
s.Use(s.handleMw)
|
||||||
s.Use(render.SetContentType(render.ContentTypeJSON))
|
s.Use(render.SetContentType(render.ContentTypeJSON))
|
||||||
|
|
||||||
s.Get("/ping", s.handlePing) // debug
|
s.Get("/ping", s.handle(s.controllers.Ping.Ping, "ping"))
|
||||||
|
|
||||||
// auth
|
// auth
|
||||||
s.Post("/join", s.handle(s.handleJoin, "join")) // new user
|
s.Post("/join", s.handle(s.controllers.Auth.Join, "join"))
|
||||||
s.Post("/login", nil) // login
|
s.Post("/login", s.handle(s.controllers.Auth.Login, "login"))
|
||||||
|
|
||||||
s.Route("/organization/{organization_id}", func(r chi.Router) {
|
s.Route("/organization/{organization_id}", func(r chi.Router) {
|
||||||
s.Route("/transactions", func(r chi.Router) {
|
s.Route("/transactions", func(r chi.Router) {
|
||||||
@ -110,7 +110,10 @@ func (s *Server) buildRouter() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) handle(h http.HandlerFunc, method_name string) http.HandlerFunc {
|
func (s *Server) handle(
|
||||||
|
h func(w http.ResponseWriter, req *http.Request) error,
|
||||||
|
method_name string,
|
||||||
|
) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
started := time.Now()
|
started := time.Now()
|
||||||
defer func() {
|
defer func() {
|
||||||
@ -122,11 +125,17 @@ func (s *Server) handle(h http.HandlerFunc, method_name string) http.HandlerFunc
|
|||||||
"method_name": method_name,
|
"method_name": method_name,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
metrics.RequestsAccepted.Add(1)
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
h(w, r)
|
if err := h(w, r); err != nil {
|
||||||
|
s.log.Error(
|
||||||
|
"http error",
|
||||||
|
slog.String("method_name", method_name),
|
||||||
|
logger.Err(err),
|
||||||
|
)
|
||||||
|
|
||||||
|
s.responseError(w, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,17 +171,3 @@ func (s *Server) handleMw(next http.Handler) http.Handler {
|
|||||||
|
|
||||||
return http.HandlerFunc(fn)
|
return http.HandlerFunc(fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) handleJoin(w http.ResponseWriter, req *http.Request) {
|
|
||||||
if err := s.controllers.Auth.Join(w, req); err != nil {
|
|
||||||
s.responseError(w, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) handlePing(w http.ResponseWriter, req *http.Request) {
|
|
||||||
s.log.Debug("ping request")
|
|
||||||
|
|
||||||
if err := s.controllers.Ping.Ping(w, req); err != nil {
|
|
||||||
s.responseError(w, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -2,6 +2,7 @@ package users
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"time"
|
"time"
|
||||||
@ -12,6 +13,10 @@ import (
|
|||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrorUsersNotFound = errors.New("users not found")
|
||||||
|
)
|
||||||
|
|
||||||
type CreateParams struct {
|
type CreateParams struct {
|
||||||
Mnemonic string
|
Mnemonic string
|
||||||
IsAdmin bool
|
IsAdmin bool
|
||||||
@ -88,7 +93,20 @@ func (i *usersInteractor) Activate(ctx context.Context, params ActivateParams) e
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (i *usersInteractor) Get(ctx context.Context, params GetParams) ([]*models.User, error) {
|
func (i *usersInteractor) Get(ctx context.Context, params GetParams) ([]*models.User, error) {
|
||||||
return nil, nil
|
users, err := i.usersRepo.Get(ctx, users.GetParams{
|
||||||
|
Ids: params.Ids,
|
||||||
|
OrganizationId: params.OrganizationId,
|
||||||
|
Seed: params.Seed,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error fetch users from repository. %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(users) == 0 {
|
||||||
|
return nil, fmt.Errorf("error empty users set. %w", ErrorUsersNotFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
return users, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *usersInteractor) Delete(ctx context.Context, params DeleteParams) error {
|
func (i *usersInteractor) Delete(ctx context.Context, params DeleteParams) error {
|
||||||
|
@ -3,6 +3,7 @@ package users
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -14,13 +15,13 @@ import (
|
|||||||
|
|
||||||
type GetParams struct {
|
type GetParams struct {
|
||||||
Ids uuid.UUIDs
|
Ids uuid.UUIDs
|
||||||
OrganizationId uuid.UUIDs
|
OrganizationId uuid.UUID
|
||||||
Seed []byte
|
Seed []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo implement
|
// todo implement
|
||||||
type Repository interface {
|
type Repository interface {
|
||||||
Get(ctx context.Context, params GetParams) (*models.User, error)
|
Get(ctx context.Context, params GetParams) ([]*models.User, error)
|
||||||
Create(ctx context.Context, user *models.User) error
|
Create(ctx context.Context, user *models.User) error
|
||||||
Activate(ctx context.Context, id uuid.UUID) error
|
Activate(ctx context.Context, id uuid.UUID) error
|
||||||
Update(ctx context.Context, user *models.User) error
|
Update(ctx context.Context, user *models.User) error
|
||||||
@ -45,16 +46,65 @@ func (s *repositorySQL) Conn(ctx context.Context) sqltools.DBTX {
|
|||||||
return s.db
|
return s.db
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *repositorySQL) Get(ctx context.Context, params GetParams) (*models.User, error) {
|
func (r *repositorySQL) Get(ctx context.Context, params GetParams) ([]*models.User, error) {
|
||||||
var user *models.User
|
var users []*models.User = make([]*models.User, 0, len(params.Ids))
|
||||||
|
|
||||||
|
if err := sqltools.Transaction(ctx, r.db, func(ctx context.Context) (err error) {
|
||||||
|
query := sq.Select("id, seed, created_at, activated_at").
|
||||||
|
From("users").
|
||||||
|
PlaceholderFormat(sq.Dollar)
|
||||||
|
|
||||||
|
if len(params.Ids) > 0 {
|
||||||
|
query = query.Where("id", params.Ids)
|
||||||
|
}
|
||||||
|
|
||||||
|
// if params.OrganizationId != uuid.Nil {
|
||||||
|
// // todo join org users
|
||||||
|
// }
|
||||||
|
|
||||||
|
if params.Seed != nil {
|
||||||
|
query = query.Where("seed = ?", params.Seed)
|
||||||
|
}
|
||||||
|
|
||||||
|
rows, err := query.RunWith(r.Conn(ctx)).QueryContext(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error fetch data from database. %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if cErr := rows.Close(); cErr != nil {
|
||||||
|
err = errors.Join(fmt.Errorf("error close database rows. %w", cErr), err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
var (
|
||||||
|
id uuid.UUID
|
||||||
|
seed []byte
|
||||||
|
//isAdmin bool
|
||||||
|
createdAt time.Time
|
||||||
|
activatedAt sql.NullTime
|
||||||
|
)
|
||||||
|
|
||||||
|
if err = rows.Scan(&id, &seed, &createdAt, &activatedAt); err != nil {
|
||||||
|
return fmt.Errorf("error scan row. %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
users = append(users, &models.User{
|
||||||
|
ID: id,
|
||||||
|
Bip32Seed: seed,
|
||||||
|
//Admin: isAdmin,
|
||||||
|
CreatedAt: createdAt,
|
||||||
|
Activated: activatedAt.Valid,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if err := sqltools.Transaction(ctx, r.db, func(ctx context.Context) error {
|
|
||||||
return nil
|
return nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, fmt.Errorf("error execute transactional operation. %w", err)
|
return nil, fmt.Errorf("error execute transactional operation. %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return user, nil
|
return users, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *repositorySQL) Create(ctx context.Context, user *models.User) error {
|
func (r *repositorySQL) Create(ctx context.Context, user *models.User) error {
|
||||||
|
Loading…
Reference in New Issue
Block a user