add bookmark model

This commit is contained in:
Zhao-Linux 2022-11-18 02:17:45 +07:00
parent 03db2db899
commit d0e4d9512c
14 changed files with 223 additions and 16 deletions

View file

@ -60,6 +60,7 @@ from judge.views import (
user,
volunteer,
pagevote,
bookmark,
widgets,
internal,
)
@ -448,6 +449,8 @@ urlpatterns = [
),
url(r"^pagevotes/upvote/$", pagevote.upvote_page, name="pagevote_upvote"),
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/downvote/$", comment.downvote_comment, name="comment_downvote"),
url(r"^comments/hide/$", comment.comment_hide, name="comment_hide"),

View 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')},
},
),
]

View file

@ -55,6 +55,7 @@ from judge.models.submission import (
from judge.models.ticket import Ticket, TicketMessage
from judge.models.volunteer import VolunteerProblemVote
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(Problem, follow=["language_limits"])
@ -79,4 +80,5 @@ revisions.register(ContestParticipation)
revisions.register(Rating)
revisions.register(PageVoteVoter)
revisions.register(VolunteerProblemVote)
revisions.register(MakeBookMark)
del revisions

38
judge/models/bookmark.py Normal file
View file

@ -0,0 +1,38 @@
from django.db import models
from django.db.models import CASCADE
from django.utils.translation import gettext_lazy as _
from judge.models import Profile
__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
class Meta:
verbose_name = _("bookmark")
verbose_name_plural = _("bookmarks")
def __str__(self):
return f"bookmark for {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")

View file

@ -8,6 +8,7 @@ from django.views.generic import ListView
from judge.comments import CommentedDetailView
from judge.views.pagevote import PageVoteDetailView, PageVoteListView
from judge.views.bookmark import BookMarkDetailView, BookMarkListView
from judge.models import (
BlogPost,
Comment,
@ -93,7 +94,7 @@ class FeedView(ListView):
return context
class PostList(FeedView, PageVoteListView):
class PostList(FeedView, PageVoteListView, BookMarkListView):
model = BlogPost
paginate_by = 10
context_object_name = "posts"
@ -194,7 +195,7 @@ class CommentFeed(FeedView):
return context
class PostView(TitleMixin, CommentedDetailView, PageVoteDetailView):
class PostView(TitleMixin, CommentedDetailView, PageVoteDetailView, BookMarkDetailView):
model = BlogPost
pk_url_kwarg = "id"
context_object_name = "post"

87
judge/views/bookmark.py Normal file
View file

@ -0,0 +1,87 @@
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.filter(page=self.get_comment_page())
if queryset.exists() == False:
bookmark = BookMark(page=self.get_comment_page(),)
bookmark.save()
context["bookmark"] = queryset.first()
return context
class BookMarkListView(ListView):
def get_context_data(self, **kwargs):
context = super(BookMarkListView, self).get_context_data(**kwargs)
for item in context["object_list"]:
bookmark, _ = BookMark.objects.get_or_create(
page=self.get_comment_page(item)
)
setattr(item, "bookmark", bookmark)
return context

View file

@ -83,6 +83,7 @@ from judge.utils.views import (
)
from judge.widgets import HeavyPreviewPageDownWidget
from judge.views.pagevote import PageVoteDetailView
from judge.views.bookmark import BookMarkDetailView
__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"
def get_comment_page(self):

View file

@ -19,6 +19,8 @@ from django.views.generic import View, ListView
__all__ = [
"upvote_page",
"downvote_page",
"PageVoteDetailView",
"PageVoteListView",
]
@ -97,14 +99,6 @@ class PageVoteDetailView(TemplateResponseMixin, SingleObjectMixin, View):
raise NotImplementedError()
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):
context = super(PageVoteDetailView, self).get_context_data(**kwargs)
queryset = PageVote.objects.filter(page=self.get_comment_page())

View file

@ -87,6 +87,7 @@ from judge.utils.views import (
)
from judge.ml.collab_filter import CollabFilter
from judge.views.pagevote import PageVoteDetailView, PageVoteListView
from judge.views.bookmark import BookMarkDetailView, BookMarkListView
def get_contest_problem(problem, profile):
@ -178,6 +179,7 @@ class ProblemSolution(
TitleMixin,
CommentedDetailView,
PageVoteDetailView,
BookMarkDetailView,
):
context_object_name = "problem"
template_name = "problem/editorial.html"
@ -243,7 +245,7 @@ class ProblemRaw(
class ProblemDetail(
ProblemMixin, SolvedProblemMixin, CommentedDetailView, PageVoteDetailView
ProblemMixin, SolvedProblemMixin, CommentedDetailView, PageVoteDetailView, BookMarkDetailView
):
context_object_name = "problem"
template_name = "problem/problem.html"
@ -813,7 +815,7 @@ class ProblemList(QueryStringSortMixin, TitleMixin, SolvedProblemMixin, ListView
return HttpResponseRedirect(request.get_full_path())
class ProblemFeed(ProblemList, PageVoteListView):
class ProblemFeed(ProblemList, PageVoteListView, BookMarkListView):
model = Problem
context_object_name = "problems"
template_name = "problem/feed.html"

View file

@ -25,9 +25,12 @@
</span>
{% endif %}
<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>
<span class="actionbar-text">{{_("Bookmark")}}</span>
<span class="actionbar-text">{{_("Bookmark")}} {{ bookmark.id }} </span>
</span>
</span>
<span class="actionbar-block">

View file

@ -39,6 +39,10 @@
.actionbar-text {
padding-left: 0.4em;
}
.bookmarked {
color: rgb(180, 180, 7);
}
@media (max-width: 799px) {
.actionbar-text {
display: none;

View file

@ -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 $post = $('#page-vote-' + id);
return {
@ -30,7 +63,6 @@
window.pagevote_upvote = function (id) {
var $votes = get_$votes(id);
console.log($votes.upvote, $votes.downvote);
if ($votes.upvote.hasClass('voted')) {
ajax_vote('{{ url('pagevote_downvote') }}', id, -1, function () {
$votes.upvote.removeClass('voted');

View file

@ -43,6 +43,7 @@
{% endcache %}
</div>
{% set pagevote = post.pagevote %}
{% set bookmark = post.bookmark %}
{% set hide_actionbar_comment = True %}
{% set include_hr = True %}
{% include "actionbar/list.html" %}

View file

@ -64,6 +64,7 @@
{% set include_hr = True %}
{% set hide_actionbar_comment = True %}
{% set pagevote = problem.pagevote %}
{% set bookmark = post.bookmark %}
{% include "actionbar/list.html" %}
{% if feed_type=='volunteer' and request.user.has_perm('judge.suggest_problem_changes') %}