initial commit
This commit is contained in:
202
internal/service/request_service.go
Normal file
202
internal/service/request_service.go
Normal file
@@ -0,0 +1,202 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"git.kirlllll.ru/volontery/backend/internal/database"
|
||||
"git.kirlllll.ru/volontery/backend/internal/repository"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
// RequestService предоставляет методы для работы с заявками
|
||||
type RequestService struct {
|
||||
requestRepo *repository.RequestRepository
|
||||
}
|
||||
|
||||
// NewRequestService создает новый RequestService
|
||||
func NewRequestService(requestRepo *repository.RequestRepository) *RequestService {
|
||||
return &RequestService{
|
||||
requestRepo: requestRepo,
|
||||
}
|
||||
}
|
||||
|
||||
// CreateRequestInput - входные данные для создания заявки
|
||||
type CreateRequestInput struct {
|
||||
RequesterID int64 `json:"requester_id"`
|
||||
RequestTypeID int64 `json:"request_type_id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Latitude float64 `json:"latitude"`
|
||||
Longitude float64 `json:"longitude"`
|
||||
Address string `json:"address"`
|
||||
City string `json:"city,omitempty"`
|
||||
DesiredCompletionDate *string `json:"desired_completion_date,omitempty"`
|
||||
Urgency string `json:"urgency"`
|
||||
ContactPhone string `json:"contact_phone,omitempty"`
|
||||
ContactNotes string `json:"contact_notes,omitempty"`
|
||||
}
|
||||
|
||||
// CreateRequest создает новую заявку
|
||||
func (s *RequestService) CreateRequest(ctx context.Context, input CreateRequestInput) (*database.CreateRequestRow, error) {
|
||||
// Валидация
|
||||
if input.Title == "" {
|
||||
return nil, fmt.Errorf("title is required")
|
||||
}
|
||||
if input.Description == "" {
|
||||
return nil, fmt.Errorf("description is required")
|
||||
}
|
||||
if input.Latitude == 0 || input.Longitude == 0 {
|
||||
return nil, fmt.Errorf("location is required")
|
||||
}
|
||||
|
||||
// Создание заявки
|
||||
return s.requestRepo.Create(ctx, database.CreateRequestParams{
|
||||
RequesterID: input.RequesterID,
|
||||
RequestTypeID: input.RequestTypeID,
|
||||
Title: input.Title,
|
||||
Description: input.Description,
|
||||
StMakepoint: input.Longitude,
|
||||
StMakepoint_2: input.Latitude,
|
||||
Address: input.Address,
|
||||
City: stringToPgText(input.City),
|
||||
Urgency: stringToPgText(input.Urgency),
|
||||
ContactPhone: stringToPgText(input.ContactPhone),
|
||||
ContactNotes: stringToPgText(input.ContactNotes),
|
||||
})
|
||||
}
|
||||
|
||||
// GetRequest получает заявку по ID
|
||||
func (s *RequestService) GetRequest(ctx context.Context, id int64) (*database.GetRequestByIDRow, error) {
|
||||
return s.requestRepo.GetByID(ctx, id)
|
||||
}
|
||||
|
||||
// GetUserRequests получает заявки пользователя
|
||||
func (s *RequestService) GetUserRequests(ctx context.Context, userID int64, limit, offset int32) ([]database.GetRequestsByRequesterRow, error) {
|
||||
return s.requestRepo.GetByRequester(ctx, database.GetRequestsByRequesterParams{
|
||||
RequesterID: userID,
|
||||
Limit: limit,
|
||||
Offset: offset,
|
||||
})
|
||||
}
|
||||
|
||||
// FindNearbyRequests ищет заявки рядом с точкой
|
||||
func (s *RequestService) FindNearbyRequests(ctx context.Context, lat, lon float64, radiusMeters float64, statuses []database.RequestStatus, limit, offset int32) ([]database.FindRequestsNearbyRow, error) {
|
||||
// Конвертируем []RequestStatus в []string
|
||||
statusStrings := make([]string, len(statuses))
|
||||
for i, status := range statuses {
|
||||
statusStrings[i] = string(status)
|
||||
}
|
||||
|
||||
return s.requestRepo.FindNearby(ctx, database.FindRequestsNearbyParams{
|
||||
StMakepoint: lon,
|
||||
StMakepoint_2: lat,
|
||||
Column3: statusStrings,
|
||||
StDwithin: radiusMeters,
|
||||
Limit: limit,
|
||||
Offset: offset,
|
||||
})
|
||||
}
|
||||
|
||||
// FindRequestsInBounds ищет заявки в прямоугольной области (для карты)
|
||||
func (s *RequestService) FindRequestsInBounds(ctx context.Context, statuses []database.RequestStatus, minLon, minLat, maxLon, maxLat float64) ([]database.FindRequestsInBoundsRow, error) {
|
||||
// Конвертируем []RequestStatus в []string
|
||||
statusStrings := make([]string, len(statuses))
|
||||
for i, status := range statuses {
|
||||
statusStrings[i] = string(status)
|
||||
}
|
||||
|
||||
return s.requestRepo.FindInBounds(ctx, database.FindRequestsInBoundsParams{
|
||||
Column1: statusStrings,
|
||||
StMakeenvelope: minLon,
|
||||
StMakeenvelope_2: minLat,
|
||||
StMakeenvelope_3: maxLon,
|
||||
StMakeenvelope_4: maxLat,
|
||||
})
|
||||
}
|
||||
|
||||
// CreateVolunteerResponse создает отклик волонтера на заявку
|
||||
func (s *RequestService) CreateVolunteerResponse(ctx context.Context, requestID, volunteerID int64, message string) (*database.VolunteerResponse, error) {
|
||||
return s.requestRepo.CreateVolunteerResponse(ctx, database.CreateVolunteerResponseParams{
|
||||
RequestID: requestID,
|
||||
VolunteerID: volunteerID,
|
||||
Message: stringToPgText(message),
|
||||
})
|
||||
}
|
||||
|
||||
// GetRequestResponses получает отклики на заявку
|
||||
func (s *RequestService) GetRequestResponses(ctx context.Context, requestID int64) ([]database.GetResponsesByRequestRow, error) {
|
||||
return s.requestRepo.GetResponsesByRequest(ctx, requestID)
|
||||
}
|
||||
|
||||
// ListRequestTypes получает список типов заявок
|
||||
func (s *RequestService) ListRequestTypes(ctx context.Context) ([]database.RequestType, error) {
|
||||
return s.requestRepo.ListTypes(ctx)
|
||||
}
|
||||
|
||||
// GetPendingModerationRequests получает заявки на модерации
|
||||
func (s *RequestService) GetPendingModerationRequests(ctx context.Context, limit, offset int32) ([]database.GetPendingModerationRequestsRow, error) {
|
||||
return s.requestRepo.GetPendingModerationRequests(ctx, limit, offset)
|
||||
}
|
||||
|
||||
// ApproveRequest одобряет заявку
|
||||
func (s *RequestService) ApproveRequest(ctx context.Context, requestID, moderatorID int64, comment *string) error {
|
||||
moderationComment := stringToPgText("")
|
||||
if comment != nil {
|
||||
moderationComment = stringToPgText(*comment)
|
||||
}
|
||||
|
||||
return s.requestRepo.ApproveRequest(ctx, database.ApproveRequestParams{
|
||||
ID: requestID,
|
||||
ModeratedBy: pgtype.Int8{
|
||||
Int64: moderatorID,
|
||||
Valid: true,
|
||||
},
|
||||
ModerationComment: moderationComment,
|
||||
})
|
||||
}
|
||||
|
||||
// RejectRequest отклоняет заявку
|
||||
func (s *RequestService) RejectRequest(ctx context.Context, requestID, moderatorID int64, comment string) error {
|
||||
if comment == "" {
|
||||
return fmt.Errorf("rejection comment is required")
|
||||
}
|
||||
|
||||
return s.requestRepo.RejectRequest(ctx, database.RejectRequestParams{
|
||||
ID: requestID,
|
||||
ModeratedBy: pgtype.Int8{
|
||||
Int64: moderatorID,
|
||||
Valid: true,
|
||||
},
|
||||
ModerationComment: stringToPgText(comment),
|
||||
})
|
||||
}
|
||||
|
||||
// GetModeratedRequests получает заявки, модерированные указанным модератором
|
||||
func (s *RequestService) GetModeratedRequests(ctx context.Context, moderatorID int64, limit, offset int32) ([]database.GetModeratedRequestsRow, error) {
|
||||
return s.requestRepo.GetModeratedRequests(ctx, moderatorID, limit, offset)
|
||||
}
|
||||
|
||||
// AcceptVolunteerResponse принимает отклик волонтера через хранимую процедуру
|
||||
func (s *RequestService) AcceptVolunteerResponse(ctx context.Context, responseID, requesterID int64) (*database.CallAcceptVolunteerResponseRow, error) {
|
||||
return s.requestRepo.AcceptVolunteerResponse(ctx, responseID, requesterID)
|
||||
}
|
||||
|
||||
// CompleteRequestWithRating завершает заявку с рейтингом через хранимую процедуру
|
||||
func (s *RequestService) CompleteRequestWithRating(ctx context.Context, requestID, requesterID int64, rating int32, comment *string) (*database.CallCompleteRequestWithRatingRow, error) {
|
||||
if rating < 1 || rating > 5 {
|
||||
return nil, fmt.Errorf("rating must be between 1 and 5")
|
||||
}
|
||||
return s.requestRepo.CompleteRequestWithRating(ctx, requestID, requesterID, rating, comment)
|
||||
}
|
||||
|
||||
// ModerateRequestProcedure модерирует заявку через хранимую процедуру
|
||||
func (s *RequestService) ModerateRequestProcedure(ctx context.Context, requestID, moderatorID int64, action string, comment *string) (*database.CallModerateRequestRow, error) {
|
||||
if action != "approve" && action != "reject" {
|
||||
return nil, fmt.Errorf("action must be 'approve' or 'reject'")
|
||||
}
|
||||
if action == "reject" && (comment == nil || *comment == "") {
|
||||
return nil, fmt.Errorf("comment is required when rejecting")
|
||||
}
|
||||
return s.requestRepo.ModerateRequestProcedure(ctx, requestID, moderatorID, action, comment)
|
||||
}
|
||||
Reference in New Issue
Block a user