591 lines
14 KiB
Go
591 lines
14 KiB
Go
package rest
|
|
|
|
import (
|
|
"git.sch9.ru/new_gate/ms-tester/internal/models"
|
|
"git.sch9.ru/new_gate/ms-tester/internal/tester"
|
|
"git.sch9.ru/new_gate/ms-tester/pkg"
|
|
testerv1 "git.sch9.ru/new_gate/ms-tester/proto/tester/v1"
|
|
"github.com/gofiber/fiber/v2"
|
|
"io"
|
|
)
|
|
|
|
type TesterHandlers struct {
|
|
problemsUC tester.ProblemUseCase
|
|
contestsUC tester.ContestUseCase
|
|
}
|
|
|
|
func NewTesterHandlers(problemsUC tester.ProblemUseCase, contestsUC tester.ContestUseCase) *TesterHandlers {
|
|
return &TesterHandlers{
|
|
problemsUC: problemsUC,
|
|
contestsUC: contestsUC,
|
|
}
|
|
}
|
|
|
|
func (h *TesterHandlers) ListContests(c *fiber.Ctx, params testerv1.ListContestsParams) error {
|
|
contestsList, err := h.contestsUC.ListContests(c.Context(), models.ContestsFilter{
|
|
Page: params.Page,
|
|
PageSize: params.PageSize,
|
|
})
|
|
if err != nil {
|
|
return c.SendStatus(pkg.ToREST(err))
|
|
}
|
|
|
|
resp := testerv1.ListContestsResponse{
|
|
Contests: make([]testerv1.ContestsListItem, len(contestsList.Contests)),
|
|
Pagination: P2P(contestsList.Pagination),
|
|
}
|
|
|
|
for i, contest := range contestsList.Contests {
|
|
resp.Contests[i] = CLI2CLI(*contest)
|
|
}
|
|
|
|
return c.JSON(resp)
|
|
}
|
|
|
|
func (h *TesterHandlers) ListProblems(c *fiber.Ctx, params testerv1.ListProblemsParams) error {
|
|
problemsList, err := h.problemsUC.ListProblems(c.Context(), models.ProblemsFilter{
|
|
Page: params.Page,
|
|
PageSize: params.PageSize,
|
|
})
|
|
if err != nil {
|
|
return c.SendStatus(pkg.ToREST(err))
|
|
}
|
|
|
|
resp := testerv1.ListProblemsResponse{
|
|
Problems: make([]testerv1.ProblemsListItem, len(problemsList.Problems)),
|
|
Pagination: P2P(problemsList.Pagination),
|
|
}
|
|
|
|
for i, problem := range problemsList.Problems {
|
|
resp.Problems[i] = PLI2PLI(*problem)
|
|
}
|
|
|
|
return c.JSON(resp)
|
|
}
|
|
|
|
func (h *TesterHandlers) CreateContest(c *fiber.Ctx) error {
|
|
id, err := h.contestsUC.CreateContest(c.Context(), "Название контеста")
|
|
if err != nil {
|
|
return c.SendStatus(pkg.ToREST(err))
|
|
}
|
|
|
|
return c.JSON(testerv1.CreateContestResponse{
|
|
Id: id,
|
|
})
|
|
}
|
|
|
|
func (h *TesterHandlers) DeleteContest(c *fiber.Ctx, id int32) error {
|
|
err := h.contestsUC.DeleteContest(c.Context(), id)
|
|
if err != nil {
|
|
return c.SendStatus(pkg.ToREST(err))
|
|
}
|
|
|
|
return c.SendStatus(fiber.StatusOK)
|
|
}
|
|
|
|
func (h *TesterHandlers) GetContest(c *fiber.Ctx, id int32) error {
|
|
contest, err := h.contestsUC.ReadContestById(c.Context(), id)
|
|
if err != nil {
|
|
return c.SendStatus(pkg.ToREST(err))
|
|
}
|
|
|
|
//token, ok := c.Locals(TokenKey).(*models.JWT)
|
|
//if !ok {
|
|
// return c.SendStatus(fiber.StatusUnauthorized)
|
|
//}
|
|
|
|
tasks, err := h.contestsUC.ReadTasks(c.Context(), id)
|
|
if err != nil {
|
|
return c.SendStatus(pkg.ToREST(err))
|
|
}
|
|
|
|
resp := testerv1.GetContestResponse{
|
|
Contest: C2C(*contest),
|
|
Tasks: make([]struct {
|
|
Solution testerv1.Solution `json:"solution"`
|
|
Task testerv1.TasksListItem `json:"task"`
|
|
}, len(tasks)),
|
|
}
|
|
|
|
for i, task := range tasks {
|
|
resp.Tasks[i] = struct {
|
|
Solution testerv1.Solution `json:"solution"`
|
|
Task testerv1.TasksListItem `json:"task"`
|
|
}{
|
|
Solution: testerv1.Solution{},
|
|
Task: TLI2TLI(*task),
|
|
}
|
|
}
|
|
|
|
return c.JSON(resp)
|
|
}
|
|
|
|
func (h *TesterHandlers) DeleteParticipant(c *fiber.Ctx, params testerv1.DeleteParticipantParams) error {
|
|
err := h.contestsUC.DeleteParticipant(c.Context(), params.ParticipantId)
|
|
if err != nil {
|
|
return c.SendStatus(pkg.ToREST(err))
|
|
}
|
|
|
|
return c.SendStatus(fiber.StatusOK)
|
|
}
|
|
|
|
func (h *TesterHandlers) AddParticipant(c *fiber.Ctx, params testerv1.AddParticipantParams) error {
|
|
id, err := h.contestsUC.AddParticipant(c.Context(), params.ContestId, params.UserId)
|
|
if err != nil {
|
|
return c.SendStatus(pkg.ToREST(err))
|
|
}
|
|
|
|
return c.JSON(testerv1.AddParticipantResponse{
|
|
Id: id,
|
|
})
|
|
}
|
|
|
|
func (h *TesterHandlers) DeleteTask(c *fiber.Ctx, id int32) error {
|
|
err := h.contestsUC.DeleteTask(c.Context(), id)
|
|
if err != nil {
|
|
return c.SendStatus(pkg.ToREST(err))
|
|
}
|
|
|
|
return c.SendStatus(fiber.StatusOK)
|
|
}
|
|
|
|
func (h *TesterHandlers) AddTask(c *fiber.Ctx, params testerv1.AddTaskParams) error {
|
|
id, err := h.contestsUC.AddTask(c.Context(), params.ContestId, params.ProblemId)
|
|
if err != nil {
|
|
return c.SendStatus(pkg.ToREST(err))
|
|
}
|
|
|
|
return c.JSON(testerv1.AddTaskResponse{
|
|
Id: id,
|
|
})
|
|
}
|
|
|
|
func (h *TesterHandlers) CreateProblem(c *fiber.Ctx) error {
|
|
id, err := h.problemsUC.CreateProblem(c.Context(), "Название задачи")
|
|
if err != nil {
|
|
return c.SendStatus(pkg.ToREST(err))
|
|
}
|
|
|
|
return c.JSON(testerv1.CreateProblemResponse{
|
|
Id: id,
|
|
})
|
|
}
|
|
|
|
func (h *TesterHandlers) DeleteProblem(c *fiber.Ctx, id int32) error {
|
|
err := h.problemsUC.DeleteProblem(c.Context(), id)
|
|
if err != nil {
|
|
return c.SendStatus(pkg.ToREST(err))
|
|
}
|
|
|
|
return c.SendStatus(fiber.StatusOK)
|
|
|
|
}
|
|
|
|
func (h *TesterHandlers) GetProblem(c *fiber.Ctx, id int32) error {
|
|
problem, err := h.problemsUC.ReadProblemById(c.Context(), id)
|
|
if err != nil {
|
|
return c.SendStatus(pkg.ToREST(err))
|
|
}
|
|
|
|
return c.JSON(
|
|
testerv1.GetProblemResponse{Problem: *PR2PR(problem)},
|
|
)
|
|
}
|
|
|
|
func (h *TesterHandlers) ListParticipants(c *fiber.Ctx, params testerv1.ListParticipantsParams) error {
|
|
participantsList, err := h.contestsUC.ListParticipants(c.Context(), models.ParticipantsFilter{
|
|
Page: params.Page,
|
|
PageSize: params.PageSize,
|
|
ContestId: params.ContestId,
|
|
})
|
|
if err != nil {
|
|
return c.SendStatus(pkg.ToREST(err))
|
|
}
|
|
|
|
resp := testerv1.ListParticipantsResponse{
|
|
Participants: make([]testerv1.ParticipantsListItem, len(participantsList.Participants)),
|
|
Pagination: P2P(participantsList.Pagination),
|
|
}
|
|
|
|
for i, participant := range participantsList.Participants {
|
|
resp.Participants[i] = PTLI2PTLI(*participant)
|
|
}
|
|
|
|
return c.JSON(resp)
|
|
}
|
|
|
|
func (h *TesterHandlers) UpdateProblem(c *fiber.Ctx, id int32) error {
|
|
var req testerv1.UpdateProblemRequest
|
|
err := c.BodyParser(&req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = h.problemsUC.UpdateProblem(c.Context(), id, models.ProblemUpdate{
|
|
Title: req.Title,
|
|
MemoryLimit: req.MemoryLimit,
|
|
TimeLimit: req.TimeLimit,
|
|
|
|
Legend: req.Legend,
|
|
InputFormat: req.InputFormat,
|
|
OutputFormat: req.OutputFormat,
|
|
Notes: req.Notes,
|
|
Scoring: req.Scoring,
|
|
})
|
|
|
|
if err != nil {
|
|
return c.SendStatus(pkg.ToREST(err))
|
|
}
|
|
|
|
return c.SendStatus(fiber.StatusOK)
|
|
}
|
|
|
|
func (h *TesterHandlers) UpdateContest(c *fiber.Ctx, id int32) error {
|
|
var req testerv1.UpdateContestRequest
|
|
err := c.BodyParser(&req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = h.contestsUC.UpdateContest(c.Context(), id, models.ContestUpdate{
|
|
Title: req.Title,
|
|
})
|
|
if err != nil {
|
|
return c.SendStatus(pkg.ToREST(err))
|
|
}
|
|
|
|
return c.SendStatus(fiber.StatusOK)
|
|
}
|
|
|
|
func (h *TesterHandlers) UpdateParticipant(c *fiber.Ctx, params testerv1.UpdateParticipantParams) error {
|
|
var req testerv1.UpdateParticipantRequest
|
|
err := c.BodyParser(&req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = h.contestsUC.UpdateParticipant(c.Context(), params.ParticipantId, models.ParticipantUpdate{
|
|
Name: req.Name,
|
|
})
|
|
if err != nil {
|
|
return c.SendStatus(pkg.ToREST(err))
|
|
}
|
|
|
|
return c.SendStatus(fiber.StatusOK)
|
|
}
|
|
|
|
func (h *TesterHandlers) ListSolutions(c *fiber.Ctx, params testerv1.ListSolutionsParams) error {
|
|
solutionsList, err := h.contestsUC.ListSolutions(c.Context(), models.SolutionsFilter{
|
|
ContestId: params.ContestId,
|
|
Page: params.Page,
|
|
PageSize: params.PageSize,
|
|
ParticipantId: params.ParticipantId,
|
|
TaskId: params.TaskId,
|
|
Language: params.Language,
|
|
Order: params.Order,
|
|
State: params.State,
|
|
})
|
|
if err != nil {
|
|
return c.SendStatus(pkg.ToREST(err))
|
|
}
|
|
|
|
resp := testerv1.ListSolutionsResponse{
|
|
Solutions: make([]testerv1.SolutionsListItem, len(solutionsList.Solutions)),
|
|
Pagination: P2P(solutionsList.Pagination),
|
|
}
|
|
|
|
for i, solution := range solutionsList.Solutions {
|
|
resp.Solutions[i] = SLI2SLI(*solution)
|
|
}
|
|
|
|
return c.JSON(resp)
|
|
}
|
|
|
|
const (
|
|
maxSolutionSize int64 = 10 * 1024 * 1024
|
|
)
|
|
|
|
func (h *TesterHandlers) CreateSolution(c *fiber.Ctx, params testerv1.CreateSolutionParams) error {
|
|
s, err := c.FormFile("solution")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if s.Size == 0 || s.Size > maxSolutionSize {
|
|
return c.SendStatus(fiber.StatusBadRequest)
|
|
}
|
|
|
|
f, err := s.Open()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
|
|
b, err := io.ReadAll(f)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
id, err := h.contestsUC.CreateSolution(c.Context(), &models.SolutionCreation{
|
|
TaskId: params.TaskId,
|
|
ParticipantId: 1,
|
|
Language: params.Language,
|
|
Penalty: 0,
|
|
Solution: string(b),
|
|
})
|
|
if err != nil {
|
|
return c.SendStatus(pkg.ToREST(err))
|
|
}
|
|
|
|
return c.JSON(testerv1.CreateSolutionResponse{
|
|
Id: id,
|
|
})
|
|
}
|
|
|
|
func (h *TesterHandlers) GetSolution(c *fiber.Ctx, id int32) error {
|
|
solution, err := h.contestsUC.ReadSolution(c.Context(), id)
|
|
if err != nil {
|
|
return c.SendStatus(pkg.ToREST(err))
|
|
}
|
|
|
|
return c.JSON(
|
|
testerv1.GetSolutionResponse{Solution: S2S(*solution)},
|
|
)
|
|
}
|
|
|
|
func (h *TesterHandlers) GetTask(c *fiber.Ctx, id int32) error {
|
|
contest, err := h.contestsUC.ReadContestById(c.Context(), id)
|
|
if err != nil {
|
|
return c.SendStatus(pkg.ToREST(err))
|
|
}
|
|
|
|
tasks, err := h.contestsUC.ReadTasks(c.Context(), id)
|
|
if err != nil {
|
|
return c.SendStatus(pkg.ToREST(err))
|
|
}
|
|
|
|
t, err := h.contestsUC.ReadTask(c.Context(), id)
|
|
if err != nil {
|
|
return c.SendStatus(pkg.ToREST(err))
|
|
}
|
|
|
|
resp := testerv1.GetTaskResponse{
|
|
Contest: C2C(*contest),
|
|
Tasks: make([]testerv1.TasksListItem, len(tasks)),
|
|
Task: *T2T(t),
|
|
}
|
|
|
|
for i, task := range tasks {
|
|
resp.Tasks[i] = TLI2TLI(*task)
|
|
}
|
|
|
|
return c.JSON(resp)
|
|
}
|
|
|
|
func (h *TesterHandlers) GetMonitor(c *fiber.Ctx, params testerv1.GetMonitorParams) error {
|
|
contest, err := h.contestsUC.ReadContestById(c.Context(), params.ContestId)
|
|
if err != nil {
|
|
return c.SendStatus(pkg.ToREST(err))
|
|
}
|
|
|
|
monitor, err := h.contestsUC.ReadMonitor(c.Context(), params.ContestId)
|
|
if err != nil {
|
|
return c.SendStatus(pkg.ToREST(err))
|
|
}
|
|
|
|
tasks, err := h.contestsUC.ReadTasks(c.Context(), params.ContestId)
|
|
if err != nil {
|
|
return c.SendStatus(pkg.ToREST(err))
|
|
}
|
|
|
|
resp := testerv1.GetMonitorResponse{
|
|
Contest: C2C(*contest),
|
|
Tasks: make([]testerv1.TasksListItem, len(tasks)),
|
|
Participants: make([]testerv1.ParticipantsStat, len(monitor.Participants)),
|
|
SummaryPerProblem: make([]testerv1.ProblemStatSummary, len(monitor.Summary)),
|
|
}
|
|
|
|
for i, participant := range monitor.Participants {
|
|
resp.Participants[i] = testerv1.ParticipantsStat{
|
|
Id: participant.Id,
|
|
Name: participant.Name,
|
|
PenaltyInTotal: participant.PenaltyInTotal,
|
|
Solutions: make([]testerv1.SolutionsListItem, len(participant.Solutions)),
|
|
SolvedInTotal: participant.SolvedInTotal,
|
|
}
|
|
|
|
for j, solution := range participant.Solutions {
|
|
resp.Participants[i].Solutions[j] = SLI2SLI(*solution)
|
|
}
|
|
}
|
|
|
|
for i, problem := range monitor.Summary {
|
|
resp.SummaryPerProblem[i] = testerv1.ProblemStatSummary{
|
|
Id: problem.Id,
|
|
Success: problem.Success,
|
|
Total: problem.Total,
|
|
}
|
|
}
|
|
|
|
for i, task := range tasks {
|
|
resp.Tasks[i] = TLI2TLI(*task)
|
|
}
|
|
|
|
return c.JSON(resp)
|
|
}
|
|
|
|
func P2P(p models.Pagination) testerv1.Pagination {
|
|
return testerv1.Pagination{
|
|
Page: p.Page,
|
|
Total: p.Total,
|
|
}
|
|
}
|
|
|
|
func C2C(c models.Contest) testerv1.Contest {
|
|
return testerv1.Contest{
|
|
Id: c.Id,
|
|
Title: c.Title,
|
|
CreatedAt: c.CreatedAt,
|
|
UpdatedAt: c.UpdatedAt,
|
|
}
|
|
}
|
|
|
|
func CLI2CLI(c models.ContestsListItem) testerv1.ContestsListItem {
|
|
return testerv1.ContestsListItem{
|
|
Id: c.Id,
|
|
Title: c.Title,
|
|
CreatedAt: c.CreatedAt,
|
|
UpdatedAt: c.UpdatedAt,
|
|
}
|
|
}
|
|
|
|
func PLI2PLI(p models.ProblemsListItem) testerv1.ProblemsListItem {
|
|
return testerv1.ProblemsListItem{
|
|
Id: p.Id,
|
|
Title: p.Title,
|
|
MemoryLimit: p.MemoryLimit,
|
|
TimeLimit: p.TimeLimit,
|
|
CreatedAt: p.CreatedAt,
|
|
UpdatedAt: p.UpdatedAt,
|
|
}
|
|
}
|
|
|
|
func TLI2TLI(t models.TasksListItem) testerv1.TasksListItem {
|
|
return testerv1.TasksListItem{
|
|
Id: t.Id,
|
|
Position: t.Position,
|
|
Title: t.Title,
|
|
MemoryLimit: t.MemoryLimit,
|
|
ProblemId: t.ProblemId,
|
|
TimeLimit: t.TimeLimit,
|
|
CreatedAt: t.CreatedAt,
|
|
UpdatedAt: t.UpdatedAt,
|
|
}
|
|
}
|
|
|
|
func T2T(t *models.Task) *testerv1.Task {
|
|
return &testerv1.Task{
|
|
Id: t.Id,
|
|
Title: t.Title,
|
|
MemoryLimit: t.MemoryLimit,
|
|
TimeLimit: t.TimeLimit,
|
|
|
|
InputFormatHtml: t.InputFormatHtml,
|
|
LegendHtml: t.LegendHtml,
|
|
NotesHtml: t.NotesHtml,
|
|
OutputFormatHtml: t.OutputFormatHtml,
|
|
Position: t.Position,
|
|
ScoringHtml: t.ScoringHtml,
|
|
|
|
CreatedAt: t.CreatedAt,
|
|
UpdatedAt: t.UpdatedAt,
|
|
}
|
|
}
|
|
|
|
func PR2PR(p *models.Problem) *testerv1.Problem {
|
|
return &testerv1.Problem{
|
|
Id: p.Id,
|
|
Title: p.Title,
|
|
TimeLimit: p.TimeLimit,
|
|
MemoryLimit: p.MemoryLimit,
|
|
|
|
Legend: p.Legend,
|
|
InputFormat: p.InputFormat,
|
|
OutputFormat: p.OutputFormat,
|
|
Notes: p.Notes,
|
|
Scoring: p.Scoring,
|
|
|
|
LegendHtml: p.LegendHtml,
|
|
InputFormatHtml: p.InputFormatHtml,
|
|
OutputFormatHtml: p.OutputFormatHtml,
|
|
NotesHtml: p.NotesHtml,
|
|
ScoringHtml: p.ScoringHtml,
|
|
|
|
CreatedAt: p.CreatedAt,
|
|
UpdatedAt: p.UpdatedAt,
|
|
}
|
|
}
|
|
|
|
func PTLI2PTLI(p models.ParticipantsListItem) testerv1.ParticipantsListItem {
|
|
return testerv1.ParticipantsListItem{
|
|
Id: p.Id,
|
|
UserId: p.UserId,
|
|
Name: p.Name,
|
|
CreatedAt: p.CreatedAt,
|
|
UpdatedAt: p.UpdatedAt,
|
|
}
|
|
}
|
|
|
|
func SLI2SLI(s models.SolutionsListItem) testerv1.SolutionsListItem {
|
|
return testerv1.SolutionsListItem{
|
|
Id: s.Id,
|
|
|
|
ParticipantId: s.ParticipantId,
|
|
ParticipantName: s.ParticipantName,
|
|
|
|
State: s.State,
|
|
Score: s.Score,
|
|
Penalty: s.Penalty,
|
|
TimeStat: s.TimeStat,
|
|
MemoryStat: s.MemoryStat,
|
|
Language: s.Language,
|
|
|
|
TaskId: s.TaskId,
|
|
TaskPosition: s.TaskPosition,
|
|
TaskTitle: s.TaskTitle,
|
|
|
|
ContestId: s.ContestId,
|
|
ContestTitle: s.ContestTitle,
|
|
|
|
CreatedAt: s.CreatedAt,
|
|
UpdatedAt: s.UpdatedAt,
|
|
}
|
|
}
|
|
|
|
func S2S(s models.Solution) testerv1.Solution {
|
|
return testerv1.Solution{
|
|
Id: s.Id,
|
|
|
|
ParticipantId: s.ParticipantId,
|
|
ParticipantName: s.ParticipantName,
|
|
|
|
Solution: s.Solution,
|
|
|
|
State: s.State,
|
|
Score: s.Score,
|
|
Penalty: s.Penalty,
|
|
TimeStat: s.TimeStat,
|
|
MemoryStat: s.MemoryStat,
|
|
Language: s.Language,
|
|
|
|
TaskId: s.TaskId,
|
|
TaskPosition: s.TaskPosition,
|
|
TaskTitle: s.TaskTitle,
|
|
|
|
ContestId: s.ContestId,
|
|
ContestTitle: s.ContestTitle,
|
|
|
|
CreatedAt: s.CreatedAt,
|
|
UpdatedAt: s.UpdatedAt,
|
|
}
|
|
}
|