New home UI

This commit is contained in:
cuom1999 2022-03-21 16:09:16 -05:00
parent e8ee2ac4aa
commit d10173df5d
14 changed files with 478 additions and 222 deletions

View file

@ -65,7 +65,9 @@ class Comment(MPTTModel):
problem_access = CacheDict(lambda code: Problem.objects.get(code=code).is_accessible_by(user))
contest_access = CacheDict(lambda key: Contest.objects.get(key=key).is_accessible_by(user))
blog_access = CacheDict(lambda id: BlogPost.objects.get(id=id).can_see(user))
if n == -1:
n = len(queryset)
if user.is_superuser:
return queryset[:n]
if batch is None:
@ -105,7 +107,7 @@ class Comment(MPTTModel):
try:
link = None
if self.page.startswith('p:'):
link = reverse('problem_comments', args=(self.page[2:],))
link = reverse('problem_detail', args=(self.page[2:],))
elif self.page.startswith('c:'):
link = reverse('contest_view', args=(self.page[2:],))
elif self.page.startswith('b:'):

View file

@ -17,10 +17,8 @@ from judge.utils.tickets import filter_visible_tickets
from judge.utils.views import TitleMixin
class PostList(ListView):
model = BlogPost
paginate_by = 10
context_object_name = 'posts'
# General view for all content list on home feed
class FeedView(ListView):
template_name = 'blog/list.html'
title = None
@ -29,6 +27,56 @@ class PostList(ListView):
return DiggPaginator(queryset, per_page, body=6, padding=2,
orphans=orphans, allow_empty_first_page=allow_empty_first_page, **kwargs)
def get_context_data(self, **kwargs):
context = super(FeedView, self).get_context_data(**kwargs)
context['has_clarifications'] = False
if self.request.user.is_authenticated:
participation = self.request.profile.current_contest
if participation:
clarifications = ProblemClarification.objects.filter(problem__in=participation.contest.problems.all())
context['has_clarifications'] = clarifications.count() > 0
context['clarifications'] = clarifications.order_by('-date')
if participation.contest.is_editable_by(self.request.user):
context['can_edit_contest'] = True
context['page_titles'] = CacheDict(lambda page: Comment.get_page_title(page))
context['user_count'] = lazy(Profile.objects.count, int, int)
context['problem_count'] = lazy(Problem.objects.filter(is_public=True).count, int, int)
context['submission_count'] = lazy(Submission.objects.count, int, int)
context['language_count'] = lazy(Language.objects.count, int, int)
now = timezone.now()
# Dashboard stuff
# if self.request.user.is_authenticated:
# user = self.request.profile
# context['recently_attempted_problems'] = (Submission.objects.filter(user=user)
# .exclude(problem__in=user_completed_ids(user))
# .values_list('problem__code', 'problem__name', 'problem__points')
# .annotate(points=Max('points'), latest=Max('date'))
# .order_by('-latest')
# [:settings.DMOJ_BLOG_RECENTLY_ATTEMPTED_PROBLEMS_COUNT])
visible_contests = Contest.get_visible_contests(self.request.user).filter(is_visible=True) \
.order_by('start_time')
context['current_contests'] = visible_contests.filter(start_time__lte=now, end_time__gt=now)
context['future_contests'] = visible_contests.filter(start_time__gt=now)
visible_contests = Contest.get_visible_contests(self.request.user).filter(is_visible=True)
context['top_rated'] = Profile.objects.order_by('-rating')[:10]
context['top_scorer'] = Profile.objects.order_by('-performance_points')[:10]
return context
class PostList(FeedView):
model = BlogPost
paginate_by = 10
context_object_name = 'posts'
def get_queryset(self):
queryset = BlogPost.objects.filter(visible=True, publish_on__lte=timezone.now()) \
.order_by('-sticky', '-publish_on') \
@ -45,25 +93,7 @@ class PostList(ListView):
context['title'] = self.title or _('Page %d of Posts') % context['page_obj'].number
context['first_page_href'] = reverse('home')
context['page_prefix'] = reverse('blog_post_list')
context['comments'] = Comment.most_recent(self.request.user, 25)
context['new_problems'] = Problem.objects.filter(is_public=True, is_organization_private=False) \
.order_by('-date', '-id')[:settings.DMOJ_BLOG_NEW_PROBLEM_COUNT]
context['page_titles'] = CacheDict(lambda page: Comment.get_page_title(page))
context['has_clarifications'] = False
if self.request.user.is_authenticated:
participation = self.request.profile.current_contest
if participation:
clarifications = ProblemClarification.objects.filter(problem__in=participation.contest.problems.all())
context['has_clarifications'] = clarifications.count() > 0
context['clarifications'] = clarifications.order_by('-date')
if participation.contest.is_editable_by(self.request.user):
context['can_edit_contest'] = True
context['user_count'] = lazy(Profile.objects.count, int, int)
context['problem_count'] = lazy(Problem.objects.filter(is_public=True).count, int, int)
context['submission_count'] = lazy(Submission.objects.count, int, int)
context['language_count'] = lazy(Language.objects.count, int, int)
context['feed_type'] = 'blog'
context['post_comment_counts'] = {
int(page[2:]): count for page, count in
Comment.objects
@ -71,40 +101,55 @@ class PostList(ListView):
.values_list('page').annotate(count=Count('page')).order_by()
}
now = timezone.now()
return context
# Dashboard stuff
if self.request.user.is_authenticated:
user = self.request.profile
context['recently_attempted_problems'] = (Submission.objects.filter(user=user)
.exclude(problem__in=user_completed_ids(user))
.values_list('problem__code', 'problem__name', 'problem__points')
.annotate(points=Max('points'), latest=Max('date'))
.order_by('-latest')
[:settings.DMOJ_BLOG_RECENTLY_ATTEMPTED_PROBLEMS_COUNT])
visible_contests = Contest.get_visible_contests(self.request.user).filter(is_visible=True) \
.order_by('start_time')
context['current_contests'] = visible_contests.filter(start_time__lte=now, end_time__gt=now)
context['future_contests'] = visible_contests.filter(start_time__gt=now)
class TicketFeed(FeedView):
model = Ticket
context_object_name = 'tickets'
paginate_by = 30
visible_contests = Contest.get_visible_contests(self.request.user).filter(is_visible=True)
if self.request.user.is_authenticated:
profile = self.request.profile
context['own_open_tickets'] = (Ticket.objects.filter(Q(user=profile) | Q(assignees__in=[profile]), is_open=True).order_by('-id')
.prefetch_related('linked_item').select_related('user__user'))
def get_queryset(self, is_own=False):
profile = self.request.profile
if is_own:
if self.request.user.is_authenticated:
return (Ticket.objects.filter(Q(user=profile) | Q(assignees__in=[profile]), is_open=True).order_by('-id')
.prefetch_related('linked_item').select_related('user__user'))
else:
return []
else:
profile = None
context['own_open_tickets'] = []
# Superusers better be staffs, not the spell-casting kind either.
if self.request.user.is_staff:
tickets = (Ticket.objects.order_by('-id').filter(is_open=True).prefetch_related('linked_item')
.select_related('user__user'))
return filter_visible_tickets(tickets, self.request.user, profile)
else:
return []
# Superusers better be staffs, not the spell-casting kind either.
if self.request.user.is_staff:
tickets = (Ticket.objects.order_by('-id').filter(is_open=True).prefetch_related('linked_item')
.select_related('user__user'))
context['open_tickets'] = filter_visible_tickets(tickets, self.request.user, profile)[:10]
else:
context['open_tickets'] = []
def get_context_data(self, **kwargs):
context = super(TicketFeed, self).get_context_data(**kwargs)
context['feed_type'] = 'ticket'
context['first_page_href'] = self.request.path
context['page_prefix'] = '?page='
context['title'] = _('Ticket feed')
return context
class CommentFeed(FeedView):
model = Comment
context_object_name = 'comments'
paginate_by = 50
def get_queryset(self):
return Comment.most_recent(self.request.user, 1000)
def get_context_data(self, **kwargs):
context = super(CommentFeed, self).get_context_data(**kwargs)
context['feed_type'] = 'comment'
context['first_page_href'] = self.request.path
context['page_prefix'] = '?page='
context['title'] = _('Comment feed')
return context

