support share submission

This commit is contained in:
zema1 2017-10-15 18:36:55 +08:00
parent 080ecf1bcf
commit 2c5a1e42bf
6 changed files with 85 additions and 35 deletions

View File

@ -74,6 +74,10 @@ class UserProfile(models.Model):
# } # }
# }, # },
# "contest_problems": { # "contest_problems": {
# "1": {
# "status": JudgeStatus.ACCEPTED,
# "_id": "1000"
# }
# } # }
# } # }
acm_problems_status = JSONField(default=dict) acm_problems_status = JSONField(default=dict)

View File

@ -65,7 +65,7 @@ class Problem(models.Model):
total_score = models.IntegerField(default=0, blank=True) total_score = models.IntegerField(default=0, blank=True)
submission_number = models.BigIntegerField(default=0) submission_number = models.BigIntegerField(default=0)
accepted_number = models.BigIntegerField(default=0) accepted_number = models.BigIntegerField(default=0)
# ACM rule_type: {JudgeStatus.ACCEPTED: 3, JudgeStaus.WRONG_ANSWER: 11}, the number means count # {JudgeStatus.ACCEPTED: 3, JudgeStaus.WRONG_ANSWER: 11}, the number means count
statistic_info = JSONField(default=dict) statistic_info = JSONField(default=dict)
class Meta: class Meta:

View File

@ -13,6 +13,25 @@ class ProblemTagAPI(APIView):
class ProblemAPI(APIView): class ProblemAPI(APIView):
@staticmethod
def _add_problem_status(request, queryset_values):
if request.user.is_authenticated():
profile = request.user.userprofile
acm_problems_status = profile.acm_problems_status.get("problems", {})
oi_problems_status = profile.oi_problems_status.get("problems", {})
# paginate data
results = queryset_values.get("results")
if results:
problems = results
else:
problems = [queryset_values,]
for problem in problems:
if problem["rule_type"] == ProblemRuleType.ACM:
problem["my_status"] = acm_problems_status.get(str(problem["id"]), {}).get("status")
else:
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")
@ -20,7 +39,9 @@ class ProblemAPI(APIView):
try: try:
problem = Problem.objects.select_related("created_by")\ problem = Problem.objects.select_related("created_by")\
.get(_id=problem_id, contest_id__isnull=True, visible=True) .get(_id=problem_id, contest_id__isnull=True, visible=True)
return self.success(ProblemSerializer(problem).data) problem_data = ProblemSerializer(problem).data
self._add_problem_status(request, problem_data)
return self.success(problem_data)
except Problem.DoesNotExist: except Problem.DoesNotExist:
return self.error("Problem does not exist") return self.error("Problem does not exist")
@ -49,19 +70,21 @@ class ProblemAPI(APIView):
problems = problems.filter(difficulty=difficulty) problems = problems.filter(difficulty=difficulty)
# 根据profile 为做过的题目添加标记 # 根据profile 为做过的题目添加标记
data = self.paginate_data(request, problems, ProblemSerializer) data = self.paginate_data(request, problems, ProblemSerializer)
if request.user.id: self._add_problem_status(request, data)
profile = request.user.userprofile
acm_problems_status = profile.acm_problems_status.get("problems", {})
oi_problems_status = profile.oi_problems_status.get("problems", {})
for problem in data["results"]:
if problem["rule_type"] == ProblemRuleType.ACM:
problem["my_status"] = acm_problems_status.get(str(problem["id"]), {}).get("status")
else:
problem["my_status"] = oi_problems_status.get(str(problem["id"]), {}).get("status")
return self.success(data) return self.success(data)
class ContestProblemAPI(APIView): class ContestProblemAPI(APIView):
def _add_problem_status(self, request, queryset_values):
if request.user.is_authenticated() and self.contest.rule_type != ContestRuleType.OI:
profile = request.user.userprofile
if self.contest.rule_type == ContestRuleType.ACM:
problems_status = profile.acm_problems_status.get("contest_problems", {})
else:
problems_status = profile.oi_problems_status.get("contest_problems", {})
for problem in queryset_values:
problem["my_status"] = problems_status.get(str(problem["id"]), {}).get("status")
@check_contest_permission @check_contest_permission
def get(self, request): def get(self, request):
problem_id = request.GET.get("problem_id") problem_id = request.GET.get("problem_id")
@ -72,17 +95,12 @@ class ContestProblemAPI(APIView):
visible=True) visible=True)
except Problem.DoesNotExist: except Problem.DoesNotExist:
return self.error("Problem does not exist.") return self.error("Problem does not exist.")
return self.success(ContestProblemSerializer(problem).data) problem_data = ContestProblemSerializer(problem).data
self._add_problem_status(request, 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)
# 根据profile 为做过的题目添加标记 # 根据profile 为做过的题目添加标记
data = ContestProblemSerializer(contest_problems, many=True).data data = ContestProblemSerializer(contest_problems, many=True).data
if request.user.is_authenticated() and self.contest.rule_type != ContestRuleType.OI: self._add_problem_status(request, data)
profile = request.user.userprofile
if self.contest.rule_type == ContestRuleType.ACM:
problems_status = profile.acm_problems_status.get("contest_problems", {})
else:
problems_status = profile.oi_problems_status.get("contest_problems", {})
for problem in data:
problem["my_status"] = problems_status.get(str(problem["id"]), None)
return self.success(data) return self.success(data)

