This commit is contained in:
Your Name 2021-12-24 11:54:12 -08:00
parent c7b25744f6
commit 3875a82381
5 changed files with 258 additions and 104 deletions

View file

@ -2,28 +2,39 @@ from django import forms
from django.contrib.postgres.forms import SimpleArrayField
from django.utils.translation import gettext_lazy as _
from .models import Collection
from common.models import MarkStatusEnum
from common.forms import *
class CollectionForm(forms.ModelForm):
# id = forms.IntegerField(required=False, widget=forms.HiddenInput())
name = forms.CharField(label=_("标题"))
title = forms.CharField(label=_("标题"))
description = MarkdownxFormField(label=_("正文 (Markdown)"))
share_to_mastodon = forms.BooleanField(
label=_("分享到联邦网络"), initial=True, required=False)
rating = forms.IntegerField(
label=_("评分"), validators=[RatingValidator()], widget=forms.HiddenInput(), required=False)
visibility = forms.TypedChoiceField(
label=_("可见性"),
initial=0,
coerce=int,
choices=VISIBILITY_CHOICES,
widget=forms.RadioSelect
)
class Meta:
model = Collection
fields = [
'name',
'title',
'visibility',
'description',
'cover',
]
widgets = {
'name': forms.TextInput(attrs={'placeholder': _("收藏单名称")}),
'developer': forms.TextInput(attrs={'placeholder': _("多个开发商使用英文逗号分隔")}),
'publisher': forms.TextInput(attrs={'placeholder': _("多个发行商使用英文逗号分隔")}),
'genre': forms.TextInput(attrs={'placeholder': _("多个类型使用英文逗号分隔")}),
'platform': forms.TextInput(attrs={'placeholder': _("多个平台使用英文逗号分隔")}),
# 'name': forms.TextInput(attrs={'placeholder': _("收藏单名称")}),
# 'developer': forms.TextInput(attrs={'placeholder': _("多个开发商使用英文逗号分隔")}),
# 'publisher': forms.TextInput(attrs={'placeholder': _("多个发行商使用英文逗号分隔")}),
# 'genre': forms.TextInput(attrs={'placeholder': _("多个类型使用英文逗号分隔")}),
# 'platform': forms.TextInput(attrs={'placeholder': _("多个平台使用英文逗号分隔")}),
'cover': PreviewImageInput(),
}

View file

@ -5,8 +5,9 @@ from books.models import Book
from music.models import Song, Album
from games.models import Game
from markdownx.models import MarkdownxField
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from django.conf import settings
from common.utils import ChoicesDictGenerator, GenerateDateUUIDMediaFilePath
def collection_cover_path(instance, filename):
@ -14,7 +15,7 @@ def collection_cover_path(instance, filename):
class Collection(UserOwnedEntity):
name = models.CharField(max_length=200)
title = models.CharField(max_length=200)
description = MarkdownxField()
cover = models.ImageField(_("封面"), upload_to=collection_cover_path, default=settings.DEFAULT_COLLECTION_IMAGE, blank=True)

View file

@ -0,0 +1,90 @@
{% load static %}
{% load i18n %}
{% load admin_url %}
{% load mastodon %}
{% load oauth_token %}
{% load truncate %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ site_name }} - {{ title }}</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<link rel="stylesheet" href="{% static 'css/boofilsic.min.css' %}">
</head>
<body>
<div id="page-wrapper">
<div id="content-wrapper">
{% include "partial/_navbar.html" %}
<section id="content" class="container">
<div class="grid">
<div class="single-section-wrapper" id="main">
<form class="entity-form" action="{{ submit_url }}" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.media }}
{% for field in form %}
{% if field.name == 'release_date' %}
{{ field.label_tag }}
{% else %}
{% if field.name != 'id' %}
{{ field.label_tag }}
{% endif %}
{{ field }}
{% endif %}
{% endfor %}
<input class="button" type="submit" value="{% trans '提交' %}">
</form>
</div>
</section>
</div>
{% include "partial/_footer.html" %}
</div>
{% comment %}
<div id="oauth2Token" hidden="true">{% oauth_token %}</div>
<div id="mastodonURI" hidden="true">{% mastodon request.user.mastodon_site %}</div>
<!--current user mastodon id-->
<div id="userMastodonID" hidden="true">{{ user.mastodon_id }}</div>
{% endcomment %}
<script>
// mark required
$("#content *[required]").each(function () {
$(this).prev().prepend("*");
});
// when source site is this site, hide url input box and populate it with fake url
// the backend would update this field
if ($("select[name='source_site']").val() == "{{ this_site_enum_value }}") {
$("input[name='source_url']").hide();
$("label[for='id_source_url']").hide();
$("input[name='source_url']").val("https://www.temp.com/" + Date.now() + Math.random());
}
$("select[name='source_site']").change(function () {
let value = $(this).val();
if (value == "{{ this_site_enum_value }}") {
$("input[name='source_url']").hide();
$("label[for='id_source_url']").hide();
$("input[name='source_url']").val("https://www.temp.com/" + Date.now() + Math.random());
} else {
$("input[name='source_url']").show();
$("label[for='id_source_url']").show();
$("input[name='source_url']").val("");
}
});
</script>
</body>
</html>

