Add init
This commit is contained in:
@@ -58,7 +58,7 @@ func (s *AuthServiceImpl) Login(ctx context.Context, req *contract.LoginRequest)
|
||||
|
||||
roles, _ := s.userProcessor.GetUserRoles(ctx, userResponse.ID)
|
||||
permCodes, _ := s.userProcessor.GetUserPermissionCodes(ctx, userResponse.ID)
|
||||
departments, _ := s.userProcessor.GetUserDepartments(ctx, userResponse.ID)
|
||||
// Departments are now preloaded, so they're already in userResponse
|
||||
|
||||
token, expiresAt, err := s.generateToken(userResponse, roles, permCodes)
|
||||
if err != nil {
|
||||
@@ -71,7 +71,7 @@ func (s *AuthServiceImpl) Login(ctx context.Context, req *contract.LoginRequest)
|
||||
User: *userResponse,
|
||||
Roles: roles,
|
||||
Permissions: permCodes,
|
||||
Departments: departments,
|
||||
Departments: userResponse.DepartmentResponse,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -90,6 +90,7 @@ func (s *AuthServiceImpl) ValidateToken(tokenString string) (*contract.UserRespo
|
||||
return nil, fmt.Errorf("user account is deactivated")
|
||||
}
|
||||
|
||||
// Departments are now preloaded, so they're already in the response
|
||||
return userResponse, nil
|
||||
}
|
||||
|
||||
@@ -115,14 +116,14 @@ func (s *AuthServiceImpl) RefreshToken(ctx context.Context, tokenString string)
|
||||
return nil, fmt.Errorf("failed to generate token: %w", err)
|
||||
}
|
||||
|
||||
departments, _ := s.userProcessor.GetUserDepartments(ctx, userResponse.ID)
|
||||
// Departments are now preloaded, so they're already in userResponse
|
||||
return &contract.LoginResponse{
|
||||
Token: newToken,
|
||||
ExpiresAt: expiresAt,
|
||||
User: *userResponse,
|
||||
Roles: roles,
|
||||
Permissions: permCodes,
|
||||
Departments: departments,
|
||||
Departments: userResponse.DepartmentResponse,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ type LetterProcessor interface {
|
||||
SoftDeleteIncomingLetter(ctx context.Context, id uuid.UUID) error
|
||||
|
||||
CreateDispositions(ctx context.Context, req *contract.CreateLetterDispositionRequest) (*contract.ListDispositionsResponse, error)
|
||||
ListDispositionsByLetter(ctx context.Context, letterID uuid.UUID) (*contract.ListDispositionsResponse, error)
|
||||
GetEnhancedDispositionsByLetter(ctx context.Context, letterID uuid.UUID) (*contract.ListEnhancedDispositionsResponse, error)
|
||||
|
||||
CreateDiscussion(ctx context.Context, letterID uuid.UUID, req *contract.CreateLetterDiscussionRequest) (*contract.LetterDiscussionResponse, error)
|
||||
UpdateDiscussion(ctx context.Context, letterID uuid.UUID, discussionID uuid.UUID, req *contract.UpdateLetterDiscussionRequest) (*contract.LetterDiscussionResponse, error)
|
||||
@@ -50,8 +50,8 @@ func (s *LetterServiceImpl) CreateDispositions(ctx context.Context, req *contrac
|
||||
return s.processor.CreateDispositions(ctx, req)
|
||||
}
|
||||
|
||||
func (s *LetterServiceImpl) ListDispositionsByLetter(ctx context.Context, letterID uuid.UUID) (*contract.ListDispositionsResponse, error) {
|
||||
return s.processor.ListDispositionsByLetter(ctx, letterID)
|
||||
func (s *LetterServiceImpl) GetEnhancedDispositionsByLetter(ctx context.Context, letterID uuid.UUID) (*contract.ListEnhancedDispositionsResponse, error) {
|
||||
return s.processor.GetEnhancedDispositionsByLetter(ctx, letterID)
|
||||
}
|
||||
|
||||
func (s *LetterServiceImpl) CreateDiscussion(ctx context.Context, letterID uuid.UUID, req *contract.CreateLetterDiscussionRequest) (*contract.LetterDiscussionResponse, error) {
|
||||
|
||||
@@ -26,4 +26,7 @@ type UserProcessor interface {
|
||||
|
||||
// New optimized listing
|
||||
ListUsersWithFilters(ctx context.Context, req *contract.ListUsersRequest) ([]contract.UserResponse, int, error)
|
||||
|
||||
// Get active users for mention purposes
|
||||
GetActiveUsersForMention(ctx context.Context, search *string, limit int) ([]contract.UserResponse, error)
|
||||
}
|
||||
|
||||
@@ -30,6 +30,40 @@ func (s *UserServiceImpl) CreateUser(ctx context.Context, req *contract.CreateUs
|
||||
return s.userProcessor.CreateUser(ctx, req)
|
||||
}
|
||||
|
||||
func (s *UserServiceImpl) BulkCreateUsers(ctx context.Context, req *contract.BulkCreateUsersRequest) (*contract.BulkCreateUsersResponse, error) {
|
||||
response := &contract.BulkCreateUsersResponse{
|
||||
Created: []contract.UserResponse{},
|
||||
Failed: []contract.BulkUserErrorResult{},
|
||||
Summary: contract.BulkCreationSummary{
|
||||
Total: len(req.Users),
|
||||
Succeeded: 0,
|
||||
Failed: 0,
|
||||
},
|
||||
}
|
||||
|
||||
for _, userReq := range req.Users {
|
||||
createReq := &contract.CreateUserRequest{
|
||||
Name: userReq.Name,
|
||||
Email: userReq.Email,
|
||||
Password: userReq.Password,
|
||||
}
|
||||
|
||||
userResponse, err := s.userProcessor.CreateUser(ctx, createReq)
|
||||
if err != nil {
|
||||
response.Failed = append(response.Failed, contract.BulkUserErrorResult{
|
||||
User: userReq,
|
||||
Error: err.Error(),
|
||||
})
|
||||
response.Summary.Failed++
|
||||
} else {
|
||||
response.Created = append(response.Created, *userResponse)
|
||||
response.Summary.Succeeded++
|
||||
}
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (s *UserServiceImpl) UpdateUser(ctx context.Context, id uuid.UUID, req *contract.UpdateUserRequest) (*contract.UserResponse, error) {
|
||||
return s.userProcessor.UpdateUser(ctx, id, req)
|
||||
}
|
||||
@@ -96,3 +130,8 @@ func (s *UserServiceImpl) ListTitles(ctx context.Context) (*contract.ListTitlesR
|
||||
}
|
||||
return &contract.ListTitlesResponse{Titles: transformer.TitlesToContract(titles)}, nil
|
||||
}
|
||||
|
||||
// GetActiveUsersForMention retrieves active users for mention purposes
|
||||
func (s *UserServiceImpl) GetActiveUsersForMention(ctx context.Context, search *string, limit int) ([]contract.UserResponse, error) {
|
||||
return s.userProcessor.GetActiveUsersForMention(ctx, search, limit)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,258 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"eslogad-be/internal/contract"
|
||||
"eslogad-be/internal/entities"
|
||||
"eslogad-be/internal/transformer"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type VoteEventRepository interface {
|
||||
Create(ctx context.Context, voteEvent *entities.VoteEvent) error
|
||||
GetByID(ctx context.Context, id uuid.UUID) (*entities.VoteEvent, error)
|
||||
GetActiveEvents(ctx context.Context) ([]*entities.VoteEvent, error)
|
||||
List(ctx context.Context, limit, offset int) ([]*entities.VoteEvent, int64, error)
|
||||
Update(ctx context.Context, voteEvent *entities.VoteEvent) error
|
||||
Delete(ctx context.Context, id uuid.UUID) error
|
||||
CreateCandidate(ctx context.Context, candidate *entities.Candidate) error
|
||||
GetCandidatesByEventID(ctx context.Context, eventID uuid.UUID) ([]*entities.Candidate, error)
|
||||
SubmitVote(ctx context.Context, vote *entities.Vote) error
|
||||
HasUserVoted(ctx context.Context, userID, eventID uuid.UUID) (bool, error)
|
||||
GetVoteResults(ctx context.Context, eventID uuid.UUID) (map[uuid.UUID]int64, error)
|
||||
}
|
||||
|
||||
type VoteEventServiceImpl struct {
|
||||
voteEventRepo VoteEventRepository
|
||||
}
|
||||
|
||||
func NewVoteEventService(voteEventRepo VoteEventRepository) *VoteEventServiceImpl {
|
||||
return &VoteEventServiceImpl{
|
||||
voteEventRepo: voteEventRepo,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *VoteEventServiceImpl) CreateVoteEvent(ctx context.Context, req *contract.CreateVoteEventRequest) (*contract.VoteEventResponse, error) {
|
||||
if req.EndDate.Before(req.StartDate) {
|
||||
return nil, errors.New("end date must be after start date")
|
||||
}
|
||||
|
||||
voteEvent := &entities.VoteEvent{
|
||||
Title: req.Title,
|
||||
Description: req.Description,
|
||||
StartDate: req.StartDate,
|
||||
EndDate: req.EndDate,
|
||||
IsActive: true,
|
||||
ResultsOpen: false,
|
||||
}
|
||||
|
||||
if req.ResultsOpen != nil {
|
||||
voteEvent.ResultsOpen = *req.ResultsOpen
|
||||
}
|
||||
|
||||
if err := s.voteEventRepo.Create(ctx, voteEvent); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return transformer.VoteEventToContract(voteEvent), nil
|
||||
}
|
||||
|
||||
func (s *VoteEventServiceImpl) GetVoteEventByID(ctx context.Context, id uuid.UUID) (*contract.VoteEventResponse, error) {
|
||||
voteEvent, err := s.voteEventRepo.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return transformer.VoteEventToContract(voteEvent), nil
|
||||
}
|
||||
|
||||
func (s *VoteEventServiceImpl) GetActiveEvents(ctx context.Context) ([]contract.VoteEventResponse, error) {
|
||||
events, err := s.voteEventRepo.GetActiveEvents(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var responses []contract.VoteEventResponse
|
||||
for _, event := range events {
|
||||
responses = append(responses, *transformer.VoteEventToContract(event))
|
||||
}
|
||||
|
||||
return responses, nil
|
||||
}
|
||||
|
||||
func (s *VoteEventServiceImpl) ListVoteEvents(ctx context.Context, req *contract.ListVoteEventsRequest) (*contract.ListVoteEventsResponse, error) {
|
||||
page := req.Page
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
limit := req.Limit
|
||||
if limit <= 0 {
|
||||
limit = 10
|
||||
}
|
||||
|
||||
offset := (page - 1) * limit
|
||||
|
||||
events, total, err := s.voteEventRepo.List(ctx, limit, offset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var responses []contract.VoteEventResponse
|
||||
for _, event := range events {
|
||||
responses = append(responses, *transformer.VoteEventToContract(event))
|
||||
}
|
||||
|
||||
return &contract.ListVoteEventsResponse{
|
||||
VoteEvents: responses,
|
||||
Pagination: transformer.CreatePaginationResponse(int(total), page, limit),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *VoteEventServiceImpl) UpdateVoteEvent(ctx context.Context, id uuid.UUID, req *contract.UpdateVoteEventRequest) (*contract.VoteEventResponse, error) {
|
||||
if req.EndDate.Before(req.StartDate) {
|
||||
return nil, errors.New("end date must be after start date")
|
||||
}
|
||||
|
||||
voteEvent, err := s.voteEventRepo.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
voteEvent.Title = req.Title
|
||||
voteEvent.Description = req.Description
|
||||
voteEvent.StartDate = req.StartDate
|
||||
voteEvent.EndDate = req.EndDate
|
||||
voteEvent.IsActive = req.IsActive
|
||||
|
||||
if req.ResultsOpen != nil {
|
||||
voteEvent.ResultsOpen = *req.ResultsOpen
|
||||
}
|
||||
|
||||
if err := s.voteEventRepo.Update(ctx, voteEvent); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return transformer.VoteEventToContract(voteEvent), nil
|
||||
}
|
||||
|
||||
func (s *VoteEventServiceImpl) DeleteVoteEvent(ctx context.Context, id uuid.UUID) error {
|
||||
return s.voteEventRepo.Delete(ctx, id)
|
||||
}
|
||||
|
||||
func (s *VoteEventServiceImpl) CreateCandidate(ctx context.Context, req *contract.CreateCandidateRequest) (*contract.CandidateResponse, error) {
|
||||
voteEvent, err := s.voteEventRepo.GetByID(ctx, req.VoteEventID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !voteEvent.IsActive {
|
||||
return nil, errors.New("cannot add candidates to inactive vote event")
|
||||
}
|
||||
|
||||
candidate := &entities.Candidate{
|
||||
VoteEventID: req.VoteEventID,
|
||||
Name: req.Name,
|
||||
ImageURL: req.ImageURL,
|
||||
Description: req.Description,
|
||||
}
|
||||
|
||||
if err := s.voteEventRepo.CreateCandidate(ctx, candidate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return transformer.CandidateToContract(candidate), nil
|
||||
}
|
||||
|
||||
func (s *VoteEventServiceImpl) GetCandidates(ctx context.Context, eventID uuid.UUID) ([]contract.CandidateResponse, error) {
|
||||
candidates, err := s.voteEventRepo.GetCandidatesByEventID(ctx, eventID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var responses []contract.CandidateResponse
|
||||
for _, candidate := range candidates {
|
||||
responses = append(responses, *transformer.CandidateToContract(candidate))
|
||||
}
|
||||
|
||||
return responses, nil
|
||||
}
|
||||
|
||||
func (s *VoteEventServiceImpl) SubmitVote(ctx context.Context, userID uuid.UUID, req *contract.SubmitVoteRequest) (*contract.VoteResponse, error) {
|
||||
voteEvent, err := s.voteEventRepo.GetByID(ctx, req.VoteEventID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !voteEvent.IsVotingOpen() {
|
||||
return nil, errors.New("voting is not open for this event")
|
||||
}
|
||||
|
||||
hasVoted, err := s.voteEventRepo.HasUserVoted(ctx, userID, req.VoteEventID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if hasVoted {
|
||||
return nil, errors.New("user has already voted for this event")
|
||||
}
|
||||
|
||||
vote := &entities.Vote{
|
||||
VoteEventID: req.VoteEventID,
|
||||
CandidateID: req.CandidateID,
|
||||
UserID: userID,
|
||||
}
|
||||
|
||||
if err := s.voteEventRepo.SubmitVote(ctx, vote); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return transformer.VoteToContract(vote), nil
|
||||
}
|
||||
|
||||
func (s *VoteEventServiceImpl) GetVoteResults(ctx context.Context, eventID uuid.UUID) (*contract.VoteResultsResponse, error) {
|
||||
|
||||
candidates, err := s.voteEventRepo.GetCandidatesByEventID(ctx, eventID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
voteResults, err := s.voteEventRepo.GetVoteResults(ctx, eventID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var candidatesWithVotes []contract.CandidateWithVotesResponse
|
||||
var totalVotes int64
|
||||
|
||||
for _, candidate := range candidates {
|
||||
voteCount := voteResults[candidate.ID]
|
||||
totalVotes += voteCount
|
||||
|
||||
candidatesWithVotes = append(candidatesWithVotes, contract.CandidateWithVotesResponse{
|
||||
CandidateResponse: *transformer.CandidateToContract(candidate),
|
||||
VoteCount: voteCount,
|
||||
})
|
||||
}
|
||||
|
||||
return &contract.VoteResultsResponse{
|
||||
VoteEventID: eventID,
|
||||
Candidates: candidatesWithVotes,
|
||||
TotalVotes: totalVotes,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *VoteEventServiceImpl) CheckVoteStatus(ctx context.Context, userID, eventID uuid.UUID) (*contract.CheckVoteStatusResponse, error) {
|
||||
hasVoted, err := s.voteEventRepo.HasUserVoted(ctx, userID, eventID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response := &contract.CheckVoteStatusResponse{
|
||||
HasVoted: hasVoted,
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
Reference in New Issue
Block a user