View File

@ -30,7 +30,7 @@ class Submission(models.Model):
username = models.CharField(max_length=30) username = models.CharField(max_length=30)
code = models.TextField() code = models.TextField()
result = models.IntegerField(db_index=True, default=JudgeStatus.PENDING) result = models.IntegerField(db_index=True, default=JudgeStatus.PENDING)
# 判题结果的详细信息 # 从JudgeServer返回的判题详情
info = JSONField(default=dict) info = JSONField(default=dict)
language = models.CharField(max_length=20) language = models.CharField(max_length=20)
shared = models.BooleanField(default=False) shared = models.BooleanField(default=False)
@ -38,10 +38,12 @@ class Submission(models.Model):
# {time_cost: "", memory_cost: "", err_info: "", score: 0} # {time_cost: "", memory_cost: "", err_info: "", score: 0}
statistic_info = JSONField(default=dict) statistic_info = JSONField(default=dict)
def check_user_permission(self, user): def check_user_permission(self, user, check_share=True):
return self.user_id == user.id or \ return self.user_id == user.id or \
self.shared is True or \ (check_share and self.shared is True) or \
user.admin_type == AdminType.SUPER_ADMIN user.is_super_admin() or \
user.can_mgmt_all_problem() or \
self.problem.created_by_id == user.id
class Meta: class Meta:
db_table = "submission" db_table = "submission"

View File

@ -10,6 +10,11 @@ class CreateSubmissionSerializer(serializers.Serializer):
contest_id = serializers.IntegerField(required=False) contest_id = serializers.IntegerField(required=False)
class ShareSubmissionSerializer(serializers.Serializer):
id = serializers.CharField()
shared = serializers.BooleanField()
class SubmissionModelSerializer(serializers.ModelSerializer): class SubmissionModelSerializer(serializers.ModelSerializer):
info = serializers.JSONField() info = serializers.JSONField()
statistic_info = serializers.JSONField() statistic_info = serializers.JSONField()
@ -19,7 +24,7 @@ class SubmissionModelSerializer(serializers.ModelSerializer):
# 不显示submission info的serializer, 用于ACM rule_type # 不显示submission info的serializer, 用于ACM rule_type
class SubmissionSafeSerializer(serializers.ModelSerializer): class SubmissionSafeModelSerializer(serializers.ModelSerializer):
problem = serializers.SlugRelatedField(read_only=True, slug_field="_id") problem = serializers.SlugRelatedField(read_only=True, slug_field="_id")
statistic_info = serializers.JSONField() statistic_info = serializers.JSONField()
@ -43,6 +48,6 @@ class SubmissionListSerializer(serializers.ModelSerializer):
def get_show_link(self, obj): def get_show_link(self, obj):
# 没传user或为匿名user # 没传user或为匿名user
if self.user is None or self.user.id is None: if self.user is None or not self.user.is_authenticated():
return False return False
return obj.check_user_permission(self.user) return obj.check_user_permission(self.user)

View File

@ -7,8 +7,9 @@ from utils.api import APIView, validate_serializer
from utils.throttling import TokenBucket, BucketController from utils.throttling import TokenBucket, BucketController
from utils.cache import cache from utils.cache import cache
from ..models import Submission from ..models import Submission
from ..serializers import CreateSubmissionSerializer, SubmissionModelSerializer from ..serializers import (CreateSubmissionSerializer, SubmissionModelSerializer,
from ..serializers import SubmissionSafeSerializer, SubmissionListSerializer ShareSubmissionSerializer)
from ..serializers import SubmissionSafeModelSerializer, SubmissionListSerializer
def _submit(response, user, problem_id, language, code, contest_id): def _submit(response, user, problem_id, language, code, contest_id):
@ -63,17 +64,37 @@ class SubmissionAPI(APIView):
def get(self, request): def get(self, request):
submission_id = request.GET.get("id") submission_id = request.GET.get("id")
if not submission_id: if not submission_id:
return self.error("Parameter id doesn't exist.") return self.error("Parameter id doesn't exist")
try: try:
submission = Submission.objects.select_related("problem").get(id=submission_id) submission = Submission.objects.select_related("problem").get(id=submission_id)
except Submission.DoesNotExist: except Submission.DoesNotExist:
return self.error("Submission doesn't exist.") return self.error("Submission doesn't exist")
if not submission.check_user_permission(request.user): if not submission.check_user_permission(request.user):
return self.error("No permission for this submission.") return self.error("No permission for this submission")
if submission.problem.rule_type == ProblemRuleType.ACM: if submission.problem.rule_type == ProblemRuleType.ACM:
return self.success(SubmissionSafeSerializer(submission).data) submission_data = SubmissionSafeModelSerializer(submission).data
return self.success(SubmissionModelSerializer(submission).data) else:
submission_data = SubmissionModelSerializer(submission).data
# 是否有权限取消共享
submission_data["can_unshare"] = submission.check_user_permission(request.user, check_share=False)
return self.success(submission_data)
@validate_serializer(ShareSubmissionSerializer)
@login_required
def put(self, request):
try:
submission = Submission.objects.select_related("problem")\
.get(id=request.data["id"], contest__isnull=True)
except Submission.DoesNotExist:
return self.error("Submission doesn't exist")
if not submission.check_user_permission(request.user, check_share=False):
return self.error("No permission to share the submission")
if submission.contest and submission.contest.status == ContestStatus.CONTEST_UNDERWAY:
return self.error("Can not share submission during a contest going")
submission.shared = request.data["shared"]
submission.save(update_fields=["shared"])
return self.success()
class SubmissionListAPI(APIView): class SubmissionListAPI(APIView):
@ -83,7 +104,7 @@ class SubmissionListAPI(APIView):
if request.GET.get("contest_id"): if request.GET.get("contest_id"):
return self.error("Parameter error") return self.error("Parameter error")
submissions = Submission.objects.filter(contest_id__isnull=True) submissions = Submission.objects.filter(contest_id__isnull=True).select_related("problem__created_by")
problem_id = request.GET.get("problem_id") problem_id = request.GET.get("problem_id")
myself = request.GET.get("myself") myself = request.GET.get("myself")
result = request.GET.get("result") result = request.GET.get("result")
@ -112,7 +133,7 @@ class ContestSubmissionListAPI(APIView):
if contest.rule_type == ContestRuleType.OI and not contest.is_contest_admin(request.user): if contest.rule_type == ContestRuleType.OI and not contest.is_contest_admin(request.user):
return self.error("No permission for OI contest submissions") return self.error("No permission for OI contest submissions")
submissions = Submission.objects.filter(contest_id=contest.id) submissions = Submission.objects.filter(contest_id=contest.id).select_related("problem__created_by")
problem_id = request.GET.get("problem_id") problem_id = request.GET.get("problem_id")
myself = request.GET.get("myself") myself = request.GET.get("myself")
result = request.GET.get("result") result = request.GET.get("result")