user_repository.go 9.5 KB
package repository

import (
	"context"
	"fmt"

	"github.com/jinzhu/copier"
	"github.com/pkg/errors"
	"github.com/tiptok/gocomm/pkg/cache"
	"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/interanl/pkg/db/models"
	"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/interanl/pkg/db/transaction"
	"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/interanl/pkg/domain"
	"gorm.io/gorm"
)

type UserRepository struct {
	*cache.CachedRepository
}

func (repository *UserRepository) Insert(ctx context.Context, conn transaction.Conn, dm *domain.User) (*domain.User, error) {
	var (
		err error
		m   = &models.User{}
		tx  = conn.DB()
	)
	if m, err = repository.DomainModelToModel(dm); err != nil {
		return nil, err
	}
	if tx = tx.Model(m).Save(m); tx.Error != nil {
		return nil, tx.Error
	}
	dm.Id = m.Id
	return repository.ModelToDomainModel(m)

}

func (repository *UserRepository) Update(ctx context.Context, conn transaction.Conn, dm *domain.User) (*domain.User, error) {
	var (
		err error
		m   *models.User
		tx  = conn.DB()
	)
	if m, err = repository.DomainModelToModel(dm); err != nil {
		return nil, err
	}
	queryFunc := func() (interface{}, error) {
		tx = tx.Model(m).Select("*").Updates(m)
		return nil, tx.Error
	}
	if _, err = repository.Query(queryFunc, m.CacheKeyFunc()); err != nil {
		return nil, err
	}
	return repository.ModelToDomainModel(m)
}

func (repository *UserRepository) UpdateWithVersion(ctx context.Context, transaction transaction.Conn, dm *domain.User) (*domain.User, error) {
	var (
		err error
		m   *models.User
		tx  = transaction.DB()
	)
	if m, err = repository.DomainModelToModel(dm); err != nil {
		return nil, err
	}
	oldVersion := dm.Version
	m.Version += 1
	queryFunc := func() (interface{}, error) {
		tx = tx.Model(m).Select("*").Where("id = ?", m.Id).Where("version = ?", oldVersion).Updates(m)
		if tx.RowsAffected == 0 {
			return nil, domain.ErrUpdateFail
		}
		return nil, tx.Error
	}
	if _, err = repository.Query(queryFunc, m.CacheKeyFunc()); err != nil {
		return nil, err
	}
	return repository.ModelToDomainModel(m)
}

func (repository *UserRepository) Delete(ctx context.Context, conn transaction.Conn, dm *domain.User) (*domain.User, error) {
	var (
		tx = conn.DB()
		m  = &models.User{Id: dm.Identify().(int64)}
	)
	queryFunc := func() (interface{}, error) {
		tx = tx.Where("id = ?", m.Id).Delete(m)
		return m, tx.Error
	}
	if _, err := repository.Query(queryFunc, m.CacheKeyFunc()); err != nil {
		return dm, err
	}
	return repository.ModelToDomainModel(m)
}

func (repository *UserRepository) FindOne(ctx context.Context, conn transaction.Conn, id int64) (*domain.User, error) {
	var (
		err error
		tx  = conn.DB()
		m   = new(models.User)
	)
	queryFunc := func() (interface{}, error) {
		tx = tx.Model(m).Where("id = ?", id).First(m)
		if errors.Is(tx.Error, gorm.ErrRecordNotFound) {
			return nil, domain.ErrNotFound
		}
		return m, tx.Error
	}
	cacheModel := new(models.User)
	cacheModel.Id = id
	if err = repository.QueryCache(cacheModel.CacheKeyFunc, m, queryFunc); err != nil {
		return nil, err
	}
	return repository.ModelToDomainModel(m)
}

