lib.itmens/music/views.py
2022-11-09 02:41:53 +00:00

1154 lines
39 KiB
Python

from .forms import *
from .models import *
from common.models import SourceSiteEnum
from common.views import PAGE_LINK_NUMBER, jump_or_scrape, go_relogin
from common.utils import PageLinksGenerator
from mastodon.models import MastodonApplication
from mastodon.api import share_mark, share_review
from mastodon import mastodon_request_included
from django.core.paginator import Paginator
from django.utils import timezone
from django.db.models import Count
from django.db import IntegrityError, transaction
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
from django.http import HttpResponseBadRequest, HttpResponseServerError, HttpResponse
from django.utils.translation import gettext_lazy as _
from django.contrib.auth.decorators import login_required, permission_required
from django.shortcuts import render, get_object_or_404, redirect, reverse
import logging
from django.shortcuts import render
from collection.models import CollectionItem
from common.scraper import get_scraper_by_url, get_normalized_url
logger = logging.getLogger(__name__)
mastodon_logger = logging.getLogger("django.mastodon")
# 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
# max tags on detail page
TAG_NUMBER = 10
# public data
###########################
@login_required
def create_song(request):
if request.method == 'GET':
form = SongForm()
return render(
request,
'music/create_update_song.html',
{
'form': form,
'title': _('添加音乐'),
'submit_url': reverse("music:create_song"),
# provided for frontend js
'this_site_enum_value': SourceSiteEnum.IN_SITE.value,
}
)
elif request.method == 'POST':
if request.user.is_authenticated:
# only local user can alter public data
form = SongForm(request.POST, request.FILES)
if form.is_valid():
form.instance.last_editor = request.user
try:
with transaction.atomic():
form.save()
if form.instance.source_site == SourceSiteEnum.IN_SITE.value:
real_url = form.instance.get_absolute_url()
form.instance.source_url = real_url
form.instance.save()
except IntegrityError as e:
logger.error(e.__str__())
return HttpResponseServerError("integrity error")
return redirect(reverse("music:retrieve_song", args=[form.instance.id]))
else:
return render(
request,
'music/create_update_song.html',
{
'form': form,
'title': _('添加音乐'),
'submit_url': reverse("music:create_song"),
# provided for frontend js
'this_site_enum_value': SourceSiteEnum.IN_SITE.value,
}
)
else:
return redirect(reverse("users:login"))
else:
return HttpResponseBadRequest()
@login_required
def update_song(request, id):
if request.method == 'GET':
song = get_object_or_404(Song, pk=id)
form = SongForm(instance=song)
page_title = _('修改音乐')
return render(
request,
'music/create_update_song.html',
{
'form': form,
'is_update': True,
'title': page_title,
'submit_url': reverse("music:update_song", args=[song.id]),
# provided for frontend js
'this_site_enum_value': SourceSiteEnum.IN_SITE.value,
}
)
elif request.method == 'POST':
song = get_object_or_404(Song, pk=id)
form = SongForm(request.POST, request.FILES, instance=song)
page_title = _('修改音乐')
if form.is_valid():
form.instance.last_editor = request.user
form.instance.edited_time = timezone.now()
try:
with transaction.atomic():
form.save()
if form.instance.source_site == SourceSiteEnum.IN_SITE.value:
real_url = form.instance.get_absolute_url()
form.instance.source_url = real_url
form.instance.save()
except IntegrityError as e:
logger.error(e.__str__())
return HttpResponseServerError("integrity error")
else:
return render(
request,
'music/create_update_song.html',
{
'form': form,
'is_update': True,
'title': page_title,
'submit_url': reverse("music:update_song", args=[song.id]),
# provided for frontend js
'this_site_enum_value': SourceSiteEnum.IN_SITE.value,
}
)
return redirect(reverse("music:retrieve_song", args=[form.instance.id]))
else:
return HttpResponseBadRequest()
@mastodon_request_included
# @login_required
def retrieve_song(request, id):
if request.method == 'GET':
song = get_object_or_404(Song, pk=id)
mark = None
mark_tags = None
review = None
def ms_to_readable(ms):
if not ms:
return
x = ms // 1000
seconds = x % 60
x //= 60
if x == 0:
return f"{seconds}"
minutes = x % 60
x //= 60
if x == 0:
return f"{minutes}{seconds}"
hours = x % 24
return f"{hours}{minutes}{seconds}"
song.get_duration_display = ms_to_readable(song.duration)
# retrieve tags
song_tag_list = song.song_tags.values('content').annotate(
tag_frequency=Count('content')).order_by('-tag_frequency')[:TAG_NUMBER]
# retrieve user mark and initialize mark form
try:
if request.user.is_authenticated:
mark = SongMark.objects.get(owner=request.user, song=song)
except ObjectDoesNotExist:
mark = None
if mark:
mark_tags = mark.songmark_tags.all()
mark.get_status_display = MusicMarkStatusTranslator(mark.status)
mark_form = SongMarkForm(instance=mark, initial={
'tags': mark_tags
})
else:
mark_form = SongMarkForm(initial={
'song': song,
'visibility': request.user.get_preference().default_visibility if request.user.is_authenticated else 0,
'tags': mark_tags
})
# retrieve user review
try:
if request.user.is_authenticated:
review = SongReview.objects.get(
owner=request.user, song=song)
except ObjectDoesNotExist:
review = None
# retrieve other related reviews and marks
if request.user.is_anonymous:
# hide all marks and reviews for anonymous user
mark_list = None
review_list = None
mark_list_more = None
review_list_more = None
else:
mark_list = SongMark.get_available(song, request.user)
review_list = SongReview.get_available(song, request.user)
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 = MusicMarkStatusTranslator(m.status)
review_list_more = True if len(
review_list) > REVIEW_NUMBER else False
review_list = review_list[:REVIEW_NUMBER]
all_collections = CollectionItem.objects.filter(song=song).annotate(num_marks=Count('collection__collection_marks')).order_by('-num_marks')[:20]
collection_list = filter(lambda c: c.is_visible_to(request.user), map(lambda i: i.collection, all_collections))
# 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)
return render(
request,
'music/song_detail.html',
{
'song': song,
'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,
'song_tag_list': song_tag_list,
'mark_tags': mark_tags,
'collection_list': collection_list,
}
)
else:
logger.warning('non-GET method at /song/<id>')
return HttpResponseBadRequest()
@permission_required("music.delete_song")
@login_required
def delete_song(request, id):
if request.method == 'GET':
song = get_object_or_404(Song, pk=id)
return render(
request,
'music/delete_song.html',
{
'song': song,
}
)
elif request.method == 'POST':
if request.user.is_staff:
# only staff has right to delete
song = get_object_or_404(Song, pk=id)
song.delete()
return redirect(reverse("common:home"))
else:
raise PermissionDenied()
else:
return HttpResponseBadRequest()
# user owned entites
###########################
@mastodon_request_included
@login_required
def create_update_song_mark(request):
# check list:
# clean rating if is wish
# transaction on updating song rating
# owner check(guarantee)
if request.method == 'POST':
pk = request.POST.get('id')
old_rating = None
old_tags = None
if not pk:
song_id = request.POST.get('song')
mark = SongMark.objects.filter(song_id=song_id, owner=request.user).first()
if mark:
pk = mark.id
if pk:
mark = get_object_or_404(SongMark, pk=pk)
if request.user != mark.owner:
return HttpResponseBadRequest()
old_rating = mark.rating
old_tags = mark.songmark_tags.all()
if mark.status != request.POST.get('status'):
mark.created_time = timezone.now()
# update
form = SongMarkForm(request.POST, instance=mark)
else:
# create
form = SongMarkForm(request.POST)
if form.is_valid():
if form.instance.status == MarkStatusEnum.WISH.value or form.instance.rating == 0:
form.instance.rating = None
form.cleaned_data['rating'] = None
form.instance.owner = request.user
form.instance.edited_time = timezone.now()
song = form.instance.song
try:
with transaction.atomic():
# update song rating
song.update_rating(old_rating, form.instance.rating)
form.save()
# update tags
if old_tags:
for tag in old_tags:
tag.delete()
if form.cleaned_data['tags']:
for tag in form.cleaned_data['tags']:
SongTag.objects.create(
content=tag,
song=song,
mark=form.instance
)
except IntegrityError as e:
logger.error(e.__str__())
return HttpResponseServerError("integrity error")
if form.cleaned_data['share_to_mastodon']:
if not share_mark(form.instance):
return go_relogin(request)
else:
return HttpResponseBadRequest(f"invalid form data {form.errors}")
return redirect(reverse("music:retrieve_song", args=[form.instance.song.id]))
else:
return HttpResponseBadRequest("invalid method")
@mastodon_request_included
@login_required
def wish_song(request, id):
if request.method == 'POST':
song = get_object_or_404(Song, pk=id)
params = {
'owner': request.user,
'status': MarkStatusEnum.WISH,
'visibility': 0,
'song': song,
}
try:
SongMark.objects.create(**params)
except Exception:
pass
return HttpResponse("✔️")
else:
return HttpResponseBadRequest("invalid method")
@mastodon_request_included
@login_required
def retrieve_song_mark_list(request, song_id, following_only=False):
if request.method == 'GET':
song = get_object_or_404(Song, pk=song_id)
queryset = SongMark.get_available(song, request.user, following_only=following_only)
paginator = Paginator(queryset, MARK_PER_PAGE)
page_number = request.GET.get('page', default=1)
marks = paginator.get_page(page_number)
marks.pagination = PageLinksGenerator(
PAGE_LINK_NUMBER, page_number, paginator.num_pages)
for m in marks:
m.get_status_display = MusicMarkStatusTranslator(m.status)
return render(
request,
'music/song_mark_list.html',
{
'marks': marks,
'song': song,
}
)
else:
return HttpResponseBadRequest()
@login_required
def delete_song_mark(request, id):
if request.method == 'POST':
mark = get_object_or_404(SongMark, pk=id)
if request.user != mark.owner:
return HttpResponseBadRequest()
song_id = mark.song.id
try:
with transaction.atomic():
# update song rating
mark.song.update_rating(mark.rating, None)
mark.delete()
except IntegrityError as e:
return HttpResponseServerError()
return redirect(reverse("music:retrieve_song", args=[song_id]))
else:
return HttpResponseBadRequest()
@mastodon_request_included
@login_required
def create_song_review(request, song_id):
if request.method == 'GET':
form = SongReviewForm(initial={'song': song_id})
song = get_object_or_404(Song, pk=song_id)
return render(
request,
'music/create_update_song_review.html',
{
'form': form,
'title': _("添加评论"),
'song': song,
'submit_url': reverse("music:create_song_review", args=[song_id]),
}
)
elif request.method == 'POST':
form = SongReviewForm(request.POST)
if form.is_valid():
form.instance.owner = request.user
form.save()
if form.cleaned_data['share_to_mastodon']:
if not share_review(form.instance):
return go_relogin(request)
return redirect(reverse("music:retrieve_song_review", args=[form.instance.id]))
else:
return HttpResponseBadRequest()
else:
return HttpResponseBadRequest()
@mastodon_request_included
@login_required
def update_song_review(request, id):
if request.method == 'GET':
review = get_object_or_404(SongReview, pk=id)
if request.user != review.owner:
return HttpResponseBadRequest()
form = SongReviewForm(instance=review)
song = review.song
return render(
request,
'music/create_update_song_review.html',
{
'form': form,
'title': _("编辑评论"),
'song': song,
'submit_url': reverse("music:update_song_review", args=[review.id]),
}
)
elif request.method == 'POST':
review = get_object_or_404(SongReview, pk=id)
if request.user != review.owner:
return HttpResponseBadRequest()
form = SongReviewForm(request.POST, instance=review)
if form.is_valid():
form.instance.edited_time = timezone.now()
form.save()
if form.cleaned_data['share_to_mastodon']:
if not share_review(form.instance):
return go_relogin(request)
return redirect(reverse("music:retrieve_song_review", args=[form.instance.id]))
else:
return HttpResponseBadRequest()
else:
return HttpResponseBadRequest()
@login_required
def delete_song_review(request, id):
if request.method == 'GET':
review = get_object_or_404(SongReview, pk=id)
if request.user != review.owner:
return HttpResponseBadRequest()
review_form = SongReviewForm(instance=review)
return render(
request,
'music/delete_song_review.html',
{
'form': review_form,
'review': review,
}
)
elif request.method == 'POST':
review = get_object_or_404(SongReview, pk=id)
if request.user != review.owner:
return HttpResponseBadRequest()
song_id = review.song.id
review.delete()
return redirect(reverse("music:retrieve_song", args=[song_id]))
else:
return HttpResponseBadRequest()
@mastodon_request_included
def retrieve_song_review(request, id):
if request.method == 'GET':
review = get_object_or_404(SongReview, pk=id)
if not review.is_visible_to(request.user):
msg = _("你没有访问这个页面的权限😥")
return render(
request,
'common/error.html',
{
'msg': msg,
}
)
review_form = SongReviewForm(instance=review)
song = review.song
try:
mark = SongMark.objects.get(owner=review.owner, song=song)
mark.get_status_display = MusicMarkStatusTranslator(mark.status)
except ObjectDoesNotExist:
mark = None
return render(
request,
'music/song_review_detail.html',
{
'form': review_form,
'review': review,
'song': song,
'mark': mark,
}
)
else:
return HttpResponseBadRequest()
@mastodon_request_included
@login_required
def retrieve_song_review_list(request, song_id):
if request.method == 'GET':
song = get_object_or_404(Song, pk=song_id)
queryset = SongReview.get_available(song, request.user)
paginator = Paginator(queryset, REVIEW_PER_PAGE)
page_number = request.GET.get('page', default=1)
reviews = paginator.get_page(page_number)
reviews.pagination = PageLinksGenerator(
PAGE_LINK_NUMBER, page_number, paginator.num_pages)
return render(
request,
'music/song_review_list.html',
{
'reviews': reviews,
'song': song,
}
)
else:
return HttpResponseBadRequest()
@login_required
def scrape_song(request):
if request.method == 'GET':
keywords = request.GET.get('q')
form = SongForm()
return render(
request,
'music/scrape_song.html',
{
'q': keywords,
'form': form,
}
)
else:
return HttpResponseBadRequest()
@login_required
def click_to_scrape_song(request):
if request.method == "POST":
url = request.POST.get("url")
if url:
return jump_or_scrape(request, url)
else:
return HttpResponseBadRequest()
else:
return HttpResponseBadRequest()
@login_required
def create_album(request):
if request.method == 'GET':
form = AlbumForm()
return render(
request,
'music/create_update_album.html',
{
'form': form,
'title': _('添加音乐'),
'submit_url': reverse("music:create_album"),
# provided for frontend js
'this_site_enum_value': SourceSiteEnum.IN_SITE.value,
}
)
elif request.method == 'POST':
if request.user.is_authenticated:
# only local user can alter public data
form = AlbumForm(request.POST, request.FILES)
if form.is_valid():
form.instance.last_editor = request.user
try:
with transaction.atomic():
form.save()
if form.instance.source_site == SourceSiteEnum.IN_SITE.value:
real_url = form.instance.get_absolute_url()
form.instance.source_url = real_url
form.instance.save()
except IntegrityError as e:
logger.error(e.__str__())
return HttpResponseServerError("integrity error")
return redirect(reverse("music:retrieve_album", args=[form.instance.id]))
else:
return render(
request,
'music/create_update_album.html',
{
'form': form,
'title': _('添加音乐'),
'submit_url': reverse("music:create_album"),
# provided for frontend js
'this_site_enum_value': SourceSiteEnum.IN_SITE.value,
}
)
else:
return redirect(reverse("users:login"))
else:
return HttpResponseBadRequest()
@login_required
def rescrape(request, id):
if request.method != 'POST':
return HttpResponseBadRequest()
item = get_object_or_404(Album, pk=id)
url = get_normalized_url(item.source_url)
scraper = get_scraper_by_url(url)
scraper.scrape(url)
form = scraper.save(request_user=request.user, instance=item)
return redirect(reverse("music:retrieve_album", args=[form.instance.id]))
@login_required
def update_album(request, id):
if request.method == 'GET':
album = get_object_or_404(Album, pk=id)
form = AlbumForm(instance=album)
page_title = _('修改音乐')
return render(
request,
'music/create_update_album.html',
{
'form': form,
'is_update': True,
'title': page_title,
'submit_url': reverse("music:update_album", args=[album.id]),
# provided for frontend js
'this_site_enum_value': SourceSiteEnum.IN_SITE.value,
}
)
elif request.method == 'POST':
album = get_object_or_404(Album, pk=id)
form = AlbumForm(request.POST, request.FILES, instance=album)
page_title = _('修改音乐')
if form.is_valid():
form.instance.last_editor = request.user
form.instance.edited_time = timezone.now()
try:
with transaction.atomic():
form.save()
if form.instance.source_site == SourceSiteEnum.IN_SITE.value:
real_url = form.instance.get_absolute_url()
form.instance.source_url = real_url
form.instance.save()
except IntegrityError as e:
logger.error(e.__str__())
return HttpResponseServerError("integrity error")
else:
return render(
request,
'music/create_update_album.html',
{
'form': form,
'is_update': True,
'title': page_title,
'submit_url': reverse("music:update_album", args=[album.id]),
# provided for frontend js
'this_site_enum_value': SourceSiteEnum.IN_SITE.value,
}
)
return redirect(reverse("music:retrieve_album", args=[form.instance.id]))
else:
return HttpResponseBadRequest()
@mastodon_request_included
# @login_required
def retrieve_album(request, id):
if request.method == 'GET':
album = get_object_or_404(Album, pk=id)
mark = None
mark_tags = None
review = None
def ms_to_readable(ms):
if not ms:
return
x = ms // 1000
seconds = x % 60
x //= 60
if x == 0:
return f"{seconds}"
minutes = x % 60
x //= 60
if x == 0:
return f"{minutes}{seconds}"
hours = x % 24
return f"{hours}{minutes}{seconds}"
album.get_duration_display = ms_to_readable(album.duration)
# retrieve tags
album_tag_list = album.album_tags.values('content').annotate(
tag_frequency=Count('content')).order_by('-tag_frequency')[:TAG_NUMBER]
# retrieve user mark and initialize mark form
try:
if request.user.is_authenticated:
mark = AlbumMark.objects.get(owner=request.user, album=album)
except ObjectDoesNotExist:
mark = None
if mark:
mark_tags = mark.albummark_tags.all()
mark.get_status_display = MusicMarkStatusTranslator(mark.status)
mark_form = AlbumMarkForm(instance=mark, initial={
'tags': mark_tags
})
else:
mark_form = AlbumMarkForm(initial={
'album': album,
'visibility': request.user.get_preference().default_visibility if request.user.is_authenticated else 0,
'tags': mark_tags
})
# retrieve user review
try:
if request.user.is_authenticated:
review = AlbumReview.objects.get(
owner=request.user, album=album)
except ObjectDoesNotExist:
review = None
# retrieve other related reviews and marks
if request.user.is_anonymous:
# hide all marks and reviews for anonymous user
mark_list = None
review_list = None
mark_list_more = None
review_list_more = None
else:
mark_list = AlbumMark.get_available(album, request.user)
review_list = AlbumReview.get_available(album, request.user)
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 = MusicMarkStatusTranslator(m.status)
review_list_more = True if len(
review_list) > REVIEW_NUMBER else False
review_list = review_list[:REVIEW_NUMBER]
all_collections = CollectionItem.objects.filter(album=album).annotate(num_marks=Count('collection__collection_marks')).order_by('-num_marks')[:20]
collection_list = filter(lambda c: c.is_visible_to(request.user), map(lambda i: i.collection, all_collections))
# 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)
return render(
request,
'music/album_detail.html',
{
'album': album,
'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,
'album_tag_list': album_tag_list,
'mark_tags': mark_tags,
'collection_list': collection_list,
}
)
else:
logger.warning('non-GET method at /album/<id>')
return HttpResponseBadRequest()
@permission_required("music.delete_album")
@login_required
def delete_album(request, id):
if request.method == 'GET':
album = get_object_or_404(Album, pk=id)
return render(
request,
'music/delete_album.html',
{
'album': album,
}
)
elif request.method == 'POST':
if request.user.is_staff:
# only staff has right to delete
album = get_object_or_404(Album, pk=id)
album.delete()
return redirect(reverse("common:home"))
else:
raise PermissionDenied()
else:
return HttpResponseBadRequest()
# user owned entites
###########################
@mastodon_request_included
@login_required
def create_update_album_mark(request):
# check list:
# clean rating if is wish
# transaction on updating album rating
# owner check(guarantee)
if request.method == 'POST':
pk = request.POST.get('id')
old_rating = None
old_tags = None
if not pk:
album_id = request.POST.get('album')
mark = AlbumMark.objects.filter(album_id=album_id, owner=request.user).first()
if mark:
pk = mark.id
if pk:
mark = get_object_or_404(AlbumMark, pk=pk)
if request.user != mark.owner:
return HttpResponseBadRequest()
old_rating = mark.rating
old_tags = mark.albummark_tags.all()
if mark.status != request.POST.get('status'):
mark.created_time = timezone.now()
# update
form = AlbumMarkForm(request.POST, instance=mark)
else:
# create
form = AlbumMarkForm(request.POST)
if form.is_valid():
if form.instance.status == MarkStatusEnum.WISH.value or form.instance.rating == 0:
form.instance.rating = None
form.cleaned_data['rating'] = None
form.instance.owner = request.user
form.instance.edited_time = timezone.now()
album = form.instance.album
try:
with transaction.atomic():
# update album rating
album.update_rating(old_rating, form.instance.rating)
form.save()
# update tags
if old_tags:
for tag in old_tags:
tag.delete()
if form.cleaned_data['tags']:
for tag in form.cleaned_data['tags']:
AlbumTag.objects.create(
content=tag,
album=album,
mark=form.instance
)
except IntegrityError as e:
logger.error(e.__str__())
return HttpResponseServerError("integrity error")
if form.cleaned_data['share_to_mastodon']:
if not share_mark(form.instance):
return go_relogin(request)
else:
return HttpResponseBadRequest(f"invalid form data {form.errors}")
return redirect(reverse("music:retrieve_album", args=[form.instance.album.id]))
else:
return HttpResponseBadRequest("invalid method")
@mastodon_request_included
@login_required
def wish_album(request, id):
if request.method == 'POST':
album = get_object_or_404(Album, pk=id)
params = {
'owner': request.user,
'status': MarkStatusEnum.WISH,
'visibility': 0,
'album': album,
}
try:
AlbumMark.objects.create(**params)
except Exception:
pass
return HttpResponse("✔️")
else:
return HttpResponseBadRequest("invalid method")
@mastodon_request_included
@login_required
def retrieve_album_mark_list(request, album_id, following_only=False):
if request.method == 'GET':
album = get_object_or_404(Album, pk=album_id)
queryset = AlbumMark.get_available(album, request.user, following_only=following_only)
paginator = Paginator(queryset, MARK_PER_PAGE)
page_number = request.GET.get('page', default=1)
marks = paginator.get_page(page_number)
marks.pagination = PageLinksGenerator(
PAGE_LINK_NUMBER, page_number, paginator.num_pages)
for m in marks:
m.get_status_display = MusicMarkStatusTranslator(m.status)
return render(
request,
'music/album_mark_list.html',
{
'marks': marks,
'album': album,
}
)
else:
return HttpResponseBadRequest()
@login_required
def delete_album_mark(request, id):
if request.method == 'POST':
mark = get_object_or_404(AlbumMark, pk=id)
if request.user != mark.owner:
return HttpResponseBadRequest()
album_id = mark.album.id
try:
with transaction.atomic():
# update album rating
mark.album.update_rating(mark.rating, None)
mark.delete()
except IntegrityError as e:
return HttpResponseServerError()
return redirect(reverse("music:retrieve_album", args=[album_id]))
else:
return HttpResponseBadRequest()
@mastodon_request_included
@login_required
def create_album_review(request, album_id):
if request.method == 'GET':
form = AlbumReviewForm(initial={'album': album_id})
album = get_object_or_404(Album, pk=album_id)
return render(
request,
'music/create_update_album_review.html',
{
'form': form,
'title': _("添加评论"),
'album': album,
'submit_url': reverse("music:create_album_review", args=[album_id]),
}
)
elif request.method == 'POST':
form = AlbumReviewForm(request.POST)
if form.is_valid():
form.instance.owner = request.user
form.save()
if form.cleaned_data['share_to_mastodon']:
if not share_review(form.instance):
return go_relogin(request)
return redirect(reverse("music:retrieve_album_review", args=[form.instance.id]))
else:
return HttpResponseBadRequest()
else:
return HttpResponseBadRequest()
@mastodon_request_included
@login_required
def update_album_review(request, id):
if request.method == 'GET':
review = get_object_or_404(AlbumReview, pk=id)
if request.user != review.owner:
return HttpResponseBadRequest()
form = AlbumReviewForm(instance=review)
album = review.album
return render(
request,
'music/create_update_album_review.html',
{
'form': form,
'title': _("编辑评论"),
'album': album,
'submit_url': reverse("music:update_album_review", args=[review.id]),
}
)
elif request.method == 'POST':
review = get_object_or_404(AlbumReview, pk=id)
if request.user != review.owner:
return HttpResponseBadRequest()
form = AlbumReviewForm(request.POST, instance=review)
if form.is_valid():
form.instance.edited_time = timezone.now()
form.save()
if form.cleaned_data['share_to_mastodon']:
if not share_review(form.instance):
return go_relogin(request)
return redirect(reverse("music:retrieve_album_review", args=[form.instance.id]))
else:
return HttpResponseBadRequest()
else:
return HttpResponseBadRequest()
@login_required
def delete_album_review(request, id):
if request.method == 'GET':
review = get_object_or_404(AlbumReview, pk=id)
if request.user != review.owner:
return HttpResponseBadRequest()
review_form = AlbumReviewForm(instance=review)
return render(
request,
'music/delete_album_review.html',
{
'form': review_form,
'review': review,
}
)
elif request.method == 'POST':
review = get_object_or_404(AlbumReview, pk=id)
if request.user != review.owner:
return HttpResponseBadRequest()
album_id = review.album.id
review.delete()
return redirect(reverse("music:retrieve_album", args=[album_id]))
else:
return HttpResponseBadRequest()
@mastodon_request_included
def retrieve_album_review(request, id):
if request.method == 'GET':
review = get_object_or_404(AlbumReview, pk=id)
if not review.is_visible_to(request.user):
msg = _("你没有访问这个页面的权限😥")
return render(
request,
'common/error.html',
{
'msg': msg,
}
)
review_form = AlbumReviewForm(instance=review)
album = review.album
try:
mark = AlbumMark.objects.get(owner=review.owner, album=album)
mark.get_status_display = MusicMarkStatusTranslator(mark.status)
except ObjectDoesNotExist:
mark = None
return render(
request,
'music/album_review_detail.html',
{
'form': review_form,
'review': review,
'album': album,
'mark': mark,
}
)
else:
return HttpResponseBadRequest()
@mastodon_request_included
@login_required
def retrieve_album_review_list(request, album_id):
if request.method == 'GET':
album = get_object_or_404(Album, pk=album_id)
queryset = AlbumReview.get_available(album, request.user)
paginator = Paginator(queryset, REVIEW_PER_PAGE)
page_number = request.GET.get('page', default=1)
reviews = paginator.get_page(page_number)
reviews.pagination = PageLinksGenerator(
PAGE_LINK_NUMBER, page_number, paginator.num_pages)
return render(
request,
'music/album_review_list.html',
{
'reviews': reviews,
'album': album,
}
)
else:
return HttpResponseBadRequest()
@login_required
def scrape_album(request):
if request.method == 'GET':
keywords = request.GET.get('q')
form = AlbumForm()
return render(
request,
'music/scrape_album.html',
{
'q': keywords,
'form': form,
}
)
else:
return HttpResponseBadRequest()
@login_required
def click_to_scrape_album(request):
if request.method == "POST":
url = request.POST.get("url")
if url:
return jump_or_scrape(request, url)
else:
return HttpResponseBadRequest()
else:
return HttpResponseBadRequest()