unique username and unique email; move mastodon username to a separate field
This commit is contained in:
parent
ae22923027
commit
83aeec1f2b
38 changed files with 300 additions and 185 deletions
|
@ -227,7 +227,6 @@ STATICFILES_FINDERS = [
|
|||
AUTH_USER_MODEL = "users.User"
|
||||
|
||||
SILENCED_SYSTEM_CHECKS = [
|
||||
"auth.W004", # User.username is non-unique
|
||||
"admin.E404", # Required by django-user-messages
|
||||
]
|
||||
|
||||
|
|
|
@ -45,9 +45,9 @@
|
|||
</span>
|
||||
<span>
|
||||
{% if comment.rating_grade %}{{ comment.rating_grade|rating_star }}{% endif %}
|
||||
<a href="{% url 'journal:user_profile' comment.owner.mastodon_username %}"
|
||||
<a href="{{ comment.owner.url }}"
|
||||
class="nickname"
|
||||
title="@{{ comment.owner.mastodon_username }}">{{ comment.owner.display_name }}</a>
|
||||
title="@{{ comment.owner.handler }}">{{ comment.owner.display_name }}</a>
|
||||
</span>
|
||||
<span class="action inline">
|
||||
<span class="timestamp">
|
||||
|
|
|
@ -63,9 +63,9 @@
|
|||
</span>
|
||||
<span>
|
||||
{% if comment.rating_grade %}{{ comment.rating_grade|rating_star }}{% endif %}
|
||||
<a href="{% url 'journal:user_profile' comment.owner.mastodon_username %}"
|
||||
<a href="{{ comment.owner.url }}"
|
||||
class="nickname"
|
||||
title="@{{ comment.owner.mastodon_username }}">{{ comment.owner.display_name }}</a>
|
||||
title="@{{ comment.owner.handler }}">{{ comment.owner.display_name }}</a>
|
||||
</span>
|
||||
<span class="action inline">
|
||||
<span class="timestamp">
|
||||
|
|
|
@ -23,9 +23,9 @@
|
|||
</span>
|
||||
<span>
|
||||
{% if review.rating_grade %}{{ review.rating_grade|rating_star }}{% endif %}
|
||||
<a href="{% url 'journal:user_profile' review.owner.mastodon_username %}"
|
||||
<a href="{{ review.owner.url }}"
|
||||
class="nickname"
|
||||
title="@{{ review.owner.mastodon_username }}">{{ review.owner.display_name }}</a>
|
||||
title="@{{ review.owner.handler }}">{{ review.owner.display_name }}</a>
|
||||
</span>
|
||||
<span class="action inline">
|
||||
<span class="timestamp">{{ review.created_time|date }}</span>
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
<div class="tag-list">
|
||||
{% for tag in mark.tags %}
|
||||
<span>
|
||||
<a href="{% url 'journal:user_tag_member_list' request.user.mastodon_username tag %}">{{ tag }}</a>
|
||||
<a href="{% url 'journal:user_tag_member_list' request.user.handler tag %}">{{ tag }}</a>
|
||||
</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
|
|
@ -146,7 +146,7 @@
|
|||
{% if item.last_editor and item.last_editor.preference.show_last_edit %}
|
||||
<span>
|
||||
{% trans '最近编辑:' %}
|
||||
<a href="{% url 'journal:user_profile' item.last_editor.mastodon_username %}">{{ item.last_editor | default:"" }}</a>
|
||||
<a href="{{ item.last_editor.url }}">{{ item.last_editor | default:"" }}</a>
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
|
|
@ -48,8 +48,7 @@
|
|||
<span class="timestamp">{{ mark.created_time|date }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<a href="{% url 'journal:user_profile' mark.owner.mastodon_username %}"
|
||||
title="@{{ mark.owner.mastodon_username }}">{{ mark.owner.display_name }}</a>
|
||||
<a href="{{ mark.owner.url }}" title="@{{ mark.owner.handler }}">{{ mark.owner.display_name }}</a>
|
||||
<span>{{ mark.action_label }}</span>
|
||||
{% if mark.rating_grade %}{{ mark.rating_grade|rating_star }}{% endif %}
|
||||
{% if mark.comment.focus_item %}
|
||||
|
|
|
@ -46,9 +46,9 @@
|
|||
</span>
|
||||
-
|
||||
<span>
|
||||
<a href="{% url 'journal:user_profile' review.owner.mastodon_username %}"
|
||||
<a href="{{ review.owner.url }}"
|
||||
class="nickname"
|
||||
title="@{{ review.owner.mastodon_username }}">{{ review.owner.display_name }}</a>
|
||||
title="@{{ review.owner.handler }}">{{ review.owner.display_name }}</a>
|
||||
</span>
|
||||
</div>
|
||||
<div>{{ review.plain_content | truncate:200 }}</div>
|
||||
|
|
|
@ -38,8 +38,7 @@
|
|||
<summary>
|
||||
<div>
|
||||
<div class="avatar">
|
||||
<a href="{% url 'journal:user_profile' user.mastodon_username %}"
|
||||
onclick="window.location = this.href">
|
||||
<a href="{{ user.url }}" onclick="window.location = this.href">
|
||||
{% comment %} onclick to workaround webkit issue with <a /> in <summary /> {% endcomment %}
|
||||
<img src="{{ user.mastodon_account.avatar }}" alt="">
|
||||
</a>
|
||||
|
@ -52,7 +51,7 @@
|
|||
target="_blank"
|
||||
rel="noopener"
|
||||
onclick="window.open(this.href)">
|
||||
<span class="handler">@{{ user.mastodon_username }}</span>
|
||||
<span class="handler">@{{ user.handler }}</span>
|
||||
</a>
|
||||
{% current_user_relationship user as relationship %}
|
||||
{% if relationship %}<span>{{ relationship }}</span>{% endif %}
|
||||
|
@ -188,7 +187,7 @@
|
|||
<div class="tag-list">
|
||||
{% for t in top_tags %}
|
||||
<span>
|
||||
<a href="{% url 'journal:user_tag_member_list' user.mastodon_username t %}">{{ t }}</a>
|
||||
<a href="{% url 'journal:user_tag_member_list' user.handler t %}">{{ t }}</a>
|
||||
</span>
|
||||
{% empty %}
|
||||
<div class="empty">暂无可见标签</div>
|
||||
|
@ -196,7 +195,7 @@
|
|||
</div>
|
||||
<small>
|
||||
{% if top_tags %}
|
||||
<a href="{% url 'journal:user_tag_list' user.mastodon_username %}">...{% trans '全部' %}</a>
|
||||
<a href="{% url 'journal:user_tag_list' user.handler %}">...{% trans '全部' %}</a>
|
||||
{% endif %}
|
||||
</small>
|
||||
</details>
|
||||
|
|
|
@ -6,18 +6,14 @@ from django.contrib.auth.decorators import login_required
|
|||
|
||||
@login_required
|
||||
def me(request):
|
||||
return redirect(
|
||||
reverse("journal:user_profile", args=[request.user.mastodon_username])
|
||||
)
|
||||
return redirect(request.user.url)
|
||||
|
||||
|
||||
def home(request):
|
||||
if request.user.is_authenticated:
|
||||
home = request.user.get_preference().classic_homepage
|
||||
if home == 1:
|
||||
return redirect(
|
||||
reverse("journal:user_profile", args=[request.user.mastodon_username])
|
||||
)
|
||||
return redirect(request.user.url)
|
||||
elif home == 2:
|
||||
return redirect(reverse("social:feed"))
|
||||
else:
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
{% csrf_token %}
|
||||
{% if not application.is_official %}
|
||||
<p>
|
||||
<b>{{ application.name }}</b> 是由 <a href="{% url 'journal:user_profile' application.user.mastodon_username %}">{{ application.user.mastodon_username }}</a> 创建和维护的应用程序。
|
||||
<b>{{ application.name }}</b> 是由 <a href="{{ application.user.url }}">@{{ application.user.handler }}</a> 创建和维护的应用程序。
|
||||
{{ site_name }}无法保证其安全性和有效性,请自行验证确认后再授权。
|
||||
</p>
|
||||
{% endif %}
|
||||
|
|
|
@ -36,9 +36,10 @@ class OPMLImporter:
|
|||
def import_from_file_task(self, feeds):
|
||||
print(f"{self.user} import opml start")
|
||||
skip = 0
|
||||
collection = None
|
||||
if self.mode == 1:
|
||||
collection = Collection.objects.create(
|
||||
owner=self.user, title=f"{self.user.username}的播客订阅列表"
|
||||
owner=self.user, title=f"{self.user.display_name}的播客订阅列表"
|
||||
)
|
||||
for feed in feeds:
|
||||
print(f"{self.user} import {feed.url}")
|
||||
|
@ -56,7 +57,7 @@ class OPMLImporter:
|
|||
mark.update(
|
||||
ShelfType.PROGRESS, None, None, visibility=self.visibility
|
||||
)
|
||||
elif self.mode == 1:
|
||||
elif self.mode == 1 and collection:
|
||||
collection.append_item(item)
|
||||
print(f"{self.user} import opml end")
|
||||
msg.success(
|
||||
|
|
|
@ -44,7 +44,7 @@ class UserOwnedObjectMixin:
|
|||
filter(
|
||||
lambda _entity: _entity.is_visible_to(request_user)
|
||||
and (
|
||||
_entity.owner.mastodon_username in request_user.mastodon_following
|
||||
_entity.owner.mastodon_acct in request_user.mastodon_following
|
||||
if following_only
|
||||
else True
|
||||
),
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
<span class="timestamp">{{ mark.created_time|date }}</span>
|
||||
</div>
|
||||
<div>
|
||||
{% comment %} <a href="{% url 'journal:user_profile' mark.owner.mastodon_username %}" title="@{{ mark.owner.mastodon_username }}">{{ mark.owner.display_name }}</a> {% endcomment %}
|
||||
{% comment %} <a href="{{mark.owner.url }}" title="@{{ mark.owner.handler }}">{{ mark.owner.display_name }}</a> {% endcomment %}
|
||||
<span>{{ mark.action_label }}</span>
|
||||
{% if mark.rating_grade %}{{ mark.rating_grade|rating_star }}{% endif %}
|
||||
{% if mark.comment.focus_item %}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<meta property="og:description" content="{{ collection.description }}">
|
||||
<meta property="og:type" content="article">
|
||||
<meta property="og:article:author"
|
||||
content="{{ collection.owner.username }}">
|
||||
content="{{ collection.owner.display_name }}">
|
||||
<meta property="og:url" content="{{ request.build_absolute_uri }}">
|
||||
<meta property="og:image" content="{{ collection.cover|thumb:'normal' }}">
|
||||
<title>{{ site_name }} {% trans '收藏单' %} - {{ collection.title }}</title>
|
||||
|
@ -56,13 +56,13 @@
|
|||
<div class="owner">
|
||||
<span class="avatar">
|
||||
<img src="{{ collection.owner.mastodon_account.avatar }}"
|
||||
alt="{{ collection.owner.username }}">
|
||||
alt="{{ collection.owner.display_name }}">
|
||||
</span>
|
||||
</div>
|
||||
<div class="info">
|
||||
<p>
|
||||
<a href="{% url 'journal:user_profile' collection.owner.mastodon_username %}">{{ collection.owner.mastodon_account.display_name }}</a>
|
||||
<span class="handler">@{{ collection.owner.mastodon_username }}</span>
|
||||
<a href="{{ collection.owner.url }}">{{ collection.owner.mastodon_account.display_name }}</a>
|
||||
<span class="handler">@{{ collection.owner.handler }}</span>
|
||||
</p>
|
||||
<p>
|
||||
{% for cat, count in collection.get_summary.items %}
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
<div>
|
||||
<h6>{{ piece.title }}</h6>
|
||||
{% if piece.visibility > 0 %}<i class="fa-solid fa-lock"></i>{% endif %}
|
||||
<a href="{% url 'journal:user_profile' piece.owner.mastodon_username %}">{{ piece.owner.username }}</a>
|
||||
<a href="{{ piece.owner.url }}">{{ piece.owner.display_name }}</a>
|
||||
{{ piece.edited_time }}
|
||||
</div>
|
||||
<footer>
|
||||
|
|
|
@ -15,15 +15,14 @@
|
|||
{% else %}
|
||||
<title>{{ site_name }} - {{ user.display_name }}</title>
|
||||
{% endif %}
|
||||
<meta property="og:title"
|
||||
content="{{ site_name }}用户 - @{{ user.mastodon_username }}">
|
||||
<meta property="og:title" content="{{ site_name }}用户 - @{{ user.handler }}">
|
||||
<meta property="og:url" content="{{ request.build_absolute_uri }}">
|
||||
<meta property="og:image" content="{{ user.mastodon_account.avatar }}">
|
||||
<meta property="og:site_name" content="{{ site_name }}">
|
||||
{% if user.preference.no_anonymous_view %}<meta name="robots" content="noindex">{% endif %}
|
||||
<link rel="alternate"
|
||||
type="application/rss+xml"
|
||||
title="{{ site_name }} - {{ user.mastodon_username }}的评论"
|
||||
title="{{ site_name }} - @{{ user.handler }}的评论"
|
||||
href="{{ request.build_absolute_uri }}feed/reviews/">
|
||||
{% include "common_libs.html" with jquery=0 v2=1 %}
|
||||
<script src="{% static 'lib/js/calendar_yearview_blocks.js' %}" defer></script>
|
||||
|
@ -49,7 +48,7 @@
|
|||
</p>
|
||||
</div>
|
||||
<span class="calendar_data"
|
||||
hx-get="{% url 'journal:user_calendar_data' user.mastodon_username %}"
|
||||
hx-get="{% url 'journal:user_calendar_data' user.handler %}"
|
||||
hx-trigger="load"
|
||||
hx-swap="innerHTML"
|
||||
style="display:none"></span>
|
||||
|
@ -63,7 +62,7 @@
|
|||
<h5>
|
||||
{{ shelf.title }}
|
||||
<small>
|
||||
<a href="{% if shelf_type == 'reviewed' %}{% url 'journal:user_review_list' user.mastodon_username category %}{% else %}{% url 'journal:user_mark_list' user.mastodon_username shelf_type category %}{% endif %}">{{ shelf.count }}</a>
|
||||
<a href="{% if shelf_type == 'reviewed' %}{% url 'journal:user_review_list' user.handler category %}{% else %}{% url 'journal:user_mark_list' user.handler shelf_type category %}{% endif %}">{{ shelf.count }}</a>
|
||||
</small>
|
||||
</h5>
|
||||
<ul class="cards">
|
||||
|
@ -90,7 +89,7 @@
|
|||
<h5>
|
||||
{% trans '创建的收藏单' %}
|
||||
<small>
|
||||
<a href="{% url 'journal:user_collection_list' user.mastodon_username %}">{{ collections_count }}</a>
|
||||
<a href="{% url 'journal:user_collection_list' user.handler %}">{{ collections_count }}</a>
|
||||
{% if user == request.user %}
|
||||
<a href="{% url 'journal:collection_create' %}">
|
||||
<i class="fa-regular fa-square-plus"></i>
|
||||
|
@ -118,7 +117,7 @@
|
|||
<h5>
|
||||
{% trans '关注的收藏单' %}
|
||||
<small>
|
||||
<a href="{% url 'journal:user_liked_collection_list' user.mastodon_username %}">{{ liked_collections_count }}</a>
|
||||
<a href="{% url 'journal:user_liked_collection_list' user.handler %}">{{ liked_collections_count }}</a>
|
||||
</small>
|
||||
</h5>
|
||||
<ul class="cards">
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
<meta property="og:title"
|
||||
content="{{ site_name }} - {{ review.title }} ({{ review.item.title }} {% trans '评论' %})">
|
||||
<meta property="og:type" content="article">
|
||||
<meta property="og:article:author" content="{{ review.owner.username }}">
|
||||
<meta property="og:article:author"
|
||||
content="{{ review.owner.display_name }}">
|
||||
<meta property="og:url" content="{{ request.build_absolute_uri }}">
|
||||
<meta property="og:image" content="{{ review.item.cover|thumb:'normal' }}">
|
||||
<meta property="og:site_name" content="{{ site_name }}">
|
||||
|
@ -51,12 +52,12 @@
|
|||
<div class="owner">
|
||||
<span class="avatar">
|
||||
<img src="{{ review.owner.mastodon_account.avatar }}"
|
||||
alt="{{ review.owner.username }}">
|
||||
alt="{{ review.owner.display_name }}">
|
||||
</span>
|
||||
</div>
|
||||
<div class="info">
|
||||
<a href="{% url 'journal:user_profile' review.owner.mastodon_username %}">{{ review.owner.display_name }}</a>
|
||||
<span class="handler">@{{ review.owner.mastodon_username }}</span>
|
||||
<a href="{{ review.owner.url }}">{{ review.owner.display_name }}</a>
|
||||
<span class="handler">@{{ review.owner.handler }}</span>
|
||||
<br>
|
||||
评论
|
||||
<a href="{{ review.item.url }}">{{ review.item.title }}</a>
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{{ site_name }} - {{ user.mastodon_username }} -
|
||||
<title>{{ site_name }} - {{ user.display_name }} -
|
||||
{% if liked %}关注的{% endif %}
|
||||
收藏单</title>
|
||||
{% include "common_libs.html" with jquery=0 v2=1 %}
|
||||
|
@ -44,8 +44,8 @@
|
|||
<span><a href="{{ collection.url }}">{{ collection.title }}</a></span>
|
||||
{% if liked %}
|
||||
-
|
||||
<a href="{% url 'journal:user_profile' collection.owner.mastodon_username %}"
|
||||
title="@{{ collection.owner.mastodon_username }}">{{ collection.owner.display_name }}</a>
|
||||
<a href="{{ collection.owner.url }}"
|
||||
title="@{{ collection.owner.handler }}">{{ collection.owner.display_name }}</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
{% empty %}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
{% block title %}<title>{{ site_name }} - {{ user.mastodon_username }}</title>{% endblock %}
|
||||
{% block title %}<title>{{ site_name }} - {{ user.display_name }}</title>{% endblock %}
|
||||
{% include "common_libs.html" with jquery=0 v2=1 %}
|
||||
</head>
|
||||
<body>
|
||||
|
@ -19,7 +19,7 @@
|
|||
<main>
|
||||
<div class="grid__main">
|
||||
<h5>
|
||||
{% block head %}{{ user.mastodon_username }}{% endblock %}
|
||||
{% block head %}{{ user.display_name }}{% endblock %}
|
||||
</h5>
|
||||
<div>
|
||||
{% for member in members %}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{{ site_name }} - 我的标签</title>
|
||||
<title>{{ site_name }} - {{ user.display_name }} 的标签</title>
|
||||
{% include "common_libs.html" with jquery=0 v2=1 %}
|
||||
</head>
|
||||
<body>
|
||||
|
@ -25,7 +25,7 @@
|
|||
{% for v in tags %}
|
||||
<span style="margin-right:2em; white-space: nowrap;">
|
||||
<span>
|
||||
<a href="{% url 'journal:user_tag_member_list' user.mastodon_username v.title %}">{{ v.title }}</a>
|
||||
<a href="{% url 'journal:user_tag_member_list' user.handler v.title %}">{{ v.title }}</a>
|
||||
</span>
|
||||
<span>({{ v.total }})</span>
|
||||
</span>
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
{% extends "user_item_list_base.html" %}
|
||||
{% load i18n %}
|
||||
{% block title %}
|
||||
<title>{{ site_name }} - {{ user.mastodon_username }} - {{ tag.title }} {% trans '标签' %}</title>
|
||||
<title>{{ site_name }} - {{ user.display_name }} - {{ tag.title }} {% trans '标签' %}</title>
|
||||
{% endblock %}
|
||||
{% block head %}
|
||||
{{ tag.title }}
|
||||
<br>
|
||||
<small>
|
||||
{% if tag.visibility > 0 %}<i class="fa-solid fa-user" title="个人标签"></i>{% endif %}
|
||||
{{ user.mastodon_username }}的{% trans '标签' %}
|
||||
{{ user.display_name }}的{% trans '标签' %}
|
||||
{% if user == request.user %}
|
||||
<form style="display:inline"
|
||||
hx-get="{% url 'journal:user_tag_edit' %}"
|
||||
|
|
|
@ -114,7 +114,7 @@ def add_to_collection(request, item_uuid):
|
|||
cid = int(request.POST.get("collection_id", default=0))
|
||||
if not cid:
|
||||
cid = Collection.objects.create(
|
||||
owner=request.user, title=f"{request.user.username}的收藏单"
|
||||
owner=request.user, title=f"{request.user.display_name}的收藏单"
|
||||
).id
|
||||
collection = Collection.objects.get(owner=request.user, id=cid)
|
||||
collection.append_item(item, note=request.POST.get("note"))
|
||||
|
@ -738,7 +738,7 @@ def user_tag_edit(request):
|
|||
tag.delete()
|
||||
msg.info(request.user, _("标签已删除"))
|
||||
return redirect(
|
||||
reverse("journal:user_tag_list", args=[request.user.mastodon_username])
|
||||
reverse("journal:user_tag_list", args=[request.user.mastodon_acct])
|
||||
)
|
||||
elif (
|
||||
tag_title != tag.title
|
||||
|
@ -754,7 +754,7 @@ def user_tag_edit(request):
|
|||
return redirect(
|
||||
reverse(
|
||||
"journal:user_tag_member_list",
|
||||
args=[request.user.mastodon_username, tag.title],
|
||||
args=[request.user.mastodon_acct, tag.title],
|
||||
)
|
||||
)
|
||||
raise BadRequest()
|
||||
|
|
|
@ -110,12 +110,12 @@ def post_toot(
|
|||
try:
|
||||
if update_id:
|
||||
response = put(url + "/" + update_id, headers=headers, data=payload)
|
||||
if update_id is None or response.status_code != 200:
|
||||
if update_id is None or (response and response.status_code != 200):
|
||||
headers["Idempotency-Key"] = random_string_generator(16)
|
||||
response = post(url, headers=headers, data=payload)
|
||||
if response.status_code == 201:
|
||||
if response and response.status_code == 201:
|
||||
response.status_code = 200
|
||||
if response.status_code != 200:
|
||||
if response and response.status_code != 200:
|
||||
logger.error(f"Error {url} {response.status_code}")
|
||||
except Exception:
|
||||
response = None
|
||||
|
@ -470,7 +470,7 @@ def share_mark(mark):
|
|||
mark.shared_link = j["url"]
|
||||
elif "data" in j:
|
||||
mark.shared_link = (
|
||||
f"https://twitter.com/{user.username}/status/{j['data']['id']}"
|
||||
f"https://twitter.com/{user.mastodon_username}/status/{j['data']['id']}"
|
||||
)
|
||||
if mark.shared_link:
|
||||
mark.save(update_fields=["shared_link"])
|
||||
|
@ -539,7 +539,11 @@ def share_collection(collection, comment, user, visibility_no):
|
|||
user_str = (
|
||||
"我"
|
||||
if user == collection.owner
|
||||
else " @" + collection.owner.mastodon_username + " "
|
||||
else (
|
||||
" @" + collection.owner.mastodon_acct + " "
|
||||
if collection.owner.mastodon_acct
|
||||
else " " + collection.owner.username + " "
|
||||
)
|
||||
)
|
||||
content = f"分享{user_str}的收藏单《{collection.title}》\n{collection.absolute_url}\n{comment}{tags}"
|
||||
response = post_toot(user.mastodon_site, content, visibility, user.mastodon_token)
|
||||
|
|
|
@ -13,23 +13,17 @@ class OAuth2Backend(ModelBackend):
|
|||
"""when username is provided, assume that token is newly obtained and valid"""
|
||||
if token is None or site is None:
|
||||
return
|
||||
|
||||
mastodon_id = None
|
||||
if username is None:
|
||||
code, user_data = verify_account(site, token)
|
||||
if code == 200:
|
||||
userid = user_data["id"]
|
||||
else:
|
||||
# aquiring user data fail means token is invalid thus auth fail
|
||||
return None
|
||||
|
||||
# when username is provided, assume that token is newly obtained and valid
|
||||
if code == 200 and user_data:
|
||||
mastodon_id = user_data["id"]
|
||||
if not mastodon_id:
|
||||
return None
|
||||
try:
|
||||
user = UserModel._default_manager.get(
|
||||
mastodon_id=userid, mastodon_site=site
|
||||
mastodon_id=mastodon_id, mastodon_site=site
|
||||
)
|
||||
return user if self.user_can_authenticate(user) else None
|
||||
except UserModel.DoesNotExist:
|
||||
return None
|
||||
else:
|
||||
if self.user_can_authenticate(user):
|
||||
return user
|
||||
return None
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</span>
|
||||
<div class="spacing">
|
||||
关注了
|
||||
<a href="{% url 'journal:user_profile' collection.owner.mastodon_username %}">{{ collection.owner.display_name }}</a>
|
||||
<a href="{{ collection.owner.url }}">{{ collection.owner.display_name }}</a>
|
||||
的收藏单
|
||||
<a href="{{ collection.url }}">{{ collection.title }}</a>
|
||||
</div>
|
||||
|
|
|
@ -21,12 +21,10 @@
|
|||
</span>
|
||||
<div class="spacing">
|
||||
<span>
|
||||
<a href="{% url 'journal:user_profile' activity.owner.mastodon_username %}"
|
||||
class="nickname">{{ activity.owner.display_name }}</a>
|
||||
<a href="{{ activity.owner.url }}" class="nickname">{{ activity.owner.display_name }}</a>
|
||||
</span>
|
||||
<span>
|
||||
<a href="{% url 'journal:user_profile' activity.owner.mastodon_username %}"
|
||||
class="handler">@{{ activity.owner.mastodon_username }}</a>
|
||||
<a href="{{ activity.owner.url }}" class="handler">@{{ activity.owner.handler }}</a>
|
||||
</span>
|
||||
</div>
|
||||
{% with "activity/"|add:activity.template|add:".html" as template %}
|
||||
|
|
|
@ -10,8 +10,10 @@ class SocialTest(TestCase):
|
|||
self.book1 = Edition.objects.create(title="Hyperion")
|
||||
self.book2 = Edition.objects.create(title="Andymion")
|
||||
self.movie = Edition.objects.create(title="Fight Club")
|
||||
self.alice = User.objects.create(mastodon_site="MySpace", username="Alice")
|
||||
self.bob = User.objects.create(mastodon_site="KKCity", username="Bob")
|
||||
self.alice = User.objects.create(
|
||||
mastodon_site="MySpace", mastodon_username="Alice"
|
||||
)
|
||||
self.bob = User.objects.create(mastodon_site="KKCity", mastodon_username="Bob")
|
||||
|
||||
def test_timeline(self):
|
||||
# alice see 0 activity in timeline in the beginning
|
||||
|
|
|
@ -1,22 +1,19 @@
|
|||
from django.shortcuts import reverse, redirect, render, get_object_or_404
|
||||
from django.shortcuts import redirect, render, get_object_or_404
|
||||
from django.urls import reverse
|
||||
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, BadRequest
|
||||
from django.db.models import Count
|
||||
from .models import User, Report, Preference
|
||||
from .forms import ReportForm
|
||||
from .models import User, Preference
|
||||
from mastodon.api import *
|
||||
from mastodon import mastodon_request_included
|
||||
from common.config import *
|
||||
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
|
||||
|
@ -113,7 +110,7 @@ def OAuth2_login(request):
|
|||
{"msg": _("认证失败😫"), "secondary_msg": _("Mastodon服务未能返回有效认证信息")},
|
||||
)
|
||||
site = request.COOKIES.get("mastodon_domain")
|
||||
if not code:
|
||||
if not site:
|
||||
return render(
|
||||
request,
|
||||
"common/error.html",
|
||||
|
@ -137,8 +134,8 @@ def OAuth2_login(request):
|
|||
|
||||
user = authenticate(request, token=token, site=site)
|
||||
if user: # existing user
|
||||
user.mastodon_token = token
|
||||
user.mastodon_refresh_token = refresh_token
|
||||
user.mastodon_token = token # type: ignore
|
||||
user.mastodon_refresh_token = refresh_token # type: ignore
|
||||
user.save(update_fields=["mastodon_token", "mastodon_refresh_token"])
|
||||
auth_login(request, user)
|
||||
if request.session.get("next_url") is not None:
|
||||
|
@ -152,7 +149,8 @@ def OAuth2_login(request):
|
|||
if code != 200 or user_data is None:
|
||||
return render(request, "common/error.html", {"msg": _("联邦网络访问失败😫")})
|
||||
new_user = User(
|
||||
username=user_data["username"],
|
||||
username=None,
|
||||
mastodon_username=user_data["username"],
|
||||
mastodon_id=user_data["id"],
|
||||
mastodon_site=site,
|
||||
mastodon_token=token,
|
||||
|
@ -206,18 +204,23 @@ def swap_login(request, token, site, refresh_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:
|
||||
if (
|
||||
username == current_user.mastodon_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)
|
||||
existing_user = User.objects.get(
|
||||
mastodon_username=username, mastodon_site=site
|
||||
)
|
||||
messages.add_message(
|
||||
request, messages.ERROR, _(f"该身份 {username}@{site} 已被用于其它账号。")
|
||||
)
|
||||
except ObjectDoesNotExist:
|
||||
current_user.username = username
|
||||
current_user.mastodon_username = username
|
||||
current_user.mastodon_id = data["id"]
|
||||
current_user.mastodon_site = site
|
||||
current_user.mastodon_token = token
|
||||
|
@ -227,6 +230,7 @@ def swap_login(request, token, site, refresh_token):
|
|||
update_fields=[
|
||||
"username",
|
||||
"mastodon_id",
|
||||
"mastodon_username",
|
||||
"mastodon_site",
|
||||
"mastodon_token",
|
||||
"mastodon_refresh_token",
|
||||
|
@ -264,22 +268,9 @@ def clear_data(request):
|
|||
if request.META.get("HTTP_AUTHORIZATION"):
|
||||
raise BadRequest("Only for web login")
|
||||
if request.method == "POST":
|
||||
if request.POST.get("verification") == request.user.mastodon_username:
|
||||
if request.POST.get("verification") == request.user.mastodon_acct:
|
||||
remove_data_by_user(request.user)
|
||||
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.clear()
|
||||
request.user.save()
|
||||
auth_logout(request)
|
||||
return redirect(reverse("users:login"))
|
||||
|
|
|
@ -19,7 +19,7 @@ class UserSchema(Schema):
|
|||
def me(request):
|
||||
return 200, {
|
||||
"url": settings.SITE_INFO["site_url"] + request.user.url,
|
||||
"external_acct": request.user.mastodon_username,
|
||||
"external_acct": request.user.mastodon_acct,
|
||||
"display_name": request.user.display_name,
|
||||
"avatar": request.user.mastodon_account.get("avatar"),
|
||||
}
|
||||
|
|
|
@ -12,8 +12,7 @@ class Command(BaseCommand):
|
|||
|
||||
def handle(self, *args, **options):
|
||||
h = int(options["id"])
|
||||
u = User.objects.get(id=h)
|
||||
u.username = "(duplicated)" + u.username
|
||||
u = User.objects.get(pk=h)
|
||||
u.is_active = False
|
||||
u.save()
|
||||
print(f"{u} updated")
|
||||
print(f"{u} disabled")
|
||||
|
|
72
users/migrations/0005_add_dedicated_username.py
Normal file
72
users/migrations/0005_add_dedicated_username.py
Normal file
|
@ -0,0 +1,72 @@
|
|||
# Generated by Django 3.2.19 on 2023-06-30 02:39
|
||||
|
||||
import django.contrib.auth.validators
|
||||
from django.db import migrations, models
|
||||
import users.models
|
||||
|
||||
|
||||
def set_username(apps, schema_editor):
|
||||
User = apps.get_model("users", "User")
|
||||
for u in User.objects.all():
|
||||
u.mastodon_username = u.username
|
||||
u.username = None
|
||||
u.save()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("users", "0004_alter_preference_classic_homepage"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveConstraint(
|
||||
model_name="user",
|
||||
name="unique_user_identity",
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="user",
|
||||
name="mastodon_username",
|
||||
field=models.CharField(default=None, max_length=100, null=True),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="user",
|
||||
name="mastodon_site",
|
||||
field=models.CharField(default=None, max_length=100, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="user",
|
||||
name="mastodon_id",
|
||||
field=models.CharField(default=None, max_length=100, null=True),
|
||||
),
|
||||
migrations.RunPython(set_username),
|
||||
migrations.RunSQL(
|
||||
"UPDATE users_user SET mastodon_id = null where mastodon_id = '0';"
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="user",
|
||||
name="username",
|
||||
field=models.CharField(
|
||||
error_messages={"unique": "A user with that username already exists."},
|
||||
help_text="Required. 50 characters or fewer. Letters, digits and _ only.",
|
||||
max_length=50,
|
||||
null=True,
|
||||
unique=True,
|
||||
validators=[users.models.UsernameValidator()],
|
||||
verbose_name="username",
|
||||
),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name="user",
|
||||
constraint=models.UniqueConstraint(
|
||||
fields=("mastodon_username", "mastodon_site"),
|
||||
name="unique_mastodon_username",
|
||||
),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name="user",
|
||||
constraint=models.UniqueConstraint(
|
||||
fields=("mastodon_id", "mastodon_site"), name="unique_mastodon_id"
|
||||
),
|
||||
),
|
||||
]
|
35
users/migrations/0006_unique_email.py
Normal file
35
users/migrations/0006_unique_email.py
Normal file
|
@ -0,0 +1,35 @@
|
|||
# Generated by Django 3.2.19 on 2023-06-30 13:50
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("users", "0005_add_dedicated_username"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="user",
|
||||
name="email",
|
||||
field=models.EmailField(
|
||||
default=None,
|
||||
null=True,
|
||||
max_length=254,
|
||||
unique=False,
|
||||
verbose_name="email address",
|
||||
),
|
||||
),
|
||||
migrations.RunSQL("UPDATE users_user SET email = null;"),
|
||||
migrations.AlterField(
|
||||
model_name="user",
|
||||
name="email",
|
||||
field=models.EmailField(
|
||||
default=None,
|
||||
null=True,
|
||||
max_length=254,
|
||||
unique=True,
|
||||
verbose_name="email address",
|
||||
),
|
||||
),
|
||||
]
|
132
users/models.py
132
users/models.py
|
@ -1,4 +1,7 @@
|
|||
import uuid
|
||||
import re
|
||||
from django.core import validators
|
||||
from django.utils.deconstruct import deconstructible
|
||||
import django.contrib.postgres.fields as postgres
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.db import models
|
||||
|
@ -13,6 +16,16 @@ from mastodon.api import *
|
|||
from django.urls import reverse
|
||||
|
||||
|
||||
@deconstructible
|
||||
class UsernameValidator(validators.RegexValidator):
|
||||
regex = r"^[a-zA-Z0-9_]{2,50}$"
|
||||
message = _(
|
||||
"Enter a valid username. This value may contain only unaccented lowercase a-z "
|
||||
"and uppercase A-Z letters, numbers, and _ characters."
|
||||
)
|
||||
flags = re.ASCII
|
||||
|
||||
|
||||
def report_image_path(instance, filename):
|
||||
return GenerateDateUUIDMediaFilePath(
|
||||
instance, filename, settings.REPORT_MEDIA_PATH_ROOT
|
||||
|
@ -20,19 +33,23 @@ def report_image_path(instance, filename):
|
|||
|
||||
|
||||
class User(AbstractUser):
|
||||
if settings.MASTODON_ALLOW_ANY_SITE:
|
||||
username = models.CharField(
|
||||
_("username"),
|
||||
max_length=150,
|
||||
unique=False,
|
||||
help_text=_(
|
||||
"Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only."
|
||||
),
|
||||
)
|
||||
username_validator = UsernameValidator()
|
||||
username = models.CharField(
|
||||
_("username"),
|
||||
max_length=50,
|
||||
unique=True,
|
||||
null=True, # allow null for newly registered users who has not set a user name
|
||||
help_text=_("Required. 50 characters or fewer. Letters, digits and _ only."),
|
||||
validators=[username_validator],
|
||||
error_messages={
|
||||
"unique": _("A user with that username already exists."),
|
||||
},
|
||||
)
|
||||
email = models.EmailField(_("email address"), unique=True, default=None, null=True)
|
||||
following = models.JSONField(default=list)
|
||||
mastodon_id = models.CharField(max_length=100, blank=False)
|
||||
# mastodon domain name, eg donotban.com
|
||||
mastodon_site = models.CharField(max_length=100, blank=False)
|
||||
mastodon_id = models.CharField(max_length=100, default=None, null=True)
|
||||
mastodon_username = models.CharField(max_length=100, default=None, null=True)
|
||||
mastodon_site = models.CharField(max_length=100, default=None, null=True)
|
||||
mastodon_token = models.CharField(max_length=2048, default="")
|
||||
mastodon_refresh_token = models.CharField(max_length=2048, default="")
|
||||
mastodon_locked = models.BooleanField(default=False)
|
||||
|
@ -50,8 +67,13 @@ class User(AbstractUser):
|
|||
class Meta:
|
||||
constraints = [
|
||||
models.UniqueConstraint(
|
||||
fields=["username", "mastodon_site"], name="unique_user_identity"
|
||||
)
|
||||
fields=["mastodon_username", "mastodon_site"],
|
||||
name="unique_mastodon_username",
|
||||
),
|
||||
models.UniqueConstraint(
|
||||
fields=["mastodon_id", "mastodon_site"],
|
||||
name="unique_mastodon_id",
|
||||
),
|
||||
]
|
||||
|
||||
# def save(self, *args, **kwargs):
|
||||
|
@ -60,25 +82,31 @@ class User(AbstractUser):
|
|||
# return super().save(*args, **kwargs)
|
||||
|
||||
@property
|
||||
def mastodon_username(self):
|
||||
return self.username + "@" + self.mastodon_site
|
||||
def mastodon_acct(self):
|
||||
return (
|
||||
f"{self.mastodon_username}@{self.mastodon_site}"
|
||||
if self.mastodon_username
|
||||
else ""
|
||||
)
|
||||
|
||||
@property
|
||||
def display_name(self):
|
||||
return (
|
||||
self.mastodon_account["display_name"]
|
||||
self.mastodon_account.get("display_name")
|
||||
if self.mastodon_account
|
||||
and "display_name" in self.mastodon_account
|
||||
and self.mastodon_account["display_name"]
|
||||
else self.mastodon_username
|
||||
else (self.username or self.mastodon_acct or "")
|
||||
)
|
||||
|
||||
@property
|
||||
def handler(self):
|
||||
return self.mastodon_acct or self.username or f"~{self.pk}"
|
||||
|
||||
@property
|
||||
def url(self):
|
||||
return reverse("journal:user_profile", args=[self.mastodon_username])
|
||||
return reverse("journal:user_profile", args=[self.handler])
|
||||
|
||||
def __str__(self):
|
||||
return self.mastodon_username
|
||||
return f'{self.pk}:{self.username or ""}:{self.mastodon_acct}'
|
||||
|
||||
def get_preference(self):
|
||||
pref = Preference.objects.filter(user=self).first() # self.preference
|
||||
|
@ -86,6 +114,27 @@ class User(AbstractUser):
|
|||
pref = Preference.objects.create(user=self)
|
||||
return pref
|
||||
|
||||
def clear(self):
|
||||
if self.mastodon_site == "removed" and not self.is_active:
|
||||
return
|
||||
self.first_name = self.mastodon_username
|
||||
self.last_name = self.mastodon_site
|
||||
self.is_active = False
|
||||
self.email = None
|
||||
# self.username = "~removed~" + str(self.pk)
|
||||
# to get ready for federation, username has to be reserved
|
||||
self.mastodon_username = "~removed~" + str(self.pk)
|
||||
self.mastodon_id = None
|
||||
self.mastodon_site = "removed"
|
||||
self.mastodon_token = ""
|
||||
self.mastodon_locked = False
|
||||
self.mastodon_followers = []
|
||||
self.mastodon_following = []
|
||||
self.mastodon_mutes = []
|
||||
self.mastodon_blocks = []
|
||||
self.mastodon_domain_blocks = []
|
||||
self.mastodon_account = {}
|
||||
|
||||
def refresh_mastodon_data(self):
|
||||
"""Try refresh account data from mastodon server, return true if refreshed successfully, note it will not save to db"""
|
||||
self.mastodon_last_refresh = timezone.now()
|
||||
|
@ -102,9 +151,11 @@ class User(AbstractUser):
|
|||
if mastodon_account:
|
||||
self.mastodon_account = mastodon_account
|
||||
self.mastodon_locked = mastodon_account["locked"]
|
||||
if self.username != mastodon_account["username"]:
|
||||
print(f"username changed from {self} to {mastodon_account['username']}")
|
||||
self.username = mastodon_account["username"]
|
||||
if self.mastodon_username != mastodon_account["username"]:
|
||||
logger.warn(
|
||||
f"username changed from {self} to {mastodon_account['username']}"
|
||||
)
|
||||
self.mastodon_username = mastodon_account["username"]
|
||||
# self.mastodon_token = token
|
||||
# user.mastodon_id = mastodon_account['id']
|
||||
self.mastodon_followers = get_related_acct_list(
|
||||
|
@ -139,7 +190,7 @@ class User(AbstractUser):
|
|||
target = User.get(m)
|
||||
if target and (
|
||||
(not target.mastodon_locked)
|
||||
or self.mastodon_username in target.mastodon_followers
|
||||
or self.mastodon_acct in target.mastodon_followers
|
||||
):
|
||||
fl.append(target.pk)
|
||||
return fl
|
||||
|
@ -147,25 +198,25 @@ class User(AbstractUser):
|
|||
def is_blocking(self, target):
|
||||
return (
|
||||
(
|
||||
target.mastodon_username in self.mastodon_blocks
|
||||
target.mastodon_acct in self.mastodon_blocks
|
||||
or target.mastodon_site in self.mastodon_domain_blocks
|
||||
)
|
||||
if target.is_authenticated
|
||||
else self.preference.no_anonymous_view
|
||||
else self.preference.no_anonymous_view # type: ignore
|
||||
)
|
||||
|
||||
def is_blocked_by(self, target):
|
||||
return target.is_authenticated and target.is_blocking(self)
|
||||
|
||||
def is_muting(self, target):
|
||||
return target.mastodon_username in self.mastodon_mutes
|
||||
return target.mastodon_acct in self.mastodon_mutes
|
||||
|
||||
def is_following(self, target):
|
||||
return (
|
||||
self.mastodon_username in target.mastodon_followers
|
||||
self.mastodon_acct in target.mastodon_followers
|
||||
if target.mastodon_locked
|
||||
else self.mastodon_username in target.mastodon_followers
|
||||
or target.mastodon_username in self.mastodon_following
|
||||
else self.mastodon_acct in target.mastodon_followers
|
||||
or target.mastodon_acct in self.mastodon_following
|
||||
)
|
||||
|
||||
def is_followed_by(self, target):
|
||||
|
@ -196,14 +247,15 @@ class User(AbstractUser):
|
|||
return unread_announcements
|
||||
|
||||
@classmethod
|
||||
def get(cls, id):
|
||||
if isinstance(id, str):
|
||||
try:
|
||||
username = id.split("@")[0]
|
||||
site = id.split("@")[1]
|
||||
except IndexError:
|
||||
def get(cls, name):
|
||||
if isinstance(name, str):
|
||||
sp = name.split("@")
|
||||
if len(sp) == 1:
|
||||
query_kwargs = {"username": name}
|
||||
elif len(sp) == 2:
|
||||
query_kwargs = {"mastodon_username": sp[0], "mastodon_site": sp[1]}
|
||||
else:
|
||||
return None
|
||||
query_kwargs = {"username": username, "mastodon_site": site}
|
||||
elif isinstance(id, int):
|
||||
query_kwargs = {"pk": id}
|
||||
else:
|
||||
|
@ -248,8 +300,6 @@ class Report(models.Model):
|
|||
)
|
||||
image = models.ImageField(
|
||||
upload_to=report_image_path,
|
||||
height_field=None,
|
||||
width_field=None,
|
||||
blank=True,
|
||||
default="",
|
||||
)
|
||||
|
|
|
@ -1,26 +1,4 @@
|
|||
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.utils import PageLinksGenerator
|
||||
from management.models import Announcement
|
||||
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 refresh_mastodon_data_task(user, token=None):
|
||||
|
|
|
@ -18,9 +18,9 @@
|
|||
{% for report in reports %}
|
||||
<article>
|
||||
<header>
|
||||
<a href="{% url 'journal:user_profile' report.submit_user.mastodon_username %}">{{ report.submit_user.username }}</a>
|
||||
<a href="{{ report.submit_user.url }}">{{ report.submit_user.display_name }}</a>
|
||||
{% trans '投诉了' %}
|
||||
<a href="{% url 'journal:user_profile' report.reported_user.mastodon_username %}">{{ report.reported_user.username }}</a>
|
||||
<a href="{{ report.reported_user.url }}">{{ report.reported_user.display_name }}</a>
|
||||
@{{ report.submitted_time }}
|
||||
</header>
|
||||
<p>{{ report.message }}</p>
|
||||
|
|
|
@ -58,7 +58,7 @@
|
|||
{% else %}
|
||||
<div id="userMastodonID" hidden="true"></div>
|
||||
{% endif %}
|
||||
<div id="userPageURL" hidden="true">{% url 'journal:user_profile' 0 %}</div>
|
||||
<div id="userPageURL" hidden="true">/users/0/</div>
|
||||
<div id="spinner" hidden>
|
||||
<div class="spinner">
|
||||
<div></div>
|
||||
|
|
|
@ -2,6 +2,7 @@ from django.shortcuts import redirect, render, get_object_or_404
|
|||
from django.urls import reverse
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from management.models import Announcement
|
||||
from .models import User, Report, Preference
|
||||
from .forms import ReportForm
|
||||
from mastodon.api import *
|
||||
|
@ -81,15 +82,12 @@ def set_layout(request):
|
|||
if request.POST.get("name") == "profile":
|
||||
request.user.preference.profile_layout = layout
|
||||
request.user.preference.save(update_fields=["profile_layout"])
|
||||
return redirect(
|
||||
reverse("journal:user_profile", args=[request.user.mastodon_username])
|
||||
)
|
||||
return redirect(request.user.url)
|
||||
elif request.POST.get("name") == "discover":
|
||||
request.user.preference.discover_layout = layout
|
||||
request.user.preference.save(update_fields=["discover_layout"])
|
||||
return redirect(reverse("catalog:discover"))
|
||||
else:
|
||||
raise BadRequest()
|
||||
raise BadRequest()
|
||||
|
||||
|
||||
@login_required
|
||||
|
|
Loading…
Add table
Reference in a new issue