export marks via rq; pref to send public toot; move import to data page

This commit is contained in:
Your Name 2021-12-11 09:43:31 -05:00
parent 0c785320e7
commit 4f504288ca
17 changed files with 647 additions and 20 deletions

View file

@ -33,6 +33,10 @@ urlpatterns = [
]
urlpatterns += [
path('django-rq/', include('django_rq.urls'))
]
if settings.DEBUG:
from django.conf.urls.static import static
urlpatterns += static(settings.MEDIA_URL,

View file

@ -308,7 +308,7 @@ def create_update_mark(request):
if form.cleaned_data['is_private']:
visibility = TootVisibilityEnum.PRIVATE
else:
visibility = TootVisibilityEnum.UNLISTED
visibility = TootVisibilityEnum.PUBLIC if request.user.preference.mastodon_publish_public else TootVisibilityEnum.UNLISTED
url = "https://" + request.get_host() + reverse("books:retrieve",
args=[book.id])
words = BookMarkStatusTranslator(form.cleaned_data['status']) +\
@ -402,7 +402,7 @@ def create_review(request, book_id):
if form.cleaned_data['is_private']:
visibility = TootVisibilityEnum.PRIVATE
else:
visibility = TootVisibilityEnum.UNLISTED
visibility = TootVisibilityEnum.PUBLIC if request.user.preference.mastodon_publish_public else TootVisibilityEnum.UNLISTED
url = "https://" + request.get_host() + reverse("books:retrieve_review",
args=[form.instance.id])
words = "发布了关于" + f"{form.instance.book.title}" + "的评论"
@ -454,7 +454,7 @@ def update_review(request, id):
if form.cleaned_data['is_private']:
visibility = TootVisibilityEnum.PRIVATE
else:
visibility = TootVisibilityEnum.UNLISTED
visibility = TootVisibilityEnum.PUBLIC if request.user.preference.mastodon_publish_public else TootVisibilityEnum.UNLISTED
url = "https://" + request.get_host() + reverse("books:retrieve_review",
args=[form.instance.id])
words = "发布了关于" + f"{form.instance.book.title}" + "的评论"

View file

@ -1164,6 +1164,10 @@ select::placeholder {
width: 100%;
}
.tools-section-wrapper input, .tools-section-wrapperl select {
width: unset;
}
.entity-list .entity-list__title {
margin-bottom: 20px;
}

File diff suppressed because one or more lines are too long

View file

@ -26,8 +26,10 @@
{% if request.user.is_authenticated %}
<a class="navbar__link" id="logoutLink" href="{% url 'users:logout' %}">{% trans '登出' %}</a>
<a class="navbar__link" href="{% url 'common:home' %}">{% trans '主页' %}</a>
<a class="navbar__link" id="logoutLink" href="{% url 'users:data' %}">{% trans '数据' %}</a>
<a class="navbar__link" id="logoutLink" href="{% url 'users:preferences' %}">{% trans '设置' %}</a>
<a class="navbar__link" id="logoutLink" href="{% url 'users:logout' %}">{% trans '登出' %}</a>
{% if request.user.is_staff %}
<a class="navbar__link" href="{% admin_url %}">{% trans '后台' %}</a>
{% endif %}

View file

@ -310,7 +310,7 @@ def create_update_mark(request):
if form.cleaned_data['is_private']:
visibility = TootVisibilityEnum.PRIVATE
else:
visibility = TootVisibilityEnum.UNLISTED
visibility = TootVisibilityEnum.PUBLIC if request.user.preference.mastodon_publish_public else TootVisibilityEnum.UNLISTED
url = "https://" + request.get_host() + reverse("games:retrieve",
args=[game.id])
words = GameMarkStatusTranslator(form.cleaned_data['status']) +\
@ -405,7 +405,7 @@ def create_review(request, game_id):
if form.cleaned_data['is_private']:
visibility = TootVisibilityEnum.PRIVATE
else:
visibility = TootVisibilityEnum.UNLISTED
visibility = TootVisibilityEnum.PUBLIC if request.user.preference.mastodon_publish_public else TootVisibilityEnum.UNLISTED
url = "https://" + request.get_host() + reverse("games:retrieve_review",
args=[form.instance.id])
words = "发布了关于" + f"{form.instance.game.title}" + "的评论"
@ -457,7 +457,7 @@ def update_review(request, id):
if form.cleaned_data['is_private']:
visibility = TootVisibilityEnum.PRIVATE
else:
visibility = TootVisibilityEnum.UNLISTED
visibility = TootVisibilityEnum.PUBLIC if request.user.preference.mastodon_publish_public else TootVisibilityEnum.UNLISTED
url = "https://" + request.get_host() + reverse("games:retrieve_review",
args=[form.instance.id])
words = "发布了关于" + f"{form.instance.game.title}" + "的评论"

View file

@ -309,7 +309,7 @@ def create_update_mark(request):
if form.cleaned_data['is_private']:
visibility = TootVisibilityEnum.PRIVATE
else:
visibility = TootVisibilityEnum.UNLISTED
visibility = TootVisibilityEnum.PUBLIC if request.user.preference.mastodon_publish_public else TootVisibilityEnum.UNLISTED
url = "https://" + request.get_host() + reverse("movies:retrieve",
args=[movie.id])
words = MovieMarkStatusTranslator(form.cleaned_data['status']) +\
@ -404,7 +404,7 @@ def create_review(request, movie_id):
if form.cleaned_data['is_private']:
visibility = TootVisibilityEnum.PRIVATE
else:
visibility = TootVisibilityEnum.UNLISTED
visibility = TootVisibilityEnum.PUBLIC if request.user.preference.mastodon_publish_public else TootVisibilityEnum.UNLISTED
url = "https://" + request.get_host() + reverse("movies:retrieve_review",
args=[form.instance.id])
words = "发布了关于" + f"{form.instance.movie.title}" + "的评论"
@ -456,7 +456,7 @@ def update_review(request, id):
if form.cleaned_data['is_private']:
visibility = TootVisibilityEnum.PRIVATE
else:
visibility = TootVisibilityEnum.UNLISTED
visibility = TootVisibilityEnum.PUBLIC if request.user.preference.mastodon_publish_public else TootVisibilityEnum.UNLISTED
url = "https://" + request.get_host() + reverse("movies:retrieve_review",
args=[form.instance.id])
words = "发布了关于" + f"{form.instance.movie.title}" + "的评论"

View file

@ -328,7 +328,7 @@ def create_update_song_mark(request):
if form.cleaned_data['is_private']:
visibility = TootVisibilityEnum.PRIVATE
else:
visibility = TootVisibilityEnum.UNLISTED
visibility = TootVisibilityEnum.PUBLIC if request.user.preference.mastodon_publish_public else TootVisibilityEnum.UNLISTED
url = "https://" + request.get_host() + reverse("music:retrieve_song",
args=[song.id])
words = MusicMarkStatusTranslator(form.cleaned_data['status']) +\
@ -423,7 +423,7 @@ def create_song_review(request, song_id):
if form.cleaned_data['is_private']:
visibility = TootVisibilityEnum.PRIVATE
else:
visibility = TootVisibilityEnum.UNLISTED
visibility = TootVisibilityEnum.PUBLIC if request.user.preference.mastodon_publish_public else TootVisibilityEnum.UNLISTED
url = "https://" + request.get_host() + reverse("music:retrieve_song_review",
args=[form.instance.id])
words = "发布了关于" + f"{form.instance.song.title}" + "的评论"
@ -475,7 +475,7 @@ def update_song_review(request, id):
if form.cleaned_data['is_private']:
visibility = TootVisibilityEnum.PRIVATE
else:
visibility = TootVisibilityEnum.UNLISTED
visibility = TootVisibilityEnum.PUBLIC if request.user.preference.mastodon_publish_public else TootVisibilityEnum.UNLISTED
url = "https://" + request.get_host() + reverse("music:retrieve_song_review",
args=[form.instance.id])
words = "发布了关于" + f"{form.instance.song.title}" + "的评论"
@ -899,7 +899,7 @@ def create_update_album_mark(request):
if form.cleaned_data['is_private']:
visibility = TootVisibilityEnum.PRIVATE
else:
visibility = TootVisibilityEnum.UNLISTED
visibility = TootVisibilityEnum.PUBLIC if request.user.preference.mastodon_publish_public else TootVisibilityEnum.UNLISTED
url = "https://" + request.get_host() + reverse("music:retrieve_album",
args=[album.id])
words = MusicMarkStatusTranslator(form.cleaned_data['status']) +\
@ -994,7 +994,7 @@ def create_album_review(request, album_id):
if form.cleaned_data['is_private']:
visibility = TootVisibilityEnum.PRIVATE
else:
visibility = TootVisibilityEnum.UNLISTED
visibility = TootVisibilityEnum.PUBLIC if request.user.preference.mastodon_publish_public else TootVisibilityEnum.UNLISTED
url = "https://" + request.get_host() + reverse("music:retrieve_album_review",
args=[form.instance.id])
words = "发布了关于" + f"{form.instance.album.title}" + "的评论"
@ -1046,7 +1046,7 @@ def update_album_review(request, id):
if form.cleaned_data['is_private']:
visibility = TootVisibilityEnum.PRIVATE
else:
visibility = TootVisibilityEnum.UNLISTED
visibility = TootVisibilityEnum.PUBLIC if request.user.preference.mastodon_publish_public else TootVisibilityEnum.UNLISTED
url = "https://" + request.get_host() + reverse("music:retrieve_album_review",
args=[form.instance.id])
words = "发布了关于" + f"{form.instance.album.title}" + "的评论"

View file

@ -3,6 +3,7 @@ django
django-hstore
django-markdownx
django-sass
django-rq
easy-thumbnails
lxml
openpyxl

120
users/export.py Normal file
View file

@ -0,0 +1,120 @@
from django.shortcuts import reverse, redirect, render, get_object_or_404
from django.http import HttpResponseBadRequest, HttpResponse
from django.contrib.auth.decorators import login_required
from django.contrib import auth
from django.contrib.auth import authenticate
from django.core.paginator import Paginator
from django.utils.translation import gettext_lazy as _
from django.core.exceptions import ObjectDoesNotExist
from django.db.models import Count
from .models import User, Report, Preference
from .forms import ReportForm
from mastodon.auth import *
from mastodon.api import *
from mastodon import mastodon_request_included
from common.config import *
from common.models import MarkStatusEnum
from common.utils import PageLinksGenerator
from management.models import Announcement
from books.models import *
from movies.models import *
from music.models import *
from games.models import *
from books.forms import BookMarkStatusTranslator
from movies.forms import MovieMarkStatusTranslator
from music.forms import MusicMarkStatusTranslator
from games.forms import GameMarkStatusTranslator
from mastodon.models import MastodonApplication
from django.conf import settings
from urllib.parse import quote
from openpyxl import Workbook
from common.utils import GenerateDateUUIDMediaFilePath
from datetime import datetime
import os
def export_marks_task(user):
user.preference.export_status['marks_pending'] = True
user.preference.save()
filename = GenerateDateUUIDMediaFilePath(None, 'f.xlsx', settings.MEDIA_ROOT + settings.EXPORT_FILE_PATH_ROOT)
if not os.path.exists(os.path.dirname(filename)):
os.makedirs(os.path.dirname(filename))
heading = ['标题', '简介', '豆瓣评分', '链接', '创建时间', '我的评分', '标签', '评论', 'NeoDB链接', '其它ID']
wb = Workbook() # adding write_only=True will speed up but corrupt the xlsx and won't be importable
for status, label in [('collect', '看过'), ('do', '在看'), ('wish', '想看')]:
ws = wb.create_sheet(title=label)
marks = MovieMark.objects.filter(owner=user, status=status).order_by("-edited_time")
ws.append(heading)
for mark in marks:
movie = mark.movie
title = movie.title
summary = str(movie.year) + ' / ' + ','.join(movie.area) + ' / ' + ','.join(map(lambda x: str(MovieGenreTranslator[x]), movie.genre)) + ' / ' + ','.join(movie.director) + ' / ' + ','.join(movie.actor)
tags = ','.join(map(lambda t: t['content'], movie.get_tags_manager().values()))
world_rating = (movie.rating / 2) if movie.rating else None
timestamp = mark.edited_time.strftime('%Y-%m-%d %H:%M:%S')
my_rating = (mark.rating / 2) if mark.rating else None
text = mark.text
source_url = movie.source_url
url = settings.APP_WEBSITE + movie.get_absolute_url()
line = [title, summary, world_rating, source_url, timestamp, my_rating, tags, text, url, movie.imdb_code]
ws.append(line)
for status, label in [('collect', '听过'), ('do', '在听'), ('wish', '想听')]:
ws = wb.create_sheet(title=label)
marks = AlbumMark.objects.filter(owner=user, status=status).order_by("-edited_time")
ws.append(heading)
for mark in marks:
album = mark.album
title = album.title
summary = ','.join(album.artist) + ' / ' + (album.release_date.strftime('%Y') if album.release_date else '')
tags = ','.join(map(lambda t: t['content'], album.get_tags_manager().values()))
world_rating = (album.rating / 2) if album.rating else None
timestamp = mark.edited_time.strftime('%Y-%m-%d %H:%M:%S')
my_rating = (mark.rating / 2) if mark.rating else None
text = mark.text
source_url = album.source_url
url = settings.APP_WEBSITE + album.get_absolute_url()
line = [title, summary, world_rating, source_url, timestamp, my_rating, tags, text, url, '']
ws.append(line)
for status, label in [('collect', '读过'), ('do', '在读'), ('wish', '想读')]:
ws = wb.create_sheet(title=label)
marks = BookMark.objects.filter(owner=user, status=status).order_by("-edited_time")
ws.append(heading)
for mark in marks:
book = mark.book
title = book.title
summary = ','.join(book.author) + ' / ' + str(book.pub_year) + ' / ' + book.pub_house
tags = ','.join(map(lambda t: t['content'], book.get_tags_manager().values()))
world_rating = (book.rating / 2) if book.rating else None
timestamp = mark.edited_time.strftime('%Y-%m-%d %H:%M:%S')
my_rating = (mark.rating / 2) if mark.rating else None
text = mark.text
source_url = book.source_url
url = settings.APP_WEBSITE + book.get_absolute_url()
line = [title, summary, world_rating, source_url, timestamp, my_rating, tags, text, url, book.isbn]
ws.append(line)
for status, label in [('collect', '玩过'), ('do', '在玩'), ('wish', '想玩')]:
ws = wb.create_sheet(title=label)
marks = GameMark.objects.filter(owner=user, status=status).order_by("-edited_time")
ws.append(heading)
for mark in marks:
game = mark.game
title = game.title
summary = ','.join(game.genre) + ' / ' + ','.join(game.platform) + ' / ' + game.release_date.strftime('%Y-%m-%d')
tags = ','.join(map(lambda t: t['content'], game.get_tags_manager().values()))
world_rating = (game.rating / 2) if game.rating else None
timestamp = mark.edited_time.strftime('%Y-%m-%d %H:%M:%S')
my_rating = (mark.rating / 2) if mark.rating else None
text = mark.text
source_url = game.source_url
url = settings.APP_WEBSITE + game.get_absolute_url()
line = [title, summary, world_rating, source_url, timestamp, my_rating, tags, text, url, '']
ws.append(line)
wb.save(filename=filename)
user.preference.export_status['marks_pending'] = False
user.preference.export_status['marks_file'] = filename
user.preference.export_status['marks_date'] = datetime.now().strftime("%Y-%m-%d %H:%M")
user.preference.save()

View file

@ -50,9 +50,11 @@ class Preference(models.Model):
blank=True,
default=list,
)
export_status = models.JSONField(blank=True, null=True, encoder=DjangoJSONEncoder, default=dict)
mastodon_publish_public = models.BooleanField(null=False, default=False)
def get_serialized_home_layout(self):
return str(self.home_layout).replace("\'","\"")
return str(self.home_layout).replace("\'", "\"")
def __str__(self):
return str(self.user)

