Yimaru-BackEnd/internal/repository/team.go

458 lines
14 KiB
Go

package repository
import (
"context"
"encoding/json"
"errors"
"time"
dbgen "Yimaru-Backend/gen/db"
"Yimaru-Backend/internal/domain"
"Yimaru-Backend/internal/ports"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgtype"
)
func NewTeamStore(s *Store) ports.TeamStore { return s }
func (s *Store) CreateTeamMember(ctx context.Context, member domain.TeamMember) (domain.TeamMember, error) {
var permissionsJSON []byte
if len(member.Permissions) > 0 {
var err error
permissionsJSON, err = json.Marshal(member.Permissions)
if err != nil {
return domain.TeamMember{}, err
}
}
var hireDate pgtype.Date
if member.HireDate != nil {
hireDate = pgtype.Date{Time: *member.HireDate, Valid: true}
}
var createdBy pgtype.Int8
if member.CreatedBy != nil {
createdBy = pgtype.Int8{Int64: *member.CreatedBy, Valid: true}
}
res, err := s.queries.CreateTeamMember(ctx, dbgen.CreateTeamMemberParams{
FirstName: member.FirstName,
LastName: member.LastName,
Email: member.Email,
PhoneNumber: pgtype.Text{String: member.PhoneNumber, Valid: member.PhoneNumber != ""},
Password: member.Password,
TeamRole: string(member.TeamRole),
Department: pgtype.Text{String: member.Department, Valid: member.Department != ""},
JobTitle: pgtype.Text{String: member.JobTitle, Valid: member.JobTitle != ""},
EmploymentType: pgtype.Text{String: string(member.EmploymentType), Valid: member.EmploymentType != ""},
HireDate: hireDate,
ProfilePictureUrl: pgtype.Text{String: member.ProfilePictureURL, Valid: member.ProfilePictureURL != ""},
Bio: pgtype.Text{String: member.Bio, Valid: member.Bio != ""},
WorkPhone: pgtype.Text{String: member.WorkPhone, Valid: member.WorkPhone != ""},
EmergencyContact: pgtype.Text{String: member.EmergencyContact, Valid: member.EmergencyContact != ""},
Status: string(member.Status),
EmailVerified: member.EmailVerified,
Permissions: permissionsJSON,
CreatedBy: createdBy,
})
if err != nil {
return domain.TeamMember{}, err
}
return mapDBTeamMember(res), nil
}
func (s *Store) GetTeamMemberByID(ctx context.Context, id int64) (domain.TeamMember, error) {
res, err := s.queries.GetTeamMemberByID(ctx, id)
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return domain.TeamMember{}, domain.ErrTeamMemberNotFound
}
return domain.TeamMember{}, err
}
return mapDBTeamMember(res), nil
}
func (s *Store) GetTeamMemberByEmail(ctx context.Context, email string) (domain.TeamMember, error) {
res, err := s.queries.GetTeamMemberByEmail(ctx, email)
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return domain.TeamMember{}, domain.ErrTeamMemberNotFound
}
return domain.TeamMember{}, err
}
return mapDBTeamMember(res), nil
}
func (s *Store) GetAllTeamMembers(
ctx context.Context,
teamRole, department, status *string,
limit, offset int32,
) ([]domain.TeamMember, int64, error) {
var teamRoleParam, departmentParam, statusParam pgtype.Text
if teamRole != nil {
teamRoleParam = pgtype.Text{String: *teamRole, Valid: true}
}
if department != nil {
departmentParam = pgtype.Text{String: *department, Valid: true}
}
if status != nil {
statusParam = pgtype.Text{String: *status, Valid: true}
}
rows, err := s.queries.GetAllTeamMembers(ctx, dbgen.GetAllTeamMembersParams{
TeamRole: teamRoleParam,
Department: departmentParam,
Status: statusParam,
Limit: pgtype.Int4{Int32: limit, Valid: true},
Offset: pgtype.Int4{Int32: offset, Valid: true},
})
if err != nil {
return nil, 0, err
}
if len(rows) == 0 {
return []domain.TeamMember{}, 0, nil
}
var totalCount int64
members := make([]domain.TeamMember, len(rows))
for i, row := range rows {
if i == 0 {
totalCount = row.TotalCount
}
members[i] = mapGetAllTeamMembersRow(row)
}
return members, totalCount, nil
}
func (s *Store) SearchTeamMembers(
ctx context.Context,
search string,
teamRole, status *string,
) ([]domain.TeamMember, error) {
var teamRoleParam, statusParam pgtype.Text
if teamRole != nil {
teamRoleParam = pgtype.Text{String: *teamRole, Valid: true}
}
if status != nil {
statusParam = pgtype.Text{String: *status, Valid: true}
}
rows, err := s.queries.SearchTeamMembers(ctx, dbgen.SearchTeamMembersParams{
Column1: pgtype.Text{String: search, Valid: true},
TeamRole: teamRoleParam,
Status: statusParam,
})
if err != nil {
return nil, err
}
members := make([]domain.TeamMember, len(rows))
for i, row := range rows {
members[i] = mapSearchTeamMembersRow(row)
}
return members, nil
}
func (s *Store) UpdateTeamMember(ctx context.Context, req domain.UpdateTeamMemberReq) error {
var permissionsJSON []byte
if len(req.Permissions) > 0 {
var err error
permissionsJSON, err = json.Marshal(req.Permissions)
if err != nil {
return err
}
}
var hireDate pgtype.Date
if req.HireDate != "" {
t, err := parseDate(req.HireDate)
if err != nil {
return err
}
hireDate = pgtype.Date{Time: t, Valid: true}
}
return s.queries.UpdateTeamMember(ctx, dbgen.UpdateTeamMemberParams{
FirstName: req.FirstName,
LastName: req.LastName,
PhoneNumber: pgtype.Text{String: req.PhoneNumber, Valid: req.PhoneNumber != ""},
TeamRole: req.TeamRole,
Department: pgtype.Text{String: req.Department, Valid: req.Department != ""},
JobTitle: pgtype.Text{String: req.JobTitle, Valid: req.JobTitle != ""},
EmploymentType: pgtype.Text{String: req.EmploymentType, Valid: req.EmploymentType != ""},
HireDate: hireDate,
ProfilePictureUrl: pgtype.Text{String: req.ProfilePictureURL, Valid: req.ProfilePictureURL != ""},
Bio: pgtype.Text{String: req.Bio, Valid: req.Bio != ""},
WorkPhone: pgtype.Text{String: req.WorkPhone, Valid: req.WorkPhone != ""},
EmergencyContact: pgtype.Text{String: req.EmergencyContact, Valid: req.EmergencyContact != ""},
Permissions: permissionsJSON,
UpdatedBy: pgtype.Int8{Int64: req.UpdatedBy, Valid: req.UpdatedBy > 0},
ID: req.TeamMemberID,
})
}
func (s *Store) UpdateTeamMemberStatus(ctx context.Context, req domain.UpdateTeamMemberStatusReq) error {
return s.queries.UpdateTeamMemberStatus(ctx, dbgen.UpdateTeamMemberStatusParams{
Status: req.Status,
UpdatedBy: pgtype.Int8{Int64: req.UpdatedBy, Valid: req.UpdatedBy > 0},
ID: req.TeamMemberID,
})
}
func (s *Store) UpdateTeamMemberPassword(ctx context.Context, memberID int64, password string) error {
return s.queries.UpdateTeamMemberPassword(ctx, dbgen.UpdateTeamMemberPasswordParams{
Password: []byte(password),
ID: memberID,
})
}
func (s *Store) UpdateTeamMemberLastLogin(ctx context.Context, memberID int64) error {
return s.queries.UpdateTeamMemberLastLogin(ctx, memberID)
}
func (s *Store) DeleteTeamMember(ctx context.Context, memberID int64) error {
return s.queries.DeleteTeamMember(ctx, memberID)
}
func (s *Store) CheckTeamMemberEmailExists(ctx context.Context, email string) (bool, error) {
return s.queries.CheckTeamMemberEmailExists(ctx, email)
}
func (s *Store) GetTeamMembersByDepartment(ctx context.Context, department string) ([]domain.TeamMember, error) {
rows, err := s.queries.GetTeamMembersByDepartment(ctx, pgtype.Text{String: department, Valid: true})
if err != nil {
return nil, err
}
members := make([]domain.TeamMember, len(rows))
for i, row := range rows {
members[i] = mapGetTeamMembersByDepartmentRow(row)
}
return members, nil
}
func (s *Store) GetTeamMembersByRole(ctx context.Context, role string) ([]domain.TeamMember, error) {
rows, err := s.queries.GetTeamMembersByRole(ctx, role)
if err != nil {
return nil, err
}
members := make([]domain.TeamMember, len(rows))
for i, row := range rows {
members[i] = mapGetTeamMembersByRoleRow(row)
}
return members, nil
}
func (s *Store) CountTeamMembersByStatus(ctx context.Context) (domain.TeamMemberStats, error) {
res, err := s.queries.CountTeamMembersByStatus(ctx)
if err != nil {
return domain.TeamMemberStats{}, err
}
return domain.TeamMemberStats{
ActiveCount: res.ActiveCount,
InactiveCount: res.InactiveCount,
SuspendedCount: res.SuspendedCount,
TerminatedCount: res.TerminatedCount,
TotalCount: res.TotalCount,
}, nil
}
func (s *Store) UpdateTeamMemberEmailVerified(ctx context.Context, memberID int64, verified bool) error {
return s.queries.UpdateTeamMemberEmailVerified(ctx, dbgen.UpdateTeamMemberEmailVerifiedParams{
EmailVerified: verified,
ID: memberID,
})
}
func mapDBTeamMember(m dbgen.TeamMember) domain.TeamMember {
var permissions []string
if len(m.Permissions) > 0 {
_ = json.Unmarshal(m.Permissions, &permissions)
}
var hireDate *time.Time
if m.HireDate.Valid {
hireDate = &m.HireDate.Time
}
var lastLogin *time.Time
if m.LastLogin.Valid {
lastLogin = &m.LastLogin.Time
}
var createdBy *int64
if m.CreatedBy.Valid {
createdBy = &m.CreatedBy.Int64
}
var updatedBy *int64
if m.UpdatedBy.Valid {
updatedBy = &m.UpdatedBy.Int64
}
var updatedAt *time.Time
if m.UpdatedAt.Valid {
updatedAt = &m.UpdatedAt.Time
}
return domain.TeamMember{
ID: m.ID,
FirstName: m.FirstName,
LastName: m.LastName,
Email: m.Email,
PhoneNumber: m.PhoneNumber.String,
Password: m.Password,
TeamRole: domain.TeamRole(m.TeamRole),
Department: m.Department.String,
JobTitle: m.JobTitle.String,
EmploymentType: domain.EmploymentType(m.EmploymentType.String),
HireDate: hireDate,
ProfilePictureURL: m.ProfilePictureUrl.String,
Bio: m.Bio.String,
WorkPhone: m.WorkPhone.String,
EmergencyContact: m.EmergencyContact.String,
Status: domain.TeamMemberStatus(m.Status),
EmailVerified: m.EmailVerified,
Permissions: permissions,
LastLogin: lastLogin,
CreatedBy: createdBy,
UpdatedBy: updatedBy,
CreatedAt: m.CreatedAt.Time,
UpdatedAt: updatedAt,
}
}
func mapGetAllTeamMembersRow(row dbgen.GetAllTeamMembersRow) domain.TeamMember {
var permissions []string
if len(row.Permissions) > 0 {
_ = json.Unmarshal(row.Permissions, &permissions)
}
var hireDate *time.Time
if row.HireDate.Valid {
hireDate = &row.HireDate.Time
}
var lastLogin *time.Time
if row.LastLogin.Valid {
lastLogin = &row.LastLogin.Time
}
var updatedAt *time.Time
if row.UpdatedAt.Valid {
updatedAt = &row.UpdatedAt.Time
}
return domain.TeamMember{
ID: row.ID,
FirstName: row.FirstName,
LastName: row.LastName,
Email: row.Email,
PhoneNumber: row.PhoneNumber.String,
TeamRole: domain.TeamRole(row.TeamRole),
Department: row.Department.String,
JobTitle: row.JobTitle.String,
EmploymentType: domain.EmploymentType(row.EmploymentType.String),
HireDate: hireDate,
ProfilePictureURL: row.ProfilePictureUrl.String,
Bio: row.Bio.String,
WorkPhone: row.WorkPhone.String,
Status: domain.TeamMemberStatus(row.Status),
EmailVerified: row.EmailVerified,
Permissions: permissions,
LastLogin: lastLogin,
CreatedAt: row.CreatedAt.Time,
UpdatedAt: updatedAt,
}
}
func mapSearchTeamMembersRow(row dbgen.SearchTeamMembersRow) domain.TeamMember {
var permissions []string
if len(row.Permissions) > 0 {
_ = json.Unmarshal(row.Permissions, &permissions)
}
var hireDate *time.Time
if row.HireDate.Valid {
hireDate = &row.HireDate.Time
}
var lastLogin *time.Time
if row.LastLogin.Valid {
lastLogin = &row.LastLogin.Time
}
var updatedAt *time.Time
if row.UpdatedAt.Valid {
updatedAt = &row.UpdatedAt.Time
}
return domain.TeamMember{
ID: row.ID,
FirstName: row.FirstName,
LastName: row.LastName,
Email: row.Email,
PhoneNumber: row.PhoneNumber.String,
TeamRole: domain.TeamRole(row.TeamRole),
Department: row.Department.String,
JobTitle: row.JobTitle.String,
EmploymentType: domain.EmploymentType(row.EmploymentType.String),
HireDate: hireDate,
ProfilePictureURL: row.ProfilePictureUrl.String,
Bio: row.Bio.String,
Status: domain.TeamMemberStatus(row.Status),
EmailVerified: row.EmailVerified,
Permissions: permissions,
LastLogin: lastLogin,
CreatedAt: row.CreatedAt.Time,
UpdatedAt: updatedAt,
}
}
func mapGetTeamMembersByDepartmentRow(row dbgen.GetTeamMembersByDepartmentRow) domain.TeamMember {
return domain.TeamMember{
ID: row.ID,
FirstName: row.FirstName,
LastName: row.LastName,
Email: row.Email,
PhoneNumber: row.PhoneNumber.String,
TeamRole: domain.TeamRole(row.TeamRole),
Department: row.Department.String,
JobTitle: row.JobTitle.String,
EmploymentType: domain.EmploymentType(row.EmploymentType.String),
ProfilePictureURL: row.ProfilePictureUrl.String,
Status: domain.TeamMemberStatus(row.Status),
CreatedAt: row.CreatedAt.Time,
}
}
func mapGetTeamMembersByRoleRow(row dbgen.GetTeamMembersByRoleRow) domain.TeamMember {
return domain.TeamMember{
ID: row.ID,
FirstName: row.FirstName,
LastName: row.LastName,
Email: row.Email,
PhoneNumber: row.PhoneNumber.String,
TeamRole: domain.TeamRole(row.TeamRole),
Department: row.Department.String,
JobTitle: row.JobTitle.String,
EmploymentType: domain.EmploymentType(row.EmploymentType.String),
ProfilePictureURL: row.ProfilePictureUrl.String,
Status: domain.TeamMemberStatus(row.Status),
CreatedAt: row.CreatedAt.Time,
}
}
func parseDate(dateStr string) (time.Time, error) {
return time.Parse("2006-01-02", dateStr)
}