Skip to content
This repository has been archived by the owner on Jan 3, 2024. It is now read-only.

Commit

Permalink
Merge branch 'main' into documentation/sprint-reuniao
Browse files Browse the repository at this point in the history
  • Loading branch information
bitterteriyaki committed Nov 29, 2023
2 parents 93b380b + a5cd539 commit cfdced2
Show file tree
Hide file tree
Showing 33 changed files with 798 additions and 108 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ repos:
hooks:
- id: flake8
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.5.1
rev: v1.6.1
hooks:
- id: mypy
additional_dependencies:
Expand Down
2 changes: 2 additions & 0 deletions Procfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
release: python manage.py migrate
web: gunicorn server.wsgi
101 changes: 84 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,22 @@ Repositório contendo o código do projeto da disciplina de Métodos de
Desenvolvimento de Software. O projeto consiste em um juíz online para
programação competitiva.

## Membros

| Nome | Matrícula | GitHub |
|------------------|-----------|--------|
| Caio Alexandre | 221007644 | [@bitterteriyaki](https://github.com/bitterteriyaki) |
| João Farias | 221008187 | [@jpcfarias](https://github.com/jpcfarias) |
| Gabriel Moura | 221008060 | [@thegm445](https://github.com/thegm445) |
| Luiza Maluf | 221008294 | [@LuizaMaluf](https://github.com/LuizaMaluf) |
| Letícia Hladczuk | 221039209 | [@HladczukLe](https://github.com/HladczukLe) |
| Gabriel Fernando | 222022162 | [@MMcLovin](https://github.com/MMcLovin) |

## Resumo

Um juiz online representa uma plataforma essencial em competições de programação, desempenhando o papel crucial de avaliar e classificar as soluções submetidas pelos participantes. Além de ser uma ferramenta valiosa para competições, também serve como um ambiente propício para a exploração e aprendizado de novas linguagens de programação. Nessa plataforma, os participantes enfrentam desafios por meio de questões específicas, e ao submeterem seus códigos, essas submissões são sujeitas a limites rigorosos de tempo e memória, adicionando uma dimensão adicional de desafio e eficiência à avaliação.

Um juiz online representa uma plataforma essencial em competições de
programação, desempenhando o papel crucial de avaliar e classificar as soluções
submetidas pelos participantes. Além de ser uma ferramenta valiosa para
competições, também serve como um ambiente propício para a exploração e
aprendizado de novas linguagens de programação. Nessa plataforma, os
participantes enfrentam desafios por meio de questões específicas, e ao
submeterem seus códigos, essas submissões são sujeitas a limites rigorosos de
tempo e memória, adicionando uma dimensão adicional de desafio e eficiência à
avaliação.

## Motivação

Nossa motivação é desenvolver um juiz online que adira estritamente aos princípios do Software Livre.
Nossa motivação é desenvolver um juiz online que adira estritamente aos
princípios do software livre.

## Instalação

Expand Down Expand Up @@ -60,14 +57,16 @@ $ poetry run ./bin/create-env
Por fim, rode o projeto com o Docker:

```bash
$ docker compose up # para rodar em segundo plano, adicione ' -d '
$ docker compose up
# Ou para rodar em segundo plano:
$ docker compose up -d
```

Para rodar as migrações do banco de dados, você precisará criar um container
temporário que executará as migrações. Faça isso com o seguinte comando:

```bash
$ docker compose run --rm web python manage.py migrate
$ docker compose run --rm django python manage.py migrate
```

Para fechar o servidor do Django, use o seguinte comando:
Expand All @@ -76,7 +75,8 @@ Para fechar o servidor do Django, use o seguinte comando:
$ docker compose down
# Caso você queira remover os volumes do Docker, use:
$ docker compose down -v
# Isto removerá os volumes do Docker, o que significa que os dados do banco de dados serão perdidos.
# Isto removerá os volumes do Docker, o que significa que os dados do banco de
# dados serão perdidos.
```

Em caso de problemas com a instalação, verifique a
Expand All @@ -85,3 +85,70 @@ Em caso de problemas com a instalação, verifique a
## Links

- [Documentação](https://mds.kyomi.dev/pt/latest/)

## Membros

<table>
<tr>
<td align="center">
<a href="https://github.com/bitterteriyaki">
<img style="border-radius: 50%;" src="https://github.com/bitterteriyaki.png?size=100" width="100px;" />
<br />
<sub>
<b>Caio Alexandre</b>
</sub>
</a>
<br />
</td>
<td align="center">
<a href="https://github.com/jpcfarias">
<img style="border-radius: 50%;" src="https://github.com/jpcfarias.png?size=100" width="100px;" />
<br />
<sub>
<b>João Farias</b>
</sub>
</a>
<br />
</td>
<td align="center">
<a href="https://github.com/thegm445">
<img style="border-radius: 50%;" src="https://github.com/thegm445.png?size=100" width="100px;" />
<br />
<sub>
<b>Gabriel Moura</b>
</sub>
</a>
<br />
</td>
<td align="center">
<a href="https://github.com/LuizaMaluf">
<img style="border-radius: 50%;" src="https://github.com/LuizaMaluf.png?size=100" width="100px;" />
<br />
<sub>
<b>Luiza Maluf</b>
</sub>
</a>
<br />
</td>
<td align="center">
<a href="https://github.com/HladczukLe">
<img style="border-radius: 50%;" src="https://github.com/HladczukLe.png?size=100" width="100px;" />
<br />
<sub>
<b>Letícia Hladczuk</b>
</sub>
</a>
<br />
</td>
<td align="center">
<a href="https://github.com/MMcLovin">
<img style="border-radius: 50%;" src="https://github.com/MMcLovin.png?size=100" width="100px;" />
<br />
<sub>
<b>Gabriel Fernando</b>
</sub>
</a>
<br />
</td>
</tr>
</table>
16 changes: 16 additions & 0 deletions app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"repository": "https://github.com/unb-mds/2023-2-Squad06",
"addons": ["heroku-postgresql:mini", "papertrail:choklad"],
"buildpacks": [
{
"url": "https://github.com/moneymeets/python-poetry-buildpack.git"
},
{
"url": "heroku/python"
}
],
"env": {
"PYTHON_RUNTIME_VERSION": "3.11.5",
"POETRY_VERSION": "1.6.1"
}
}
34 changes: 34 additions & 0 deletions apps/submissions/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from typing import TYPE_CHECKING

from django.contrib.admin import ModelAdmin, register
from django.forms import CharField, ModelForm, Textarea
from django.utils.translation import gettext_lazy as _

from apps.submissions.models import Submission

if TYPE_CHECKING:
SubmissionAdminBase = ModelAdmin[Submission]
SubmissionModelFormBase = ModelForm[Submission]
else:
SubmissionAdminBase = ModelAdmin
SubmissionModelFormBase = ModelForm


class SubmissionModelForm(SubmissionModelFormBase):
code = CharField(widget=Textarea(attrs={"rows": 20, "cols": 80}))

class Meta:
model = Submission
fields = "__all__"


@register(Submission)
class SubmissionAdmin(SubmissionAdminBase):
form = SubmissionModelForm

list_display = ("__str__", "author", "task")
list_filter = ("author", "task", "created_at")

fieldsets = [
(_("Details"), {"fields": ("author", "task", "code", "status")})
]
10 changes: 10 additions & 0 deletions apps/submissions/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from django.forms import CharField, Form, Textarea


class SubmissionForm(Form):
code = CharField(
label="Source Code",
required=True,
min_length=15,
widget=Textarea(attrs={"rows": 12, "style": "width: 100%;"}),
)
34 changes: 34 additions & 0 deletions apps/submissions/migrations/0003_submission_status.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Generated by Django 4.2.7 on 2023-11-26 22:26

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("submissions", "0002_alter_submission_code"),
]

operations = [
migrations.AddField(
model_name="submission",
name="status",
field=models.TextField(
choices=[
("WJ", "Waiting judge"),
("JG", "Judging"),
("AC", "Accepted"),
("WA", "Wrong answer"),
("RE", "Runtime error"),
("TLE", "Time limit exceeded"),
("MLE", "Memory limit exceeded"),
("CE", "Compilation error"),
("IE", "Internal error"),
("UE", "Unknown error"),
("SE", "Submission error"),
("PE", "Presentation error"),
],
default="WJ",
max_length=3,
),
),
]
25 changes: 24 additions & 1 deletion apps/submissions/models.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,29 @@
from django.core.validators import MinLengthValidator
from django.db.models import CASCADE, ForeignKey, TextField
from django.db.models import CASCADE, ForeignKey, TextChoices, TextField
from django.utils.translation import gettext_lazy as _

from apps.tasks.models import Task
from apps.users.models import User
from core.models import TimestampedModel


class SubmissionStatus(TextChoices):
"""Represents the status of a submission."""

WAITING_JUDGE = ("WJ", _("Waiting judge"))
JUDGING = ("JG", _("Judging"))
ACCEPTED = ("AC", _("Accepted"))
WRONG_ANSWER = ("WA", _("Wrong answer"))
RUNTIME_ERROR = ("RE", _("Runtime error"))
TIME_LIMIT_EXCEEDED = ("TLE", _("Time limit exceeded"))
MEMORY_LIMIT_EXCEEDED = ("MLE", _("Memory limit exceeded"))
COMPILATION_ERROR = ("CE", _("Compilation error"))
INTERNAL_ERROR = ("IE", _("Internal error"))
UNKNOWN_ERROR = ("UE", _("Unknown error"))
SUBMISSION_ERROR = ("SE", _("Submission error"))
PRESENTATION_ERROR = ("PE", _("Presentation error"))


class Submission(TimestampedModel):
"""
Represents a submission to a task by an user. The code field is
Expand All @@ -16,6 +34,11 @@ class Submission(TimestampedModel):
author = ForeignKey(User, related_name="submissions", on_delete=CASCADE)
task = ForeignKey(Task, related_name="submissions", on_delete=CASCADE)
code = TextField(validators=[MinLengthValidator(15)])
status = TextField(
max_length=3,
choices=SubmissionStatus.choices,
default=SubmissionStatus.WAITING_JUDGE,
)

class Meta:
db_table = "submissions"
Expand Down
59 changes: 48 additions & 11 deletions apps/submissions/tests.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
from datetime import timedelta

from django.contrib.admin.sites import AdminSite
from django.core.exceptions import ValidationError
from django.test import TestCase
from django.utils import timezone
from django.utils.translation import gettext as _

from apps.contests.models import Contest
from apps.submissions.admin import SubmissionAdmin
from apps.submissions.models import Submission
from apps.tasks.models import Task
from apps.users.models import User
Expand All @@ -14,40 +17,54 @@ class SubmissionTestCase(TestCase):
def setUp(self) -> None:
self.user = User.objects.create_user(
username="user",
email="user@email.com",
email="user@example",
password="password",
)

self.contest = Contest._default_manager.create(
title="Test Contest",
description="This is a test contest",
start_time=timezone.now(),
end_time=timezone.now() + timedelta(hours=1),
cancelled=False,
)

self.task = Task._default_manager.create(
title="Test Task",
description="This is a test task",
contest=self.contest,
)
self.submission = Submission(

self.code = "print('hello world')"

def test_create_submission(self) -> None:
submission = Submission._default_manager.create(
author=self.user,
task=self.task,
code="print('hello world')",
code=self.code,
)

def test_submission_representation(self) -> None:
expected = f"#{self.submission.id}"
self.assertEqual(str(self.submission), expected)
self.assertEqual(submission.author, self.user)
self.assertEqual(submission.task, self.task)
self.assertEqual(submission.code, self.code)

def test_submission_has_author_relationship(self) -> None:
self.assertEqual(self.submission.author, self.user)
def test_submission_representation(self) -> None:
submission = Submission._default_manager.create(
author=self.user,
task=self.task,
code=self.code,
)

def test_submission_has_task_relationship(self) -> None:
self.assertEqual(self.submission.task, self.task)
expected = f"#{submission.id}"
self.assertEqual(str(submission), expected)

def test_submission_code_min_length_validator(self) -> None:
code = "a" * 14
submission = Submission(author=self.user, task=self.task, code=code)
submission = Submission(
author=self.user,
task=self.task,
code=code,
)

expected = [
"Ensure this value has at least 15 characters (it has 14)."
Expand All @@ -57,3 +74,23 @@ def test_submission_code_min_length_validator(self) -> None:
submission.full_clean()

self.assertEqual(context.exception.messages, expected)


class SubmissionAdminTest(TestCase):
def setUp(self) -> None:
self.site = AdminSite()
self.submission_admin = SubmissionAdmin(Submission, self.site)

def test_list_display(self) -> None:
expected = ("__str__", "author", "task")
self.assertEqual(self.submission_admin.list_display, expected)

def test_list_filter(self) -> None:
expected = ("author", "task", "created_at")
self.assertEqual(self.submission_admin.list_filter, expected)

def test_fieldsets(self) -> None:
expected = [
(_("Details"), {"fields": ("author", "task", "code", "status")})
]
self.assertEqual(self.submission_admin.fieldsets, expected)
Loading

0 comments on commit cfdced2

Please sign in to comment.