feat: add customer list, modify pagination utils

This commit is contained in:
2026-04-07 09:28:39 +02:00
parent c5cc4f7a48
commit 813d1f4879
8 changed files with 61 additions and 55 deletions

View File

@@ -4,10 +4,12 @@ import (
"strconv" "strconv"
"git.ma-al.com/goc_daniel/b2b/app/delivery/middleware/perms" "git.ma-al.com/goc_daniel/b2b/app/delivery/middleware/perms"
"git.ma-al.com/goc_daniel/b2b/app/model"
"git.ma-al.com/goc_daniel/b2b/app/service/customerService" "git.ma-al.com/goc_daniel/b2b/app/service/customerService"
"git.ma-al.com/goc_daniel/b2b/app/utils/i18n" "git.ma-al.com/goc_daniel/b2b/app/utils/i18n"
"git.ma-al.com/goc_daniel/b2b/app/utils/localeExtractor" "git.ma-al.com/goc_daniel/b2b/app/utils/localeExtractor"
"git.ma-al.com/goc_daniel/b2b/app/utils/nullable" "git.ma-al.com/goc_daniel/b2b/app/utils/nullable"
"git.ma-al.com/goc_daniel/b2b/app/utils/query/query_params"
"git.ma-al.com/goc_daniel/b2b/app/utils/response" "git.ma-al.com/goc_daniel/b2b/app/utils/response"
"git.ma-al.com/goc_daniel/b2b/app/utils/responseErrors" "git.ma-al.com/goc_daniel/b2b/app/utils/responseErrors"
"github.com/gofiber/fiber/v3" "github.com/gofiber/fiber/v3"
@@ -28,7 +30,7 @@ func CustomerHandlerRoutes(r fiber.Router) fiber.Router {
handler := NewCustomerHandler() handler := NewCustomerHandler()
r.Get("", handler.customerData) r.Get("", handler.customerData)
// r.Get("/list", handler.listCustomers) r.Get("/list", handler.listCustomers)
return r return r
} }
@@ -67,41 +69,28 @@ func (h *customerHandler) customerData(fc fiber.Ctx) error {
return fc.JSON(response.Make(&customer, 0, i18n.T_(fc, response.Message_OK))) return fc.JSON(response.Make(&customer, 0, i18n.T_(fc, response.Message_OK)))
} }
// func (h *customerHandler) listCustomers(fc fiber.Ctx) error { func (h *customerHandler) listCustomers(fc fiber.Ctx) error {
// var customerId uint p, filt, err := query_params.ParseFilters[model.Customer](fc, columnMappingListProducts)
// customerIdStr := fc.Query("id") if err != nil {
// if customerIdStr != "" { return fc.Status(responseErrors.GetErrorStatus(err)).
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(fc, err)))
}
// user, ok := localeExtractor.GetCustomer(fc) user, ok := localeExtractor.GetCustomer(fc)
// if !ok || user == nil { if !ok || user == nil {
// return fc.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)). return fc.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).
// JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(fc, responseErrors.ErrBadAttribute))) JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(fc, responseErrors.ErrBadAttribute)))
// } }
// id, err := strconv.ParseUint(customerIdStr, 10, 64) if !user.HasPermission(perms.UserReadAny) {
// if err != nil { return fc.Status(fiber.StatusForbidden).
// return fiber.ErrBadRequest JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(fc, responseErrors.ErrForbidden)))
// } }
// if user.UserID != uint(id) && !user.HasPermission(perms.UserReadAny) { customer, err := h.service.Find(user.LangID, p, filt)
// return fc.Status(fiber.StatusForbidden). if err != nil {
// JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(fc, responseErrors.ErrForbidden))) return fc.Status(responseErrors.GetErrorStatus(err)).
// } JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(fc, err)))
}
// customerId = uint(id) return fc.JSON(response.Make(&customer, 0, i18n.T_(fc, response.Message_OK)))
// } else { }
// id, ok := fc.Locals("userID").(uint)
// if !ok {
// return fc.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).
// JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(fc, responseErrors.ErrBadAttribute)))
// }
// customerId = id
// }
// customer, err := h.service.GetById(customerId)
// if err != nil {
// return fc.Status(responseErrors.GetErrorStatus(err)).
// JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(fc, err)))
// }
// return fc.JSON(response.Make(&customer, 0, i18n.T_(fc, response.Message_OK)))
// }

View File

