wip
This commit is contained in:
parent
c7b25744f6
commit
3875a82381
5 changed files with 258 additions and 104 deletions
|
@ -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(),
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
90
collection/templates/create_update.html
Normal file
90
collection/templates/create_update.html
Normal 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>
|
114
collection/templates/detail.html
Normal file
114
collection/templates/detail.html
Normal 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>
|
|
@ -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:
|
||||
|
|
Loading…
Add table
Reference in a new issue