Skip to content

Commit

Permalink
Redesign Bookmark (#112)
Browse files Browse the repository at this point in the history
  • Loading branch information
anhkha2003 authored May 29, 2024
1 parent 829e6a8 commit c6acfa5
Show file tree
Hide file tree
Showing 13 changed files with 396 additions and 241 deletions.
4 changes: 4 additions & 0 deletions judge/models/problem.py
Original file line number Diff line number Diff line change
Expand Up @@ -704,6 +704,10 @@ def get_absolute_url(self):
else:
return reverse("problem_editorial", args=[problem.code])

@cache_wrapper(prefix="Sga", expected_type=models.query.QuerySet)
def get_authors(self):
return self.authors.only("id")

def __str__(self):
return _("Editorial for %s") % self.problem.name

Expand Down
15 changes: 7 additions & 8 deletions judge/signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
Profile,
Submission,
NavigationBar,
Solution,
)


Expand Down Expand Up @@ -120,14 +121,7 @@ def comment_update(sender, instance, **kwargs):

@receiver(post_save, sender=BlogPost)
def post_update(sender, instance, **kwargs):
cache.delete_many(
[
make_template_fragment_key("post_summary", (instance.id,)),
"blog_slug:%d" % instance.id,
"blog_feed:%d" % instance.id,
]
+ [make_template_fragment_key("post_content", (instance.id,))]
)
cache.delete(make_template_fragment_key("post_content", (instance.id,)))
BlogPost.get_authors.dirty(instance)


Expand Down Expand Up @@ -175,3 +169,8 @@ def contest_submission_update(sender, instance, **kwargs):
@receiver(post_save, sender=NavigationBar)
def navbar_update(sender, instance, **kwargs):
judge.template_context._nav_bar.dirty()


@receiver(post_save, sender=Solution)
def solution_update(sender, instance, **kwargs):
cache.delete(make_template_fragment_key("solution_content", (instance.id,)))
11 changes: 11 additions & 0 deletions judge/views/problem.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
Q,
When,
IntegerField,
Sum,
)
from django.db.models.functions import Coalesce
from django.db.utils import ProgrammingError
Expand Down Expand Up @@ -644,6 +645,16 @@ def get_normal_queryset(self):
queryset = queryset.filter(points__gte=self.point_start)
if self.point_end is not None:
queryset = queryset.filter(points__lte=self.point_end)

queryset = queryset.annotate(
has_public_editorial=Sum(
Case(
When(solution__is_public=True, then=1),
default=0,
output_field=IntegerField(),
)
)
)
return queryset.distinct()

def get_queryset(self):
Expand Down
59 changes: 52 additions & 7 deletions judge/views/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,17 @@
from reversion import revisions

from judge.forms import UserForm, ProfileForm, ProfileInfoForm
from judge.models import Profile, Rating, Submission, Friend, ProfileInfo
from judge.models import (
Profile,
Rating,
Submission,
Friend,
ProfileInfo,
BlogPost,
Problem,
Contest,
Solution,
)
from judge.performance_points import get_pp_breakdown
from judge.ratings import rating_class, rating_progress
from judge.tasks import import_users
Expand All @@ -54,10 +64,13 @@
TitleMixin,
generic_message,
SingleObjectFormView,
DiggPaginatorMixin,
)
from judge.utils.infinite_paginator import InfinitePaginationMixin
from judge.views.problem import ProblemList
from .contests import ContestRanking


