commit
bba7a761ac
18 changed files with 354 additions and 23 deletions
|
@ -60,6 +60,7 @@ from judge.views import (
|
||||||
user,
|
user,
|
||||||
volunteer,
|
volunteer,
|
||||||
pagevote,
|
pagevote,
|
||||||
|
bookmark,
|
||||||
widgets,
|
widgets,
|
||||||
internal,
|
internal,
|
||||||
)
|
)
|
||||||
|
@ -403,6 +404,7 @@ urlpatterns = [
|
||||||
),
|
),
|
||||||
url(r"^user$", user.UserAboutPage.as_view(), name="user_page"),
|
url(r"^user$", user.UserAboutPage.as_view(), name="user_page"),
|
||||||
url(r"^edit/profile/$", user.edit_profile, name="user_edit_profile"),
|
url(r"^edit/profile/$", user.edit_profile, name="user_edit_profile"),
|
||||||
|
url(r"^user/bookmarks", user.UserBookMarkPage.as_view(), name="user_bookmark"),
|
||||||
url(
|
url(
|
||||||
r"^user/(?P<user>\w+)",
|
r"^user/(?P<user>\w+)",
|
||||||
include(
|
include(
|
||||||
|
@ -448,6 +450,8 @@ urlpatterns = [
|
||||||
),
|
),
|
||||||
url(r"^pagevotes/upvote/$", pagevote.upvote_page, name="pagevote_upvote"),
|
url(r"^pagevotes/upvote/$", pagevote.upvote_page, name="pagevote_upvote"),
|
||||||
url(r"^pagevotes/downvote/$", pagevote.downvote_page, name="pagevote_downvote"),
|
url(r"^pagevotes/downvote/$", pagevote.downvote_page, name="pagevote_downvote"),
|
||||||
|
url(r"^bookmarks/dobookmark/$", bookmark.dobookmark_page, name="dobookmark"),
|
||||||
|
url(r"^bookmarks/undobookmark/$", bookmark.undobookmark_page, name="undobookmark"),
|
||||||
url(r"^comments/upvote/$", comment.upvote_comment, name="comment_upvote"),
|
url(r"^comments/upvote/$", comment.upvote_comment, name="comment_upvote"),
|
||||||
url(r"^comments/downvote/$", comment.downvote_comment, name="comment_downvote"),
|
url(r"^comments/downvote/$", comment.downvote_comment, name="comment_downvote"),
|
||||||
url(r"^comments/hide/$", comment.comment_hide, name="comment_hide"),
|
url(r"^comments/hide/$", comment.comment_hide, name="comment_hide"),
|
||||||
|
|
38
judge/migrations/0138_bookmark_makebookmark.py
Normal file
38
judge/migrations/0138_bookmark_makebookmark.py
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
# Generated by Django 3.2.16 on 2022-11-17 17:13
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('judge', '0137_auto_20221116_2201'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='BookMark',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('page', models.CharField(db_index=True, max_length=30, verbose_name='associated page')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'bookmark',
|
||||||
|
'verbose_name_plural': 'bookmarks',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='MakeBookMark',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('bookmark', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='bookmark', to='judge.bookmark')),
|
||||||
|
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='user_bookmark', to='judge.profile')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'make bookmark',
|
||||||
|
'verbose_name_plural': 'make bookmarks',
|
||||||
|
'unique_together': {('user', 'bookmark')},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
|
@ -55,6 +55,7 @@ from judge.models.submission import (
|
||||||
from judge.models.ticket import Ticket, TicketMessage
|
from judge.models.ticket import Ticket, TicketMessage
|
||||||
from judge.models.volunteer import VolunteerProblemVote
|
from judge.models.volunteer import VolunteerProblemVote
|
||||||
from judge.models.pagevote import PageVote, PageVoteVoter
|
from judge.models.pagevote import PageVote, PageVoteVoter
|
||||||
|
from judge.models.bookmark import BookMark, MakeBookMark
|
||||||
|
|
||||||
revisions.register(Profile, exclude=["points", "last_access", "ip", "rating"])
|
revisions.register(Profile, exclude=["points", "last_access", "ip", "rating"])
|
||||||
revisions.register(Problem, follow=["language_limits"])
|
revisions.register(Problem, follow=["language_limits"])
|
||||||
|
@ -79,4 +80,5 @@ revisions.register(ContestParticipation)
|
||||||
revisions.register(Rating)
|
revisions.register(Rating)
|
||||||
revisions.register(PageVoteVoter)
|
revisions.register(PageVoteVoter)
|
||||||
revisions.register(VolunteerProblemVote)
|
revisions.register(VolunteerProblemVote)
|
||||||
|
revisions.register(MakeBookMark)
|
||||||
del revisions
|
del revisions
|
||||||
|
|
57
judge/models/bookmark.py
Normal file
57
judge/models/bookmark.py
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
from django.db import models
|
||||||
|
from django.db.models import CASCADE
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
|
|
||||||
|
from judge.models import Profile
|
||||||
|
from judge.models.contest import Contest
|
||||||
|
from judge.models.interface import BlogPost
|
||||||
|
from judge.models.problem import Problem, Solution
|
||||||
|
|
||||||
|
__all__ = ["BookMark"]
|
||||||
|
|
||||||
|
|
||||||
|
class BookMark(models.Model):
|
||||||
|
page = models.CharField(
|
||||||
|
max_length=30,
|
||||||
|
verbose_name=_("associated page"),
|
||||||
|
db_index=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_bookmark(self, user):
|
||||||
|
userqueryset = MakeBookMark.objects.filter(bookmark=self, user=user)
|
||||||
|
if userqueryset.exists():
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def page_object(self):
|
||||||
|
try:
|
||||||
|
page = self.page
|
||||||
|
if page.startswith("p:"):
|
||||||
|
return Problem.objects.get(code=page[2:])
|
||||||
|
elif page.startswith("c:"):
|
||||||
|
return Contest.objects.get(key=page[2:])
|
||||||
|
elif page.startswith("b:"):
|
||||||
|
return BlogPost.objects.get(id=page[2:])
|
||||||
|
elif page.startswith("s:"):
|
||||||
|
return Solution.objects.get(problem__code=page[2:])
|
||||||
|
return None
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
return None
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _("bookmark")
|
||||||
|
verbose_name_plural = _("bookmarks")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.page
|
||||||
|
|
||||||
|
class MakeBookMark(models.Model):
|
||||||
|
bookmark = models.ForeignKey(BookMark, related_name="bookmark", on_delete=CASCADE)
|
||||||
|
user = models.ForeignKey(Profile, related_name="user_bookmark", on_delete=CASCADE, db_index=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
unique_together = ["user", "bookmark"]
|
||||||
|
verbose_name = _("make bookmark")
|
||||||
|
verbose_name_plural = _("make bookmarks")
|
|
@ -8,6 +8,7 @@ from django.views.generic import ListView
|
||||||
|
|
||||||
from judge.comments import CommentedDetailView
|
from judge.comments import CommentedDetailView
|
||||||
from judge.views.pagevote import PageVoteDetailView, PageVoteListView
|
from judge.views.pagevote import PageVoteDetailView, PageVoteListView
|
||||||
|
from judge.views.bookmark import BookMarkDetailView, BookMarkListView
|
||||||
from judge.models import (
|
from judge.models import (
|
||||||
BlogPost,
|
BlogPost,
|
||||||
Comment,
|
Comment,
|
||||||
|
@ -93,7 +94,7 @@ class FeedView(ListView):
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class PostList(FeedView, PageVoteListView):
|
class PostList(FeedView, PageVoteListView, BookMarkListView):
|
||||||
model = BlogPost
|
model = BlogPost
|
||||||
paginate_by = 10
|
paginate_by = 10
|
||||||
context_object_name = "posts"
|
context_object_name = "posts"
|
||||||
|
@ -128,7 +129,7 @@ class PostList(FeedView, PageVoteListView):
|
||||||
.order_by()
|
.order_by()
|
||||||
}
|
}
|
||||||
context = self.add_pagevote_context_data(context)
|
context = self.add_pagevote_context_data(context)
|
||||||
|
context = self.add_bookmark_context_data(context)
|
||||||
return context
|
return context
|
||||||
|
|
||||||
def get_comment_page(self, post):
|
def get_comment_page(self, post):
|
||||||
|
@ -195,7 +196,7 @@ class CommentFeed(FeedView):
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class PostView(TitleMixin, CommentedDetailView, PageVoteDetailView):
|
class PostView(TitleMixin, CommentedDetailView, PageVoteDetailView, BookMarkDetailView):
|
||||||
model = BlogPost
|
model = BlogPost
|
||||||
pk_url_kwarg = "id"
|
pk_url_kwarg = "id"
|
||||||
context_object_name = "post"
|
context_object_name = "post"
|
||||||
|
|
82
judge/views/bookmark.py
Normal file
82
judge/views/bookmark.py
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
|
from django.db import IntegrityError
|
||||||
|
from django.db.models import F
|
||||||
|
from django.http import (
|
||||||
|
Http404,
|
||||||
|
HttpResponse,
|
||||||
|
HttpResponseBadRequest,
|
||||||
|
HttpResponseForbidden,
|
||||||
|
)
|
||||||
|
from django.utils.translation import gettext as _
|
||||||
|
from judge.models.bookmark import BookMark, MakeBookMark
|
||||||
|
from django.views.generic.base import TemplateResponseMixin
|
||||||
|
from django.views.generic.detail import SingleObjectMixin
|
||||||
|
|
||||||
|
from judge.dblock import LockModel
|
||||||
|
from django.views.generic import View, ListView
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"dobookmark_page",
|
||||||
|
"undobookmark_page",
|
||||||
|
"BookMarkDetailView",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def bookmark_page(request, delta):
|
||||||
|
if request.method != "POST":
|
||||||
|
return HttpResponseForbidden()
|
||||||
|
|
||||||
|
if "id" not in request.POST:
|
||||||
|
return HttpResponseBadRequest()
|
||||||
|
|
||||||
|
try:
|
||||||
|
bookmark_id = int(request.POST["id"])
|
||||||
|
bookmark_page = BookMark.objects.filter(id=bookmark_id)
|
||||||
|
except ValueError:
|
||||||
|
return HttpResponseBadRequest()
|
||||||
|
else:
|
||||||
|
if not bookmark_page.exists():
|
||||||
|
raise Http404()
|
||||||
|
|
||||||
|
if delta == 0:
|
||||||
|
bookmarklist = MakeBookMark.objects.filter(bookmark=bookmark_page.first(), user=request.profile)
|
||||||
|
if not bookmarklist.exists():
|
||||||
|
newbookmark = MakeBookMark(
|
||||||
|
bookmark=bookmark_page.first(),
|
||||||
|
user=request.profile,
|
||||||
|
)
|
||||||
|
newbookmark.save()
|
||||||
|
else:
|
||||||
|
bookmarklist = MakeBookMark.objects.filter(bookmark=bookmark_page.first(), user=request.profile)
|
||||||
|
if bookmarklist.exists():
|
||||||
|
bookmarklist.delete()
|
||||||
|
|
||||||
|
return HttpResponse("success", content_type="text/plain")
|
||||||
|
|
||||||
|
|
||||||
|
def dobookmark_page(request):
|
||||||
|
return bookmark_page(request, 0)
|
||||||
|
|
||||||
|
|
||||||
|
def undobookmark_page(request):
|
||||||
|
return bookmark_page(request, 1)
|
||||||
|
|
||||||
|
|
||||||
|
class BookMarkDetailView(TemplateResponseMixin, SingleObjectMixin, View):
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(BookMarkDetailView, self).get_context_data(**kwargs)
|
||||||
|
queryset = BookMark.objects.get_or_create(page=self.get_comment_page())
|
||||||
|
context["bookmark"] = queryset[0]
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class BookMarkListView(ListView):
|
||||||
|
def add_bookmark_context_data(self, context, obj_list="object_list"):
|
||||||
|
for item in context[obj_list]:
|
||||||
|
bookmark, _ = BookMark.objects.get_or_create(
|
||||||
|
page=self.get_comment_page(item)
|
||||||
|
)
|
||||||
|
setattr(item, "bookmark", bookmark)
|
||||||
|
return context
|
|
@ -83,6 +83,7 @@ from judge.utils.views import (
|
||||||
)
|
)
|
||||||
from judge.widgets import HeavyPreviewPageDownWidget
|
from judge.widgets import HeavyPreviewPageDownWidget
|
||||||
from judge.views.pagevote import PageVoteDetailView
|
from judge.views.pagevote import PageVoteDetailView
|
||||||
|
from judge.views.bookmark import BookMarkDetailView
|
||||||
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
|
@ -382,7 +383,7 @@ class ContestMixin(object):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class ContestDetail(ContestMixin, TitleMixin, CommentedDetailView, PageVoteDetailView):
|
class ContestDetail(ContestMixin, TitleMixin, CommentedDetailView, PageVoteDetailView, BookMarkDetailView):
|
||||||
template_name = "contest/contest.html"
|
template_name = "contest/contest.html"
|
||||||
|
|
||||||
def get_comment_page(self):
|
def get_comment_page(self):
|
||||||
|
|
|
@ -72,6 +72,7 @@ from judge.views.problem import ProblemList
|
||||||
from judge.views.contests import ContestList
|
from judge.views.contests import ContestList
|
||||||
from judge.views.submission import AllSubmissions, SubmissionsListBase
|
from judge.views.submission import AllSubmissions, SubmissionsListBase
|
||||||
from judge.views.pagevote import PageVoteListView
|
from judge.views.pagevote import PageVoteListView
|
||||||
|
from judge.views.bookmark import BookMarkListView
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"OrganizationList",
|
"OrganizationList",
|
||||||
|
@ -266,7 +267,7 @@ class OrganizationList(TitleMixin, ListView, OrganizationBase):
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class OrganizationHome(OrganizationDetailView, PageVoteListView):
|
class OrganizationHome(OrganizationDetailView, PageVoteListView, BookMarkListView):
|
||||||
template_name = "organization/home.html"
|
template_name = "organization/home.html"
|
||||||
pagevote_object_name = "posts"
|
pagevote_object_name = "posts"
|
||||||
|
|
||||||
|
@ -294,6 +295,7 @@ class OrganizationHome(OrganizationDetailView, PageVoteListView):
|
||||||
context["title"] = self.object.name
|
context["title"] = self.object.name
|
||||||
context["posts"], context["page_obj"] = self.get_posts_and_page_obj()
|
context["posts"], context["page_obj"] = self.get_posts_and_page_obj()
|
||||||
context = self.add_pagevote_context_data(context, "posts")
|
context = self.add_pagevote_context_data(context, "posts")
|
||||||
|
context = self.add_bookmark_context_data(context, "posts")
|
||||||
|
|
||||||
# Hack: This allows page_obj to have page_range for non-ListView class
|
# Hack: This allows page_obj to have page_range for non-ListView class
|
||||||
setattr(
|
setattr(
|
||||||
|
|
|
@ -19,6 +19,8 @@ from django.views.generic import View, ListView
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"upvote_page",
|
"upvote_page",
|
||||||
"downvote_page",
|
"downvote_page",
|
||||||
|
"PageVoteDetailView",
|
||||||
|
"PageVoteListView",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -97,21 +99,10 @@ class PageVoteDetailView(TemplateResponseMixin, SingleObjectMixin, View):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
return self.pagevote_page
|
return self.pagevote_page
|
||||||
|
|
||||||
# def get(self, request, *args, **kwargs):
|
|
||||||
# self.object = self.get_object()
|
|
||||||
# return self.render_to_response(
|
|
||||||
# self.get_context_data(
|
|
||||||
# object=self.object,
|
|
||||||
# )
|
|
||||||
# )
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(PageVoteDetailView, self).get_context_data(**kwargs)
|
context = super(PageVoteDetailView, self).get_context_data(**kwargs)
|
||||||
queryset = PageVote.objects.filter(page=self.get_comment_page())
|
queryset = PageVote.objects.get_or_create(page=self.get_comment_page())
|
||||||
if queryset.exists() == False:
|
context["pagevote"] = queryset[0]
|
||||||
pagevote = PageVote(page=self.get_comment_page(), score=0)
|
|
||||||
pagevote.save()
|
|
||||||
context["pagevote"] = queryset.first()
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -87,6 +87,7 @@ from judge.utils.views import (
|
||||||
)
|
)
|
||||||
from judge.ml.collab_filter import CollabFilter
|
from judge.ml.collab_filter import CollabFilter
|
||||||
from judge.views.pagevote import PageVoteDetailView, PageVoteListView
|
from judge.views.pagevote import PageVoteDetailView, PageVoteListView
|
||||||
|
from judge.views.bookmark import BookMarkDetailView, BookMarkListView
|
||||||
|
|
||||||
|
|
||||||
def get_contest_problem(problem, profile):
|
def get_contest_problem(problem, profile):
|
||||||
|
@ -178,6 +179,7 @@ class ProblemSolution(
|
||||||
TitleMixin,
|
TitleMixin,
|
||||||
CommentedDetailView,
|
CommentedDetailView,
|
||||||
PageVoteDetailView,
|
PageVoteDetailView,
|
||||||
|
BookMarkDetailView,
|
||||||
):
|
):
|
||||||
context_object_name = "problem"
|
context_object_name = "problem"
|
||||||
template_name = "problem/editorial.html"
|
template_name = "problem/editorial.html"
|
||||||
|
@ -243,7 +245,7 @@ class ProblemRaw(
|
||||||
|
|
||||||
|
|
||||||
class ProblemDetail(
|
class ProblemDetail(
|
||||||
ProblemMixin, SolvedProblemMixin, CommentedDetailView, PageVoteDetailView
|
ProblemMixin, SolvedProblemMixin, CommentedDetailView, PageVoteDetailView, BookMarkDetailView
|
||||||
):
|
):
|
||||||
context_object_name = "problem"
|
context_object_name = "problem"
|
||||||
template_name = "problem/problem.html"
|
template_name = "problem/problem.html"
|
||||||
|
@ -813,7 +815,7 @@ class ProblemList(QueryStringSortMixin, TitleMixin, SolvedProblemMixin, ListView
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
|
|
||||||
|
|
||||||
class ProblemFeed(ProblemList, PageVoteListView):
|
class ProblemFeed(ProblemList, PageVoteListView, BookMarkListView):
|
||||||
model = Problem
|
model = Problem
|
||||||
context_object_name = "problems"
|
context_object_name = "problems"
|
||||||
template_name = "problem/feed.html"
|
template_name = "problem/feed.html"
|
||||||
|
|
|
@ -13,6 +13,7 @@ from django.db import transaction
|
||||||
from django.db.models import Count, Max, Min
|
from django.db.models import Count, Max, Min
|
||||||
from django.db.models.fields import DateField
|
from django.db.models.fields import DateField
|
||||||
from django.db.models.functions import Cast, ExtractYear
|
from django.db.models.functions import Cast, ExtractYear
|
||||||
|
from judge.models.bookmark import MakeBookMark
|
||||||
from django.forms import Form
|
from django.forms import Form
|
||||||
from django.http import (
|
from django.http import (
|
||||||
Http404,
|
Http404,
|
||||||
|
@ -52,7 +53,7 @@ from judge.utils.views import (
|
||||||
)
|
)
|
||||||
from .contests import ContestRanking
|
from .contests import ContestRanking
|
||||||
|
|
||||||
__all__ = ["UserPage", "UserAboutPage", "UserProblemsPage", "users", "edit_profile"]
|
__all__ = ["UserPage", "UserAboutPage", "UserProblemsPage", "UserBookMarkPage", "users", "edit_profile"]
|
||||||
|
|
||||||
|
|
||||||
def remap_keys(iterable, mapping):
|
def remap_keys(iterable, mapping):
|
||||||
|
@ -349,6 +350,24 @@ class UserProblemsPage(UserPage):
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
class UserBookMarkPage(UserPage):
|
||||||
|
template_name = "user/user-bookmarks.html"
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(UserBookMarkPage, self).get_context_data(**kwargs)
|
||||||
|
|
||||||
|
makedownlist = MakeBookMark.objects.filter(user=self.object)
|
||||||
|
pagelist = makedownlist.filter(bookmark__page__startswith='b')
|
||||||
|
problemlist = makedownlist.filter(bookmark__page__startswith='p')
|
||||||
|
contestlist = makedownlist.filter(bookmark__page__startswith='c')
|
||||||
|
|
||||||
|
context["pagelist"] = makedownlist
|
||||||
|
context["postlist"] = pagelist
|
||||||
|
context["problemlist"] = problemlist
|
||||||
|
context["contestlist"] = contestlist
|
||||||
|
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
class UserPerformancePointsAjax(UserProblemsPage):
|
class UserPerformancePointsAjax(UserProblemsPage):
|
||||||
template_name = "user/pp-table-body.html"
|
template_name = "user/pp-table-body.html"
|
||||||
|
|
|
@ -25,7 +25,10 @@
|
||||||
</span>
|
</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<span class="actionbar-block">
|
<span class="actionbar-block">
|
||||||
<span class="actionbar-button">
|
<span id="bookmark-button-{{bookmark.id}}"
|
||||||
|
class="bookmark-button actionbar-button {% if bookmark.get_bookmark(request.profile) == True %} bookmarked {% endif %}"
|
||||||
|
onclick="javascript:bookmark({{ bookmark.id }})"
|
||||||
|
>
|
||||||
<i class="fa fa-bookmark-o" style="font-size: large;"></i>
|
<i class="fa fa-bookmark-o" style="font-size: large;"></i>
|
||||||
<span class="actionbar-text">{{_("Bookmark")}}</span>
|
<span class="actionbar-text">{{_("Bookmark")}}</span>
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -39,6 +39,10 @@
|
||||||
.actionbar-text {
|
.actionbar-text {
|
||||||
padding-left: 0.4em;
|
padding-left: 0.4em;
|
||||||
}
|
}
|
||||||
|
.bookmarked {
|
||||||
|
color: rgb(180, 180, 7);
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 799px) {
|
@media (max-width: 799px) {
|
||||||
.actionbar-text {
|
.actionbar-text {
|
||||||
display: none;
|
display: none;
|
||||||
|
|
|
@ -20,6 +20,39 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ajax_bookmark(url, id, on_success) {
|
||||||
|
return $.ajax({
|
||||||
|
url: url,
|
||||||
|
type: 'POST',
|
||||||
|
data: {
|
||||||
|
id: id
|
||||||
|
},
|
||||||
|
success: function (data, textStatus, jqXHR) {
|
||||||
|
if (typeof on_success !== 'undefined')
|
||||||
|
on_success();
|
||||||
|
},
|
||||||
|
error: function (data, textStatus, jqXHR) {
|
||||||
|
alert('Could not bookmark: ' + data.responseText);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
window.bookmark = function(id) {
|
||||||
|
var $bookmark = $('#bookmark-button-' + id);
|
||||||
|
if ($bookmark.hasClass('bookmarked')) {
|
||||||
|
ajax_bookmark('{{ url('undobookmark') }}', id, function () {
|
||||||
|
$bookmark.removeClass('bookmarked');
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
ajax_bookmark('{{ url('dobookmark') }}', id, function () {
|
||||||
|
if ($bookmark.hasClass('bookmarked'))
|
||||||
|
$bookmark.removeClass('bookmarked');
|
||||||
|
$bookmark.addClass('bookmarked');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
var get_$votes = function (id) {
|
var get_$votes = function (id) {
|
||||||
var $post = $('#page-vote-' + id);
|
var $post = $('#page-vote-' + id);
|
||||||
return {
|
return {
|
||||||
|
@ -30,7 +63,6 @@
|
||||||
|
|
||||||
window.pagevote_upvote = function (id) {
|
window.pagevote_upvote = function (id) {
|
||||||
var $votes = get_$votes(id);
|
var $votes = get_$votes(id);
|
||||||
console.log($votes.upvote, $votes.downvote);
|
|
||||||
if ($votes.upvote.hasClass('voted')) {
|
if ($votes.upvote.hasClass('voted')) {
|
||||||
ajax_vote('{{ url('pagevote_downvote') }}', id, -1, function () {
|
ajax_vote('{{ url('pagevote_downvote') }}', id, -1, function () {
|
||||||
$votes.upvote.removeClass('voted');
|
$votes.upvote.removeClass('voted');
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
{% endcache %}
|
{% endcache %}
|
||||||
</div>
|
</div>
|
||||||
{% set pagevote = post.pagevote %}
|
{% set pagevote = post.pagevote %}
|
||||||
|
{% set bookmark = post.bookmark %}
|
||||||
{% set hide_actionbar_comment = True %}
|
{% set hide_actionbar_comment = True %}
|
||||||
{% set include_hr = True %}
|
{% set include_hr = True %}
|
||||||
{% include "actionbar/list.html" %}
|
{% include "actionbar/list.html" %}
|
||||||
|
|
|
@ -64,6 +64,7 @@
|
||||||
{% set include_hr = True %}
|
{% set include_hr = True %}
|
||||||
{% set hide_actionbar_comment = True %}
|
{% set hide_actionbar_comment = True %}
|
||||||
{% set pagevote = problem.pagevote %}
|
{% set pagevote = problem.pagevote %}
|
||||||
|
{% set bookmark = post.bookmark %}
|
||||||
{% include "actionbar/list.html" %}
|
{% include "actionbar/list.html" %}
|
||||||
|
|
||||||
{% if feed_type=='volunteer' and request.user.has_perm('judge.suggest_problem_changes') %}
|
{% if feed_type=='volunteer' and request.user.has_perm('judge.suggest_problem_changes') %}
|
||||||
|
|
90
templates/user/user-bookmarks.html
Normal file
90
templates/user/user-bookmarks.html
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
{% extends "user/user-base.html" %}
|
||||||
|
|
||||||
|
{% block title_ruler %}{% endblock %}
|
||||||
|
|
||||||
|
{% block title_row %}
|
||||||
|
{% set tab = 'bookmark' %}
|
||||||
|
{% include "user/user-tabs.html" %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block user_content %}
|
||||||
|
{% if postlist %}
|
||||||
|
<div class="bookmark-group">
|
||||||
|
<h3 class="unselectable toggle closed">
|
||||||
|
<span class="fa fa-chevron-right fa-fw"></span>{{ _('Bookmarked Posts') }} ({{ postlist|length }})
|
||||||
|
</h3>
|
||||||
|
<table style="display: none" class="table toggled">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{{ _('Post') }}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for post in postlist %}
|
||||||
|
<tr>
|
||||||
|
<td class="bookmark-name">
|
||||||
|
<a href="{{ url('blog_post', post.bookmark.page_object().id, post.bookmark.page_object().slug) }}">{{ post.bookmark.page_object().title}} </a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<i>{{ _('You have not yet bookmarked any post.') }}</i>
|
||||||
|
{% endif %}
|
||||||
|
<hr>
|
||||||
|
{% if problemlist %}
|
||||||
|
<div class="bookmark-group">
|
||||||
|
<h3 class="unselectable toggle closed">
|
||||||
|
<span class="fa fa-chevron-right fa-fw"></span>{{ _('Bookmarked Problems') }} ({{ problemlist|length }})
|
||||||
|
</h3>
|
||||||
|
<table style="display: none" class="table toggled">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{{ _('Problem') }}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for problem in problemlist %}
|
||||||
|
<tr>
|
||||||
|
<td class="bookmark-name">
|
||||||
|
<a href="{{ url('problem_detail', problem.bookmark.page_object().code) }}">{{ problem.bookmark.page_object().name}} </a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<i>{{ _('You have not yet bookmarked any problem.') }}</i>
|
||||||
|
{% endif %}
|
||||||
|
<hr>
|
||||||
|
{% if contestlist %}
|
||||||
|
<div class="bookmark-group">
|
||||||
|
<h3 class="unselectable toggle closed">
|
||||||
|
<span class="fa fa-chevron-right fa-fw"></span>{{ _('Bookmarked Contests') }} ({{ contestlist|length }})
|
||||||
|
</h3>
|
||||||
|
<table style="display: none" class="table toggled">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{{ _('Contest') }}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for contest in contestlist %}
|
||||||
|
<tr>
|
||||||
|
<td class="bookmark-name">
|
||||||
|
<a href="{{ url('contest_view', contest.bookmark.page_object().key) }}">{{ contest.bookmark.page_object().name}} </a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<i>{{ _('You have not yet bookmarked any contest.') }}</i>
|
||||||
|
{% endif %}
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -7,6 +7,7 @@
|
||||||
{{ make_tab('impersonate', 'fa-eye', url('impersonate-start', user.user.id), _('Impersonate')) }}
|
{{ make_tab('impersonate', 'fa-eye', url('impersonate-start', user.user.id), _('Impersonate')) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if user.user == request.user %}
|
{% if user.user == request.user %}
|
||||||
|
{{ make_tab('bookmark', 'fa-bookmark', url('user_bookmark'), _('Bookmark')) }}
|
||||||
{{ make_tab('edit', 'fa-edit', url('user_edit_profile'), _('Edit profile')) }}
|
{{ make_tab('edit', 'fa-edit', url('user_edit_profile'), _('Edit profile')) }}
|
||||||
{% else %}
|
{% else %}
|
||||||
{% if perms.auth.change_user %}
|
{% if perms.auth.change_user %}
|
||||||
|
|
Loading…
Reference in a new issue