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 { contests, count, err := h.contestsUC.ListContests(c.Context(), params.Page, params.PageSize) if err != nil { return c.SendStatus(pkg.ToREST(err)) } resp := testerv1.ListContestsResponse{ Contests: make([]testerv1.ContestsListItem, len(contests)), Page: params.Page, MaxPage: func() int32 { if count%params.PageSize == 0 { return count / params.PageSize } return count/params.PageSize + 1 }(), } for i, contest := range contests { resp.Contests[i] = testerv1.ContestsListItem{ Id: contest.Id, Title: contest.Title, CreatedAt: contest.CreatedAt, UpdatedAt: contest.UpdatedAt, } } return c.JSON(resp) } func (h *TesterHandlers) ListProblems(c *fiber.Ctx, params testerv1.ListProblemsParams) error { problems, count, err := h.problemsUC.ListProblems(c.Context(), params.Page, params.PageSize) if err != nil { return c.SendStatus(pkg.ToREST(err)) } resp := testerv1.ListProblemsResponse{ Problems: make([]testerv1.ProblemListItem, len(problems)), Page: params.Page, MaxPage: func() int32 { if count%params.PageSize == 0 { return count / params.PageSize } return count/params.PageSize + 1 }(), } for i, problem := range problems { resp.Problems[i] = testerv1.ProblemListItem{ Id: problem.Id, Title: problem.Title, MemoryLimit: problem.MemoryLimit, TimeLimit: problem.TimeLimit, CreatedAt: problem.CreatedAt, UpdatedAt: problem.UpdatedAt, } } 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.ReadRichTasks(c.Context(), id) if err != nil { return c.SendStatus(pkg.ToREST(err)) } resp := testerv1.GetContestResponse{ Contest: testerv1.Contest{ Id: id, Title: contest.Title, CreatedAt: contest.CreatedAt, UpdatedAt: contest.UpdatedAt, }, Tasks: make([]struct { BestSolution testerv1.BestSolution `json:"best_solution"` Task testerv1.RichTask `json:"task"` }, len(tasks)), } for i, task := range tasks { resp.Tasks[i] = struct { BestSolution testerv1.BestSolution `json:"best_solution"` Task testerv1.RichTask `json:"task"` }{ BestSolution: testerv1.BestSolution{}, Task: testerv1.RichTask{ Id: task.Id, ProblemId: task.ProblemId, Position: task.Position, Title: task.Title, MemoryLimit: task.MemoryLimit, TimeLimit: task.TimeLimit, CreatedAt: task.CreatedAt, UpdatedAt: task.UpdatedAt, }, } } 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: testerv1.Problem{ Id: problem.Id, Title: problem.Title, TimeLimit: problem.TimeLimit, MemoryLimit: problem.MemoryLimit, Legend: problem.Legend, InputFormat: problem.InputFormat, OutputFormat: problem.OutputFormat, Notes: problem.Notes, Scoring: problem.Scoring, LegendHtml: problem.LegendHtml, InputFormatHtml: problem.InputFormatHtml, OutputFormatHtml: problem.OutputFormatHtml, NotesHtml: problem.NotesHtml, ScoringHtml: problem.ScoringHtml, CreatedAt: problem.CreatedAt, UpdatedAt: problem.UpdatedAt, }}, ) } func (h *TesterHandlers) ListParticipants(c *fiber.Ctx, params testerv1.ListParticipantsParams) error { participants, count, err := h.contestsUC.ListParticipants(c.Context(), params.ContestId, params.Page, params.PageSize) if err != nil { return c.SendStatus(pkg.ToREST(err)) } resp := testerv1.ListParticipantsResponse{ Participants: make([]testerv1.ParticipantsListItem, len(participants)), Page: params.Page, MaxPage: func() int32 { if count%params.PageSize == 0 { return count / params.PageSize } return count/params.PageSize + 1 }(), } for i, participant := range participants { resp.Participants[i] = testerv1.ParticipantsListItem{ Id: participant.Id, UserId: participant.UserId, Name: participant.Name, CreatedAt: participant.CreatedAt, UpdatedAt: participant.UpdatedAt, } } 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 { list, total, 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.SolutionListItem, len(list)), Page: params.Page, MaxPage: func() int32 { if total%params.PageSize == 0 { return total / params.PageSize } return total/params.PageSize + 1 }(), } for i, solution := range list { resp.Solutions[i] = testerv1.SolutionListItem{ Id: solution.Id, TaskId: solution.TaskId, ContestId: solution.ContestId, ParticipantId: solution.ParticipantId, Language: solution.Language, Penalty: solution.Penalty, Score: solution.Score, State: solution.State, TotalScore: solution.TotalScore, CreatedAt: solution.CreatedAt, UpdatedAt: solution.UpdatedAt, } } 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: testerv1.Solution{ Id: solution.Id, TaskId: solution.TaskId, ParticipantId: solution.ParticipantId, Solution: solution.Solution, State: solution.State, Score: solution.Score, Penalty: solution.Penalty, TotalScore: solution.TotalScore, Language: solution.Language, CreatedAt: solution.CreatedAt, UpdatedAt: solution.UpdatedAt, }}, ) } 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.ReadRichTasks(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: struct { Id int32 `json:"id"` Tasks []testerv1.RichTask `json:"tasks"` Title string `json:"title"` }{ Id: contest.Id, Title: contest.Title, Tasks: make([]testerv1.RichTask, len(tasks)), }, Task: 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, }, } for i, task := range tasks { resp.Contest.Tasks[i] = testerv1.RichTask{ Id: task.Id, Position: task.Position, Title: task.Title, MemoryLimit: task.MemoryLimit, ProblemId: task.ProblemId, TimeLimit: task.TimeLimit, CreatedAt: task.CreatedAt, UpdatedAt: task.UpdatedAt} } 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.ReadRichTasks(c.Context(), params.ContestId) if err != nil { return c.SendStatus(pkg.ToREST(err)) } resp := testerv1.GetMonitorResponse{ Contest: struct { Id int32 `json:"id"` Tasks []testerv1.RichTask `json:"tasks"` Title string `json:"title"` }{ Id: contest.Id, Title: contest.Title, Tasks: make([]testerv1.RichTask, len(tasks)), }, Participants: make([]struct { Id int32 `json:"id"` Name string `json:"name"` PenaltyInTotal int32 `json:"penalty_in_total"` Solutions []testerv1.SolutionListItem `json:"solutions"` SolvedInTotal int32 `json:"solved_in_total"` }, len(monitor.Participants)), SummaryPerProblem: make([]struct { Id int32 `json:"id"` Success int32 `json:"success"` Total int32 `json:"total"` }, len(monitor.Summary)), } for i, participant := range monitor.Participants { resp.Participants[i] = struct { Id int32 `json:"id"` Name string `json:"name"` PenaltyInTotal int32 `json:"penalty_in_total"` Solutions []testerv1.SolutionListItem `json:"solutions"` SolvedInTotal int32 `json:"solved_in_total"` }{ Id: participant.Id, Name: participant.Name, PenaltyInTotal: participant.PenaltyInTotal, Solutions: make([]testerv1.SolutionListItem, len(participant.Solutions)), SolvedInTotal: participant.SolvedInTotal, } for j, solution := range participant.Solutions { resp.Participants[i].Solutions[j] = testerv1.SolutionListItem{ ContestId: solution.ContestId, CreatedAt: solution.CreatedAt, Id: solution.Id, Language: solution.Language, ParticipantId: solution.ParticipantId, Penalty: solution.Penalty, Score: solution.Score, State: solution.State, TaskId: solution.TaskId, TotalScore: solution.TotalScore, UpdatedAt: solution.UpdatedAt, } } } for i, problem := range monitor.Summary { resp.SummaryPerProblem[i] = struct { Id int32 `json:"id"` Success int32 `json:"success"` Total int32 `json:"total"` }{ Id: problem.Id, Success: problem.Success, Total: problem.Total, } } for i, task := range tasks { resp.Contest.Tasks[i] = testerv1.RichTask{ Id: task.Id, Position: task.Position, Title: task.Title, MemoryLimit: task.MemoryLimit, ProblemId: task.ProblemId, TimeLimit: task.TimeLimit, CreatedAt: task.CreatedAt, UpdatedAt: task.UpdatedAt} } return c.JSON(resp) }