feat: UploadProblem #6

Open
Holoti wants to merge 1 commit from feature/upload-problem into develop
6 changed files with 140 additions and 3 deletions

View file

@ -20,6 +20,7 @@ type Handlers interface {
DeleteProblem(c *fiber.Ctx, id int32) error
GetProblem(c *fiber.Ctx, id int32) error
UpdateProblem(c *fiber.Ctx, id int32) error
UploadProblem(c *fiber.Ctx, id int32) error
ListSolutions(c *fiber.Ctx, params testerv1.ListSolutionsParams) error
CreateSolution(c *fiber.Ctx, params testerv1.CreateSolutionParams) error
GetSolution(c *fiber.Ctx, id int32) error

View file

@ -1,12 +1,13 @@
package rest
import (
"io"
"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 {
@ -240,6 +241,23 @@ func (h *TesterHandlers) UpdateProblem(c *fiber.Ctx, id int32) error {
return c.SendStatus(fiber.StatusOK)
}
func (h *TesterHandlers) UploadProblem(c *fiber.Ctx, id int32) error {
var req testerv1.UploadProblemRequest
err := c.BodyParser(&req)
if err != nil {
return err
}
data, err := req.Archive.Bytes()
if err != nil {
return err
}
if err = h.problemsUC.UploadProblem(c.Context(), id, data); err != nil {
return err
}
return nil
}
func (h *TesterHandlers) UpdateContest(c *fiber.Ctx, id int32) error {
var req testerv1.UpdateContestRequest
err := c.BodyParser(&req)

View file

@ -2,6 +2,7 @@ package repository
import (
"context"
"git.sch9.ru/new_gate/ms-tester/internal/models"
"git.sch9.ru/new_gate/ms-tester/internal/tester"
"github.com/jmoiron/sqlx"

View file

@ -2,6 +2,7 @@ package tester
import (
"context"
"git.sch9.ru/new_gate/ms-tester/internal/models"
)
@ -11,6 +12,7 @@ type ProblemUseCase interface {
DeleteProblem(ctx context.Context, id int32) error
ListProblems(ctx context.Context, filter models.ProblemsFilter) (*models.ProblemsList, error)
UpdateProblem(ctx context.Context, id int32, problem models.ProblemUpdate) error
UploadProblem(ctx context.Context, id int32, archive []byte) error
}
type ContestUseCase interface {

View file

@ -1,14 +1,19 @@
package usecase
import (
"archive/zip"
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"strings"
"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"
"github.com/microcosm-cc/bluemonday"
"strings"
)
type ProblemUseCase struct {
@ -115,6 +120,116 @@ func (u *ProblemUseCase) UpdateProblem(ctx context.Context, id int32, problemUpd
return nil
}
type ProblemProperties struct {
Title string `json:"name"`
TimeLimit int32 `json:"timeLimit"`
MemoryLimit int32 `json:"memoryLimit"`
}
func (u *ProblemUseCase) UploadProblem(ctx context.Context, id int32, data []byte) error {
locale := "russian"
defaultLocale := "english"
var localeProblem, defaultProblem string
var localeProperties, defaultProperties ProblemProperties
r := bytes.NewReader(data)
rc, err := zip.NewReader(r, int64(r.Len()))
if err != nil {
return err
}
testsZipBuf := new(bytes.Buffer)
w := zip.NewWriter(testsZipBuf)
for _, f := range rc.File {
if f.FileInfo().IsDir() {
continue
}
if f.Name == fmt.Sprintf("statements/%s/problem.tex", locale) {
localeProblem, err = readProblem(f)
if err != nil {
return err
}
}
if f.Name == fmt.Sprintf("statements/%s/problem.tex", defaultLocale) {
defaultProblem, err = readProblem(f)
if err != nil {
return err
}
}
if f.Name == fmt.Sprintf("statements/%s/problem-properties.json", locale) {
localeProperties, err = readProperties(f)
if err != nil {
return err
}
}
if f.Name == fmt.Sprintf("statements/%s/problem-properties.json", defaultLocale) {
defaultProperties, err = readProperties(f)
if err != nil {
return err
}
}
if strings.HasPrefix(f.Name, "tests/") {
if err := w.Copy(f); err != nil {
return err
}
}
}
if err := w.Close(); err != nil {
return err
}
// testsZipBuf contains test files; this is for s3
localeProperties.MemoryLimit /= 1024 * 1024
defaultProperties.MemoryLimit /= 1024 * 1024
var problemUpdate models.ProblemUpdate
if localeProblem != "" {
problemUpdate.Legend = &localeProblem
problemUpdate.Title = &localeProperties.Title
problemUpdate.TimeLimit = &localeProperties.TimeLimit
problemUpdate.MemoryLimit = &localeProperties.MemoryLimit
} else {
problemUpdate.Legend = &defaultProblem
problemUpdate.Title = &defaultProperties.Title
problemUpdate.TimeLimit = &defaultProperties.TimeLimit
problemUpdate.MemoryLimit = &defaultProperties.MemoryLimit
}
if err := u.UpdateProblem(ctx, id, problemUpdate); err != nil {
return err
}
return nil
}
func readProblem(f *zip.File) (string, error) {
rc, err := f.Open()
if err != nil {
return "", err
}
defer rc.Close()
problemData, err := io.ReadAll(rc)
if err != nil {
return "", err
}
return string(problemData), nil
}
func readProperties(f *zip.File) (ProblemProperties, error) {
rc, err := f.Open()
if err != nil {
return ProblemProperties{}, err
}
defer rc.Close()
var properties ProblemProperties
if err := json.NewDecoder(rc).Decode(&properties); err != nil {
return ProblemProperties{}, err
}
return properties, nil
}
func isEmpty(p models.ProblemUpdate) bool {
return p.Title == nil &&
p.Legend == nil &&

2
proto

@ -1 +1 @@
Subproject commit 1fbee7ba29c358c76d1c835ac6999ce9e1b59ee9
Subproject commit f00483d24a53a243734c793fc24e02d52d39fdab