feat(tester): integrate pandoc

This commit is contained in:
Vyacheslav1557 2025-03-16 19:16:27 +05:00
parent ffacc9e3ac
commit 94fc50e272
9 changed files with 315 additions and 105 deletions

View file

@ -3,18 +3,26 @@ package models
import "time"
type Problem struct {
Id int32 `db:"id"`
Title string `db:"title"`
Legend string `db:"legend"`
InputFormat string `db:"input_format"`
OutputFormat string `db:"output_format"`
Notes string `db:"notes"`
Tutorial string `db:"tutorial"`
LatexSummary string `db:"latex_summary"`
TimeLimit int32 `db:"time_limit"`
MemoryLimit int32 `db:"memory_limit"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
Id int32 `db:"id"`
Title string `db:"title"`
TimeLimit int32 `db:"time_limit"`
MemoryLimit int32 `db:"memory_limit"`
Legend string `db:"legend"`
InputFormat string `db:"input_format"`
OutputFormat string `db:"output_format"`
Notes string `db:"notes"`
Scoring string `db:"scoring"`
LatexSummary string `db:"latex_summary"`
LegendHtml string `db:"legend_html"`
InputFormatHtml string `db:"input_format_html"`
OutputFormatHtml string `db:"output_format_html"`
NotesHtml string `db:"notes_html"`
ScoringHtml string `db:"scoring_html"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
}
type ProblemListItem struct {
@ -27,24 +35,35 @@ type ProblemListItem struct {
}
type ProblemUpdate struct {
Title *string `db:"title"`
Title *string `db:"title"`
MemoryLimit *int32 `db:"memory_limit"`
TimeLimit *int32 `db:"time_limit"`
Legend *string `db:"legend"`
InputFormat *string `db:"input_format"`
OutputFormat *string `db:"output_format"`
Notes *string `db:"notes"`
Tutorial *string `db:"tutorial"`
LatexSummary *string `db:"latex_summary"`
MemoryLimit *int32 `db:"memory_limit"`
TimeLimit *int32 `db:"time_limit"`
Scoring *string `db:"scoring"`
LegendHtml *string `db:"legend_html"`
InputFormatHtml *string `db:"input_format_html"`
OutputFormatHtml *string `db:"output_format_html"`
NotesHtml *string `db:"notes_html"`
ScoringHtml *string `db:"scoring_html"`
}
type ProblemStatement struct {
Title string `db:"title"`
Legend string `db:"legend"`
InputFormat string `db:"input_format"`
OutputFormat string `db:"output_format"`
Notes string `db:"notes"`
Tutorial string `db:"tutorial"`
TimeLimit int32 `db:"time_limit"`
MemoryLimit int32 `db:"memory_limit"`
Scoring string `db:"scoring"`
}
type Html5ProblemStatement struct {
LegendHtml string `db:"legend_html"`
InputFormatHtml string `db:"input_format_html"`
OutputFormatHtml string `db:"output_format_html"`
NotesHtml string `db:"notes_html"`
ScoringHtml string `db:"scoring_html"`
}

View file

@ -220,18 +220,25 @@ func (h *TesterHandlers) GetProblem(c *fiber.Ctx, id int32) error {
return c.JSON(
testerv1.GetProblemResponse{Problem: testerv1.Problem{
Id: problem.Id,
Title: problem.Title,
Id: problem.Id,
Title: problem.Title,
TimeLimit: problem.TimeLimit,
MemoryLimit: problem.MemoryLimit,
Legend: problem.Legend,
InputFormat: problem.InputFormat,
OutputFormat: problem.OutputFormat,
Notes: problem.Notes,
Tutorial: problem.Tutorial,
LatexSummary: problem.LatexSummary,
TimeLimit: problem.TimeLimit,
MemoryLimit: problem.MemoryLimit,
CreatedAt: problem.CreatedAt,
UpdatedAt: problem.UpdatedAt,
Scoring: problem.Scoring,
LegendHtml: problem.LegendHtml,
InputFormatHtml: problem.InputFormatHtml,
OutputFormatHtml: problem.OutputFormatHtml,
NotesHtml: problem.NotesHtml,
ScoringHtml: problem.ScoringHtml,
CreatedAt: problem.CreatedAt,
UpdatedAt: problem.UpdatedAt,
}},
)
}
@ -274,14 +281,15 @@ func (h *TesterHandlers) UpdateProblem(c *fiber.Ctx, id int32) error {
}
err = h.problemsUC.UpdateProblem(c.Context(), id, models.ProblemUpdate{
Title: req.Title,
Title: req.Title,
MemoryLimit: req.MemoryLimit,
TimeLimit: req.TimeLimit,
Legend: req.Legend,
InputFormat: req.InputFormat,
OutputFormat: req.OutputFormat,
Notes: req.Notes,
Tutorial: req.Tutorial,
MemoryLimit: req.MemoryLimit,
TimeLimit: req.TimeLimit,
Scoring: req.Scoring,
})
if err != nil {

View file

@ -114,15 +114,22 @@ func (r *ProblemRepository) ListProblems(ctx context.Context, q tester.Querier,
const (
UpdateProblemQuery = `UPDATE problems
SET title = COALESCE(?, title),
legend = COALESCE(?, legend),
input_format = COALESCE(?, input_format),
output_format = COALESCE(?, output_format),
notes = COALESCE(?, notes),
tutorial = COALESCE(?, tutorial),
latex_summary = COALESCE(?, latex_summary),
time_limit = COALESCE(?, time_limit),
memory_limit = COALESCE(?, memory_limit)
SET title = COALESCE(?, title),
time_limit = COALESCE(?, time_limit),
memory_limit = COALESCE(?, memory_limit),
legend = COALESCE(?, legend),
input_format = COALESCE(?, input_format),
output_format = COALESCE(?, output_format),
notes = COALESCE(?, notes),
scoring = COALESCE(?, scoring),
legend_html = COALESCE(?, legend_html),
input_format_html = COALESCE(?, input_format_html),
output_format_html = COALESCE(?, output_format_html),
notes_html = COALESCE(?, notes_html),
scoring_html = COALESCE(?, scoring_html)
WHERE id=?`
)
@ -132,14 +139,21 @@ func (r *ProblemRepository) UpdateProblem(ctx context.Context, q tester.Querier,
query := q.Rebind(UpdateProblemQuery)
_, err := q.ExecContext(ctx, query,
problem.Title,
problem.TimeLimit,
problem.MemoryLimit,
problem.Legend,
problem.InputFormat,
problem.OutputFormat,
problem.Notes,
problem.Tutorial,
problem.LatexSummary,
problem.TimeLimit,
problem.MemoryLimit,
problem.Scoring,
problem.LegendHtml,
problem.InputFormatHtml,
problem.OutputFormatHtml,
problem.NotesHtml,
problem.ScoringHtml,
id,
)
if err != nil {

View file

@ -3,23 +3,25 @@ package usecase
import (
"context"
"errors"
"fmt"
"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"
"strings"
)
type ProblemUseCase struct {
problemRepo tester.ProblemPostgresRepository
//pandocClient pkg.PandocClient
problemRepo tester.ProblemPostgresRepository
pandocClient pkg.PandocClient
}
func NewProblemUseCase(
problemRepo tester.ProblemPostgresRepository,
// pandocClient pkg.PandocClient,
pandocClient pkg.PandocClient,
) *ProblemUseCase {
return &ProblemUseCase{
problemRepo: problemRepo,
//pandocClient: pandocClient,
problemRepo: problemRepo,
pandocClient: pandocClient,
}
}
@ -45,14 +47,82 @@ func isEmpty(p models.ProblemUpdate) bool {
p.InputFormat == nil &&
p.OutputFormat == nil &&
p.Notes == nil &&
p.Tutorial == nil &&
p.LatexSummary == nil &&
p.Scoring == nil &&
p.MemoryLimit == nil &&
p.TimeLimit == nil
}
func build(p models.ProblemStatement) string {
return ""
const heading = `
\newcommand{\InputFile}{\subsection*{Входные данные}}
\newcommand{\OutputFile}{\subsection*{Выходные данные}}
\newcommand{\Scoring}{\subsection*{Система оценки}}
\newcommand{\Note}{\subsection*{Примечание}}
\newcommand{\Examples}{\subsection*{Примеры}}
`
func wrap(s string) string {
return fmt.Sprintf("%s\n\\begin{document}\n%s\n\\end{document}\n", heading, s)
}
func trimSpaces(statement models.ProblemStatement) models.ProblemStatement {
return models.ProblemStatement{
Legend: strings.TrimSpace(statement.Legend),
InputFormat: strings.TrimSpace(statement.InputFormat),
OutputFormat: strings.TrimSpace(statement.OutputFormat),
Notes: strings.TrimSpace(statement.Notes),
Scoring: strings.TrimSpace(statement.Scoring),
}
}
func build(ctx context.Context, pandocClient pkg.PandocClient, p models.ProblemStatement) (models.Html5ProblemStatement, error) {
p = trimSpaces(p)
latex := models.ProblemStatement{}
if p.Legend != "" {
latex.Legend = wrap(fmt.Sprintf("\\InputFile\n%s\n", p.Legend))
}
if p.InputFormat != "" {
latex.InputFormat = wrap(fmt.Sprintf("\\InputFile\n%s\n", p.InputFormat))
}
if p.OutputFormat != "" {
latex.OutputFormat = wrap(fmt.Sprintf("\\OutputFile\n%s\n", p.OutputFormat))
}
if p.Notes != "" {
latex.Notes = wrap(fmt.Sprintf("\\Note\n%s\n", p.Notes))
}
if p.Scoring != "" {
latex.Scoring = wrap(fmt.Sprintf("\\Scoring\n%s\n", p.Scoring))
}
req := []string{
latex.Legend,
latex.InputFormat,
latex.OutputFormat,
latex.Notes,
latex.Scoring,
}
res, err := pandocClient.BatchConvertLatexToHtml5(ctx, req)
if err != nil {
return models.Html5ProblemStatement{}, err
}
if len(res) != len(req) {
return models.Html5ProblemStatement{}, fmt.Errorf("wrong number of fieilds returned: %d", len(res))
}
return models.Html5ProblemStatement{
LegendHtml: res[0],
InputFormatHtml: res[1],
OutputFormatHtml: res[2],
NotesHtml: res[3],
ScoringHtml: res[4],
}, nil
}
func (u *ProblemUseCase) UpdateProblem(ctx context.Context, id int32, problemUpdate models.ProblemUpdate) error {
@ -71,19 +141,13 @@ func (u *ProblemUseCase) UpdateProblem(ctx context.Context, id int32, problemUpd
}
statement := models.ProblemStatement{
Title: problem.Title,
Legend: problem.Legend,
InputFormat: problem.InputFormat,
OutputFormat: problem.OutputFormat,
Notes: problem.Notes,
Tutorial: problem.Tutorial,
TimeLimit: problem.TimeLimit,
MemoryLimit: problem.MemoryLimit,
Scoring: problem.Scoring,
}
if problemUpdate.Title != nil {
statement.Title = *problemUpdate.Title
}
if problemUpdate.Legend != nil {
statement.Legend = *problemUpdate.Legend
}
@ -96,19 +160,29 @@ func (u *ProblemUseCase) UpdateProblem(ctx context.Context, id int32, problemUpd
if problemUpdate.Notes != nil {
statement.Notes = *problemUpdate.Notes
}
if problemUpdate.Tutorial != nil {
statement.Tutorial = *problemUpdate.Tutorial
}
if problemUpdate.TimeLimit != nil {
statement.TimeLimit = *problemUpdate.TimeLimit
}
if problemUpdate.MemoryLimit != nil {
statement.MemoryLimit = *problemUpdate.MemoryLimit
if problemUpdate.Scoring != nil {
statement.Scoring = *problemUpdate.Scoring
}
builtStatement := build(statement)
if builtStatement != problem.LatexSummary {
problemUpdate.LatexSummary = &builtStatement
builtStatement, err := build(ctx, u.pandocClient, trimSpaces(statement))
if err != nil {
return errors.Join(err, tx.Rollback())
}
if builtStatement.LegendHtml != problem.LegendHtml {
problemUpdate.LegendHtml = &builtStatement.LegendHtml
}
if builtStatement.InputFormatHtml != problem.InputFormatHtml {
problemUpdate.InputFormatHtml = &builtStatement.InputFormatHtml
}
if builtStatement.OutputFormatHtml != problem.OutputFormatHtml {
problemUpdate.OutputFormatHtml = &builtStatement.OutputFormatHtml
}
if builtStatement.NotesHtml != problem.NotesHtml {
problemUpdate.NotesHtml = &builtStatement.NotesHtml
}
if builtStatement.ScoringHtml != problem.ScoringHtml {
problemUpdate.ScoringHtml = &builtStatement.ScoringHtml
}
err = u.problemRepo.UpdateProblem(ctx, tx, id, problemUpdate)