simplify user register flow to avoid inconsistent state

This commit is contained in:
Your Name 2022-05-07 17:00:52 -04:00
parent 09870e9b50
commit f1010531b0
6 changed files with 406 additions and 350 deletions

254
users/account.py Normal file
View file

@ -0,0 +1,254 @@
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.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 mastodon.api import verify_account
from django.conf import settings
from urllib.parse import quote
import django_rq
from .account import *
from .tasks import *
from datetime import timedelta
from django.utils import timezone
import json
from django.contrib import messages
from books.models import BookMark, BookReview
from movies.models import MovieMark, MovieReview
from games.models import GameMark, GameReview
from music.models import AlbumMark, SongMark, AlbumReview, SongReview
from collection.models import Collection
from common.importers.goodreads import GoodreadsImporter
from common.importers.douban import DoubanImporter
# the 'login' page that user can see
def login(request):
if request.method == 'GET':
selected_site = request.GET.get('site', default='')
sites = MastodonApplication.objects.all().order_by("domain_name")
# store redirect url in the cookie
if request.GET.get('next'):
request.session['next_url'] = request.GET.get('next')
return render(
request,
'users/login.html',
{
'sites': sites,
'scope': quote(settings.MASTODON_CLIENT_SCOPE),
'selected_site': selected_site,
'allow_any_site': settings.MASTODON_ALLOW_ANY_SITE,
}
)
else:
return HttpResponseBadRequest()
# connect will redirect to mastodon server
def connect(request):
if not settings.MASTODON_ALLOW_ANY_SITE:
return redirect(reverse("users:login"))
login_domain = request.session['swap_domain'] if request.session.get('swap_login') else request.GET.get('domain')
if not login_domain:
return render(request, 'common/error.html', {'msg': '未指定实例域名', 'secondary_msg': "", })
login_domain = login_domain.strip().lower().split('//')[-1].split('/')[0].split('@')[-1]
domain, version = get_instance_info(login_domain)
app, error_msg = get_mastodon_application(domain)
if app is None:
return render(request, 'common/error.html', {'msg': error_msg, 'secondary_msg': "", })
else:
login_url = get_mastodon_login_url(app, login_domain, version, request)
resp = redirect(login_url)
resp.set_cookie('mastodon_domain', domain)
return resp
# mastodon server redirect back to here
@mastodon_request_included
def OAuth2_login(request):
if request.method != 'GET':
return HttpResponseBadRequest()
code = request.GET.get('code')
site = request.COOKIES.get('mastodon_domain')
try:
token, refresh_token = obtain_token(site, request, code)
except ObjectDoesNotExist:
return HttpResponseBadRequest("Mastodon site not registered")
if not token:
return render(
request,
'common/error.html',
{
'msg': _("认证失败😫")
}
)
if request.session.get('swap_login', False) and request.user.is_authenticated: # swap login for existing user
return swap_login(request, token, site, refresh_token)
user = authenticate(request, token=token, site=site)
if user: # existing user
user.mastodon_token = token
user.mastodon_refresh_token = refresh_token
user.save(update_fields=['mastodon_token', 'mastodon_refresh_token'])
auth_login(request, user)
if request.session.get('next_url') is not None:
response = redirect(request.session.get('next_url'))
del request.session['next_url']
else:
response = redirect(reverse('common:home'))
return response
else: # newly registered user
code, user_data = verify_account(site, token)
if code != 200 or user_data is None:
return render(
request,
'common/error.html',
{
'msg': _("联邦网络访问失败😫")
}
)
new_user = User(
username=user_data['username'],
mastodon_id=user_data['id'],
mastodon_site=site,
mastodon_token=token,
mastodon_refresh_token=refresh_token,
mastodon_account=user_data,
)
new_user.save()
request.session['new_user'] = True
auth_login(request, new_user)
return redirect(reverse('users:register'))
@mastodon_request_included
@login_required
def logout(request):
if request.method == 'GET':
# revoke_token(request.user.mastodon_site, request.user.mastodon_token)
auth_logout(request)
return redirect(reverse("users:login"))
else:
return HttpResponseBadRequest()
@mastodon_request_included
@login_required
def reconnect(request):
if request.method == 'POST':
request.session['swap_login'] = True
request.session['swap_domain'] = request.POST['domain']
return connect(request)
else:
return HttpResponseBadRequest()
@mastodon_request_included
def register(request):
if request.session.get('new_user'):
del request.session['new_user']
return render(request, 'users/register.html')
else:
return redirect(reverse('common:home'))
def swap_login(request, token, site, refresh_token):
del request.session['swap_login']
del request.session['swap_domain']
code, data = verify_account(site, token)
current_user = request.user
if code == 200 and data is not None:
username = data['username']
if username == current_user.username and site == current_user.mastodon_site:
messages.add_message(request, messages.ERROR, _(f'该身份 {username}@{site} 与当前账号相同。'))
else:
try:
existing_user = User.objects.get(username=username, mastodon_site=site)
messages.add_message(request, messages.ERROR, _(f'该身份 {username}@{site} 已被用于其它账号。'))
except ObjectDoesNotExist:
current_user.username = username
current_user.mastodon_id = data['id']
current_user.mastodon_site = site
current_user.mastodon_token = token
current_user.mastodon_refresh_token = refresh_token
current_user.mastodon_account = data
current_user.save(update_fields=['username', 'mastodon_id', 'mastodon_site', 'mastodon_token', 'mastodon_refresh_token', 'mastodon_account'])
django_rq.get_queue('mastodon').enqueue(refresh_mastodon_data_task, current_user, token)
messages.add_message(request, messages.INFO, _(f'账号身份已更新为 {username}@{site}'))
else:
messages.add_message(request, messages.ERROR, _('连接联邦网络获取身份信息失败。'))
return redirect(reverse('users:data'))
def auth_login(request, user):
""" Decorates django ``login()``. Attach token to session."""
auth.login(request, user)
if user.mastodon_last_refresh < timezone.now() - timedelta(hours=1) or user.mastodon_account == {}:
django_rq.get_queue('mastodon').enqueue(refresh_mastodon_data_task, user)
def auth_logout(request):
""" Decorates django ``logout()``. Release token in session."""
auth.logout(request)
@login_required
def clear_data(request):
if request.method == 'POST':
if request.POST.get('verification') == request.user.mastodon_username:
BookMark.objects.filter(owner=request.user).delete()
MovieMark.objects.filter(owner=request.user).delete()
GameMark.objects.filter(owner=request.user).delete()
AlbumMark.objects.filter(owner=request.user).delete()
SongMark.objects.filter(owner=request.user).delete()
BookReview.objects.filter(owner=request.user).delete()
MovieReview.objects.filter(owner=request.user).delete()
GameReview.objects.filter(owner=request.user).delete()
AlbumReview.objects.filter(owner=request.user).delete()
SongReview.objects.filter(owner=request.user).delete()
request.user.first_name = request.user.username
request.user.last_name = request.user.mastodon_site
request.user.is_active = False
request.user.username = 'removed_' + str(request.user.id)
request.user.mastodon_id = 0
request.user.mastodon_site = 'removed'
request.user.mastodon_token = ''
request.user.mastodon_locked = False
request.user.mastodon_followers = []
request.user.mastodon_following = []
request.user.mastodon_mutes = []
request.user.mastodon_blocks = []
request.user.mastodon_domain_blocks = []
request.user.mastodon_account = {}
request.user.save()
auth_logout(request)
return redirect(reverse("users:login"))
else:
messages.add_message(request, messages.ERROR, _('验证信息不符。'))
return redirect(reverse("users:data"))

