add message and comment
This commit is contained in:
16
announcement/migrations/0007_delete_message.py
Normal file
16
announcement/migrations/0007_delete_message.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# Generated by Django 5.0.6 on 2024-06-29 15:38
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('announcement', '0006_message'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='Message',
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
from account.models import User
|
from account.models import User
|
||||||
from submission.models import Submission
|
|
||||||
from utils.models import RichTextField
|
from utils.models import RichTextField
|
||||||
|
|
||||||
|
|
||||||
@@ -19,15 +18,3 @@ class Announcement(models.Model):
|
|||||||
class Meta:
|
class Meta:
|
||||||
db_table = "announcement"
|
db_table = "announcement"
|
||||||
ordering = ("-top", "-create_time",)
|
ordering = ("-top", "-create_time",)
|
||||||
|
|
||||||
|
|
||||||
class Message(models.Model):
|
|
||||||
sender = models.ForeignKey(User, on_delete=models.CASCADE, related_name="sender")
|
|
||||||
recipient = models.ForeignKey(User, on_delete=models.CASCADE, related_name="recipient")
|
|
||||||
submission = models.ForeignKey(Submission, on_delete=models.CASCADE)
|
|
||||||
message = RichTextField()
|
|
||||||
create_time = models.DateTimeField(auto_now_add=True)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
db_table = "message"
|
|
||||||
ordering = ("-create_time",)
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
from submission.serializers import SubmissionSafeModelSerializer
|
|
||||||
from utils.api import serializers
|
from utils.api import serializers
|
||||||
from utils.api._serializers import UsernameSerializer
|
from utils.api._serializers import UsernameSerializer
|
||||||
|
|
||||||
from .models import Announcement, Message
|
from .models import Announcement
|
||||||
|
|
||||||
|
|
||||||
class CreateAnnouncementSerializer(serializers.Serializer):
|
class CreateAnnouncementSerializer(serializers.Serializer):
|
||||||
@@ -36,18 +35,3 @@ class EditAnnouncementSerializer(serializers.Serializer):
|
|||||||
content = serializers.CharField(max_length=1024 * 1024 * 8)
|
content = serializers.CharField(max_length=1024 * 1024 * 8)
|
||||||
visible = serializers.BooleanField()
|
visible = serializers.BooleanField()
|
||||||
top = serializers.BooleanField()
|
top = serializers.BooleanField()
|
||||||
|
|
||||||
|
|
||||||
class MessageSerializer(serializers.ModelSerializer):
|
|
||||||
sender = UsernameSerializer()
|
|
||||||
submission = SubmissionSafeModelSerializer()
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = Message
|
|
||||||
exclude = ["recipient"]
|
|
||||||
|
|
||||||
|
|
||||||
class CreateMessageSerializer(serializers.Serializer):
|
|
||||||
recipient = serializers.IntegerField()
|
|
||||||
submission = serializers.CharField()
|
|
||||||
message = serializers.CharField()
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
from django.urls import re_path as url
|
from django.urls import re_path as url
|
||||||
|
|
||||||
from ..views.oj import AnnouncementAPI, MessageAPI
|
from ..views.oj import AnnouncementAPI
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r"^announcement/?$", AnnouncementAPI.as_view(), name="announcement_api"),
|
url(r"^announcement/?$", AnnouncementAPI.as_view(), name="announcement_api"),
|
||||||
url(r"^message/?$", MessageAPI.as_view(), name="message_api"),
|
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,14 +1,8 @@
|
|||||||
from account.decorators import super_admin_required, login_required
|
|
||||||
from account.models import User
|
|
||||||
from submission.models import Submission
|
|
||||||
from utils.api import APIView
|
from utils.api import APIView
|
||||||
|
|
||||||
from announcement.models import Announcement, Message
|
from announcement.models import Announcement
|
||||||
from announcement.serializers import (AnnouncementSerializer,
|
from announcement.serializers import (AnnouncementSerializer,
|
||||||
AnnouncementListSerializer,
|
AnnouncementListSerializer)
|
||||||
CreateMessageSerializer,
|
|
||||||
MessageSerializer)
|
|
||||||
from utils.api.api import validate_serializer
|
|
||||||
|
|
||||||
|
|
||||||
class AnnouncementAPI(APIView):
|
class AnnouncementAPI(APIView):
|
||||||
@@ -23,30 +17,3 @@ class AnnouncementAPI(APIView):
|
|||||||
|
|
||||||
announcements = Announcement.objects.filter(visible=True)
|
announcements = Announcement.objects.filter(visible=True)
|
||||||
return self.success(self.paginate_data(request, announcements, AnnouncementListSerializer))
|
return self.success(self.paginate_data(request, announcements, AnnouncementListSerializer))
|
||||||
|
|
||||||
|
|
||||||
class MessageAPI(APIView):
|
|
||||||
@login_required
|
|
||||||
def get(self, request):
|
|
||||||
messages = Message.objects.select_related("recipient","sender", "submission").filter(recipient=request.user)
|
|
||||||
return self.success(self.paginate_data(request, messages, MessageSerializer))
|
|
||||||
|
|
||||||
@validate_serializer(CreateMessageSerializer)
|
|
||||||
@super_admin_required
|
|
||||||
def post(self, request):
|
|
||||||
data = request.data
|
|
||||||
if data["recipient"] == request.user.id:
|
|
||||||
return self.error("Can not send a message to youself")
|
|
||||||
try:
|
|
||||||
recipient = User.objects.get(id=data["recipient"], is_disabled=False)
|
|
||||||
except User.DoesNotExist:
|
|
||||||
return self.error("User does not exist")
|
|
||||||
try:
|
|
||||||
submission = Submission.objects.get(id=data["submission"])
|
|
||||||
except Submission.DoesNotExist:
|
|
||||||
return self.error("Submission does not exist")
|
|
||||||
Message.objects.create(submission=submission,
|
|
||||||
message=data["message"],
|
|
||||||
sender=request.user,
|
|
||||||
recipient=recipient)
|
|
||||||
return self.success()
|
|
||||||
|
|||||||
0
comment/__init__.py
Normal file
0
comment/__init__.py
Normal file
40
comment/migrations/0001_initial.py
Normal file
40
comment/migrations/0001_initial.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
# Generated by Django 5.0.6 on 2024-06-29 13:32
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('problem', '0015_alter_problem_io_mode_alter_problem_languages_and_more'),
|
||||||
|
('submission', '0013_alter_submission_info_and_more'),
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Comment',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('problem_solved', models.BooleanField()),
|
||||||
|
('language', models.CharField(blank=True, choices=[('Python', 'Python'), ('C', 'C'), ('C++', 'C++'), ('Java', 'Java')], max_length=10, null=True, verbose_name='解决这道题使用的语言')),
|
||||||
|
('description_rating', models.PositiveSmallIntegerField(default=5, verbose_name='题目描述的分数')),
|
||||||
|
('difficulty_rating', models.PositiveSmallIntegerField(default=5, verbose_name='题目难度的分数')),
|
||||||
|
('comprehensive_rating', models.PositiveSmallIntegerField(default=5, verbose_name='综合的分数')),
|
||||||
|
('content', models.TextField(blank=True, null=True)),
|
||||||
|
('visible', models.BooleanField(default=True)),
|
||||||
|
('create_time', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('problem', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='problem.problem')),
|
||||||
|
('submission', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='submission.submission')),
|
||||||
|
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'db_table': 'comment',
|
||||||
|
'ordering': ('create_time',),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
0
comment/migrations/__init__.py
Normal file
0
comment/migrations/__init__.py
Normal file
47
comment/models.py
Normal file
47
comment/models.py
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
from django.db import models
|
||||||
|
|
||||||
|
from account.models import User
|
||||||
|
from problem.models import Problem
|
||||||
|
from submission.models import Submission
|
||||||
|
|
||||||
|
|
||||||
|
class Languages(models.TextChoices):
|
||||||
|
Python = "Python", "Python"
|
||||||
|
C = "C", "C"
|
||||||
|
Cpp = "C++", "C++"
|
||||||
|
Java = "Java", "Java"
|
||||||
|
|
||||||
|
|
||||||
|
class Comment(models.Model):
|
||||||
|
problem = models.ForeignKey(Problem, on_delete=models.CASCADE)
|
||||||
|
user = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||||
|
submission = models.ForeignKey(Submission, null=True, blank=True, on_delete=models.SET_NULL)
|
||||||
|
problem_solved = models.BooleanField()
|
||||||
|
language = models.CharField(
|
||||||
|
max_length=10,
|
||||||
|
choices=Languages.choices,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
verbose_name="解决这道题使用的语言",
|
||||||
|
)
|
||||||
|
description_rating = models.PositiveSmallIntegerField(
|
||||||
|
default=5,
|
||||||
|
verbose_name="题目描述的分数",
|
||||||
|
)
|
||||||
|
difficulty_rating = models.PositiveSmallIntegerField(
|
||||||
|
default=5,
|
||||||
|
verbose_name="题目难度的分数",
|
||||||
|
)
|
||||||
|
comprehensive_rating = models.PositiveSmallIntegerField(
|
||||||
|
default=5,
|
||||||
|
verbose_name="综合的分数",
|
||||||
|
)
|
||||||
|
content = models.TextField(null=True, blank=True)
|
||||||
|
visible = models.BooleanField(default=True)
|
||||||
|
create_time = models.DateTimeField(auto_now_add=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_table = "comment"
|
||||||
|
ordering = ("create_time",)
|
||||||
|
|
||||||
|
|
||||||
19
comment/serializers.py
Normal file
19
comment/serializers.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
from comment.models import Comment
|
||||||
|
from utils.api import serializers
|
||||||
|
|
||||||
|
|
||||||
|
class CreateCommentSerializer(serializers.Serializer):
|
||||||
|
problem_id = serializers.IntegerField()
|
||||||
|
submission_id = serializers.CharField(max_length=32, allow_null=True)
|
||||||
|
problem_solved = serializers.BooleanField()
|
||||||
|
language = serializers.CharField(max_length=10, allow_null=True)
|
||||||
|
description_rating = serializers.IntegerField()
|
||||||
|
difficulty_rating = serializers.IntegerField()
|
||||||
|
comprehensive_rating = serializers.IntegerField()
|
||||||
|
content = serializers.CharField()
|
||||||
|
|
||||||
|
|
||||||
|
class CommentSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Comment
|
||||||
|
fields = "__all__"
|
||||||
0
comment/urls/__init__.py
Normal file
0
comment/urls/__init__.py
Normal file
8
comment/urls/oj.py
Normal file
8
comment/urls/oj.py
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
from django.urls import re_path as url
|
||||||
|
|
||||||
|
from ..views.oj import CommentAPI
|
||||||
|
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
url(r"^comment/?$", CommentAPI.as_view(), name="comment_api"),
|
||||||
|
]
|
||||||
0
comment/views/__init__.py
Normal file
0
comment/views/__init__.py
Normal file
64
comment/views/oj.py
Normal file
64
comment/views/oj.py
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
from django.db.models import Avg
|
||||||
|
from comment.models import Comment
|
||||||
|
from problem.models import Problem
|
||||||
|
from utils.api import APIView
|
||||||
|
from account.decorators import login_required
|
||||||
|
from utils.api.api import validate_serializer
|
||||||
|
from comment.serializers import CreateCommentSerializer
|
||||||
|
from submission.models import Submission, JudgeStatus
|
||||||
|
|
||||||
|
|
||||||
|
class CommentAPI(APIView):
|
||||||
|
@validate_serializer(CreateCommentSerializer)
|
||||||
|
@login_required
|
||||||
|
def post(self, request):
|
||||||
|
data = request.data
|
||||||
|
try:
|
||||||
|
problem = Problem.objects.get(id=data.problem_id, visible=True)
|
||||||
|
except Problem.DoesNotExist:
|
||||||
|
self.error("problem is not exists")
|
||||||
|
|
||||||
|
submission = None
|
||||||
|
if data.problem_solved and data.submission_id:
|
||||||
|
try:
|
||||||
|
data.submission_id
|
||||||
|
submission = Submission.objects.select_related("problem").get(
|
||||||
|
id=data.submission_id,
|
||||||
|
problem_id=data.problem_id,
|
||||||
|
result=JudgeStatus.ACCEPTED,
|
||||||
|
)
|
||||||
|
except Submission.DoesNotExist:
|
||||||
|
self.error("submission is not exists or not accepted")
|
||||||
|
|
||||||
|
if not data.problem_solved:
|
||||||
|
data.language = None
|
||||||
|
|
||||||
|
Comment.objects.create(
|
||||||
|
user=request.user,
|
||||||
|
problem=problem,
|
||||||
|
submission=submission,
|
||||||
|
problem_solved=data.problem_solved,
|
||||||
|
language=data.language,
|
||||||
|
description_rating=data.description_rating,
|
||||||
|
difficulty_rating=data.difficulty_rating,
|
||||||
|
comprehensive_rating=data.comprehensive_rating,
|
||||||
|
content=data.content,
|
||||||
|
)
|
||||||
|
return self.success()
|
||||||
|
|
||||||
|
def get(self, request):
|
||||||
|
problem_id = request.GET.get("problem_id")
|
||||||
|
comments = Comment.objects.select_related("problem").filter(
|
||||||
|
problem_id=problem_id, visible=True
|
||||||
|
)
|
||||||
|
if comments.count() == 0:
|
||||||
|
return self.success()
|
||||||
|
rating = comments.aggregate(
|
||||||
|
description=Avg("description_rating"),
|
||||||
|
difficulty=Avg("difficulty_rating"),
|
||||||
|
comprehensive=Avg("comprehensive_rating"),
|
||||||
|
)
|
||||||
|
contents = comments.filter(content__isnull=False).values_list(
|
||||||
|
"content", flat=True
|
||||||
|
)
|
||||||
|
return self.success({rating: rating, contents: contents})
|
||||||
0
message/__init__.py
Normal file
0
message/__init__.py
Normal file
34
message/migrations/0001_initial.py
Normal file
34
message/migrations/0001_initial.py
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# Generated by Django 5.0.6 on 2024-06-29 15:38
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
import utils.models
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('submission', '0013_alter_submission_info_and_more'),
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Message',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('message', utils.models.RichTextField()),
|
||||||
|
('create_time', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('recipient', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='recipient', to=settings.AUTH_USER_MODEL)),
|
||||||
|
('sender', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sender', to=settings.AUTH_USER_MODEL)),
|
||||||
|
('submission', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='submission.submission')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'db_table': 'message',
|
||||||
|
'ordering': ('-create_time',),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
0
message/migrations/__init__.py
Normal file
0
message/migrations/__init__.py
Normal file
18
message/models.py
Normal file
18
message/models.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
from django.db import models
|
||||||
|
from account.models import User
|
||||||
|
from submission.models import Submission
|
||||||
|
from utils.models import RichTextField
|
||||||
|
|
||||||
|
|
||||||
|
class Message(models.Model):
|
||||||
|
sender = models.ForeignKey(User, on_delete=models.CASCADE, related_name="sender")
|
||||||
|
recipient = models.ForeignKey(
|
||||||
|
User, on_delete=models.CASCADE, related_name="recipient"
|
||||||
|
)
|
||||||
|
submission = models.ForeignKey(Submission, on_delete=models.CASCADE)
|
||||||
|
message = RichTextField()
|
||||||
|
create_time = models.DateTimeField(auto_now_add=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_table = "message"
|
||||||
|
ordering = ("-create_time",)
|
||||||
19
message/serializers.py
Normal file
19
message/serializers.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
from submission.serializers import SubmissionSafeModelSerializer
|
||||||
|
from utils.api import UsernameSerializer, serializers
|
||||||
|
from .models import Message
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class MessageSerializer(serializers.ModelSerializer):
|
||||||
|
sender = UsernameSerializer()
|
||||||
|
submission = SubmissionSafeModelSerializer()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Message
|
||||||
|
exclude = ["recipient"]
|
||||||
|
|
||||||
|
|
||||||
|
class CreateMessageSerializer(serializers.Serializer):
|
||||||
|
recipient = serializers.IntegerField()
|
||||||
|
submission = serializers.CharField()
|
||||||
|
message = serializers.CharField()
|
||||||
0
message/urls/__init__.py
Normal file
0
message/urls/__init__.py
Normal file
7
message/urls/oj.py
Normal file
7
message/urls/oj.py
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
from django.urls import re_path as url
|
||||||
|
|
||||||
|
from ..views.oj import MessageAPI
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
url(r"^message/?$", MessageAPI.as_view(), name="message_api"),
|
||||||
|
]
|
||||||
0
message/views/__init__.py
Normal file
0
message/views/__init__.py
Normal file
40
message/views/oj.py
Normal file
40
message/views/oj.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
from account.decorators import super_admin_required, login_required
|
||||||
|
from account.models import User
|
||||||
|
from message.serializers import CreateMessageSerializer, MessageSerializer
|
||||||
|
from submission.models import Submission
|
||||||
|
from utils.api import APIView
|
||||||
|
|
||||||
|
from message.models import Message
|
||||||
|
|
||||||
|
from utils.api.api import validate_serializer
|
||||||
|
|
||||||
|
|
||||||
|
class MessageAPI(APIView):
|
||||||
|
@login_required
|
||||||
|
def get(self, request):
|
||||||
|
messages = Message.objects.select_related(
|
||||||
|
"recipient", "sender", "submission"
|
||||||
|
).filter(recipient=request.user)
|
||||||
|
return self.success(self.paginate_data(request, messages, MessageSerializer))
|
||||||
|
|
||||||
|
@validate_serializer(CreateMessageSerializer)
|
||||||
|
@super_admin_required
|
||||||
|
def post(self, request):
|
||||||
|
data = request.data
|
||||||
|
if data["recipient"] == request.user.id:
|
||||||
|
return self.error("Can not send a message to youself")
|
||||||
|
try:
|
||||||
|
recipient = User.objects.get(id=data["recipient"], is_disabled=False)
|
||||||
|
except User.DoesNotExist:
|
||||||
|
return self.error("User does not exist")
|
||||||
|
try:
|
||||||
|
submission = Submission.objects.get(id=data["submission"])
|
||||||
|
except Submission.DoesNotExist:
|
||||||
|
return self.error("Submission does not exist")
|
||||||
|
Message.objects.create(
|
||||||
|
submission=submission,
|
||||||
|
message=data["message"],
|
||||||
|
sender=request.user,
|
||||||
|
recipient=recipient,
|
||||||
|
)
|
||||||
|
return self.success()
|
||||||
@@ -51,6 +51,8 @@ LOCAL_APPS = [
|
|||||||
'submission',
|
'submission',
|
||||||
'options',
|
'options',
|
||||||
'judge',
|
'judge',
|
||||||
|
'message',
|
||||||
|
'comment'
|
||||||
]
|
]
|
||||||
|
|
||||||
INSTALLED_APPS = VENDOR_APPS + LOCAL_APPS
|
INSTALLED_APPS = VENDOR_APPS + LOCAL_APPS
|
||||||
|
|||||||
@@ -14,4 +14,6 @@ urlpatterns = [
|
|||||||
url(r"^api/", include("submission.urls.oj")),
|
url(r"^api/", include("submission.urls.oj")),
|
||||||
url(r"^api/admin/", include("submission.urls.admin")),
|
url(r"^api/admin/", include("submission.urls.admin")),
|
||||||
url(r"^api/admin/", include("utils.urls")),
|
url(r"^api/admin/", include("utils.urls")),
|
||||||
|
url(r"^api/", include("message.urls.oj")),
|
||||||
|
url(r"^api/", include("comment.urls.oj")),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -31,7 +31,11 @@ class ProblemIOMode(Choices):
|
|||||||
|
|
||||||
|
|
||||||
def _default_io_mode():
|
def _default_io_mode():
|
||||||
return {"io_mode": ProblemIOMode.standard, "input": "input.txt", "output": "output.txt"}
|
return {
|
||||||
|
"io_mode": ProblemIOMode.standard,
|
||||||
|
"input": "input.txt",
|
||||||
|
"output": "output.txt",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class Problem(models.Model):
|
class Problem(models.Model):
|
||||||
|
|||||||
@@ -3,8 +3,14 @@ from django.db.models import Q, Count
|
|||||||
from utils.api import APIView
|
from utils.api import APIView
|
||||||
from account.decorators import check_contest_permission
|
from account.decorators import check_contest_permission
|
||||||
from ..models import ProblemTag, Problem, ProblemRuleType
|
from ..models import ProblemTag, Problem, ProblemRuleType
|
||||||
from ..serializers import ProblemSerializer, TagSerializer, ProblemSafeSerializer, ProblemListSerializer
|
from ..serializers import (
|
||||||
|
ProblemSerializer,
|
||||||
|
TagSerializer,
|
||||||
|
ProblemSafeSerializer,
|
||||||
|
ProblemListSerializer,
|
||||||
|
)
|
||||||
from contest.models import ContestRuleType
|
from contest.models import ContestRuleType
|
||||||
|
from submission.models import JudgeStatus
|
||||||
|
|
||||||
|
|
||||||
class ProblemTagAPI(APIView):
|
class ProblemTagAPI(APIView):
|
||||||
@@ -38,20 +44,27 @@ class ProblemAPI(APIView):
|
|||||||
if results is not None:
|
if results is not None:
|
||||||
problems = results
|
problems = results
|
||||||
else:
|
else:
|
||||||
problems = [queryset_values, ]
|
problems = [
|
||||||
|
queryset_values,
|
||||||
|
]
|
||||||
for problem in problems:
|
for problem in problems:
|
||||||
if problem["rule_type"] == ProblemRuleType.ACM:
|
if problem["rule_type"] == ProblemRuleType.ACM:
|
||||||
problem["my_status"] = acm_problems_status.get(str(problem["id"]), {}).get("status")
|
problem["my_status"] = acm_problems_status.get(
|
||||||
|
str(problem["id"]), {}
|
||||||
|
).get("status")
|
||||||
else:
|
else:
|
||||||
problem["my_status"] = oi_problems_status.get(str(problem["id"]), {}).get("status")
|
problem["my_status"] = oi_problems_status.get(
|
||||||
|
str(problem["id"]), {}
|
||||||
|
).get("status")
|
||||||
|
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
# 问题详情页
|
# 问题详情页
|
||||||
problem_id = request.GET.get("problem_id")
|
problem_id = request.GET.get("problem_id")
|
||||||
if problem_id:
|
if problem_id:
|
||||||
try:
|
try:
|
||||||
problem = Problem.objects.select_related("created_by") \
|
problem = Problem.objects.select_related("created_by").get(
|
||||||
.get(_id=problem_id, contest_id__isnull=True, visible=True)
|
_id=problem_id, contest_id__isnull=True, visible=True
|
||||||
|
)
|
||||||
problem_data = ProblemSerializer(problem).data
|
problem_data = ProblemSerializer(problem).data
|
||||||
self._add_problem_status(request, problem_data)
|
self._add_problem_status(request, problem_data)
|
||||||
return self.success(problem_data)
|
return self.success(problem_data)
|
||||||
@@ -62,7 +75,11 @@ class ProblemAPI(APIView):
|
|||||||
if not limit:
|
if not limit:
|
||||||
return self.error("Limit is needed")
|
return self.error("Limit is needed")
|
||||||
|
|
||||||
problems = Problem.objects.select_related("created_by").filter(contest_id__isnull=True, visible=True).order_by("-create_time")
|
problems = (
|
||||||
|
Problem.objects.select_related("created_by")
|
||||||
|
.filter(contest_id__isnull=True, visible=True)
|
||||||
|
.order_by("-create_time")
|
||||||
|
)
|
||||||
# 按照标签筛选
|
# 按照标签筛选
|
||||||
tag_text = request.GET.get("tag")
|
tag_text = request.GET.get("tag")
|
||||||
if tag_text:
|
if tag_text:
|
||||||
@@ -71,7 +88,9 @@ class ProblemAPI(APIView):
|
|||||||
# 搜索的情况
|
# 搜索的情况
|
||||||
keyword = request.GET.get("keyword", "").strip()
|
keyword = request.GET.get("keyword", "").strip()
|
||||||
if keyword:
|
if keyword:
|
||||||
problems = problems.filter(Q(title__icontains=keyword) | Q(_id__icontains=keyword))
|
problems = problems.filter(
|
||||||
|
Q(title__icontains=keyword) | Q(_id__icontains=keyword)
|
||||||
|
)
|
||||||
|
|
||||||
# 难度筛选
|
# 难度筛选
|
||||||
difficulty = request.GET.get("difficulty")
|
difficulty = request.GET.get("difficulty")
|
||||||
@@ -88,30 +107,41 @@ class ContestProblemAPI(APIView):
|
|||||||
if request.user.is_authenticated:
|
if request.user.is_authenticated:
|
||||||
profile = request.user.userprofile
|
profile = request.user.userprofile
|
||||||
if self.contest.rule_type == ContestRuleType.ACM:
|
if self.contest.rule_type == ContestRuleType.ACM:
|
||||||
problems_status = profile.acm_problems_status.get("contest_problems", {})
|
problems_status = profile.acm_problems_status.get(
|
||||||
|
"contest_problems", {}
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
problems_status = profile.oi_problems_status.get("contest_problems", {})
|
problems_status = profile.oi_problems_status.get("contest_problems", {})
|
||||||
for problem in queryset_values:
|
for problem in queryset_values:
|
||||||
problem["my_status"] = problems_status.get(str(problem["id"]), {}).get("status")
|
problem["my_status"] = problems_status.get(str(problem["id"]), {}).get(
|
||||||
|
"status"
|
||||||
|
)
|
||||||
|
|
||||||
@check_contest_permission(check_type="problems")
|
@check_contest_permission(check_type="problems")
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
problem_id = request.GET.get("problem_id")
|
problem_id = request.GET.get("problem_id")
|
||||||
if problem_id:
|
if problem_id:
|
||||||
try:
|
try:
|
||||||
problem = Problem.objects.select_related("created_by").get(_id=problem_id,
|
problem = Problem.objects.select_related("created_by").get(
|
||||||
contest=self.contest,
|
_id=problem_id, contest=self.contest, visible=True
|
||||||
visible=True)
|
)
|
||||||
except Problem.DoesNotExist:
|
except Problem.DoesNotExist:
|
||||||
return self.error("Problem does not exist.")
|
return self.error("Problem does not exist.")
|
||||||
if self.contest.problem_details_permission(request.user):
|
if self.contest.problem_details_permission(request.user):
|
||||||
problem_data = ProblemSerializer(problem).data
|
problem_data = ProblemSerializer(problem).data
|
||||||
self._add_problem_status(request, [problem_data, ])
|
self._add_problem_status(
|
||||||
|
request,
|
||||||
|
[
|
||||||
|
problem_data,
|
||||||
|
],
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
problem_data = ProblemSafeSerializer(problem).data
|
problem_data = ProblemSafeSerializer(problem).data
|
||||||
return self.success(problem_data)
|
return self.success(problem_data)
|
||||||
|
|
||||||
contest_problems = Problem.objects.select_related("created_by").filter(contest=self.contest, visible=True)
|
contest_problems = Problem.objects.select_related("created_by").filter(
|
||||||
|
contest=self.contest, visible=True
|
||||||
|
)
|
||||||
if self.contest.problem_details_permission(request.user):
|
if self.contest.problem_details_permission(request.user):
|
||||||
data = ProblemListSerializer(contest_problems, many=True).data
|
data = ProblemListSerializer(contest_problems, many=True).data
|
||||||
self._add_problem_status(request, data)
|
self._add_problem_status(request, data)
|
||||||
|
|||||||
Reference in New Issue
Block a user