View file

@ -0,0 +1,274 @@
{% load static %}
{% load i18n %}
{% 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">
<title>{{ site_name }} - 数据管理</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="{% static 'js/mastodon.js' %}"></script>
<script src="{% static 'js/home.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">
<div class="grid grid--reverse-order">
<div class="grid__main grid__main--reverse-order">
<div class="main-section-wrapper">
<div class="tools-section-wrapper">
<div class="import-panel">
<h5 class="import-panel__label">{% trans '导入豆瓣标记数据' %}</h5>
<span id="importHelp" class="import-panel__help">?</span>
<div class="import-panel__body">
<form action="{% url 'sync:douban' %}" method="POST" enctype="multipart/form-data" >
{% csrf_token %}
<input type="hidden" name="user" value="{{ request.user.id }}">
<span>{% trans '导入:' %}</span>
<div class="import-panel__checkbox">
<input type="checkbox" name="sync_book" id="syncBook">
<label for="syncBook">{% trans '书' %}</label>
</div>
<div class="import-panel__checkbox">
<input type="checkbox" name="sync_movie" id="syncMovie">
<label for="syncMovie">{% trans '电影' %}</label>
</div>
<div class="import-panel__checkbox">
<input type="checkbox" name="sync_music" id="syncMusic">
<label for="syncMusic">{% trans '音乐' %}</label>
</div>
<div class="import-panel__checkbox">
<input type="checkbox" name="sync_game" id="syncGame">
<label for="syncGame">{% trans '游戏' %}</label>
</div>
<div></div>
<span>{% trans '覆盖:' %}</span>
<div class="import-panel__checkbox import-panel__checkbox--last">
<input type="checkbox" name="overwrite" id="overwrite">
<label for="overwrite">{% trans '覆盖原有标记' %}</label>
</div>
<span id="overwriteHelp" class="import-panel__help">?</span>
<div></div>
<span>{% trans '可见性:' %}</span>
<div class="import-panel__checkbox import-panel__checkbox--last">
<input type="checkbox" name="default_public" id="visibility">
<label for="visibility">{% trans '公开' %}</label>
</div>
<span id="visibilityHelp" class="import-panel__help">?</span>
<div></div>
<div class="import-panel__file-input">
<input type="file" name="file" id="excelFile" required accept=".xlsx">
</div>
<input type="submit" class="import-panel__button" value="{% trans '导入' %}" id="uploadBtn"
{% if not latest_task is None and not latest_task.is_finished %}
disabled
{% endif %}
>
</form>
<div class="import-panel__progress"
{% if latest_task.is_finished or latest_task is None %}
style="display: none;"
{% endif %}
>
<label for="importProgress">{% trans '进度' %}</label>
<progress id="importProgress" value="{{ latest_task.finished_items }}" max="{{ latest_task.total_items }}"></progress>
<span class="float-right" id="progressPercent">{{ latest_task.get_progress | floatformat:"0" }}%</span>
<span class="clearfix"></span>
</div>
<div class="import-panel__last-task"
{% if not latest_task.is_finished %}`
style="display: none;"
{% endif %}
>
{% trans '上次导入:' %}
<span class="index">{% trans '总数' %} <span id="lastTaskTotalItems">{{ latest_task.total_items }}</span></span>
<span class="index">{% trans '同步' %} <span id="lastTaskSuccessItems">{{ latest_task.success_items }}</span></span>
<span class="index">{% trans '状态' %} <span id="lastTaskStatus">{{ latest_task.get_status_emoji }}</span></span>
<div class="import-panel__fail-urls"
{% if not latest_task.failed_urls %}
style="display: none;"
{% endif %}
>
<span>
{% trans '失败条目链接' %}
</span>
<a class="float-right" style="cursor: pointer;" id="failedUrlsBtn">
</a>
<script>
$("#failedUrlsBtn").data("collapse", true);
$("#failedUrlsBtn").click(()=>{
const btn = $("#failedUrlsBtn");
if(btn.data("collapse") == true) {
btn.data("collapse", false);
btn.text("▼");
$("#failedUrls").show();
} else {
btn.data("collapse", true);
btn.text("▶");
$("#failedUrls").hide();
}
});
</script>
<span class="clearfix"></span>
<ul id="failedUrls" style="display: none;">
{% for url in latest_task.failed_urls %}
<li>{{ url }}</li>
{% endfor %}
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="main-section-wrapper">
<div class="tools-section-wrapper">
<div class="import-panel">
<h5 class="import-panel__label">{% trans '导出个人数据' %}</h5>
<div class="import-panel__body">
<form action="{% url 'users:export_marks' %}" method="POST" enctype="multipart/form-data" >
{% csrf_token %}
{% if export_status.marks_pending %}
<input type="submit" class="import-panel__button" value="{% trans '正在导出兼容豆伴(doufen)和NiceDB的标记和短评' %}" id="uploadBtn" disabled />
{% else %}
<input type="submit" class="import-panel__button" value="{% trans '导出兼容豆伴(doufen)和NiceDB的标记和短评' %}" id="uploadBtn" />
{% endif %}
{% if export_status.marks_file %}
<a href="{% url 'users:export_marks' %}" download>下载 {{ export_status.marks_date }} 的导出</a>
{% endif %}
</form>
<!-- <form action="{% url 'users:export_reviews' %}" method="POST" enctype="multipart/form-data" >
{% csrf_token %}
<input type="submit" class="import-panel__button" value="{% trans '导出评论' %}" id="uploadBtn"
>
</form> -->
</div>
</div>
</div>
</div>
</div>
<div class="grid__aside grid__aside--reverse-order grid__aside--tablet-column">
<div class="aside-section-wrapper aside-section-wrapper--no-margin">
<div class="user-profile" id="userInfoCard">
<div class="user-profile__header">
<!-- <img src="" class="user-profile__avatar mast-avatar" alt="{{ user.username }}"> -->
<img src="" class="user-profile__avatar mast-avatar">
<a href="{% url 'users:home' user.id %}">
<h5 class="user-profile__username mast-displayname"></h5>
</a>
</div>
<p><a class="user-profile__link mast-acct" target="_blank" href="https://{{ user.mastodon_site }}/@{{ user.username }}">@{{ user.username }}@{{ user.mastodon_site }}</a></p>
<p class="user-profile__bio mast-brief"></p>
<!-- <a href="#" class="follow">{% trans '关注TA' %}</a> -->
{% if request.user != user %}
<a href="{% url 'users:report' %}?user_id={{ user.id }}"
class="user-profile__report-link">{% trans '举报用户' %}</a>
{% endif %}
</div>
</div>
<!-- contains relations, reports, and upload excel entry -->
<div class="relation-dropdown">
<div class="relation-dropdown__body">
<!-- import douban data -->
{% if user == request.user %}
{% endif %}
</div>
</div>
</div>
</div>
</section>
</div>
{% include "partial/_footer.html" %}
</div>
<div id="oauth2Token" hidden="true">{% oauth_token %}</div>
<div id="mastodonURI" hidden="true">{% mastodon request.user.mastodon_site %}</div>
<div id="queryProgressURL" data-url="{% url 'sync:progress' %}"></div>
<div id="querySyncInfoURL" data-url="{% url 'sync:last' %}"></div>
<!--current user mastodon id-->
{% if user == request.user %}
<div id="userMastodonID" hidden="true">{{ user.mastodon_id }}</div>
{% else %}
<div id="userMastodonID" hidden="true">{{ user.target_site_id }}</div>
{% endif %}
<div id="userPageURL" hidden="true">{% url 'users:home' 0 %}</div>
<div id="spinner" hidden>
<div class="spinner">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</div>
<script>
// because the modal and mask elements only exist when there are new announcements
$(".bg-mask").show();
$(".modal-close").on('click', function () {
$(this).parents(".modal").hide();
$(".bg-mask").hide();
});
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/2.9.2/umd/popper.min.js"
integrity="sha512-2rNj2KJ+D8s1ceNasTIex6z4HWyOnEYLVC3FigGOmyQCZc2eBXKgOxQmo3oKLHyfcj53uz4QMsRCWNbLd32Q1g=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tippy.js/6.3.1/tippy.umd.min.js"
integrity="sha512-Ns7w8bjVjVcBVa+k3XLt0ObfsG2LQfr573HoIYtC4wh8gUKLvCx+rlggxfvsHqup6jvMAEmBtYXmhcKHL+6R5A=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script>
tippy('#importHelp', {
content: "{% trans '上传导入由<a href=\"https://github.com/doufen-org/tofu\" target=\"_blank\">豆伴</a>豆坟导出的Excel文件<strong>请勿手动修改该文件</strong>。部分条目由于需要登陆无法自动同步。' %}",
interactive: true,
allowHTML: true,
duration: 0,
});
tippy('#overwriteHelp', {
content: "{% trans '在导入之前如果已经在本站标记了某一个条目,是否使用来自豆瓣的标记覆盖原有的。' %}",
interactive: true,
allowHTML: true,
duration: 0,
});
tippy('#visibilityHelp', {
content: "{% trans '所同步的标记可见性是否为公开;对于已有的标记即便覆盖也不会改变可见性。' %}",
interactive: true,
allowHTML: true,
duration: 0,
});
</script>
</body>
</html>

View file

@ -550,7 +550,7 @@
</div>
<!-- import douban data -->
{% if user == request.user %}
<!-- {% if user == request.user %}
<div class="aside-section-wrapper aside-section-wrapper--transparent aside-section-wrapper--collapse">
<div class="import-panel">
<h5 class="import-panel__label">{% trans '导入豆瓣标记数据' %}</h5>
@ -658,7 +658,7 @@
</div>
</div>
{% endif %}
-->
<div
class="aside-section-wrapper aside-section-wrapper--transparent aside-section-wrapper--collapse">
{% if request.user.is_staff and request.user == user%}

View file

@ -6,7 +6,8 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta property="og:title" content="{{ site_name }} - {% trans '登录' %}">
<meta property="og:title" content="{{ site_name }} - 联邦宇宙书影音游戏标注平台">
<meta name="description" property="og:description" content="NeoDB致力于为联邦宇宙居民提供一个自由、开放、互联的书籍、电影、音乐和游戏收藏评论空间">
<meta property="og:type" content="website">
<meta property="og:url" content="{{ request.build_absolute_uri }}">
<meta property="og:image" content="{{ request.scheme }}://{{ request.get_host }}{% static 'img/logo_square.jpg' %}">

View file

@ -0,0 +1,164 @@
{% load static %}
{% load i18n %}
{% 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">
<title>{{ site_name }} - 设置</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="{% static 'js/mastodon.js' %}"></script>
<script src="{% static 'js/home.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">
<div class="grid grid--reverse-order">
<div class="grid__main grid__main--reverse-order">
<div class="main-section-wrapper">
<div class="tools-section-wrapper">
<div class="import-panel">
<h5 class="import-panel__label">{% trans '联邦网络(长毛象)相关设置' %}</h5>
<div class="import-panel__body">
<form action="{% url 'users:preferences' %}" method="POST" enctype="multipart/form-data" >
{% csrf_token %}
<span>{% trans '以公开方式分享的嘟文是否发布到公共时间轴上:' %}</span>
<div class="import-panel__checkbox import-panel__checkbox--last">
<input type="checkbox" name="mastodon_publish_public" id="visibility" {%if mastodon_publish_public%}checked{% endif %}>
<label for="visibility">{% trans '选中时为public未选中时为unlisted' %}</label>
</div>
<div>
<input type="submit" class="import-panel__button" value="{% trans '保存' %}" id="uploadBtn"
{% if not latest_task is None and not latest_task.is_finished %}
disabled
{% endif %}
>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<div class="grid__aside grid__aside--reverse-order grid__aside--tablet-column">
<div class="aside-section-wrapper aside-section-wrapper--no-margin">
<div class="user-profile" id="userInfoCard">
<div class="user-profile__header">
<!-- <img src="" class="user-profile__avatar mast-avatar" alt="{{ user.username }}"> -->
<img src="" class="user-profile__avatar mast-avatar">
<a href="{% url 'users:home' user.id %}">
<h5 class="user-profile__username mast-displayname"></h5>
</a>
</div>
<p><a class="user-profile__link mast-acct" target="_blank" href="https://{{ user.mastodon_site }}/@{{ user.username }}">@{{ user.username }}@{{ user.mastodon_site }}</a></p>
<p class="user-profile__bio mast-brief"></p>
<!-- <a href="#" class="follow">{% trans '关注TA' %}</a> -->
{% if request.user != user %}
<a href="{% url 'users:report' %}?user_id={{ user.id }}"
class="user-profile__report-link">{% trans '举报用户' %}</a>
{% endif %}
</div>
</div>
<!-- contains relations, reports, and upload excel entry -->
<div class="relation-dropdown">
<div class="relation-dropdown__body">
<!-- import douban data -->
{% if user == request.user %}
{% endif %}
</div>
</div>
</div>
</div>
</section>
</div>
{% include "partial/_footer.html" %}
</div>
<div id="oauth2Token" hidden="true">{% oauth_token %}</div>
<div id="mastodonURI" hidden="true">{% mastodon request.user.mastodon_site %}</div>
<div id="queryProgressURL" data-url="{% url 'sync:progress' %}"></div>
<div id="querySyncInfoURL" data-url="{% url 'sync:last' %}"></div>
<!--current user mastodon id-->
{% if user == request.user %}
<div id="userMastodonID" hidden="true">{{ user.mastodon_id }}</div>
{% else %}
<div id="userMastodonID" hidden="true">{{ user.target_site_id }}</div>
{% endif %}
<div id="userPageURL" hidden="true">{% url 'users:home' 0 %}</div>
<div id="spinner" hidden>
<div class="spinner">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</div>
<script>
// because the modal and mask elements only exist when there are new announcements
$(".bg-mask").show();
$(".modal-close").on('click', function () {
$(this).parents(".modal").hide();
$(".bg-mask").hide();
});
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/2.9.2/umd/popper.min.js"
integrity="sha512-2rNj2KJ+D8s1ceNasTIex6z4HWyOnEYLVC3FigGOmyQCZc2eBXKgOxQmo3oKLHyfcj53uz4QMsRCWNbLd32Q1g=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tippy.js/6.3.1/tippy.umd.min.js"
integrity="sha512-Ns7w8bjVjVcBVa+k3XLt0ObfsG2LQfr573HoIYtC4wh8gUKLvCx+rlggxfvsHqup6jvMAEmBtYXmhcKHL+6R5A=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script>
tippy('#importHelp', {
content: "{% trans '上传导入由<a href=\"https://github.com/doufen-org/tofu\" target=\"_blank\">豆伴</a>豆坟导出的Excel文件<strong>请勿手动修改该文件</strong>。部分条目由于需要登陆无法自动同步。' %}",
interactive: true,
allowHTML: true,
duration: 0,
});
tippy('#overwriteHelp', {
content: "{% trans '在导入之前如果已经在本站标记了某一个条目,是否使用来自豆瓣的标记覆盖原有的。' %}",
interactive: true,
allowHTML: true,
duration: 0,
});
tippy('#visibilityHelp', {
content: "{% trans '所同步的标记可见性是否为公开;对于已有的标记即便覆盖也不会改变可见性。' %}",
interactive: true,
allowHTML: true,
duration: 0,
});
</script>
</body>
</html>

View file

@ -6,6 +6,10 @@ urlpatterns = [
path('login/', login, name='login'),
path('register/', register, name='register'),
path('connect/', connect, name='connect'),
path('data/', data, name='data'),
path('data/export_reviews', export_reviews, name='export_reviews'),
path('data/export_marks', export_marks, name='export_marks'),
path('preferences/', preferences, name='preferences'),
path('logout/', logout, name='logout'),
path('delete/', delete, name='delete'),
path('layout/', set_layout, name='set_layout'),

View file

@ -27,6 +27,9 @@ from games.forms import GameMarkStatusTranslator
from mastodon.models import MastodonApplication
from django.conf import settings
from urllib.parse import quote
import django_rq
from .export import *
# Views
########################################
@ -782,8 +785,10 @@ def set_layout(request):
@login_required
def report(request):
print(request.a.a)
if request.method == 'GET':
user_id = request.GET.get('user_id')
print(user_id)
if user_id:
user = get_object_or_404(User, pk=user_id)
form = ReportForm(initial={'reported_user': user})
@ -845,3 +850,45 @@ def auth_logout(request):
""" Decorates django ``logout()``. Release token in session."""
del request.session['oauth_token']
auth.logout(request)
@mastodon_request_included
@login_required
def preferences(request):
if request.method == 'POST':
request.user.preference.mastodon_publish_public = bool(request.POST.get('mastodon_publish_public'))
request.user.preference.save()
return render(request, 'users/preferences.html', {'mastodon_publish_public': request.user.preference.mastodon_publish_public})
@mastodon_request_included
@login_required
def data(request):
return render(request, 'users/data.html', {
'latest_task': request.user.user_synctasks.order_by("-id").first(),
'export_status': request.user.preference.export_status
})
@mastodon_request_included
@login_required
def export_reviews(request):
if request.method != 'POST':
return redirect(reverse("users:data"))
return render(request, 'users/data.html')
@mastodon_request_included
@login_required
def export_marks(request):
if request.method == 'POST':
if not request.user.preference.export_status.get('marks_pending'):
django_rq.enqueue(export_marks_task, request.user)
request.user.preference.export_status['marks_pending'] = True
request.user.preference.save()
return redirect(reverse("users:data"))
else:
with open(request.user.preference.export_status['marks_file'], 'rb') as fh:
response = HttpResponse(fh.read(), content_type="application/vnd.ms-excel")
response['Content-Disposition'] = 'attachment;filename="marks.xlsx"'
return response