132
users/data.py Normal file
View file

@ -0,0 +1,132 @@
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.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 mastodon.api import verify_account
from django.conf import settings
from urllib.parse import quote
import django_rq
from .account import *
from .tasks import *
from datetime import timedelta
from django.utils import timezone
import json
from django.contrib import messages
from books.models import BookMark, BookReview
from movies.models import MovieMark, MovieReview
from games.models import GameMark, GameReview
from music.models import AlbumMark, SongMark, AlbumReview, SongReview
from collection.models import Collection
from common.importers.goodreads import GoodreadsImporter
from common.importers.douban import DoubanImporter
@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.mastodon_append_tag = request.POST.get('mastodon_append_tag', '').strip()
request.user.preference.save()
return render(request, 'users/preferences.html')
@mastodon_request_included
@login_required
def data(request):
return render(request, 'users/data.html', {
'latest_task': request.user.user_synctasks.order_by("-id").first(),
'import_status': request.user.preference.import_status,
'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.get_queue('export').enqueue(export_marks_task, request.user)
request.user.preference.export_status['marks_pending'] = True
request.user.preference.save()
messages.add_message(request, messages.INFO, _('导出已开始。'))
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
@login_required
def sync_mastodon(request):
if request.method == 'POST':
django_rq.get_queue('mastodon').enqueue(refresh_mastodon_data_task, request.user)
messages.add_message(request, messages.INFO, _('同步已开始。'))
return redirect(reverse("users:data"))
@login_required
def reset_visibility(request):
if request.method == 'POST':
visibility = int(request.POST.get('visibility'))
visibility = visibility if visibility >= 0 and visibility <= 2 else 0
BookMark.objects.filter(owner=request.user).update(visibility=visibility)
MovieMark.objects.filter(owner=request.user).update(visibility=visibility)
GameMark.objects.filter(owner=request.user).update(visibility=visibility)
AlbumMark.objects.filter(owner=request.user).update(visibility=visibility)
SongMark.objects.filter(owner=request.user).update(visibility=visibility)
messages.add_message(request, messages.INFO, _('已重置。'))
return redirect(reverse("users:data"))
@login_required
def import_goodreads(request):
if request.method == 'POST':
raw_url = request.POST.get('url')
if GoodreadsImporter.import_from_url(raw_url, request.user):
messages.add_message(request, messages.INFO, _('链接已保存,等待后台导入。'))
else:
messages.add_message(request, messages.ERROR, _('无法识别链接。'))
return redirect(reverse("users:data"))
@login_required
def import_douban(request):
if request.method == 'POST':
importer = DoubanImporter(request.user, request.POST.get('visibility'))
if importer.import_from_file(request.FILES['file']):
messages.add_message(request, messages.INFO, _('文件上传成功,等待后台导入。'))
else:
messages.add_message(request, messages.ERROR, _('无法识别文件。'))
return redirect(reverse("users:data"))

View file

@ -32,6 +32,16 @@ from datetime import datetime
import os
def refresh_mastodon_data_task(user, token=None):
if token:
user.mastodon_token = token
if user.refresh_mastodon_data():
user.save()
print(f"{user} mastodon data refreshed")
else:
print(f"{user} mastodon data refresh failed")
def export_marks_task(user):
user.preference.export_status['marks_pending'] = True
user.preference.save()

View file

@ -30,8 +30,7 @@
此外,{{ site_name }}现处于测试阶段,疏漏在所难免,请妥善备份您的数据。
使用过程中遇到的问题或者错误欢迎向<a href="{{ support_link }}">维护者</a>提出。感谢理解和支持!
</p>
<form action="{% url 'users:register' %}" method="post">
{% csrf_token %}
<form action="{% url 'common:home' %}">
<input type="submit" class="button" value="{% trans 'Cut the sh*t and get me in!' %}">
</form>

View file

@ -17,7 +17,6 @@ urlpatterns = [
path('data/clear_data', clear_data, name='clear_data'),
path('preferences/', preferences, name='preferences'),
path('logout/', logout, name='logout'),
path('delete/', delete, name='delete'),
path('layout/', set_layout, name='set_layout'),
path('OAuth2_login/', OAuth2_login, name='OAuth2_login'),
path('<int:id>/', home_redirect, name='home_redirect'),

View file

@ -28,7 +28,8 @@ from mastodon.api import verify_account
from django.conf import settings
from urllib.parse import quote
import django_rq
from .export import *
from .account import *
from .data import *
from datetime import timedelta
from django.utils import timezone
import json
@ -42,196 +43,6 @@ from common.importers.goodreads import GoodreadsImporter
from common.importers.douban import DoubanImporter
# Views
########################################
def swap_login(request, token, site, refresh_token):
del request.session['swap_login']
del request.session['swap_domain']
code, data = verify_account(site, token)
current_user = request.user
if code == 200 and data is not None:
username = data['username']
if username == current_user.username and site == current_user.mastodon_site:
messages.add_message(request, messages.ERROR, _(f'该身份 {username}@{site} 与当前账号相同。'))
else:
try:
existing_user = User.objects.get(username=username, mastodon_site=site)
messages.add_message(request, messages.ERROR, _(f'该身份 {username}@{site} 已被用于其它账号。'))
except ObjectDoesNotExist:
current_user.username = username
current_user.mastodon_id = data['id']
current_user.mastodon_site = site
current_user.mastodon_token = token
current_user.mastodon_refresh_token = refresh_token
current_user.mastodon_account = data
current_user.save(update_fields=['username', 'mastodon_id', 'mastodon_site', 'mastodon_token', 'mastodon_refresh_token', 'mastodon_account'])
django_rq.get_queue('mastodon').enqueue(refresh_mastodon_data_task, current_user, token)
messages.add_message(request, messages.INFO, _(f'账号身份已更新为 {username}@{site}'))
else:
messages.add_message(request, messages.ERROR, _('连接联邦网络获取身份信息失败。'))
return redirect(reverse('users:data'))
# no page rendered
@mastodon_request_included
def OAuth2_login(request):
""" oauth authentication and logging user into django system """
if request.method == 'GET':
code = request.GET.get('code')
site = request.COOKIES.get('mastodon_domain')
# Network IO
try:
token, refresh_token = obtain_token(site, request, code)
except ObjectDoesNotExist:
return HttpResponseBadRequest("Mastodon site not registered")
if token:
if request.session.get('swap_login', False) and request.user.is_authenticated: # swap login for existing user
return swap_login(request, token, site, refresh_token)
user = authenticate(request, token=token, site=site)
if user:
user.mastodon_token = token
user.mastodon_refresh_token = refresh_token
user.save(update_fields=['mastodon_token', 'mastodon_refresh_token'])
auth_login(request, user)
if request.session.get('next_url') is not None:
response = redirect(request.session.get('next_url'))
del request.session['next_url']
else:
response = redirect(reverse('common:home'))
response.delete_cookie('mastodon_domain')
return response
else:
# will be passed to register page
request.session['new_user_token'] = token
request.session['new_user_refresh_token'] = refresh_token
return redirect(reverse('users:register'))
else:
return render(
request,
'common/error.html',
{
'msg': _("认证失败😫")
}
)
else:
return HttpResponseBadRequest()
# the 'login' page that user can see
def login(request):
if request.method == 'GET':
selected_site = request.GET.get('site', default='')
sites = MastodonApplication.objects.all().order_by("domain_name")
# store redirect url in the cookie
if request.GET.get('next'):
request.session['next_url'] = request.GET.get('next')
return render(
request,
'users/login.html',
{
'sites': sites,
'scope': quote(settings.MASTODON_CLIENT_SCOPE),
'selected_site': selected_site,
'allow_any_site': settings.MASTODON_ALLOW_ANY_SITE,
}
)
else:
return HttpResponseBadRequest()
def connect(request):
if not settings.MASTODON_ALLOW_ANY_SITE:
return redirect(reverse("users:login"))
login_domain = request.session['swap_domain'] if request.session.get('swap_login') else request.GET.get('domain')
if not login_domain:
return render(request, 'common/error.html', {'msg': '未指定实例域名', 'secondary_msg': "", })
login_domain = login_domain.strip().lower().split('//')[-1].split('/')[0].split('@')[-1]
domain, version = get_instance_info(login_domain)
app, error_msg = get_mastodon_application(domain)
if app is None:
return render(request, 'common/error.html', {'msg': error_msg, 'secondary_msg': "", })
else:
login_url = get_mastodon_login_url(app, login_domain, version, request)
resp = redirect(login_url)
resp.set_cookie("mastodon_domain", domain)
return resp
@mastodon_request_included
@login_required
def reconnect(request):
if request.method == 'POST':
request.session['swap_login'] = True
request.session['swap_domain'] = request.POST['domain']
return connect(request)
else:
return HttpResponseBadRequest()
@mastodon_request_included
@login_required
def logout(request):
if request.method == 'GET':
# revoke_token(request.user.mastodon_site, request.user.mastodon_token)
auth_logout(request)
return redirect(reverse("users:login"))
else:
return HttpResponseBadRequest()
@mastodon_request_included
def register(request):
""" register confirm page """
if request.method == 'GET':
if request.user.is_authenticated:
return redirect(reverse('common:home'))
elif request.session.get('new_user_token'):
return render(
request,
'users/register.html'
)
else:
return HttpResponseBadRequest()
elif request.method == 'POST':
token = request.session['new_user_token']
refresh_token = request.session['new_user_refresh_token']
code, user_data = verify_account(request.COOKIES['mastodon_domain'], token)
if code != 200 or user_data is None:
return render(
request,
'common/error.html',
{
'msg': _("联邦网络访问失败😫")
}
)
new_user = User(
username=user_data['username'],
mastodon_id=user_data['id'],
mastodon_site=request.COOKIES['mastodon_domain'],
mastodon_token=token,
mastodon_refresh_token=refresh_token,
mastodon_account=user_data,
)
new_user.save()
del request.session['new_user_token']
del request.session['new_user_refresh_token']
auth_login(request, new_user)
response = redirect(reverse('common:home'))
response.delete_cookie('mastodon_domain')
return response
else:
return HttpResponseBadRequest()
def delete(request):
raise NotImplementedError
def home_redirect(request, id):
try:
query_kwargs = {'pk': id}
@ -247,10 +58,10 @@ def home_anonymous(request, id):
username = id.split('@')[0]
site = id.split('@')[1]
return render(request, 'users/home_anonymous.html', {
'login_url': login_url,
'username': username,
'site': site,
})
'login_url': login_url,
'username': username,
'site': site,
})
except Exception:
return redirect(login_url)
@ -349,7 +160,7 @@ def home(request, id):
# movie marks
filtered_movie_marks = filter_marks(movie_marks, MOVIES_PER_SET, 'movie')
movie_marks_count= count_marks(movie_marks, "movie")
movie_marks_count = count_marks(movie_marks, "movie")
# game marks
filtered_game_marks = filter_marks(game_marks, GAMES_PER_SET, 'game')
@ -800,7 +611,7 @@ def game_list(request, id, status):
if status == 'reviewed':
queryset = GameReview.objects.filter(owner=user).order_by("-edited_time")
elif status == 'tagged':
queryset = GameTag.objects.filter(content=tag, mark__owner=user).order_by("-mark__edited_time")
queryset = GameTag.objects.filter(content=tag, mark__owner=user).order_by("-mark__edited_time")
else:
queryset = GameMark.objects.filter(
owner=user, status=MarkStatusEnum[status.upper()]).order_by("-edited_time")
@ -816,7 +627,7 @@ def game_list(request, id, status):
elif status == 'tagged':
list_title = str(_(f"标记为「{tag}」的游戏"))
else:
list_title = str(GameMarkStatusTranslator(MarkStatusEnum[status.upper()])) + str(_("的游戏"))
list_title = str(GameMarkStatusTranslator(MarkStatusEnum[status.upper()])) + str(_("的游戏"))
return render(
request,
'users/item_list.html',
@ -1020,152 +831,3 @@ def collection_list(request, id):
}
)
return list(request, user.id)
# Utils
########################################
def refresh_mastodon_data_task(user, token=None):
if token:
user.mastodon_token = token
if user.refresh_mastodon_data():
user.save()
print(f"{user} mastodon data refreshed")
else:
print(f"{user} mastodon data refresh failed")
def auth_login(request, user):
""" Decorates django ``login()``. Attach token to session."""
auth.login(request, user)
if user.mastodon_last_refresh < timezone.now() - timedelta(hours=1) or user.mastodon_account == {}:
django_rq.get_queue('mastodon').enqueue(refresh_mastodon_data_task, user)
def auth_logout(request):
""" Decorates django ``logout()``. Release token in session."""
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.mastodon_append_tag = request.POST.get('mastodon_append_tag', '').strip()
request.user.preference.save()
return render(request, 'users/preferences.html')
@mastodon_request_included
@login_required
def data(request):
return render(request, 'users/data.html', {
'latest_task': request.user.user_synctasks.order_by("-id").first(),
'import_status': request.user.preference.import_status,
'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.get_queue('export').enqueue(export_marks_task, request.user)
request.user.preference.export_status['marks_pending'] = True
request.user.preference.save()
messages.add_message(request, messages.INFO, _('导出已开始。'))
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
@login_required
def sync_mastodon(request):
if request.method == 'POST':
django_rq.get_queue('mastodon').enqueue(refresh_mastodon_data_task, request.user)
messages.add_message(request, messages.INFO, _('同步已开始。'))
return redirect(reverse("users:data"))
@login_required
def reset_visibility(request):
if request.method == 'POST':
visibility = int(request.POST.get('visibility'))
visibility = visibility if visibility >= 0 and visibility <= 2 else 0
BookMark.objects.filter(owner=request.user).update(visibility=visibility)
MovieMark.objects.filter(owner=request.user).update(visibility=visibility)
GameMark.objects.filter(owner=request.user).update(visibility=visibility)
AlbumMark.objects.filter(owner=request.user).update(visibility=visibility)
SongMark.objects.filter(owner=request.user).update(visibility=visibility)
messages.add_message(request, messages.INFO, _('已重置。'))
return redirect(reverse("users:data"))
@login_required
def clear_data(request):
if request.method == 'POST':
if request.POST.get('verification') == request.user.mastodon_username:
BookMark.objects.filter(owner=request.user).delete()
MovieMark.objects.filter(owner=request.user).delete()
GameMark.objects.filter(owner=request.user).delete()
AlbumMark.objects.filter(owner=request.user).delete()
SongMark.objects.filter(owner=request.user).delete()
BookReview.objects.filter(owner=request.user).delete()
MovieReview.objects.filter(owner=request.user).delete()
GameReview.objects.filter(owner=request.user).delete()
AlbumReview.objects.filter(owner=request.user).delete()
SongReview.objects.filter(owner=request.user).delete()
request.user.first_name = request.user.username
request.user.last_name = request.user.mastodon_site
request.user.is_active = False
request.user.username = 'removed_' + str(request.user.id)
request.user.mastodon_id = 0
request.user.mastodon_site = 'removed'
request.user.mastodon_token = ''
request.user.mastodon_locked = False
request.user.mastodon_followers = []
request.user.mastodon_following = []
request.user.mastodon_mutes = []
request.user.mastodon_blocks = []
request.user.mastodon_domain_blocks = []
request.user.mastodon_account = {}
request.user.save()
auth_logout(request)
return redirect(reverse("users:login"))
else:
messages.add_message(request, messages.ERROR, _('验证信息不符。'))
return redirect(reverse("users:data"))
@login_required
def import_goodreads(request):
if request.method == 'POST':
raw_url = request.POST.get('url')
if GoodreadsImporter.import_from_url(raw_url, request.user):
messages.add_message(request, messages.INFO, _('链接已保存,等待后台导入。'))
else:
messages.add_message(request, messages.ERROR, _('无法识别链接。'))
return redirect(reverse("users:data"))
@login_required
def import_douban(request):
if request.method == 'POST':
importer = DoubanImporter(request.user, request.POST.get('visibility'))
if importer.import_from_file(request.FILES['file']):
messages.add_message(request, messages.INFO, _('文件上传成功,等待后台导入。'))
else:
messages.add_message(request, messages.ERROR, _('无法识别文件。'))
return redirect(reverse("users:data"))