View file

@ -0,0 +1,114 @@
{% load static %}
{% load i18n %}
{% load l10n %}
{% load humanize %}
{% load admin_url %}
{% load mastodon %}
{% load oauth_token %}
{% load truncate %}
{% load thumb %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta property="og:title" content="{{ site_name }} {% trans '收藏單' %} - {{ collection.title }}">
<meta property="og:type" content="article">
<meta property="og:article:author" content="{{ collection.owner.username }}">
<meta property="og:url" content="{{ request.build_absolute_uri }}">
<meta property="og:image" content="{{ request.scheme }}://{{ request.get_host }}{% static 'img/logo_square.svg' %}">
<title>{{ site_name }} {% trans '收藏單' %} - {{ collection.title }}</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="{% static 'lib/js/rating-star.js' %}"></script>
<script src="{% static 'js/rating-star-readonly.js' %}"></script>
<link rel="stylesheet" href="{% static 'lib/css/rating-star.css' %}">
<link rel="stylesheet" href="{% static 'css/boofilsic.min.css' %}">
</head>
<body>
<div id="page-wrapper">
<div id="content-wrapper">
{% include "partial/_navbar.html" %}
<section id="content">
<div class="grid">
<div class="grid__main" id="main">
<div class="main-section-wrapper">
<div class="review-head">
<h5 class="review-head__title">
{{ collection.title }}
</h5>
{% if collection.visibility > 0 %}
<span class="icon-lock"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
<path
d="M17,8.48h-.73V6.27a6.27,6.27,0,1,0-12.53,0V8.48H3a.67.67,0,0,0-.67.67V19.33A.67.67,0,0,0,3,20H17a.67.67,0,0,0,.67-.67V9.15A.67.67,0,0,0,17,8.48ZM6.42,6.27h0a3.57,3.57,0,0,1,7.14,0h0V8.48H6.42Z" />
</svg></span>
{% endif %}
<div class="review-head__body">
<div class="review-head__info">
<a href="{% url 'users:home' collection.owner.id %}" class="review-head__owner-link">{{ collection.owner.mastodon_username }}</a>
<span class="review-head__time">{{ collection.edited_time }}</span>
</div>
<div class="review-head__actions">
{% if request.user == collection.owner %}
<a class="review-head__action-link" href="{% url 'collection:update' collection.id %}">{% trans '编辑' %}</a>
<a class="review-head__action-link" href="{% url 'collection:delete' collection.id %}">{% trans '删除' %}</a>
{% endif %}
</div>
</div>
<!-- <div class="dividing-line"></div> -->
<div id="rawContent">
{{ form.description }}
</div>
{{ form.media }}
</div>
</div>
</div>
<div class="grid__aside" id="aside">
<div class="aside-section-wrapper">
<div class="entity-card">
<div class="entity-card__img-wrapper">
<a href="{% url 'collection:retrieve' collection.id %}"><img src="{{ collection.cover|thumb:'normal' }}" alt=""
class="entity-card__img"></a>
</div>
<div class="entity-card__info-wrapper">
<h5 class="entity-card__title">
<a href="{% url 'collection:retrieve' collection.id %}">
{{ collection.title }}
</a>
</h5>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
{% include "partial/_footer.html" %}
</div>
{% comment %}
<div id="oauth2Token" hidden="true">{% oauth_token %}</div>
<div id="mastodonURI" hidden="true">{% mastodon request.user.mastodon_site %}</div>
<!--current user mastodon id-->
<div id="userMastodonID" hidden="true">{{ user.mastodon_id }}</div>
{% endcomment %}
<script>
$(".markdownx textarea").hide();
</script>
</body>
</html>

View file

@ -41,14 +41,14 @@ TAG_NUMBER = 10
@login_required
def create(request):
if request.method == 'GET':
form = GameForm()
form = CollectionForm()
return render(
request,
'games/create_update.html',
'create_update.html',
{
'form': form,
'title': _('添加游戏'),
'submit_url': reverse("games:create"),
'title': _('添加收藏单'),
'submit_url': reverse("collection:create"),
# provided for frontend js
'this_site_enum_value': SourceSiteEnum.IN_SITE.value,
}
@ -56,28 +56,25 @@ def create(request):
elif request.method == 'POST':
if request.user.is_authenticated:
# only local user can alter public data
form = GameForm(request.POST, request.FILES)
form = CollectionForm(request.POST, request.FILES)
form.instance.owner = request.user
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("games:retrieve", args=[form.instance.id]))
return redirect(reverse("collection:retrieve", args=[form.instance.id]))
else:
return render(
request,
'games/create_update.html',
'create_update.html',
{
'form': form,
'title': _('添加游戏'),
'submit_url': reverse("games:create"),
'title': _('添加收藏單'),
'submit_url': reverse("collection:create"),
# provided for frontend js
'this_site_enum_value': SourceSiteEnum.IN_SITE.value,
}
@ -90,25 +87,25 @@ def create(request):
@login_required
def update(request, id):
page_title = _("修改游戏")
collection = get_object_or_404(Collection, pk=id)
if not collection.is_visible_to(request.user):
raise PermissionDenied()
if request.method == 'GET':
game = get_object_or_404(Game, pk=id)
form = GameForm(instance=game)
page_title = _('修改游戏')
form = CollectionForm(instance=collection)
return render(
request,
'games/create_update.html',
'create_update.html',
{
'form': form,
'title': page_title,
'submit_url': reverse("games:update", args=[game.id]),
'submit_url': reverse("collection:update", args=[collection.id]),
# provided for frontend js
'this_site_enum_value': SourceSiteEnum.IN_SITE.value,
}
)
elif request.method == 'POST':
game = get_object_or_404(Game, pk=id)
form = GameForm(request.POST, request.FILES, instance=game)
page_title = _("修改游戏")
form = CollectionForm(request.POST, request.FILES, instance=collection)
if form.is_valid():
form.instance.last_editor = request.user
form.instance.edited_time = timezone.now()
@ -125,11 +122,11 @@ def update(request, id):
else:
return render(
request,
'games/create_update.html',
'create_update.html',
{
'form': form,
'title': page_title,
'submit_url': reverse("games:update", args=[game.id]),
'submit_url': reverse("collection:update", args=[collection.id]),
# provided for frontend js
'this_site_enum_value': SourceSiteEnum.IN_SITE.value,
}
@ -144,82 +141,23 @@ def update(request, id):
# @login_required
def retrieve(request, id):
if request.method == 'GET':
game = get_object_or_404(Game, pk=id)
mark = None
mark_tags = None
review = None
collection = get_object_or_404(Collection, pk=id)
if not collection.is_visible_to(request.user):
raise PermissionDenied()
form = CollectionForm(instance=collection)
# retreive tags
game_tag_list = game.game_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 = GameMark.objects.get(owner=request.user, game=game)
except ObjectDoesNotExist:
mark = None
if mark:
mark_tags = mark.gamemark_tags.all()
mark.get_status_display = GameMarkStatusTranslator(mark.status)
mark_form = GameMarkForm(instance=mark, initial={
'tags': mark_tags
})
else:
mark_form = GameMarkForm(initial={
'game': game,
'tags': mark_tags
})
# retrieve user review
try:
if request.user.is_authenticated:
review = GameReview.objects.get(
owner=request.user, game=game)
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 = GameMark.get_available(game, request.user)
review_list = GameReview.get_available(game, 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 = GameMarkStatusTranslator(m.status)
review_list_more = True if len(
review_list) > REVIEW_NUMBER else False
review_list = review_list[:REVIEW_NUMBER]
# 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)
followers = []
if request.user.is_authenticated:
followers = []
return render(
request,
'games/detail.html',
'detail.html',
{
'game': game,
'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,
'game_tag_list': game_tag_list,
'mark_tags': mark_tags,
'collection': collection,
'form': form,
'followers': followers,
}
)
else: