2020-08-27 13:37:27 +08:00
|
|
|
import logging
|
2020-05-01 22:46:15 +08:00
|
|
|
from django.shortcuts import render, get_object_or_404, redirect, reverse
|
2020-10-26 00:17:26 +01:00
|
|
|
from django.contrib.auth.decorators import login_required, permission_required
|
2020-05-01 22:46:15 +08:00
|
|
|
from django.utils.translation import gettext_lazy as _
|
2020-05-05 23:50:48 +08:00
|
|
|
from django.http import HttpResponseBadRequest, HttpResponseServerError
|
|
|
|
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
|
|
|
|
from django.db import IntegrityError, transaction
|
2020-07-10 21:28:09 +08:00
|
|
|
from django.db.models import Count
|
2020-05-05 23:50:48 +08:00
|
|
|
from django.utils import timezone
|
|
|
|
from django.core.paginator import Paginator
|
2020-05-12 14:05:12 +08:00
|
|
|
from django.core.files.uploadedfile import SimpleUploadedFile
|
2020-10-22 21:45:05 +02:00
|
|
|
from mastodon import mastodon_request_included
|
|
|
|
from mastodon.api import check_visibility, post_toot, TootVisibilityEnum
|
|
|
|
from mastodon.utils import rating_to_emoji
|
2020-07-03 15:36:23 +08:00
|
|
|
from common.utils import PageLinksGenerator
|
|
|
|
from common.views import PAGE_LINK_NUMBER
|
2020-05-01 22:46:15 +08:00
|
|
|
from .models import *
|
|
|
|
from .forms import *
|
2020-05-05 23:50:48 +08:00
|
|
|
from .forms import BookMarkStatusTranslator
|
2020-07-29 23:34:06 +08:00
|
|
|
from boofilsic.settings import MASTODON_TAGS
|
2020-05-01 22:46:15 +08:00
|
|
|
|
|
|
|
|
2020-08-28 22:22:07 +08:00
|
|
|
logger = logging.getLogger(__name__)
|
2020-08-27 13:37:27 +08:00
|
|
|
mastodon_logger = logging.getLogger("django.mastodon")
|
|
|
|
|
|
|
|
|
2020-05-05 23:50:48 +08:00
|
|
|
# how many marks showed on the detail page
|
|
|
|
MARK_NUMBER = 5
|
|
|
|
# how many marks at the mark page
|
|
|
|
MARK_PER_PAGE = 20
|
|
|
|
# how many reviews showed on the detail page
|
|
|
|
REVIEW_NUMBER = 5
|
|
|
|
# how many reviews at the mark page
|
|
|
|
REVIEW_PER_PAGE = 20
|
2020-07-10 21:28:09 +08:00
|
|
|
# max tags on detail page
|
|
|
|
TAG_NUMBER = 10
|
2020-05-05 23:50:48 +08:00
|
|
|
|
|
|
|
|
|
|
|
# public data
|
|
|
|
###########################
|
2020-05-01 22:46:15 +08:00
|
|
|
@login_required
|
|
|
|
def create(request):
|
|
|
|
if request.method == 'GET':
|
|
|
|
form = BookForm()
|
|
|
|
return render(
|
|
|
|
request,
|
|
|
|
'books/create_update.html',
|
|
|
|
{
|
|
|
|
'form': form,
|
2020-05-05 23:50:48 +08:00
|
|
|
'title': _('添加书籍'),
|
|
|
|
'submit_url': reverse("books:create")
|
2020-05-01 22:46:15 +08:00
|
|
|
}
|
|
|
|
)
|
|
|
|
elif request.method == 'POST':
|
2020-05-05 23:50:48 +08:00
|
|
|
if request.user.is_authenticated:
|
|
|
|
# only local user can alter public data
|
|
|
|
form = BookForm(request.POST, request.FILES)
|
|
|
|
if form.is_valid():
|
|
|
|
form.instance.last_editor = request.user
|
|
|
|
form.save()
|
|
|
|
return redirect(reverse("books:retrieve", args=[form.instance.id]))
|
|
|
|
else:
|
|
|
|
return render(
|
|
|
|
request,
|
|
|
|
'books/create_update.html',
|
|
|
|
{
|
|
|
|
'form': form,
|
|
|
|
'title': _('添加书籍'),
|
|
|
|
'submit_url': reverse("books:create")
|
|
|
|
}
|
|
|
|
)
|
|
|
|
else:
|
|
|
|
return redirect(reverse("users:login"))
|
|
|
|
else:
|
|
|
|
return HttpResponseBadRequest()
|
|
|
|
|
|
|
|
|
|
|
|
@login_required
|
|
|
|
def update(request, id):
|
|
|
|
if request.method == 'GET':
|
|
|
|
book = get_object_or_404(Book, pk=id)
|
|
|
|
form = BookForm(instance=book)
|
|
|
|
return render(
|
|
|
|
request,
|
|
|
|
'books/create_update.html',
|
|
|
|
{
|
|
|
|
'form': form,
|
|
|
|
'title': _('修改书籍'),
|
|
|
|
'submit_url': reverse("books:update", args=[book.id])
|
|
|
|
}
|
|
|
|
)
|
|
|
|
elif request.method == 'POST':
|
|
|
|
book = get_object_or_404(Book, pk=id)
|
2020-05-07 06:01:22 +08:00
|
|
|
form = BookForm(request.POST, request.FILES, instance=book)
|
2020-05-01 22:46:15 +08:00
|
|
|
if form.is_valid():
|
|
|
|
form.instance.last_editor = request.user
|
2020-05-05 23:50:48 +08:00
|
|
|
form.instance.edited_time = timezone.now()
|
2020-05-01 22:46:15 +08:00
|
|
|
form.save()
|
2020-05-07 20:21:53 +08:00
|
|
|
else:
|
|
|
|
return render(
|
2020-07-10 21:28:09 +08:00
|
|
|
request,
|
|
|
|
'books/create_update.html',
|
|
|
|
{
|
|
|
|
'form': form,
|
|
|
|
'title': _('修改书籍'),
|
|
|
|
'submit_url': reverse("books:update", args=[book.id])
|
|
|
|
}
|
|
|
|
)
|
2020-05-01 22:46:15 +08:00
|
|
|
return redirect(reverse("books:retrieve", args=[form.instance.id]))
|
2020-05-05 23:50:48 +08:00
|
|
|
|
2020-05-01 22:46:15 +08:00
|
|
|
else:
|
2020-07-10 21:28:09 +08:00
|
|
|
return HttpResponseBadRequest()
|
2020-05-01 22:46:15 +08:00
|
|
|
|
|
|
|
|
2020-05-05 23:50:48 +08:00
|
|
|
@mastodon_request_included
|
2020-07-03 16:12:17 +08:00
|
|
|
# @login_required
|
2020-05-01 22:46:15 +08:00
|
|
|
def retrieve(request, id):
|
|
|
|
if request.method == 'GET':
|
|
|
|
book = get_object_or_404(Book, pk=id)
|
2020-05-05 23:50:48 +08:00
|
|
|
mark = None
|
2020-07-10 21:28:09 +08:00
|
|
|
mark_tags = None
|
2020-05-05 23:50:48 +08:00
|
|
|
review = None
|
2020-07-10 21:28:09 +08:00
|
|
|
|
|
|
|
# retreive tags
|
|
|
|
book_tag_list = book.book_tags.values('content').annotate(
|
|
|
|
tag_frequency=Count('content')).order_by('-tag_frequency')[:TAG_NUMBER]
|
|
|
|
|
|
|
|
# retrieve user mark and initialize mark form
|
2020-05-05 23:50:48 +08:00
|
|
|
try:
|
2020-07-03 16:12:17 +08:00
|
|
|
if request.user.is_authenticated:
|
|
|
|
mark = BookMark.objects.get(owner=request.user, book=book)
|
2020-05-05 23:50:48 +08:00
|
|
|
except ObjectDoesNotExist:
|
|
|
|
mark = None
|
|
|
|
if mark:
|
2020-10-03 23:27:41 +02:00
|
|
|
mark_tags = mark.bookmark_tags.all()
|
2020-05-05 23:50:48 +08:00
|
|
|
mark.get_status_display = BookMarkStatusTranslator(mark.status)
|
2020-07-10 21:28:09 +08:00
|
|
|
mark_form = BookMarkForm(instance=mark, initial={
|
|
|
|
'tags': mark_tags
|
|
|
|
})
|
2020-05-05 23:50:48 +08:00
|
|
|
else:
|
|
|
|
mark_form = BookMarkForm(initial={
|
2020-07-10 21:28:09 +08:00
|
|
|
'book': book,
|
|
|
|
'tags': mark_tags
|
2020-05-05 23:50:48 +08:00
|
|
|
})
|
|
|
|
|
2020-07-10 21:28:09 +08:00
|
|
|
# retrieve user review
|
2020-05-05 23:50:48 +08:00
|
|
|
try:
|
2020-07-03 16:12:17 +08:00
|
|
|
if request.user.is_authenticated:
|
|
|
|
review = BookReview.objects.get(owner=request.user, book=book)
|
2020-05-05 23:50:48 +08:00
|
|
|
except ObjectDoesNotExist:
|
|
|
|
review = None
|
2020-07-03 16:12:17 +08:00
|
|
|
|
2020-07-10 21:28:09 +08:00
|
|
|
# retrieve other related reviews and marks
|
2020-07-03 16:12:17 +08:00
|
|
|
if request.user.is_anonymous:
|
2020-07-10 21:28:09 +08:00
|
|
|
# hide all marks and reviews for anonymous user
|
2020-07-03 16:12:17 +08:00
|
|
|
mark_list = None
|
|
|
|
review_list = None
|
|
|
|
mark_list_more = None
|
|
|
|
review_list_more = None
|
|
|
|
else:
|
2020-07-10 21:28:09 +08:00
|
|
|
mark_list = BookMark.get_available(
|
|
|
|
book, request.user, request.session['oauth_token'])
|
|
|
|
review_list = BookReview.get_available(
|
|
|
|
book, request.user, request.session['oauth_token'])
|
2020-07-03 16:12:17 +08:00
|
|
|
mark_list_more = True if len(mark_list) > MARK_NUMBER else False
|
|
|
|
mark_list = mark_list[:MARK_NUMBER]
|
|
|
|
for m in mark_list:
|
|
|
|
m.get_status_display = BookMarkStatusTranslator(m.status)
|
2020-07-10 21:28:09 +08:00
|
|
|
review_list_more = True if len(
|
|
|
|
review_list) > REVIEW_NUMBER else False
|
2020-07-03 16:12:17 +08:00
|
|
|
review_list = review_list[:REVIEW_NUMBER]
|
|
|
|
|
2020-05-05 23:50:48 +08:00
|
|
|
# def strip_html_tags(text):
|
|
|
|
# import re
|
|
|
|
# regex = re.compile('<.*?>')
|
|
|
|
# return re.sub(regex, '', text)
|
|
|
|
|
|
|
|
# for r in review_list:
|
|
|
|
# r.content = strip_html_tags(r.content)
|
|
|
|
|
2020-05-01 22:46:15 +08:00
|
|
|
return render(
|
|
|
|
request,
|
|
|
|
'books/detail.html',
|
|
|
|
{
|
|
|
|
'book': book,
|
2020-05-05 23:50:48 +08:00
|
|
|
'mark': mark,
|
|
|
|
'review': review,
|
|
|
|
'status_enum': MarkStatusEnum,
|
|
|
|
'mark_form': mark_form,
|
|
|
|
'mark_list': mark_list,
|
|
|
|
'mark_list_more': mark_list_more,
|
|
|
|
'review_list': review_list,
|
|
|
|
'review_list_more': review_list_more,
|
2020-07-10 21:28:09 +08:00
|
|
|
'book_tag_list': book_tag_list,
|
|
|
|
'mark_tags': mark_tags,
|
2020-05-05 23:50:48 +08:00
|
|
|
}
|
|
|
|
)
|
|
|
|
else:
|
2020-08-28 22:22:07 +08:00
|
|
|
logger.warning('non-GET method at /book/<id>')
|
2020-10-22 22:21:29 +02:00
|
|
|
return HttpResponseBadRequest()
|
2020-05-05 23:50:48 +08:00
|
|
|
|
|
|
|
|
2020-10-26 00:17:26 +01:00
|
|
|
@permission_required('books.delete_book')
|
2020-05-05 23:50:48 +08:00
|
|
|
@login_required
|
|
|
|
def delete(request, id):
|
|
|
|
if request.method == 'GET':
|
|
|
|
book = get_object_or_404(Book, pk=id)
|
|
|
|
return render(
|
|
|
|
request,
|
|
|
|
'books/delete.html',
|
|
|
|
{
|
|
|
|
'book': book,
|
|
|
|
}
|
|
|
|
)
|
|
|
|
elif request.method == 'POST':
|
|
|
|
if request.user.is_staff:
|
|
|
|
# only staff has right to delete
|
|
|
|
book = get_object_or_404(Book, pk=id)
|
|
|
|
book.delete()
|
2020-10-26 00:18:57 +01:00
|
|
|
return redirect(reverse("common:home"))
|
2020-05-05 23:50:48 +08:00
|
|
|
else:
|
|
|
|
raise PermissionDenied()
|
|
|
|
else:
|
2020-07-10 21:28:09 +08:00
|
|
|
return HttpResponseBadRequest()
|
2020-05-05 23:50:48 +08:00
|
|
|
|
|
|
|
|
|
|
|
# user owned entites
|
|
|
|
###########################
|
|
|
|
@mastodon_request_included
|
|
|
|
@login_required
|
|
|
|
def create_update_mark(request):
|
|
|
|
# check list:
|
|
|
|
# clean rating if is wish
|
|
|
|
# transaction on updating book rating
|
|
|
|
# owner check(guarantee)
|
|
|
|
if request.method == 'POST':
|
|
|
|
pk = request.POST.get('id')
|
|
|
|
old_rating = None
|
2020-07-10 21:28:09 +08:00
|
|
|
old_tags = None
|
2020-05-05 23:50:48 +08:00
|
|
|
if pk:
|
|
|
|
mark = get_object_or_404(BookMark, pk=pk)
|
2020-10-26 00:17:26 +01:00
|
|
|
if request.user != mark.owner:
|
|
|
|
return HttpResponseBadRequest()
|
2020-05-05 23:50:48 +08:00
|
|
|
old_rating = mark.rating
|
2020-10-03 23:27:41 +02:00
|
|
|
old_tags = mark.bookmark_tags.all()
|
2020-05-05 23:50:48 +08:00
|
|
|
# update
|
|
|
|
form = BookMarkForm(request.POST, instance=mark)
|
|
|
|
else:
|
|
|
|
# create
|
|
|
|
form = BookMarkForm(request.POST)
|
|
|
|
|
|
|
|
if form.is_valid():
|
|
|
|
if form.instance.status == MarkStatusEnum.WISH.value:
|
|
|
|
form.instance.rating = None
|
2020-05-08 12:52:44 +08:00
|
|
|
form.cleaned_data['rating'] = None
|
2020-05-05 23:50:48 +08:00
|
|
|
form.instance.owner = request.user
|
|
|
|
form.instance.edited_time = timezone.now()
|
|
|
|
book = form.instance.book
|
2020-07-10 21:28:09 +08:00
|
|
|
|
2020-05-05 23:50:48 +08:00
|
|
|
try:
|
|
|
|
with transaction.atomic():
|
|
|
|
# update book rating
|
|
|
|
book.update_rating(old_rating, form.instance.rating)
|
|
|
|
form.save()
|
2020-07-10 21:28:09 +08:00
|
|
|
# update tags
|
|
|
|
if old_tags:
|
|
|
|
for tag in old_tags:
|
|
|
|
tag.delete()
|
|
|
|
if form.cleaned_data['tags']:
|
|
|
|
for tag in form.cleaned_data['tags']:
|
|
|
|
BookTag.objects.create(
|
|
|
|
content=tag,
|
|
|
|
book=book,
|
|
|
|
mark=form.instance
|
|
|
|
)
|
2020-05-05 23:50:48 +08:00
|
|
|
except IntegrityError as e:
|
2020-08-28 22:22:07 +08:00
|
|
|
logger.error(e.__str__())
|
2020-11-05 12:58:32 +01:00
|
|
|
return HttpResponseServerError("integrity error")
|
2020-05-05 23:50:48 +08:00
|
|
|
|
|
|
|
if form.cleaned_data['share_to_mastodon']:
|
|
|
|
if form.cleaned_data['is_private']:
|
|
|
|
visibility = TootVisibilityEnum.PRIVATE
|
|
|
|
else:
|
2020-05-08 13:56:58 +08:00
|
|
|
visibility = TootVisibilityEnum.UNLISTED
|
2020-07-10 21:28:09 +08:00
|
|
|
url = "https://" + request.get_host() + reverse("books:retrieve",
|
|
|
|
args=[book.id])
|
2020-05-06 16:42:18 +08:00
|
|
|
words = BookMarkStatusTranslator(int(form.cleaned_data['status'])) +\
|
2020-07-10 21:28:09 +08:00
|
|
|
f"《{book.title}》" + \
|
|
|
|
rating_to_emoji(form.cleaned_data['rating'])
|
2020-07-29 23:34:06 +08:00
|
|
|
|
2020-08-28 22:22:07 +08:00
|
|
|
# tags = MASTODON_TAGS % {'category': '书', 'type': '标记'}
|
|
|
|
tags = ''
|
2020-07-29 23:34:06 +08:00
|
|
|
content = words + '\n' + url + '\n' + \
|
|
|
|
form.cleaned_data['text'] + '\n' + tags
|
2020-10-22 23:27:16 +02:00
|
|
|
response = post_toot(
|
|
|
|
request.user.mastodon_site, content, visibility, request.session['oauth_token'])
|
2020-08-27 13:37:27 +08:00
|
|
|
if response.status_code != 200:
|
2020-08-28 22:22:07 +08:00
|
|
|
mastodon_logger.error(f"CODE:{response.status_code} {response.text}")
|
2020-08-27 13:37:27 +08:00
|
|
|
return HttpResponseServerError("publishing mastodon status failed")
|
2020-05-05 23:50:48 +08:00
|
|
|
else:
|
2020-07-15 16:58:19 +08:00
|
|
|
return HttpResponseBadRequest("invalid form data")
|
2020-05-05 23:50:48 +08:00
|
|
|
|
|
|
|
return redirect(reverse("books:retrieve", args=[form.instance.book.id]))
|
|
|
|
else:
|
2020-07-15 16:58:19 +08:00
|
|
|
return HttpResponseBadRequest("invalid method")
|
2020-05-05 23:50:48 +08:00
|
|
|
|
|
|
|
|
|
|
|
@mastodon_request_included
|
|
|
|
@login_required
|
|
|
|
def retrieve_mark_list(request, book_id):
|
|
|
|
if request.method == 'GET':
|
|
|
|
book = get_object_or_404(Book, pk=book_id)
|
2020-07-10 21:28:09 +08:00
|
|
|
queryset = BookMark.get_available(
|
|
|
|
book, request.user, request.session['oauth_token'])
|
2020-05-05 23:50:48 +08:00
|
|
|
paginator = Paginator(queryset, MARK_PER_PAGE)
|
|
|
|
page_number = request.GET.get('page', default=1)
|
|
|
|
marks = paginator.get_page(page_number)
|
2020-07-10 21:28:09 +08:00
|
|
|
marks.pagination = PageLinksGenerator(
|
|
|
|
PAGE_LINK_NUMBER, page_number, paginator.num_pages)
|
2020-05-05 23:50:48 +08:00
|
|
|
for m in marks:
|
|
|
|
m.get_status_display = BookMarkStatusTranslator(m.status)
|
|
|
|
return render(
|
|
|
|
request,
|
|
|
|
'books/mark_list.html',
|
|
|
|
{
|
|
|
|
'marks': marks,
|
|
|
|
'book': book,
|
|
|
|
}
|
|
|
|
)
|
|
|
|
else:
|
|
|
|
return HttpResponseBadRequest()
|
|
|
|
|
|
|
|
|
|
|
|
@login_required
|
|
|
|
def delete_mark(request, id):
|
|
|
|
if request.method == 'POST':
|
|
|
|
mark = get_object_or_404(BookMark, pk=id)
|
2020-10-26 00:17:26 +01:00
|
|
|
if request.user != mark.owner:
|
|
|
|
return HttpResponseBadRequest()
|
2020-05-05 23:50:48 +08:00
|
|
|
book_id = mark.book.id
|
|
|
|
try:
|
|
|
|
with transaction.atomic():
|
|
|
|
# update book rating
|
|
|
|
mark.book.update_rating(mark.rating, None)
|
|
|
|
mark.delete()
|
|
|
|
except IntegrityError as e:
|
|
|
|
return HttpResponseServerError()
|
|
|
|
return redirect(reverse("books:retrieve", args=[book_id]))
|
|
|
|
else:
|
|
|
|
return HttpResponseBadRequest()
|
|
|
|
|
|
|
|
|
|
|
|
@mastodon_request_included
|
|
|
|
@login_required
|
|
|
|
def create_review(request, book_id):
|
|
|
|
if request.method == 'GET':
|
|
|
|
form = BookReviewForm(initial={'book': book_id})
|
|
|
|
book = get_object_or_404(Book, pk=book_id)
|
|
|
|
return render(
|
|
|
|
request,
|
|
|
|
'books/create_update_review.html',
|
|
|
|
{
|
|
|
|
'form': form,
|
|
|
|
'title': _("添加评论"),
|
|
|
|
'book': book,
|
|
|
|
'submit_url': reverse("books:create_review", args=[book_id]),
|
|
|
|
}
|
|
|
|
)
|
|
|
|
elif request.method == 'POST':
|
|
|
|
form = BookReviewForm(request.POST)
|
|
|
|
if form.is_valid():
|
|
|
|
form.instance.owner = request.user
|
|
|
|
form.save()
|
|
|
|
if form.cleaned_data['share_to_mastodon']:
|
|
|
|
if form.cleaned_data['is_private']:
|
|
|
|
visibility = TootVisibilityEnum.PRIVATE
|
|
|
|
else:
|
2020-05-08 13:56:58 +08:00
|
|
|
visibility = TootVisibilityEnum.UNLISTED
|
2020-07-10 21:28:09 +08:00
|
|
|
url = "https://" + request.get_host() + reverse("books:retrieve_review",
|
|
|
|
args=[form.instance.id])
|
2020-05-05 23:50:48 +08:00
|
|
|
words = "发布了关于" + f"《{form.instance.book.title}》" + "的评论"
|
2020-08-28 22:22:07 +08:00
|
|
|
# tags = MASTODON_TAGS % {'category': '书', 'type': '评论'}
|
|
|
|
tags = ''
|
2020-07-10 21:28:09 +08:00
|
|
|
content = words + '\n' + url + \
|
2020-07-29 23:34:06 +08:00
|
|
|
'\n' + form.cleaned_data['title'] + '\n' + tags
|
2020-10-22 23:27:16 +02:00
|
|
|
response = post_toot(
|
|
|
|
request.user.mastodon_site, content, visibility, request.session['oauth_token'])
|
2020-08-27 13:37:27 +08:00
|
|
|
if response.status_code != 200:
|
2020-08-28 22:22:07 +08:00
|
|
|
mastodon_logger.error(
|
|
|
|
f"CODE:{response.status_code} {response.text}")
|
2020-08-27 13:37:27 +08:00
|
|
|
return HttpResponseServerError("publishing mastodon status failed")
|
2020-05-05 23:50:48 +08:00
|
|
|
return redirect(reverse("books:retrieve_review", args=[form.instance.id]))
|
|
|
|
else:
|
|
|
|
return HttpResponseBadRequest()
|
|
|
|
else:
|
|
|
|
return HttpResponseBadRequest()
|
|
|
|
|
|
|
|
|
|
|
|
@mastodon_request_included
|
|
|
|
@login_required
|
|
|
|
def update_review(request, id):
|
|
|
|
if request.method == 'GET':
|
|
|
|
review = get_object_or_404(BookReview, pk=id)
|
|
|
|
if request.user != review.owner:
|
2020-07-10 21:28:09 +08:00
|
|
|
return HttpResponseBadRequest()
|
2020-05-05 23:50:48 +08:00
|
|
|
form = BookReviewForm(instance=review)
|
|
|
|
book = review.book
|
|
|
|
return render(
|
|
|
|
request,
|
|
|
|
'books/create_update_review.html',
|
|
|
|
{
|
|
|
|
'form': form,
|
|
|
|
'title': _("编辑评论"),
|
|
|
|
'book': book,
|
|
|
|
'submit_url': reverse("books:update_review", args=[review.id]),
|
|
|
|
}
|
|
|
|
)
|
|
|
|
elif request.method == 'POST':
|
|
|
|
review = get_object_or_404(BookReview, pk=id)
|
|
|
|
if request.user != review.owner:
|
|
|
|
return HttpResponseBadRequest()
|
|
|
|
form = BookReviewForm(request.POST, instance=review)
|
|
|
|
if form.is_valid():
|
|
|
|
form.instance.edited_time = timezone.now()
|
|
|
|
form.save()
|
|
|
|
if form.cleaned_data['share_to_mastodon']:
|
|
|
|
if form.cleaned_data['is_private']:
|
|
|
|
visibility = TootVisibilityEnum.PRIVATE
|
|
|
|
else:
|
2020-05-08 13:56:58 +08:00
|
|
|
visibility = TootVisibilityEnum.UNLISTED
|
2020-07-10 21:28:09 +08:00
|
|
|
url = "https://" + request.get_host() + reverse("books:retrieve_review",
|
|
|
|
args=[form.instance.id])
|
2020-05-05 23:50:48 +08:00
|
|
|
words = "发布了关于" + f"《{form.instance.book.title}》" + "的评论"
|
2020-08-28 22:22:07 +08:00
|
|
|
# tags = MASTODON_TAGS % {'category': '书', 'type': '评论'}
|
|
|
|
tags = ''
|
2020-07-10 21:28:09 +08:00
|
|
|
content = words + '\n' + url + \
|
2020-07-29 23:34:06 +08:00
|
|
|
'\n' + form.cleaned_data['title'] + '\n' + tags
|
2020-10-22 23:27:16 +02:00
|
|
|
response = post_toot(
|
|
|
|
request.user.mastodon_site, content, visibility, request.session['oauth_token'])
|
2020-08-27 13:37:27 +08:00
|
|
|
if response.status_code != 200:
|
2020-08-28 22:22:07 +08:00
|
|
|
mastodon_logger.error(f"CODE:{response.status_code} {response.text}")
|
2020-08-27 13:37:27 +08:00
|
|
|
return HttpResponseServerError("publishing mastodon status failed")
|
2020-05-05 23:50:48 +08:00
|
|
|
return redirect(reverse("books:retrieve_review", args=[form.instance.id]))
|
|
|
|
else:
|
|
|
|
return HttpResponseBadRequest()
|
|
|
|
else:
|
2020-07-10 21:28:09 +08:00
|
|
|
return HttpResponseBadRequest()
|
2020-05-05 23:50:48 +08:00
|
|
|
|
|
|
|
|
|
|
|
@login_required
|
|
|
|
def delete_review(request, id):
|
|
|
|
if request.method == 'GET':
|
|
|
|
review = get_object_or_404(BookReview, pk=id)
|
|
|
|
if request.user != review.owner:
|
|
|
|
return HttpResponseBadRequest()
|
|
|
|
review_form = BookReviewForm(instance=review)
|
|
|
|
return render(
|
|
|
|
request,
|
|
|
|
'books/delete_review.html',
|
|
|
|
{
|
|
|
|
'form': review_form,
|
|
|
|
'review': review,
|
|
|
|
}
|
|
|
|
)
|
|
|
|
elif request.method == 'POST':
|
|
|
|
review = get_object_or_404(BookReview, pk=id)
|
|
|
|
if request.user != review.owner:
|
|
|
|
return HttpResponseBadRequest()
|
|
|
|
book_id = review.book.id
|
|
|
|
review.delete()
|
|
|
|
return redirect(reverse("books:retrieve", args=[book_id]))
|
|
|
|
else:
|
|
|
|
return HttpResponseBadRequest()
|
|
|
|
|
|
|
|
|
|
|
|
@mastodon_request_included
|
|
|
|
@login_required
|
|
|
|
def retrieve_review(request, id):
|
|
|
|
if request.method == 'GET':
|
|
|
|
review = get_object_or_404(BookReview, pk=id)
|
|
|
|
if not check_visibility(review, request.session['oauth_token'], request.user):
|
2020-05-07 20:02:36 +08:00
|
|
|
msg = _("你没有访问这个页面的权限😥")
|
|
|
|
return render(
|
|
|
|
request,
|
|
|
|
'common/error.html',
|
|
|
|
{
|
|
|
|
'msg': msg,
|
|
|
|
}
|
|
|
|
)
|
2020-05-05 23:50:48 +08:00
|
|
|
review_form = BookReviewForm(instance=review)
|
|
|
|
book = review.book
|
|
|
|
try:
|
|
|
|
mark = BookMark.objects.get(owner=review.owner, book=book)
|
|
|
|
mark.get_status_display = BookMarkStatusTranslator(mark.status)
|
|
|
|
except ObjectDoesNotExist:
|
|
|
|
mark = None
|
|
|
|
return render(
|
|
|
|
request,
|
|
|
|
'books/review_detail.html',
|
|
|
|
{
|
|
|
|
'form': review_form,
|
|
|
|
'review': review,
|
|
|
|
'book': book,
|
|
|
|
'mark': mark,
|
|
|
|
}
|
|
|
|
)
|
|
|
|
else:
|
|
|
|
return HttpResponseBadRequest()
|
|
|
|
|
|
|
|
|
|
|
|
@mastodon_request_included
|
|
|
|
@login_required
|
|
|
|
def retrieve_review_list(request, book_id):
|
|
|
|
if request.method == 'GET':
|
|
|
|
book = get_object_or_404(Book, pk=book_id)
|
2020-07-10 21:28:09 +08:00
|
|
|
queryset = BookReview.get_available(
|
|
|
|
book, request.user, request.session['oauth_token'])
|
2020-05-05 23:50:48 +08:00
|
|
|
paginator = Paginator(queryset, REVIEW_PER_PAGE)
|
|
|
|
page_number = request.GET.get('page', default=1)
|
|
|
|
reviews = paginator.get_page(page_number)
|
2020-07-10 21:28:09 +08:00
|
|
|
reviews.pagination = PageLinksGenerator(
|
|
|
|
PAGE_LINK_NUMBER, page_number, paginator.num_pages)
|
2020-05-05 23:50:48 +08:00
|
|
|
return render(
|
|
|
|
request,
|
|
|
|
'books/review_list.html',
|
|
|
|
{
|
|
|
|
'reviews': reviews,
|
|
|
|
'book': book,
|
|
|
|
}
|
|
|
|
)
|
|
|
|
else:
|
|
|
|
return HttpResponseBadRequest()
|
|
|
|
|
|
|
|
|
|
|
|
@login_required
|
|
|
|
def scrape(request):
|
|
|
|
if request.method == 'GET':
|
2020-05-07 19:30:16 +08:00
|
|
|
keywords = request.GET.get('q')
|
2020-05-05 23:50:48 +08:00
|
|
|
form = BookForm()
|
|
|
|
return render(
|
|
|
|
request,
|
|
|
|
'books/scrape.html',
|
|
|
|
{
|
2020-05-07 19:30:16 +08:00
|
|
|
'q': keywords,
|
2020-05-05 23:50:48 +08:00
|
|
|
'form': form,
|
2020-05-01 22:46:15 +08:00
|
|
|
}
|
|
|
|
)
|
2020-05-12 14:05:12 +08:00
|
|
|
else:
|
|
|
|
return HttpResponseBadRequest()
|
|
|
|
|
|
|
|
|
|
|
|
@login_required
|
|
|
|
def click_to_scrape(request):
|
|
|
|
if request.method == "POST":
|
|
|
|
url = request.POST.get("url")
|
|
|
|
if url:
|
|
|
|
from common.scraper import scrape_douban_book
|
|
|
|
try:
|
|
|
|
scraped_book, raw_cover = scrape_douban_book(url)
|
|
|
|
except TimeoutError:
|
2020-05-15 15:06:57 +08:00
|
|
|
return render(request, 'common/error.html', {'msg': _("爬取数据失败😫,请重试")})
|
|
|
|
except ValueError:
|
|
|
|
return render(request, 'common/error.html', {'msg': _("链接非法,爬取失败")})
|
2020-07-10 21:28:09 +08:00
|
|
|
scraped_cover = {
|
|
|
|
'cover': SimpleUploadedFile('temp.jpg', raw_cover)}
|
2020-05-12 14:05:12 +08:00
|
|
|
form = BookForm(scraped_book, scraped_cover)
|
|
|
|
if form.is_valid():
|
|
|
|
form.instance.last_editor = request.user
|
|
|
|
form.save()
|
|
|
|
return redirect(reverse('books:retrieve', args=[form.instance.id]))
|
|
|
|
else:
|
2020-05-15 14:49:54 +08:00
|
|
|
if 'isbn' in form.errors:
|
|
|
|
msg = _("ISBN与现有图书重复")
|
|
|
|
else:
|
|
|
|
msg = _("爬取数据失败😫")
|
2020-10-11 20:07:32 +02:00
|
|
|
logger.error(str(form.errors))
|
2020-05-15 15:06:57 +08:00
|
|
|
return render(request, 'common/error.html', {'msg': msg})
|
2020-05-12 14:05:12 +08:00
|
|
|
else:
|
|
|
|
return HttpResponseBadRequest()
|
2020-05-01 22:46:15 +08:00
|
|
|
else:
|
2020-07-10 21:28:09 +08:00
|
|
|
return HttpResponseBadRequest()
|