func (repository *UserRepository) FindOneByCompanyIdAndPhone(ctx context.Context, conn transaction.Conn, companyId int64, phone string, status []int) (*domain.User, error) {
	var (
		err error
		tx  = conn.DB()
		m   = new(models.User)
	)
	queryFunc := func() (interface{}, error) {
		tx = tx.Model(m).
			Where("company_id = ?", companyId).
			Where("phone = ?", phone).
			Where("audit_status in (?)", status).First(m)
		if errors.Is(tx.Error, gorm.ErrRecordNotFound) {
			return nil, domain.ErrNotFound
		}
		return m, tx.Error
	}
	if _, err = repository.Query(queryFunc); err != nil {
		return nil, err
	}
	return repository.ModelToDomainModel(m)
}

func (repository *UserRepository) Find(ctx context.Context, conn transaction.Conn, queryOptions map[string]interface{}) (int64, []*domain.User, error) {
	var (
		tx    = conn.DB()
		ms    []*models.User
		dms   = make([]*domain.User, 0)
		total int64
	)
	queryFunc := func() (interface{}, error) {
		tx = tx.Model(&ms)
		if v, ok := queryOptions["unscoped"]; ok && v.(bool) {
			tx.Unscoped()
		}
		if v, ok := queryOptions["companyId"]; ok {
			tx.Where("company_id = ?", v)
		}
		if v, ok := queryOptions["ids"]; ok {
			tx.Where("id in (?)", v)
		}
		if v, ok := queryOptions["phone"]; ok {
			tx.Where("phone = ?", v)
		}
		if v, ok := queryOptions["auditStatus"]; ok {
			tx.Where("audit_status in (?)", v)
		}
		if v, ok := queryOptions["accountFrom"]; ok {
			tx.Where("account_from in (?)", v)
		}

		// 列表查询条件
		if v, ok := queryOptions["likeName"]; ok {
			tx.Where("name like ? ", fmt.Sprintf("%%%v%%", v))
		}
		if v, ok := queryOptions["likePhone"]; ok {
			tx.Where("phone like ? ", fmt.Sprintf("%%%v%%", v))
		}
		if v, ok := queryOptions["position"]; ok {
			tx.Where("position = ? ", v)
		}
		if v, ok := queryOptions["departmentId"]; ok {
			// 未分组用户部门ID=0
			if vi, okVi := v.(int64); okVi && vi == domain.DefaultDepartmentId {
				tx.Where(fmt.Sprintf("departments = '[]'"))
			} else {
				tx.Where(fmt.Sprintf("departments @>'[%v]'", v))
			}
		}
		if v, ok := queryOptions["roleId"]; ok {
			tx.Where(fmt.Sprintf("roles @>'[%v]'", v))
		}
		if v, ok := queryOptions["enable"]; ok {
			tx.Where("enable = ?", v)
		}
		if v, ok := queryOptions["beginTime"]; ok {
			tx.Where("created_at >= ?", v)
		}
		if v, ok := queryOptions["endTime"]; ok {
			tx.Where("created_at < ?", v)
		}
		if v, ok := queryOptions["orderBy"]; ok {
			tx.Order(v)
		} else {
			tx.Order("id asc")
		}
		if total, tx = transaction.PaginationAndCount(ctx, tx, queryOptions, &ms); tx.Error != nil {
			return dms, tx.Error
		}
		return dms, nil
	}

	if _, err := repository.Query(queryFunc); err != nil {
		return 0, nil, err
	}

	for _, item := range ms {
		if dm, err := repository.ModelToDomainModel(item); err != nil {
			return 0, dms, err
		} else {
			dms = append(dms, dm)
		}
	}
	return total, dms, nil
}

func (repository *UserRepository) FindDepartmentUsers(ctx context.Context, conn transaction.Conn, companyId int64, queryOptions map[string]interface{}) (int64, []*domain.User, error) {
	var (
		tx    = conn.DB()
		ms    []*models.User
		dms   = make([]*domain.User, 0)
		total int64
	)
	queryFunc := func() (interface{}, error) {
		tx = tx.Model(&ms).Order("pin_yin_name asc")
		tx.Select("id", "name", "departments", "pin_yin_name", "avatar")
		tx.Where("company_id = ?", companyId)
		tx.Where("audit_status in (?)", domain.UserAuditStatusPassed)
		tx.Where("enable = ?", domain.UserEnable)
		if v, ok := queryOptions["name"]; ok {
			tx.Where("name like ?", fmt.Sprintf("%%%v%%", v))
		}
		if v, ok := queryOptions["departmentId"]; ok {
			tx.Where(fmt.Sprintf("departments::jsonb @>'[%v]'", v))
		}
		if total, tx = transaction.PaginationAndCount(ctx, tx, queryOptions, &ms); tx.Error != nil {
			return dms, tx.Error
		}
		return dms, nil
	}

	if _, err := repository.Query(queryFunc); err != nil {
		return 0, nil, err
	}

	for _, item := range ms {
		if dm, err := repository.ModelToDomainModel(item); err != nil {
			return 0, dms, err
		} else {
			dms = append(dms, dm)
		}
	}
	return total, dms, nil
}

func (repository *UserRepository) FindByCompanyRoles(ctx context.Context, conn transaction.Conn, companyId int64, roles []int64, queryOptions map[string]interface{}) (int64, []*domain.User, error) {
	var (
		tx    = conn.DB()
		ms    []*models.User
		dms   = make([]*domain.User, 0)
		total int64
	)
	queryFunc := func() (interface{}, error) {
		tx = tx.Model(&ms).Order("id asc")
		tx.Select("id", "name", "roles")
		tx.Where("company_id = ?", companyId)
		tx.Where("flag = ?", domain.UserAdmin)
		tx.Where("id in (select user_id from user_role where role_id in(?)) ", roles)
		if total, tx = transaction.PaginationAndCount(ctx, tx, queryOptions, &ms); tx.Error != nil {
			return dms, tx.Error
		}
		return dms, nil
	}

	if _, err := repository.Query(queryFunc); err != nil {
		return 0, nil, err
	}

	for _, item := range ms {
		if dm, err := repository.ModelToDomainModel(item); err != nil {
			return 0, dms, err
		} else {
			dms = append(dms, dm)
		}
	}
	return total, dms, nil
}

func (repository *UserRepository) FindCompanyPositions(ctx context.Context, conn transaction.Conn, companyId int64, queryOptions map[string]interface{}) (int64, []*domain.User, error) {
	var (
		tx    = conn.DB()
		ms    []*models.User
		dms   = make([]*domain.User, 0)
		total int64
	)
	queryFunc := func() (interface{}, error) {
		tx = tx.Model(&ms)
		tx.Select("distinct position")
		tx.Where("company_id = ?", companyId)
		tx.Where("position <> ''")
		tx.Where("audit_status in (?)", domain.UserAuditStatusPassed)
		tx.Where("enable = ?", domain.UserEnable)
		tx.Order("position asc")
		if total, tx = transaction.PaginationAndCount(ctx, tx, queryOptions, &ms); tx.Error != nil {
			return dms, tx.Error
		}
		return dms, nil
	}

	if _, err := repository.Query(queryFunc); err != nil {
		return 0, nil, err
	}

	for _, item := range ms {
		if dm, err := repository.ModelToDomainModel(item); err != nil {
			return 0, dms, err
		} else {
			dms = append(dms, dm)
		}
	}
	return total, dms, nil
}

func (repository *UserRepository) ModelToDomainModel(from *models.User) (*domain.User, error) {
	to := &domain.User{}
	err := copier.Copy(to, from)
	return to, err
}

func (repository *UserRepository) DomainModelToModel(from *domain.User) (*models.User, error) {
	to := &models.User{}
	err := copier.Copy(to, from)
	return to, err
}

func NewUserRepository(cache *cache.CachedRepository) domain.UserRepository {
	return &UserRepository{CachedRepository: cache}
}