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, } }