__all__ = [
"UserPage",
"UserAboutPage",
Expand Down Expand Up @@ -305,17 +318,49 @@ def process_group(group, problems_iter):
return context


class UserBookMarkPage(UserPage):
class UserBookMarkPage(DiggPaginatorMixin, ListView, UserPage):
template_name = "user/user-bookmarks.html"
context_object_name = "bookmarks"
paginate_by = 10

def get(self, request, *args, **kwargs):
self.current_tab = self.request.GET.get("tab", "problems")
self.user = self.object = self.get_object()
return super(UserBookMarkPage, self).get(request, *args, **kwargs)

def get_queryset(self):
model = None
if self.current_tab == "posts":
model = BlogPost
elif self.current_tab == "contests":
model = Contest
elif self.current_tab == "editorials":
model = Solution
else:
model = Problem

q = MakeBookMark.objects.filter(user=self.user).select_related("bookmark")
q = q.filter(bookmark__content_type=ContentType.objects.get_for_model(model))
object_ids = q.values_list("bookmark__object_id", flat=True)

res = model.objects.filter(id__in=object_ids)
if self.current_tab == "contests":
res = res.prefetch_related("organizations", "tags")
elif self.current_tab == "editorials":
res = res.select_related("problem")

return res

def get_context_data(self, **kwargs):
context = super(UserBookMarkPage, self).get_context_data(**kwargs)

bookmark_list = MakeBookMark.objects.filter(user=self.object)
context["blogs"] = bookmark_list.filter(bookmark__page__startswith="b")
context["problems"] = bookmark_list.filter(bookmark__page__startswith="p")
context["contests"] = bookmark_list.filter(bookmark__page__startswith="c")
context["solutions"] = bookmark_list.filter(bookmark__page__startswith="s")
context["current_tab"] = self.current_tab
context["user"] = self.user

context["page_prefix"] = (
self.request.path + "?tab=" + self.current_tab + "&page="
)
context["first_page_href"] = self.request.path

return context

Expand Down
28 changes: 28 additions & 0 deletions resources/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,33 @@ function register_copy_clipboard($elements, callback) {
});
}

function activateBlogBoxOnClick() {
$('.blog-box').on('click', function () {
var $description = $(this).children('.blog-description');
var max_height = $description.css('max-height');
if (max_height !== 'fit-content') {
$description.css('max-height', 'fit-content');
$(this).css('cursor', 'auto');
$(this).removeClass('pre-expand-blog');
$(this).children().children('.show-more').hide();
}
});

$('.blog-box').each(function () {
var $precontent = $(this).children('.blog-description').height();
var $content = $(this).children().children('.content-description').height();
if ($content == undefined) {
$content = $(this).children().children('.md-typeset').height()
}
if ($content > $precontent - 30) {
$(this).addClass('pre-expand-blog');
$(this).css('cursor', 'pointer');
} else {
$(this).children().children('.show-more').hide();
}
});
}

function onWindowReady() {
// http://stackoverflow.com/a/1060034/1090657
var hidden = 'hidden';
Expand Down Expand Up @@ -464,6 +491,7 @@ function onWindowReady() {
errorList.nextAll('input, select, textarea').first().after(errorList);
});
register_all_toggles();
activateBlogBoxOnClick();
}

