281 lines
8.4 KiB
Go
281 lines
8.4 KiB
Go
package repository
|
|
|
|
import (
|
|
"fmt"
|
|
"netidhub-saas-be/app/database"
|
|
"netidhub-saas-be/app/database/entity"
|
|
"netidhub-saas-be/app/module/clients/request"
|
|
"netidhub-saas-be/utils/client"
|
|
"netidhub-saas-be/utils/paginator"
|
|
"strings"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/rs/zerolog"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
type clientsRepository struct {
|
|
DB *database.Database
|
|
Log zerolog.Logger
|
|
}
|
|
|
|
// ClientsRepository define interface of IClientsRepository
|
|
type ClientsRepository interface {
|
|
GetAll(req request.ClientsQueryRequest) (clientss []*entity.Clients, paging paginator.Pagination, err error)
|
|
FindOne(id uuid.UUID) (clients *entity.Clients, err error)
|
|
FindOneByClientId(clientId *uuid.UUID) (clients *entity.Clients, err error)
|
|
FindByName(name string) (clients *entity.Clients, err error)
|
|
FindByImagePathName(name string) (clients *entity.Clients, err error)
|
|
Create(clients *entity.Clients) (clientsReturn *entity.Clients, err error)
|
|
Update(id uuid.UUID, clients *entity.Clients) (err error)
|
|
Delete(id uuid.UUID) (err error)
|
|
|
|
// New hierarchy methods
|
|
GetWithHierarchy(clientId uuid.UUID) (*entity.Clients, error)
|
|
GetSubClients(parentId uuid.UUID, includeInactive bool) ([]entity.Clients, error)
|
|
GetAllSubClients(parentId uuid.UUID) ([]entity.Clients, error)
|
|
GetRootClients() ([]entity.Clients, error)
|
|
GetClientStats(clientId uuid.UUID) (map[string]interface{}, error)
|
|
MoveClient(clientId, newParentId uuid.UUID) error
|
|
IsParentClient(clientId uuid.UUID) (bool, error)
|
|
}
|
|
|
|
func NewClientsRepository(db *database.Database, logger zerolog.Logger) ClientsRepository {
|
|
return &clientsRepository{
|
|
DB: db,
|
|
Log: logger,
|
|
}
|
|
}
|
|
|
|
// implement interface of IClientsRepository
|
|
func (_i *clientsRepository) GetAll(req request.ClientsQueryRequest) (clientss []*entity.Clients, paging paginator.Pagination, err error) {
|
|
var count int64
|
|
|
|
query := _i.DB.DB.Model(&entity.Clients{})
|
|
|
|
// Name filter
|
|
if req.Name != nil && *req.Name != "" {
|
|
name := strings.ToLower(*req.Name)
|
|
query = query.Where("LOWER(name) LIKE ?", "%"+strings.ToLower(name)+"%")
|
|
}
|
|
|
|
// Type filter
|
|
if req.ClientType != nil && *req.ClientType != "" && *req.ClientType != "all" {
|
|
query = query.Where("client_type = ?", *req.ClientType)
|
|
}
|
|
|
|
// Parent filter
|
|
if req.ParentClientId != nil {
|
|
query = query.Where("parent_client_id = ?", *req.ParentClientId)
|
|
}
|
|
|
|
// Only parent clients
|
|
if req.OnlyParentClients != nil && *req.OnlyParentClients {
|
|
query = query.Where("id IN (SELECT DISTINCT parent_client_id FROM clients WHERE parent_client_id IS NOT NULL)")
|
|
}
|
|
|
|
// Only standalone
|
|
if req.OnlyStandalone != nil && *req.OnlyStandalone {
|
|
query = query.Where("client_type = ?", "standalone")
|
|
}
|
|
|
|
// Active filter
|
|
if req.IsActive != nil {
|
|
query = query.Where("is_active = ?", *req.IsActive)
|
|
} else {
|
|
query = query.Where("is_active = ?", true) // Default: only active
|
|
}
|
|
|
|
// Preload relationships
|
|
query = query.Preload("ParentClient").Preload("SubClients", "is_active = ?", true)
|
|
|
|
// Count total records
|
|
query.Count(&count)
|
|
|
|
// Apply sorting
|
|
if req.Pagination.SortBy != "" {
|
|
direction := "ASC"
|
|
if req.Pagination.Sort == "desc" {
|
|
direction = "DESC"
|
|
}
|
|
query.Order(fmt.Sprintf("%s %s", req.Pagination.SortBy, direction))
|
|
} else {
|
|
direction := "DESC"
|
|
sortBy := "created_at"
|
|
query.Order(fmt.Sprintf("%s %s", sortBy, direction))
|
|
}
|
|
|
|
// Apply pagination (manual calculation for better performance)
|
|
page := req.Pagination.Page
|
|
limit := req.Pagination.Limit
|
|
if page <= 0 {
|
|
page = 1
|
|
}
|
|
if limit <= 0 {
|
|
limit = 10
|
|
}
|
|
|
|
offset := (page - 1) * limit
|
|
err = query.Offset(offset).Limit(limit).Find(&clientss).Error
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
// Create pagination response
|
|
paging = paginator.Pagination{
|
|
Page: page,
|
|
Limit: limit,
|
|
Count: count,
|
|
TotalPage: int((count + int64(limit) - 1) / int64(limit)),
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (_i *clientsRepository) FindOne(id uuid.UUID) (clients *entity.Clients, err error) {
|
|
if err := _i.DB.DB.First(&clients, id).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return clients, nil
|
|
}
|
|
|
|
func (_i *clientsRepository) FindOneByClientId(clientId *uuid.UUID) (clients *entity.Clients, err error) {
|
|
if clientId == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
if err := _i.DB.DB.Where("id = ?", *clientId).First(&clients).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return clients, nil
|
|
}
|
|
|
|
func (_i *clientsRepository) FindByName(name string) (clients *entity.Clients, err error) {
|
|
if err := _i.DB.DB.Where("name = ?", name).First(&clients).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return clients, nil
|
|
}
|
|
|
|
func (_i *clientsRepository) FindByImagePathName(name string) (clients *entity.Clients, err error) {
|
|
if err := _i.DB.DB.Where("logo_image_path like ?", "%"+name+"%").First(&clients).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return clients, nil
|
|
}
|
|
|
|
func (_i *clientsRepository) Create(clients *entity.Clients) (clientsReturn *entity.Clients, err error) {
|
|
result := _i.DB.DB.Create(clients)
|
|
return clients, result.Error
|
|
}
|
|
|
|
func (_i *clientsRepository) Update(id uuid.UUID, clients *entity.Clients) (err error) {
|
|
return _i.DB.DB.Model(&entity.Clients{}).
|
|
Where(&entity.Clients{ID: id}).
|
|
Updates(clients).Error
|
|
}
|
|
|
|
func (_i *clientsRepository) Delete(id uuid.UUID) error {
|
|
return _i.DB.DB.Delete(&entity.Clients{}, id).Error
|
|
}
|
|
|
|
// =====================================================================
|
|
// NEW HIERARCHY METHODS
|
|
// =====================================================================
|
|
|
|
// GetWithHierarchy gets client with parent and sub-clients loaded
|
|
func (_i *clientsRepository) GetWithHierarchy(clientId uuid.UUID) (*entity.Clients, error) {
|
|
var client entity.Clients
|
|
err := _i.DB.DB.Preload("ParentClient").
|
|
Preload("SubClients", "is_active = ?", true).
|
|
Where("id = ?", clientId).
|
|
First(&client).Error
|
|
return &client, err
|
|
}
|
|
|
|
// GetSubClients gets direct children of a client
|
|
func (_i *clientsRepository) GetSubClients(parentId uuid.UUID, includeInactive bool) ([]entity.Clients, error) {
|
|
var clients []entity.Clients
|
|
query := _i.DB.DB.Where("parent_client_id = ?", parentId)
|
|
|
|
if !includeInactive {
|
|
query = query.Where("is_active = ?", true)
|
|
}
|
|
|
|
err := query.Find(&clients).Error
|
|
return clients, err
|
|
}
|
|
|
|
// GetAllSubClients gets all descendants recursively
|
|
func (_i *clientsRepository) GetAllSubClients(parentId uuid.UUID) ([]entity.Clients, error) {
|
|
subClientIDs, err := client.GetSubClientIDs(_i.DB.DB, parentId)
|
|
if err != nil || len(subClientIDs) == 0 {
|
|
return []entity.Clients{}, err
|
|
}
|
|
|
|
var clients []entity.Clients
|
|
err = _i.DB.DB.Where("id IN ?", subClientIDs).Find(&clients).Error
|
|
return clients, err
|
|
}
|
|
|
|
// GetRootClients gets all clients without parent
|
|
func (_i *clientsRepository) GetRootClients() ([]entity.Clients, error) {
|
|
var clients []entity.Clients
|
|
err := _i.DB.DB.Where("parent_client_id IS NULL AND is_active = ?", true).
|
|
Find(&clients).Error
|
|
return clients, err
|
|
}
|
|
|
|
// GetClientStats gets statistics for a client
|
|
func (_i *clientsRepository) GetClientStats(clientId uuid.UUID) (map[string]interface{}, error) {
|
|
stats := make(map[string]interface{})
|
|
|
|
// Count users
|
|
var userCount int64
|
|
_i.DB.DB.Model(&entity.Users{}).Where("client_id = ? AND is_active = ?", clientId, true).Count(&userCount)
|
|
stats["total_users"] = userCount
|
|
|
|
// Count articles
|
|
var articleCount int64
|
|
_i.DB.DB.Model(&entity.Articles{}).Where("client_id = ? AND is_active = ?", clientId, true).Count(&articleCount)
|
|
stats["total_articles"] = articleCount
|
|
|
|
// Count sub-clients
|
|
var subClientCount int64
|
|
_i.DB.DB.Model(&entity.Clients{}).Where("parent_client_id = ? AND is_active = ?", clientId, true).Count(&subClientCount)
|
|
stats["sub_client_count"] = subClientCount
|
|
|
|
return stats, nil
|
|
}
|
|
|
|
// MoveClient moves a client to a different parent
|
|
func (_i *clientsRepository) MoveClient(clientId, newParentId uuid.UUID) error {
|
|
// Validate no circular reference
|
|
if newParentId != uuid.Nil {
|
|
// Check if newParent is a descendant of client (would create circle)
|
|
descendants, _ := client.GetSubClientIDs(_i.DB.DB, clientId)
|
|
for _, descId := range descendants {
|
|
if descId == newParentId {
|
|
return gorm.ErrInvalidData // Circular reference
|
|
}
|
|
}
|
|
}
|
|
|
|
return _i.DB.DB.Model(&entity.Clients{}).
|
|
Where("id = ?", clientId).
|
|
Update("parent_client_id", newParentId).Error
|
|
}
|
|
|
|
// IsParentClient checks if client has children
|
|
func (_i *clientsRepository) IsParentClient(clientId uuid.UUID) (bool, error) {
|
|
var count int64
|
|
err := _i.DB.DB.Model(&entity.Clients{}).
|
|
Where("parent_client_id = ? AND is_active = ?", clientId, true).
|
|
Count(&count).Error
|
|
return count > 0, err
|
|
}
|