View file

@ -21,7 +21,7 @@ from django.utils.functional import cached_property
from django.utils.html import escape, format_html
from django.utils.safestring import mark_safe
from django.utils.translation import gettext as _, gettext_lazy
from django.views.generic import DetailView, ListView, View
from django.views.generic import ListView, View
from django.views.generic.base import TemplateResponseMixin
from django.views.generic.detail import SingleObjectMixin
@ -38,6 +38,7 @@ from judge.utils.problems import contest_attempted_ids, contest_completed_ids, h
from judge.utils.strings import safe_float_or_none, safe_int_or_none
from judge.utils.tickets import own_ticket_filter
from judge.utils.views import QueryStringSortMixin, SingleObjectFormView, TitleMixin, generic_message
from judge.views.blog import FeedView
def get_contest_problem(problem, profile):
@ -155,10 +156,13 @@ class ProblemRaw(ProblemMixin, TitleMixin, TemplateResponseMixin, SingleObjectMi
))
class ProblemDetail(ProblemMixin, SolvedProblemMixin, DetailView):
class ProblemDetail(ProblemMixin, SolvedProblemMixin, CommentedDetailView):
context_object_name = 'problem'
template_name = 'problem/problem.html'
def get_comment_page(self):
return 'p:%s' % self.object.code
def get_context_data(self, **kwargs):
context = super(ProblemDetail, self).get_context_data(**kwargs)
user = self.request.user
@ -235,6 +239,7 @@ class ProblemDetail(ProblemMixin, SolvedProblemMixin, DetailView):
context['min_possible_vote'] = 100
return context
class DeleteVote(ProblemMixin, SingleObjectMixin, View):
def get(self, request, *args, **kwargs):
return HttpResponseForbidden(status=405, content_type='text/plain')
@ -273,21 +278,6 @@ class Vote(ProblemMixin, SingleObjectMixin, View):
return JsonResponse(form.errors, status=400)
class ProblemComments(ProblemMixin, TitleMixin, CommentedDetailView):
context_object_name = 'problem'
template_name = 'problem/comments.html'
def get_title(self):
return _('Disscuss {0}').format(self.object.name)
def get_content_title(self):
return format_html(_(u'Discuss <a href="{1}">{0}</a>'), self.object.name,
reverse('problem_detail', args=[self.object.code]))
def get_comment_page(self):
return 'p:%s' % self.object.code
class LatexError(Exception):
pass
@ -592,6 +582,49 @@ class ProblemList(QueryStringSortMixin, TitleMixin, SolvedProblemMixin, ListView
return HttpResponseRedirect(request.get_full_path())
class ProblemFeed(FeedView):
model = Problem
context_object_name = 'problems'
paginate_by = 50
title = _('Problem feed')
@cached_property
def profile(self):
if not self.request.user.is_authenticated:
return None
return self.request.profile
def get_unsolved_queryset(self):
filter = Q(is_public=True)
if self.profile is not None:
filter |= Q(authors=self.profile)
filter |= Q(curators=self.profile)
filter |= Q(testers=self.profile)
queryset = Problem.objects.filter(filter).select_related('group').defer('description')
if not self.request.user.has_perm('see_organization_problem'):
filter = Q(is_organization_private=False)
if self.profile is not None:
filter |= Q(organizations__in=self.profile.organizations.all())
queryset = queryset.filter(filter)
if self.profile is not None:
queryset = queryset.exclude(id__in=Submission.objects.filter(user=self.profile, points=F('problem__points'))
.values_list('problem__id', flat=True))
return queryset.distinct()
def get_queryset(self):
queryset = self.get_unsolved_queryset()
return queryset.order_by('?')
def get_context_data(self, **kwargs):
context = super(ProblemFeed, self).get_context_data(**kwargs)
context['first_page_href'] = self.request.path
context['page_prefix'] = '?page='
context['feed_type'] = 'problem'
context['title'] = self.title
return context
class LanguageTemplateAjax(View):
def get(self, request, *args, **kwargs):
try: