Skip to content

Commit 7d36844

Browse files
API for contest creation and problem creation
1 parent b2855b5 commit 7d36844

9 files changed

Lines changed: 211 additions & 26 deletions

File tree

api/api.go

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
"log"
77
"net/http"
88

9-
"lidsol.org/papeador/auth"
109
"lidsol.org/papeador/store"
1110
)
1211

@@ -33,19 +32,19 @@ func API(s store.Store, port int) {
3332
// mux.HandleFunc("GET /users", apiCtx.createUserView)
3433
mux.HandleFunc("GET /users/{id}", apiCtx.getUserByID)
3534

36-
mux.HandleFunc("POST /contests/new", auth.RequireAuth(apiCtx.createContest))
37-
mux.HandleFunc("GET /new-contest", auth.RequireAuth(apiCtx.createContestView))
35+
mux.HandleFunc("POST /contests/new", apiCtx.createContest)
36+
mux.HandleFunc("GET /new-contest", apiCtx.createContestView)
3837
mux.HandleFunc("GET /contests", apiCtx.getContests)
3938
mux.HandleFunc("GET /contests/{id}", apiCtx.getContestByID)
4039

41-
mux.HandleFunc("POST /contests/{id}/problems/new", auth.RequireAuth(apiCtx.createProblem))
42-
mux.HandleFunc("GET /contests/{id}/new-problem", auth.RequireAuth(apiCtx.createProblemView))
40+
mux.HandleFunc("POST /contests/{id}/problems/new", apiCtx.createProblem)
41+
mux.HandleFunc("GET /contests/{id}/new-problem", apiCtx.createProblemView)
4342
mux.HandleFunc("GET /contests/{contestID}/problems/{problemID}", apiCtx.getProblemByID)
4443
mux.HandleFunc("GET /contests/{contestID}/problems/{problemID}/pdf", apiCtx.getProblemStatementByID)
4544

46-
mux.HandleFunc("POST /contests/{constestID}/problems/{problemID}/submit", auth.RequireAuth(apiCtx.submitProgram))
45+
mux.HandleFunc("POST /contests/{contestID}/problems/{problemID}/submit", apiCtx.submitProgram)
4746
// mux.HandleFunc("GET /contests/{constestID}/problems/{problemID}/submit/{submitID}", auth.RequireAuth(apiCtx.getSubmissionByID))
48-
mux.HandleFunc("GET /contests/{constestID}/problems/{problemID}/submit", auth.RequireAuth(apiCtx.getSubmissions))
47+
mux.HandleFunc("GET /contests/{contestID}/problems/{problemID}/submit", apiCtx.getSubmissions)
4948
// mux.HandleFunc("GET /contests/{constestID}/problems/{problemID}/last-submit", auth.RequireAuth(apiCtx.getLastSubmission))
5049

5150
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), mux))