@@ -15,7 +15,7 @@ type Customer struct {
FirstName string `gorm:"size:100" json:"first_name"` FirstName string `gorm:"size:100" json:"first_name"`
LastName string `gorm:"size:100" json:"last_name"` LastName string `gorm:"size:100" json:"last_name"`
RoleID uint `gorm:"column:role_id;not null;default:1" json:"-"` RoleID uint `gorm:"column:role_id;not null;default:1" json:"-"`
Role Role `gorm:"foreignKey:RoleID" json:"role"` Role *Role `gorm:"foreignKey:RoleID" json:"role,omitempty"`
Provider AuthProvider `gorm:"type:varchar(20);default:'local'" json:"provider"` Provider AuthProvider `gorm:"type:varchar(20);default:'local'" json:"provider"`
ProviderID string `gorm:"size:255" json:"provider_id,omitempty"` // ID from OAuth provider ProviderID string `gorm:"size:255" json:"provider_id,omitempty"` // ID from OAuth provider
AvatarURL string `gorm:"size:500" json:"avatar_url,omitempty"` AvatarURL string `gorm:"size:500" json:"avatar_url,omitempty"`

View File

@@ -3,10 +3,13 @@ package customerRepo
import ( import (
"git.ma-al.com/goc_daniel/b2b/app/db" "git.ma-al.com/goc_daniel/b2b/app/db"
"git.ma-al.com/goc_daniel/b2b/app/model" "git.ma-al.com/goc_daniel/b2b/app/model"
"git.ma-al.com/goc_daniel/b2b/app/utils/query/filters"
"git.ma-al.com/goc_daniel/b2b/app/utils/query/find"
) )
type UICustomerRepo interface { type UICustomerRepo interface {
Get(id uint) (*model.Customer, error) Get(id uint) (*model.Customer, error)
Find(langId uint, p find.Paging, filt *filters.FiltersList) (*find.Found[model.Customer], error)
} }
type CustomerRepo struct{} type CustomerRepo struct{}
@@ -25,3 +28,12 @@ func (repo *CustomerRepo) Get(id uint) (*model.Customer, error) {
return &customer, err return &customer, err
} }
func (repo *CustomerRepo) Find(langId uint, p find.Paging, filt *filters.FiltersList) (*find.Found[model.Customer], error) {
found, err := find.Paginate[model.Customer](langId, p, db.DB.
Model(&model.Customer{}).
Scopes(filt.All()...),
)
return &found, err
}

View File

@@ -153,7 +153,6 @@ func (s *AuthService) Register(req *model.RegisterRequest) error {
Password: string(hashedPassword), Password: string(hashedPassword),
FirstName: req.FirstName, FirstName: req.FirstName,
LastName: req.LastName, LastName: req.LastName,
Role: model.Role{},
Provider: model.ProviderLocal, Provider: model.ProviderLocal,
IsActive: false, IsActive: false,
EmailVerified: false, EmailVerified: false,

View File

@@ -150,7 +150,6 @@ func (s *AuthService) findOrCreateGoogleUser(info *view.GoogleUserInfo) (*model.
Provider: model.ProviderGoogle, Provider: model.ProviderGoogle,
ProviderID: info.ID, ProviderID: info.ID,
AvatarURL: info.Picture, AvatarURL: info.Picture,
Role: model.Role{},
IsActive: true, IsActive: true,
EmailVerified: true, EmailVerified: true,
LangID: 2, // default is english LangID: 2, // default is english

View File

@@ -3,6 +3,8 @@ package customerService
import ( import (
"git.ma-al.com/goc_daniel/b2b/app/model" "git.ma-al.com/goc_daniel/b2b/app/model"
"git.ma-al.com/goc_daniel/b2b/app/repos/customerRepo" "git.ma-al.com/goc_daniel/b2b/app/repos/customerRepo"
"git.ma-al.com/goc_daniel/b2b/app/utils/query/filters"
"git.ma-al.com/goc_daniel/b2b/app/utils/query/find"
) )
type CustomerService struct { type CustomerService struct {
@@ -18,3 +20,7 @@ func New() *CustomerService {
func (s *CustomerService) GetById(id uint) (*model.Customer, error) { func (s *CustomerService) GetById(id uint) (*model.Customer, error) {
return s.repo.Get(id) return s.repo.Get(id)
} }
func (s *CustomerService) Find(langId uint, p find.Paging, filt *filters.FiltersList) (*find.Found[model.Customer], error) {
return s.repo.Find(langId, p, filt)
}

View File

@@ -1,7 +1,6 @@
package find package find
import ( import (
"errors"
"reflect" "reflect"
"strings" "strings"
@@ -28,18 +27,13 @@ type Found[T any] struct {
Spec map[string]interface{} `json:"spec,omitempty"` Spec map[string]interface{} `json:"spec,omitempty"`
} }
// Wraps given query adding limit, offset clauses and SQL_CALC_FOUND_ROWS to it
// and running SELECT FOUND_ROWS() afterwards to fetch the total number
// (ignoring LIMIT) of results. The final results are wrapped into the
// [find.Found] type.
func Paginate[T any](langID uint, paging Paging, stmt *gorm.DB) (Found[T], error) { func Paginate[T any](langID uint, paging Paging, stmt *gorm.DB) (Found[T], error) {
var items []T var items []T
var count uint64 var count int64
// stmt.Debug() stmt.Count(&count)
err := stmt. err := stmt.
Clauses(SqlCalcFound()).
Offset(paging.Offset()). Offset(paging.Offset()).
Limit(paging.Limit()). Limit(paging.Limit()).
Find(&items). Find(&items).
@@ -48,14 +42,6 @@ func Paginate[T any](langID uint, paging Paging, stmt *gorm.DB) (Found[T], error
return Found[T]{}, err return Found[T]{}, err
} }
countInterface, ok := stmt.Get(FOUND_ROWS_CTX_KEY)
if !ok {
return Found[T]{}, errors.New(FOUND_ROWS_CTX_KEY + " value was not found in the gorm db context")
}
if count, ok = countInterface.(uint64); !ok {
return Found[T]{}, errors.New("failed to cast value under " + FOUND_ROWS_CTX_KEY + " to uint64")
}
columnsSpec := GetColumnsSpec[T](langID) columnsSpec := GetColumnsSpec[T](langID)
return Found[T]{ return Found[T]{

View File

@@ -0,0 +1,15 @@
info:
name: Customer list
type: http
seq: 3
http:
method: GET
url: "{{bas_url}}/restricted/customer/list"
auth: inherit
settings:
encodeUrl: true
timeout: 0
followRedirects: true
maxRedirects: 5