$(function() {
Expand Down
4 changes: 2 additions & 2 deletions templates/blog/content.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ <h2 class="title">
</h2>
<div class="blog-description">
<div class="summary content-description">
{% cache 86400 'post_summary' post.id %}
{{ post.summary|default(post.content, true)|markdown(lazy_load=True)|reference|str|safe }}
{% cache 86400 'post_content' post.id %}
{{ post.content|markdown(lazy_load=True)|reference|str|safe }}
{% endcache %}
</div>
<div class="show-more"> {{_("...More")}} </div>
Expand Down
115 changes: 5 additions & 110 deletions templates/contest/list.html
Original file line number Diff line number Diff line change
Expand Up @@ -134,112 +134,7 @@
</div>
{% endblock %}

{% macro contest_head(contest) %}
<a href="{{ url('contest_view', contest.key) }}" class="contest-list-title" style="margin-right: 5px;">
{{contest.name}}
</a>
<div class="contest-tags">
{% if not contest.is_visible %}
<span class="contest-tag contest-tag-hidden">
<i class="fa fa-eye-slash"></i> {{ _('hidden') }}
</span>
{% endif %}
{% if contest.is_editable %}
<span class="contest-tag contest-tag-edit">
<a href="{{ url('organization_contest_edit', organization.id, organization.slug, contest.key) }}" class="white">
<i class="fa fa-edit"></i> {{ _('Edit') }}
</a>
</span>
{% endif %}
{% if contest.is_private %}
<span class="contest-tag contest-tag-private">
<i class="fa fa-lock"></i> {{ _('private') }}
</span>
{% endif %}
{% if not hide_contest_orgs %}
{% if contest.is_organization_private %}
{% for org in contest.organizations.all() %}
{% include "organization/tag.html" %}
{% endfor %}
{% endif %}
{% endif %}
{% if contest.is_rated %}
<span class="contest-tag contest-tag-rated">
<i class="fa fa-bar-chart"></i> {{ _('rated') }}
</span>
{% endif %}
{% for tag in contest.tags.all() %}
<span style="background-color: {{ tag.color }}" class="contest-tag">
<a href="{{ url('contest_tag', tag.name) }}"
style="color: {{ tag.text_color }}"
data-featherlight="{{ url('contest_tag_ajax', tag.name) }}">
{{- tag.name -}}
</a>
</span>
{% endfor %}
</div>
{% endmacro %}

{% macro time_left(contest) %}
<div class="time-left">
{% if contest.time_limit %}
<div>
<b>{{_("Start")}}</b>: {{ contest.start_time|date(_("H:i d/m/Y")) }}
</div>
<div>
<b>{{_("End")}}</b>: {{ contest.end_time|date(_("H:i d/m/Y")) }}
</div>
{% else %}
<div>
<b>{{_("Start")}}</b>: {{ contest.start_time|date(_("H:i d/m/Y")) }}
</div>
{% endif %}
<div>
<b>{{_("Length")}}</b>:
{% if contest.time_limit %}
{% trans time_limit=contest.time_limit|timedelta('localized-no-seconds') %}{{ time_limit }}{% endtrans %}
{% else %}
{% trans duration=contest.contest_window_length|timedelta('localized-no-seconds') %}{{ duration }}{% endtrans %}
{% endif %}
</div>
</div>
{% endmacro %}

{% macro user_count(contest, user) %}
{% if contest.can_see_own_scoreboard(user) %}
<a href="{{ url('contest_ranking', contest.key) }}"><i class="fa fa-users"></i> {{ contest.user_count }}</a>
{% else %}
<i class="fa fa-users"></i>{{ contest.user_count }}
{% endif %}
{% endmacro %}

{% macro contest_join(contest, request) %}
{% if request.in_contest and request.participation.contest == contest %}
<button class="small" disabled>{{ _('In contest') }}</button>
{% elif request.profile.id in contest.editor_ids or request.profile.id in contest.tester_ids %}
<form action="{{ url('contest_join', contest.key) }}" method="post">
{% csrf_token %}
<input type="submit" class="unselectable button full small"
value="{{ _('Spectate') }}">
</form>
{% else %}
<form action="{{ url('contest_join', contest.key) }}" method="post">
{% csrf_token %}
<input type="submit" class="unselectable button full small join-warning"
value="{{ _('Join') }}">
</form>
{% endif %}
{% endmacro %}

{% macro contest_format_user(contest, show_user=True) %}
<div style="display: flex; flex-direction: column; height: 100%;">
<div class="contest-title"> {{ _('Format') }} </div>
<div style="flex-grow: 1">{{ contest.format.name }}</div>
{% if show_user %}
<div class="contest-title">{{ user_count(contest, request.user) }}</div>
{% endif %}
</div>
{% endmacro %}
{% from "contest/macros.html" import contest_head, time_left, user_count, contest_join, contest_format_user %}

{% block middle_content %}
<div class="tabs tabs-no-flex" style="width: 100%;margin-left: auto;margin-right: auto;">
Expand Down Expand Up @@ -298,7 +193,7 @@
</div>
</div>
<div class="info-contest" style="flex: 0.5;">
{{ contest_format_user(contest) }}
{{ contest_format_user(contest, request) }}
</div>
<div class="participate-button">
{{ contest_join(contest, request) }}
Expand Down Expand Up @@ -336,7 +231,7 @@
</div>
</div>
<div class="info-contest" style="flex: 0.5;">
{{ contest_format_user(contest) }}
{{ contest_format_user(contest, request) }}
</div>
<div class="participate-button">
{{ contest_join(contest, request) }}
Expand Down Expand Up @@ -373,7 +268,7 @@
</div>
</div>
<div class="info-contest" style="flex: 0.5;">
{{ contest_format_user(contest, show_user=False) }}
{{ contest_format_user(contest, request, show_user=False) }}
</div>
</div>
{% endfor %}
Expand Down Expand Up @@ -402,7 +297,7 @@
</div>
</div>
<div class="info-contest" style="flex: 0.5;">
{{ contest_format_user(contest) }}
{{ contest_format_user(contest, request) }}
</div>
<div class="participate-button">
{% if request.in_contest and request.participation.contest == contest %}
Expand Down
Loading

0 comments on commit c6acfa5

Please sign in to comment.