Add problem volunteer
This commit is contained in:
parent
e51129d36f
commit
e70618ed19
15 changed files with 396 additions and 5 deletions
|
@ -11,9 +11,11 @@ from judge.admin.runtime import JudgeAdmin, LanguageAdmin
|
|||
from judge.admin.submission import SubmissionAdmin
|
||||
from judge.admin.taxon import ProblemGroupAdmin, ProblemTypeAdmin
|
||||
from judge.admin.ticket import TicketAdmin
|
||||
from judge.admin.volunteer import VolunteerProblemVoteAdmin
|
||||
from judge.models import BlogPost, Comment, CommentLock, Contest, ContestParticipation, \
|
||||
ContestTag, Judge, Language, License, MiscConfig, NavigationBar, Organization, \
|
||||
OrganizationRequest, Problem, ProblemGroup, ProblemPointsVote, ProblemType, Profile, Submission, Ticket
|
||||
OrganizationRequest, Problem, ProblemGroup, ProblemPointsVote, ProblemType, Profile, Submission, Ticket, \
|
||||
VolunteerProblemVote
|
||||
|
||||
|
||||
admin.site.register(BlogPost, BlogPostAdmin)
|
||||
|
@ -37,3 +39,4 @@ admin.site.register(ProblemType, ProblemTypeAdmin)
|
|||
admin.site.register(Profile, ProfileAdmin)
|
||||
admin.site.register(Submission, SubmissionAdmin)
|
||||
admin.site.register(Ticket, TicketAdmin)
|
||||
admin.site.register(VolunteerProblemVote, VolunteerProblemVoteAdmin)
|
18
judge/admin/volunteer.py
Normal file
18
judge/admin/volunteer.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
from django.contrib import admin
|
||||
from django.utils.html import format_html
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext, gettext_lazy as _, ungettext
|
||||
|
||||
from judge.models import VolunteerProblemVote
|
||||
|
||||
class VolunteerProblemVoteAdmin(admin.ModelAdmin):
|
||||
fields = ('voter', 'problem', 'time', 'thinking_points', 'knowledge_points', 'feedback')
|
||||
readonly_fields = ('time', 'problem', 'voter')
|
||||
list_display = ('voter', 'problem_link', 'time', 'thinking_points', 'knowledge_points', 'feedback')
|
||||
date_hierarchy = 'time'
|
||||
|
||||
def problem_link(self, obj):
|
||||
url = reverse('admin:judge_problem_change', args=(obj.problem.id,))
|
||||
return format_html(f"<a href='{url}'>{obj.problem.code}</a>")
|
||||
problem_link.short_description = _('Problem')
|
||||
problem_link.admin_order_field = 'problem__code'
|
36
judge/migrations/0123_auto_20220502_2356.py
Normal file
36
judge/migrations/0123_auto_20220502_2356.py
Normal file
|
@ -0,0 +1,36 @@
|
|||
# Generated by Django 2.2.25 on 2022-05-02 16:56
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('judge', '0122_auto_20220425_1202'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='problem',
|
||||
options={'permissions': (('see_private_problem', 'See hidden problems'), ('edit_own_problem', 'Edit own problems'), ('edit_all_problem', 'Edit all problems'), ('edit_public_problem', 'Edit all public problems'), ('clone_problem', 'Clone problem'), ('change_public_visibility', 'Change is_public field'), ('change_manually_managed', 'Change is_manually_managed field'), ('see_organization_problem', 'See organization-private problems'), ('suggest_problem_changes', 'Suggest changes to problem')), 'verbose_name': 'problem', 'verbose_name_plural': 'problems'},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='VolunteerProblemVote',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('time', models.DateTimeField(auto_now_add=True)),
|
||||
('knowledge_points', models.PositiveIntegerField(help_text='Points awarded by knowledge difficulty', verbose_name='knowledge points')),
|
||||
('thinking_points', models.PositiveIntegerField(help_text='Points awarded by thinking difficulty', verbose_name='thinking points')),
|
||||
('feedback', models.TextField(blank=True, verbose_name='feedback')),
|
||||
('problem', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='volunteer_user_votes', to='judge.Problem')),
|
||||
('types', models.ManyToManyField(help_text="The type of problem, as shown on the problem's page.", to='judge.ProblemType', verbose_name='problem types')),
|
||||
('voter', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='volunteer_problem_votes', to='judge.Profile')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'volunteer vote',
|
||||
'verbose_name_plural': 'volunteer votes',
|
||||
'unique_together': {('voter', 'problem')},
|
||||
},
|
||||
),
|
||||
]
|
|
@ -14,6 +14,7 @@ from judge.models.profile import Organization, OrganizationRequest, Profile, Fri
|
|||
from judge.models.runtime import Judge, Language, RuntimeVersion
|
||||
from judge.models.submission import SUBMISSION_RESULT, Submission, SubmissionSource, SubmissionTestCase
|
||||
from judge.models.ticket import Ticket, TicketMessage
|
||||
from judge.models.volunteer import VolunteerProblemVote
|
||||
|
||||
revisions.register(Profile, exclude=['points', 'last_access', 'ip', 'rating'])
|
||||
revisions.register(Problem, follow=['language_limits'])
|
||||
|
|
|
@ -377,6 +377,7 @@ class Problem(models.Model):
|
|||
save.alters_data = True
|
||||
|
||||
def can_vote(self, request):
|
||||
return False
|
||||
user = request.user
|
||||
if not user.is_authenticated:
|
||||
return False
|
||||
|
|
28
judge/models/volunteer.py
Normal file
28
judge/models/volunteer.py
Normal file
|
@ -0,0 +1,28 @@
|
|||
from django.db import models
|
||||
from django.db.models import CASCADE
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from judge.models import Profile, Problem, ProblemType
|
||||
|
||||
__all__ = ['VolunteerProblemVote']
|
||||
|
||||
class VolunteerProblemVote(models.Model):
|
||||
voter = models.ForeignKey(Profile, related_name='volunteer_problem_votes', on_delete=CASCADE)
|
||||
problem = models.ForeignKey(Problem, related_name='volunteer_user_votes', on_delete=CASCADE)
|
||||
time = models.DateTimeField(auto_now_add=True)
|
||||
knowledge_points = models.PositiveIntegerField(verbose_name=_('knowledge points'),
|
||||
help_text=_('Points awarded by knowledge difficulty'))
|
||||
thinking_points = models.PositiveIntegerField(verbose_name=_('thinking points'),
|
||||
help_text=_('Points awarded by thinking difficulty'))
|
||||
types = models.ManyToManyField(ProblemType, verbose_name=_('problem types'),
|
||||
help_text=_('The type of problem, '
|
||||
"as shown on the problem's page."))
|
||||
feedback = models.TextField(verbose_name=_('feedback'), blank=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('volunteer vote')
|
||||
verbose_name_plural = _('volunteer votes')
|
||||
unique_together = ['voter', 'problem']
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.voter} for {self.problem.code}'
|
35
judge/views/internal.py
Normal file
35
judge/views/internal.py
Normal file
|
@ -0,0 +1,35 @@
|
|||
from django.views.generic import ListView
|
||||
from django.utils.translation import gettext as _, gettext_lazy
|
||||
from django.db.models import Count
|
||||
from django.http import HttpResponseForbidden
|
||||
|
||||
from judge.utils.diggpaginator import DiggPaginator
|
||||
from judge.models import VolunteerProblemVote, Problem
|
||||
|
||||
class InternalProblem(ListView):
|
||||
model = Problem
|
||||
title = _('Internal problems')
|
||||
template_name = 'internal/base.html'
|
||||
paginate_by = 100
|
||||
context_object_name = 'problems'
|
||||
|
||||
def get_paginator(self, queryset, per_page, orphans=0,
|
||||
allow_empty_first_page=True, **kwargs):
|
||||
return DiggPaginator(queryset, per_page, body=6, padding=2, orphans=orphans,
|
||||
allow_empty_first_page=allow_empty_first_page, **kwargs)
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = Problem.objects.annotate(vote_count=Count('volunteer_user_votes')) \
|
||||
.filter(vote_count__gte=1).order_by('-vote_count')
|
||||
return queryset
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(InternalProblem, self).get_context_data(**kwargs)
|
||||
context['page_type'] = 'problem'
|
||||
context['title'] = self.title
|
||||
return context
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
if request.user.is_superuser:
|
||||
return super(InternalProblem, self).get(request, *args, **kwargs)
|
||||
return HttpResponseForbidden()
|
|
@ -30,7 +30,7 @@ from judge.comments import CommentedDetailView
|
|||
from judge.forms import ProblemCloneForm, ProblemSubmitForm, ProblemPointsVoteForm
|
||||
from judge.models import ContestProblem, ContestSubmission, Judge, Language, Problem, ProblemClarification, \
|
||||
ProblemGroup, ProblemTranslation, ProblemType, ProblemPointsVote, RuntimeVersion, Solution, Submission, SubmissionSource, \
|
||||
TranslatedProblemForeignKeyQuerySet, Organization
|
||||
TranslatedProblemForeignKeyQuerySet, Organization , VolunteerProblemVote
|
||||
from judge.pdf_problems import DefaultPdfMaker, HAS_PDF
|
||||
from judge.utils.diggpaginator import DiggPaginator
|
||||
from judge.utils.opengraph import generate_opengraph
|
||||
|
@ -594,6 +594,7 @@ class ProblemList(QueryStringSortMixin, TitleMixin, SolvedProblemMixin, ListView
|
|||
|
||||
cf_logger = logging.getLogger('judge.ml.collab_filter')
|
||||
|
||||
|
||||
class ProblemFeed(ProblemList):
|
||||
model = Problem
|
||||
context_object_name = 'problems'
|
||||
|
@ -640,6 +641,9 @@ class ProblemFeed(ProblemList):
|
|||
|
||||
if self.feed_type == 'new':
|
||||
return queryset.order_by('-date')
|
||||
elif user and self.feed_type == 'volunteer':
|
||||
voted_problems = user.volunteer_problem_votes.values_list('problem', flat=True)
|
||||
return queryset.exclude(id__in=voted_problems).order_by('?')
|
||||
if not settings.ML_OUTPUT_PATH or not user:
|
||||
return queryset.order_by('?')
|
||||
|
||||
|
|
33
judge/views/volunteer.py
Normal file
33
judge/views/volunteer.py
Normal file
|
@ -0,0 +1,33 @@
|
|||
from django.http import HttpResponseBadRequest, JsonResponse
|
||||
from django.db import transaction
|
||||
|
||||
from judge.models import VolunteerProblemVote, Problem, ProblemType
|
||||
|
||||
|
||||
def vote_problem(request):
|
||||
if not request.user or not request.user.has_perm('judge.suggest_problem_changes'):
|
||||
return HttpResponseBadRequest()
|
||||
if not request.method == 'POST':
|
||||
return HttpResponseBadRequest()
|
||||
try:
|
||||
types_id = request.POST.getlist('types[]')
|
||||
types = ProblemType.objects.filter(id__in=types_id)
|
||||
problem = Problem.objects.get(code=request.POST['problem'])
|
||||
knowledge_points = request.POST['knowledge_points']
|
||||
thinking_points = request.POST['thinking_points']
|
||||
feedback = request.POST['feedback']
|
||||
except Exception as e:
|
||||
return HttpResponseBadRequest()
|
||||
|
||||
with transaction.atomic():
|
||||
vote, _ = VolunteerProblemVote.objects.get_or_create(
|
||||
voter=request.profile,
|
||||
problem=problem,
|
||||
defaults={'knowledge_points': 0, 'thinking_points': 0},
|
||||
)
|
||||
vote.knowledge_points = knowledge_points
|
||||
vote.thinking_points = thinking_points
|
||||
vote.feedback = feedback
|
||||
vote.types.set(types)
|
||||
vote.save()
|
||||
return JsonResponse({})
|
Loading…
Add table
Add a link
Reference in a new issue