1
0
Fork 0
This repository has been archived on 2025-09-02. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
mareshq-yggdrasil/internal/server/api.go

460 lines
15 KiB
Go

package server
import (
"context"
"time"
"github.com/gofiber/fiber/v2"
"gitlab.mareshq.com/hq/yggdrasil/pkg/training"
)
type APIHandlers struct {
trainingRepository training.TrainingRepository
trainingDateRepository training.TrainingDateRepository
}
func NewAPIHandlers(trainingRepository training.TrainingRepository, trainingDateRepository training.TrainingDateRepository) *APIHandlers {
return &APIHandlers{
trainingRepository: trainingRepository,
trainingDateRepository: trainingDateRepository,
}
}
func (h *APIHandlers) ListTrainings(ctx context.Context, req ListTrainingsRequestObject) (ListTrainingsResponseObject, error) {
trainings, err := h.trainingRepository.FindAll()
if err != nil {
return ListTrainings500ApplicationProblemPlusJSONResponse{
InternalErrorApplicationProblemPlusJSONResponse: InternalErrorApplicationProblemPlusJSONResponse{
Status: fiber.StatusInternalServerError,
Title: "Internal Server Error: Failed to list trainings",
Detail: err.Error(),
}}, nil
}
data := make([]Training, len(trainings))
for idx, t := range trainings {
pricing := make([]TrainingPrice, len(t.Pricing))
for idx, p := range t.Pricing {
pricing[idx] = TrainingPrice{
Amount: p.Amount,
Currency: p.Currency,
Type: TrainingPriceType(p.Type),
}
}
data[idx] = Training{
Id: t.ID,
Name: t.Name,
Days: t.Days,
Description: t.Description,
Pricing: pricing,
}
}
return ListTrainings200JSONResponse(data), nil
}
func (h *APIHandlers) CreateTraining(ctx context.Context, req CreateTrainingRequestObject) (CreateTrainingResponseObject, error) {
pricing := make([]training.TrainingPrice, len(req.Body.Pricing))
for idx, p := range req.Body.Pricing {
pricing[idx] = training.TrainingPrice{
Amount: p.Amount,
Currency: p.Currency,
Type: training.TrainingPriceType(p.Type),
}
}
t := training.Training{
Name: req.Body.Name,
Days: req.Body.Days,
Description: req.Body.Description,
Pricing: pricing,
}
err := h.trainingRepository.Create(&t)
if err != nil {
return CreateTraining500ApplicationProblemPlusJSONResponse{
InternalErrorApplicationProblemPlusJSONResponse: InternalErrorApplicationProblemPlusJSONResponse{
Status: fiber.StatusInternalServerError,
Title: "Internal Server Error: Failed to create training",
Detail: err.Error(),
}}, nil
}
responsePricing := make([]TrainingPrice, len(t.Pricing))
for idx, p := range t.Pricing {
responsePricing[idx] = TrainingPrice{
Amount: p.Amount,
Currency: p.Currency,
Type: TrainingPriceType(p.Type),
}
}
return CreateTraining201JSONResponse{
Id: t.ID,
Name: t.Name,
Days: t.Days,
Description: t.Description,
Pricing: responsePricing,
}, nil
}
func (h *APIHandlers) DeleteTraining(ctx context.Context, req DeleteTrainingRequestObject) (DeleteTrainingResponseObject, error) {
err := h.trainingRepository.Delete(req.TrainingID)
if err == training.ErrTrainingNotFound {
return DeleteTraining404ApplicationProblemPlusJSONResponse{
NotFoundErrorApplicationProblemPlusJSONResponse: NotFoundErrorApplicationProblemPlusJSONResponse{
Status: fiber.StatusNotFound,
Title: "Not Found: Training not found",
}}, nil
} else if err != nil {
return DeleteTraining500ApplicationProblemPlusJSONResponse{
InternalErrorApplicationProblemPlusJSONResponse: InternalErrorApplicationProblemPlusJSONResponse{
Status: fiber.StatusInternalServerError,
Title: "Internal Server Error: Failed to delete training",
Detail: err.Error(),
}}, nil
}
return DeleteTraining204Response{}, nil
}
func (h *APIHandlers) GetTraining(ctx context.Context, req GetTrainingRequestObject) (GetTrainingResponseObject, error) {
t, err := h.trainingRepository.FindByID(req.TrainingID)
if err == training.ErrTrainingNotFound {
return GetTraining404ApplicationProblemPlusJSONResponse{
NotFoundErrorApplicationProblemPlusJSONResponse: NotFoundErrorApplicationProblemPlusJSONResponse{
Status: fiber.StatusNotFound,
Title: "Not Found: Training not found",
}}, nil
} else if err != nil {
return GetTraining500ApplicationProblemPlusJSONResponse{
InternalErrorApplicationProblemPlusJSONResponse: InternalErrorApplicationProblemPlusJSONResponse{
Status: fiber.StatusInternalServerError,
Title: "Internal Server Error: Failed to get training",
Detail: err.Error(),
}}, nil
}
pricing := make([]TrainingPrice, len(t.Pricing))
for idx, p := range t.Pricing {
pricing[idx] = TrainingPrice{
Amount: p.Amount,
Currency: p.Currency,
Type: TrainingPriceType(p.Type),
}
}
return GetTraining200JSONResponse{
Id: t.ID,
Name: t.Name,
Days: t.Days,
Description: t.Description,
Pricing: pricing,
}, nil
}
func (h *APIHandlers) UpdateTraining(ctx context.Context, req UpdateTrainingRequestObject) (UpdateTrainingResponseObject, error) {
pricing := make([]training.TrainingPrice, len(req.Body.Pricing))
for idx, p := range req.Body.Pricing {
pricing[idx] = training.TrainingPrice{
Amount: p.Amount,
Currency: p.Currency,
Type: training.TrainingPriceType(p.Type),
}
}
t := training.Training{
ID: req.TrainingID,
Name: req.Body.Name,
Days: req.Body.Days,
Description: req.Body.Description,
Pricing: pricing,
}
err := h.trainingRepository.Update(&t)
if err != nil {
return UpdateTraining500ApplicationProblemPlusJSONResponse{
InternalErrorApplicationProblemPlusJSONResponse: InternalErrorApplicationProblemPlusJSONResponse{
Status: fiber.StatusInternalServerError,
Title: "Internal Server Error: Failed to update training",
Detail: err.Error(),
}}, nil
}
return UpdateTraining200JSONResponse{
Id: t.ID,
Name: t.Name,
Days: t.Days,
Description: t.Description,
}, nil
}
const trainingDateStartTimeFormat = "15:04"
func (h *APIHandlers) ListTrainingDates(ctx context.Context, req ListTrainingDatesRequestObject) (ListTrainingDatesResponseObject, error) {
trainingDates, err := h.trainingDateRepository.FindAllByTrainingID(req.TrainingID)
if err != nil {
return ListTrainingDates500ApplicationProblemPlusJSONResponse{
InternalErrorApplicationProblemPlusJSONResponse: InternalErrorApplicationProblemPlusJSONResponse{
Status: fiber.StatusInternalServerError,
Title: "Internal Server Error: Failed to list training dates",
Detail: err.Error(),
}}, nil
}
data := make([]TrainingDate, len(trainingDates))
for idx, td := range trainingDates {
data[idx] = TrainingDate{
Id: td.ID,
Date: td.Date,
StartTime: td.StartTime.Format(trainingDateStartTimeFormat),
Days: td.Days,
IsOnline: td.IsOnline,
Location: td.Location,
Address: td.Address,
Capacity: td.Capacity,
Price: TrainingDatePrice{
Amount: td.Price.Amount,
Currency: td.Price.Currency,
},
}
}
return ListTrainingDates200JSONResponse(data), nil
}
func (h *APIHandlers) CreateTrainingDate(ctx context.Context, req CreateTrainingDateRequestObject) (CreateTrainingDateResponseObject, error) {
price := training.TrainingDatePrice{
Amount: req.Body.Price.Amount,
Currency: req.Body.Price.Currency,
}
startTime, err := time.Parse(time.RFC3339, "2000-01-01T"+req.Body.StartTime)
if err != nil {
return CreateTrainingDate400ApplicationProblemPlusJSONResponse{
InvalidInputErrorApplicationProblemPlusJSONResponse: InvalidInputErrorApplicationProblemPlusJSONResponse{
Status: fiber.StatusBadRequest,
Title: "Invalid Input: Invalid startTime",
Detail: err.Error(),
}}, nil
}
td := training.TrainingDate{
Date: req.Body.Date,
StartTime: startTime,
Days: req.Body.Days,
IsOnline: req.Body.IsOnline,
Location: req.Body.Location,
Address: req.Body.Address,
Capacity: req.Body.Capacity,
Price: price,
}
err = h.trainingDateRepository.Create(req.TrainingID, &td)
if err != nil {
return CreateTrainingDate500ApplicationProblemPlusJSONResponse{
InternalErrorApplicationProblemPlusJSONResponse: InternalErrorApplicationProblemPlusJSONResponse{
Status: fiber.StatusInternalServerError,
Title: "Internal Server Error: Failed to create training date",
Detail: err.Error(),
}}, nil
}
return CreateTrainingDate201JSONResponse{
Id: td.ID,
Date: td.Date,
StartTime: td.StartTime.Format(trainingDateStartTimeFormat),
Days: td.Days,
IsOnline: td.IsOnline,
Location: td.Location,
Address: td.Address,
Capacity: td.Capacity,
Price: TrainingDatePrice{
Amount: td.Price.Amount,
Currency: td.Price.Currency,
},
}, nil
}
func (h *APIHandlers) DeleteTrainingDate(ctx context.Context, req DeleteTrainingDateRequestObject) (DeleteTrainingDateResponseObject, error) {
err := h.trainingDateRepository.Delete(req.TrainingDateID)
if err == training.ErrTrainingDateNotFound {
return DeleteTrainingDate404ApplicationProblemPlusJSONResponse{
NotFoundErrorApplicationProblemPlusJSONResponse: NotFoundErrorApplicationProblemPlusJSONResponse{
Status: fiber.StatusNotFound,
Title: "Not Found: Training date not found",
}}, nil
} else if err != nil {
return DeleteTrainingDate500ApplicationProblemPlusJSONResponse{
InternalErrorApplicationProblemPlusJSONResponse: InternalErrorApplicationProblemPlusJSONResponse{
Status: fiber.StatusInternalServerError,
Title: "Internal Server Error: Failed to delete training date",
Detail: err.Error(),
}}, nil
}
return DeleteTrainingDate204Response{}, nil
}
func (h *APIHandlers) GetTrainingDate(ctx context.Context, req GetTrainingDateRequestObject) (GetTrainingDateResponseObject, error) {
td, err := h.trainingDateRepository.FindByID(req.TrainingDateID)
if err == training.ErrTrainingDateNotFound {
return GetTrainingDate404ApplicationProblemPlusJSONResponse{
NotFoundErrorApplicationProblemPlusJSONResponse: NotFoundErrorApplicationProblemPlusJSONResponse{
Status: fiber.StatusNotFound,
Title: "Not Found: Training date not found",
}}, nil
} else if err != nil {
return GetTrainingDate500ApplicationProblemPlusJSONResponse{
InternalErrorApplicationProblemPlusJSONResponse: InternalErrorApplicationProblemPlusJSONResponse{
Status: fiber.StatusInternalServerError,
Title: "Internal Server Error: Failed to get training date",
Detail: err.Error(),
}}, nil
}
return GetTrainingDate200JSONResponse{
Id: td.ID,
Date: td.Date,
StartTime: td.StartTime.Format(trainingDateStartTimeFormat),
Days: td.Days,
IsOnline: td.IsOnline,
Location: td.Location,
Address: td.Address,
Capacity: td.Capacity,
Price: TrainingDatePrice{
Amount: td.Price.Amount,
Currency: td.Price.Currency,
},
}, nil
}
func (h *APIHandlers) UpdateTrainingDate(ctx context.Context, req UpdateTrainingDateRequestObject) (UpdateTrainingDateResponseObject, error) {
price := training.TrainingDatePrice{
Amount: req.Body.Price.Amount,
Currency: req.Body.Price.Currency,
}
startTime, err := time.Parse(time.RFC3339, "2000-01-01T"+req.Body.StartTime)
if err != nil {
return UpdateTrainingDate400ApplicationProblemPlusJSONResponse{
InvalidInputErrorApplicationProblemPlusJSONResponse: InvalidInputErrorApplicationProblemPlusJSONResponse{
Status: fiber.StatusBadRequest,
Title: "Invalid Input: Invalid startTime",
Detail: err.Error(),
}}, nil
}
td := training.TrainingDate{
ID: req.TrainingDateID,
Date: req.Body.Date,
StartTime: startTime,
Days: req.Body.Days,
IsOnline: req.Body.IsOnline,
Location: req.Body.Location,
Address: req.Body.Address,
Capacity: req.Body.Capacity,
Price: price,
}
err = h.trainingDateRepository.Update(&td)
if err != nil {
return UpdateTrainingDate500ApplicationProblemPlusJSONResponse{
InternalErrorApplicationProblemPlusJSONResponse: InternalErrorApplicationProblemPlusJSONResponse{
Status: fiber.StatusInternalServerError,
Title: "Internal Server Error: Failed to update training date",
Detail: err.Error(),
}}, nil
}
return UpdateTrainingDate200JSONResponse{
Id: td.ID,
Date: td.Date,
StartTime: td.StartTime.Format(trainingDateStartTimeFormat),
Days: td.Days,
IsOnline: td.IsOnline,
Location: td.Location,
Address: td.Address,
Capacity: td.Capacity,
Price: TrainingDatePrice{
Amount: td.Price.Amount,
Currency: td.Price.Currency,
},
}, nil
}
func (h *APIHandlers) ListAllUpcomingTrainingDates(ctx context.Context, req ListAllUpcomingTrainingDatesRequestObject) (ListAllUpcomingTrainingDatesResponseObject, error) {
trainings, err := h.trainingRepository.FindAll()
if err != nil {
return ListAllUpcomingTrainingDates500ApplicationProblemPlusJSONResponse{
InternalErrorApplicationProblemPlusJSONResponse: InternalErrorApplicationProblemPlusJSONResponse{
Status: fiber.StatusInternalServerError,
Title: "Internal Server Error: Failed to list all upcoming training dates",
Detail: err.Error(),
}}, nil
}
response := make(ListAllUpcomingTrainingDatesResponse, len(trainings))
for i, t := range trainings {
trainingDates, err := h.trainingDateRepository.FindUpcomingByTrainingID(t.ID)
if err != nil {
return ListAllUpcomingTrainingDates500ApplicationProblemPlusJSONResponse{
InternalErrorApplicationProblemPlusJSONResponse: InternalErrorApplicationProblemPlusJSONResponse{
Status: fiber.StatusInternalServerError,
Title: "Internal Server Error: Failed to list all upcoming training dates",
Detail: err.Error(),
}}, nil
}
response[i].Dates = make([]TrainingDate, len(trainingDates))
response[i].TrainingID = t.ID
for j, td := range trainingDates {
response[i].Dates[j] = TrainingDate{
Id: td.ID,
Date: td.Date,
StartTime: td.StartTime.Format(trainingDateStartTimeFormat),
Days: td.Days,
IsOnline: td.IsOnline,
Location: td.Location,
Address: td.Address,
Capacity: td.Capacity,
Price: TrainingDatePrice{
Amount: td.Price.Amount,
Currency: td.Price.Currency,
},
}
}
}
return ListAllUpcomingTrainingDates200JSONResponse(response), nil
}
func (h *APIHandlers) ListTrainingUpcomingDates(ctx context.Context, req ListTrainingUpcomingDatesRequestObject) (ListTrainingUpcomingDatesResponseObject, error) {
trainingDates, err := h.trainingDateRepository.FindUpcomingByTrainingID(req.TrainingID)
if err != nil {
return ListTrainingUpcomingDates500ApplicationProblemPlusJSONResponse{
InternalErrorApplicationProblemPlusJSONResponse: InternalErrorApplicationProblemPlusJSONResponse{
Status: fiber.StatusInternalServerError,
Title: "Internal Server Error: Failed to list all upcoming training dates",
Detail: err.Error(),
}}, nil
}
data := make([]TrainingDate, len(trainingDates))
for idx, td := range trainingDates {
data[idx] = TrainingDate{
Id: td.ID,
Date: td.Date,
StartTime: td.StartTime.Format(trainingDateStartTimeFormat),
Days: td.Days,
IsOnline: td.IsOnline,
Location: td.Location,
Address: td.Address,
Capacity: td.Capacity,
Price: TrainingDatePrice{
Amount: td.Price.Amount,
Currency: td.Price.Currency,
},
}
}
return ListTrainingUpcomingDates200JSONResponse(data), nil
}