api/problem.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ func (api *ApiContext) createProblem(w http.ResponseWriter, r *http.Request) {
6565
timelimit, err := strconv.Atoi(timelimitStr)
6666
if err != nil {
6767
http.Error(w, "Error en ruta", http.StatusBadRequest)
68+
log.Println("Error", err)
6869
return
6970
}
7071

@@ -118,6 +119,7 @@ func (api *ApiContext) createProblem(w http.ResponseWriter, r *http.Request) {
118119

119120
in.CreatorID = int64(id)
120121

122+
log.Println("creandoproblema", contestIDStr)
121123
if err := api.Store.CreateProblem(r.Context(), &in); err != nil {
122124
if err == store.ErrNotFound {
123125
http.Error(w, "El concurso no existe", http.StatusConflict)

api/submit.go

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ import (
1717
var m sync.Mutex
1818

1919
func (api *ApiContext) submitProgram(w http.ResponseWriter, r *http.Request) {
20+
fmt.Println("HOLA A TODOS")
21+
err := r.ParseMultipartForm(8 << 20)
22+
if err != nil {
23+
http.Error(w, "Los archivos deben ser, como máximo, de 8 MiB", http.StatusBadRequest)
24+
log.Println("Error", err)
25+
return
26+
}
27+
2028
file, fileHeader, err := r.FormFile("program")
2129
if err != nil {
2230
log.Printf("Could not get form file: %v\n", err)
@@ -45,10 +53,12 @@ func (api *ApiContext) submitProgram(w http.ResponseWriter, r *http.Request) {
4553
filenameSep := strings.Split(fileHeader.Filename, ".")
4654
filetype := filenameSep[len(filenameSep)-1]
4755

56+
57+
// testcases, err := api.Store.GetTestCases(r.Context(), problemID)
4858
testcases := []judge.SubmissionTestCase{
49-
judge.SubmissionTestCase{Input: "10\n", Output: "20\n"},
50-
judge.SubmissionTestCase{Input: "5\n", Output: "10\n"},
51-
judge.SubmissionTestCase{Input: "20\n", Output: "40\n"},
59+
judge.SubmissionTestCase{Input: "4\n", Output: "24\n"},
60+
judge.SubmissionTestCase{Input: "5\n", Output: "120\n"},
61+
judge.SubmissionTestCase{Input: "13\n", Output: "6227020800\n"},
5262
}
5363
timelimit := 1
5464
createResponse, err := judge.CreateSandbox(conn, filetype, string(buf)[:n], testcases, timelimit)
@@ -91,16 +101,6 @@ func (api *ApiContext) submitProgram(w http.ResponseWriter, r *http.Request) {
91101
// Metelo de nuevo
92102
*judge.WorkerQueueP <- worker
93103

94-
i := 0
95-
for scanner.Scan() {
96-
res := scanner.Text()
97-
log.Printf("Testcase %v: %v", i, res)
98-
resMap[i] = res
99-
i++
100-
}
101-
102-
// Metelo de nuevo
103-
*judge.WorkerQueueP <- worker
104104

105105
w.Header().Set("Content-Type", "application/json")
106106
w.WriteHeader(http.StatusOK)

judge/judge.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,8 @@ func CreateSandbox(conn context.Context, filetype, programStr string, testcases
124124

125125
log.Println("Building image")
126126

127-
dockerfilePath := fmt.Sprintf("./Dockerfile-%v", filetype)
127+
dockerfilePath := fmt.Sprintf("/vol/podman/Dockerfile-%v", filetype)
128+
log.Println(dockerfilePath)
128129
_, err = images.Build(conn, []string{dockerfilePath}, options)
129130
if err != nil {
130131
return types.ContainerCreateResponse{}, err

store/sqlite.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,31 @@ func (s *SQLiteStore) CreateTestCase(ctx context.Context, t *TestCase) error {
251251
return nil
252252
}
253253

254+
func (s *SQLiteStore) GetTestCases(ctx context.Context, problemID int) ([]TestCase, error) {
255+
rows, err := s.DB.Query("SELECT time_limit, expected_out, given_input from test_case WHERE problem_id = ?", problemID)
256+
257+
if err != nil {
258+
return nil, err
259+
}
260+
defer rows.Close()
261+
262+
var testcases []TestCase
263+
264+
for rows.Next() {
265+
var t TestCase
266+
if err := rows.Scan(&t.TimeLimit, &t.ExpectedOut, &t.GivenInput); err != nil {
267+
return testcases, err
268+
}
269+
testcases = append(testcases, t)
270+
}
271+
272+
if err := rows.Err(); err != nil {
273+
return testcases, err
274+
}
275+
276+
return testcases, nil
277+
}
278+
254279
func (s *SQLiteStore) Login(ctx context.Context, u *User) error {
255280
var username, storedHash, salt string
256281

store/store.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,5 @@ type Store interface {
6363
GetContestByID(ctx context.Context, id int) (Contest, error)
6464
GetContestProblems(ctx context.Context, id int) ([]Problem, error)
6565
GetProblemByIDs(ctx context.Context, contestID, problemID int) (*Problem, error)
66+
GetTestCases(ctx context.Context, problemID int) ([]TestCase, error)
6667
}

templates/createProblem.html

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,36 @@
99
<link rel="icon" href="favicon.png">
1010
</head>
1111
<body>
12-
<h1>Problema</h1>
12+
<h1>Añade un nuevo problema</h1>
13+
<form hx-encoding="multipart/form-data" hx-post="/contests/{{.ID}}/problems/new">
14+
<div>
15+
Nombre del problema: <input type="text" class="form-control" name="problem-name">
16+
</div>
17+
<div>
18+
Limite de tiempo: <input type="text" class="form-control" name="time-limit">
19+
</div>
1320

14-
{{ .ProblemName }}
15-
{{ .SampleInput }}
16-
{{ .SampleOutput }}
21+
<div>
22+
Enunciado: <input type="file" class="form-control" name="description">
23+
</div>
24+
25+
<div>
26+
Entrada: <input type="file" class="form-control" name="inputs" multiple>
27+
</div>
28+
29+
<div>
30+
Salida: <input type="file" class="form-control" name="outputs" multiple>
31+
</div>
32+
33+
<div class="mt-2">
34+
<button class="btn btn-primary" hx-post="/contests/{{.ID}}/problems/new" hx-target="#responseDiv" hx-target="innerHTML">
35+
Enviar
36+
</button>
37+
</div>
38+
39+
<div class="mt-2" id="responseDiv">
40+
</div>
41+
</form>
1742

1843
<script src="https://unpkg.com/htmx.org@1.9.2"></script>
1944
</body>

templates/login.html

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
<!DOCTYPE html>
2+
<html lang="es">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>Login - Papeador</title>
7+
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
8+
</head>
9+
<style>
10+
.backg {
11+
background-color: #0a2463 !important; /* azul oscuro */
12+
}
13+
body {
14+
font-family: Arial, sans-serif;
15+
background: #f4f4f4;
16+
}
17+
18+
</style>
19+
<body>
20+
<nav class="navbar navbar-expand-lg backg navbar-dark">
21+
<div class="container-fluid">
22+
<a class="navbar-brand" href="#">Papeador</a>
23+
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
24+
<span class="navbar-toggler-icon"></span>
25+
</button>
26+
<div class="collapse navbar-collapse" id="navbarNav">
27+
<ul class="navbar-nav">
28+
<li class="nav-item">
29+
<a class="nav-link active" aria-current="page" href="./listado_concursos.html">Concursos</a>
30+
</li>
31+
<li class="nav-item">
32+
<a class="nav-link" href="#">Perfil</a>
33+
</li>
34+
<li class="nav-item">
35+
<a class="nav-link" href="#">Login</a>
36+
</li>
37+
</ul>
38+
</div>
39+
</div>
40+
</nav>
41+
42+
<div class="container mt-5">
43+
<div class="row justify-content-center">
44+
<div class="col-md-6">
45+
<ul class="nav nav-tabs mb-4" id="myTab" role="tablist">
46+
<li class="nav-item" role="presentation">
47+
<button class="nav-link active" id="login-tab" data-bs-toggle="tab" data-bs-target="#login" type="button" role="tab" aria-controls="login" aria-selected="true">Iniciar Sesión</button>
48+
</li>
49+
<li class="nav-item" role="presentation">
50+
<button class="nav-link" id="register-tab" data-bs-toggle="tab" data-bs-target="#register" type="button" role="tab" aria-controls="register" aria-selected="false">Registrarse</button>
51+
</li>
52+
</ul>
53+
54+
<div class="tab-content" id="myTabContent">
55+
<!-- Formulario de Login -->
56+
<div class="tab-pane fade show active" id="login" role="tabpanel" aria-labelledby="login-tab">
57+
<div class="card">
58+
<div class="card-body">
59+
<h3 class="card-title text-center mb-4">Iniciar Sesión</h3>
60+
<form hx-post="/users/login" hx-target="#login-response">
61+
<div class="mb-3">
62+
<label for="loginUsername" class="form-label">Usuario</label>
63+
<input type="text" class="form-control" id="loginUsername" name="username" required>
64+
</div>
65+
<div class="mb-3">
66+
<label for="loginPassword" class="form-label">Contraseña</label>
67+
<input type="password" class="form-control" id="loginPassword" name="password" required>
68+
</div>
69+
<!-- <div class="mb-3 form-check"> -->
70+
<!-- <input type="checkbox" class="form-check-input" id="rememberMe"> -->
71+
<!-- <label class="form-check-label" for="rememberMe">Recordarme</label> -->
72+
<!-- </div> -->
73+
<input type="submit" class="btn btn-primary w-100" value="Entrar">
74+
</form>
75+
<div id="login-response"></div>
76+
</div>
77+
</div>
78+
</div>
79+
80+
<!-- Formulario de Registro -->
81+
<div class="tab-pane fade" id="register" role="tabpanel" aria-labelledby="register-tab">
82+
<div class="card">
83+
<div class="card-body">
84+
<h3 class="card-title text-center mb-4">Registro de Usuario</h3>
85+
<form hx-post="/users/create" hx-target="#create-response">
86+
<div class="mb-3">
87+
<label for="registerUsername" class="form-label">Usuario</label>
88+
<input type="text" class="form-control" id="registerUsername" name="username" required>
89+
<div class="form-text">Elige un nombre de usuario único.</div>
90+
</div>
91+
<div class="mb-3">
92+
<label for="registerEmail" class="form-label">Correo electrónico</label>
93+
<input type="email" class="form-control" id="registerEmail" name="email" aria-describedby="emailHelp" required>
94+
<div id="emailHelp" class="form-text">Nunca compartiremos tu correo con nadie más.</div>
95+
</div>
96+
<div class="mb-3">
97+
<label for="registerPassword" class="form-label" name="">Contraseña</label>
98+
<input type="password" class="form-control" id="registerPassword" name="password" required>
99+
</div>
100+
<!-- <div class="mb-3"> -->
101+
<!-- <label for="registerPasswordConfirm" class="form-label">Confirmar Contraseña</label> -->
102+
<!-- <input type="password" class="form-control" id="registerPasswordConfirm" required> -->
103+
<!-- </div> -->
104+
<!-- <div class="mb-3 form-check"> -->
105+
<!-- <input type="checkbox" class="form-check-input" id="acceptTerms" required> -->
106+
<!-- <label class="form-check-label" for="acceptTerms">Acepto los términos y condiciones</label> -->
107+
<!-- </div> -->
108+
<input type="submit" class="btn btn-primary w-100" value="Registrarse">
109+
</form>
110+
<div id="create-response"></div>
111+
</div>
112+
</div>
113+
</div>
114+
</div>
115+
</div>
116+
</div>
117+
</div>
118+
119+
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
120+
<script src="https://unpkg.com/htmx.org@1.9.2"></script>
121+
</body>
122+
</html>

templates/problem.html

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,17 @@ <h6 class="fw-bold mb-2">Output</h6>
6767
</div>
6868
</div>
6969
</div>
70-
<button class="btn btn-success mb-3 mt-3" type="button">+ Subir código</button>
70+
71+
<form>
72+
73+
Código fuente: <input type="file" class="form-control" name="program">
74+
<div class="mt-2">
75+
<button class="btn btn-success mb-3 mt-3" type="button" hx-post="/contests/{{.ContestID}}/problems/{{.ProblemID}}/submit" hx-target="#responseDiv" hx-target="innerHTML" hx-encoding="multipart/form-data">+ Subir código</button>
76+
</div>
77+
78+
<div class="mt-2" id="responseDiv">
79+
</div>
80+
</form>
7181
</div>
7282
</div>
7383
</div>

0 commit comments

Comments
 (0)