diff --git a/boofilsic/settings.py b/boofilsic/settings.py index 118dacf0..995b8ecc 100644 --- a/boofilsic/settings.py +++ b/boofilsic/settings.py @@ -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 ] diff --git a/catalog/templates/_item_comments.html b/catalog/templates/_item_comments.html index 6a217222..c9607f14 100644 --- a/catalog/templates/_item_comments.html +++ b/catalog/templates/_item_comments.html @@ -45,9 +45,9 @@ {% if comment.rating_grade %}{{ comment.rating_grade|rating_star }}{% endif %} - {{ comment.owner.display_name }} + title="@{{ comment.owner.handler }}">{{ comment.owner.display_name }} diff --git a/catalog/templates/_item_comments_by_episode.html b/catalog/templates/_item_comments_by_episode.html index efe2f68b..e88b426e 100644 --- a/catalog/templates/_item_comments_by_episode.html +++ b/catalog/templates/_item_comments_by_episode.html @@ -63,9 +63,9 @@ {% if comment.rating_grade %}{{ comment.rating_grade|rating_star }}{% endif %} - {{ comment.owner.display_name }} + title="@{{ comment.owner.handler }}">{{ comment.owner.display_name }} diff --git a/catalog/templates/_item_reviews.html b/catalog/templates/_item_reviews.html index 67c54ffb..018388df 100644 --- a/catalog/templates/_item_reviews.html +++ b/catalog/templates/_item_reviews.html @@ -23,9 +23,9 @@ {% if review.rating_grade %}{{ review.rating_grade|rating_star }}{% endif %} - {{ review.owner.display_name }} + title="@{{ review.owner.handler }}">{{ review.owner.display_name }} {{ review.created_time|date }} diff --git a/catalog/templates/_item_user_pieces.html b/catalog/templates/_item_user_pieces.html index fde0f31e..8ad9570f 100644 --- a/catalog/templates/_item_user_pieces.html +++ b/catalog/templates/_item_user_pieces.html @@ -25,7 +25,7 @@
{% for tag in mark.tags %} - {{ tag }} + {{ tag }} {% endfor %}
diff --git a/catalog/templates/item_base.html b/catalog/templates/item_base.html index e356aa0a..1f1ef373 100644 --- a/catalog/templates/item_base.html +++ b/catalog/templates/item_base.html @@ -146,7 +146,7 @@ {% if item.last_editor and item.last_editor.preference.show_last_edit %} {% trans '最近编辑:' %} - {{ item.last_editor | default:"" }} + {{ item.last_editor | default:"" }} {% endif %} diff --git a/catalog/templates/item_mark_list.html b/catalog/templates/item_mark_list.html index c7722bfc..ab073d50 100644 --- a/catalog/templates/item_mark_list.html +++ b/catalog/templates/item_mark_list.html @@ -48,8 +48,7 @@ {{ mark.created_time|date }}
- {{ mark.owner.display_name }} + {{ mark.owner.display_name }} {{ mark.action_label }} {% if mark.rating_grade %}{{ mark.rating_grade|rating_star }}{% endif %} {% if mark.comment.focus_item %} diff --git a/catalog/templates/item_review_list.html b/catalog/templates/item_review_list.html index 306bc26e..c8d44bd2 100644 --- a/catalog/templates/item_review_list.html +++ b/catalog/templates/item_review_list.html @@ -46,9 +46,9 @@ - - {{ review.owner.display_name }} + title="@{{ review.owner.handler }}">{{ review.owner.display_name }}
{{ review.plain_content | truncate:200 }}
diff --git a/common/templates/_sidebar.html b/common/templates/_sidebar.html index f4f39873..42c76bb8 100644 --- a/common/templates/_sidebar.html +++ b/common/templates/_sidebar.html @@ -38,8 +38,7 @@
- + {% comment %} onclick to workaround webkit issue with in {% endcomment %} @@ -52,7 +51,7 @@ target="_blank" rel="noopener" onclick="window.open(this.href)"> - @{{ user.mastodon_username }} + @{{ user.handler }} {% current_user_relationship user as relationship %} {% if relationship %}{{ relationship }}{% endif %} @@ -188,7 +187,7 @@
{% for t in top_tags %} - {{ t }} + {{ t }} {% empty %}
暂无可见标签
@@ -196,7 +195,7 @@
{% if top_tags %} - ...{% trans '全部' %} + ...{% trans '全部' %} {% endif %} diff --git a/common/views.py b/common/views.py index cf0204db..ecf7832b 100644 --- a/common/views.py +++ b/common/views.py @@ -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: diff --git a/developer/templates/oauth2_provider/authorize.html b/developer/templates/oauth2_provider/authorize.html index bf0033b8..e67215c7 100644 --- a/developer/templates/oauth2_provider/authorize.html +++ b/developer/templates/oauth2_provider/authorize.html @@ -10,7 +10,7 @@ {% csrf_token %} {% if not application.is_official %}

- {{ application.name }} 是由 {{ application.user.mastodon_username }} 创建和维护的应用程序。 + {{ application.name }} 是由 @{{ application.user.handler }} 创建和维护的应用程序。 {{ site_name }}无法保证其安全性和有效性,请自行验证确认后再授权。

{% endif %} diff --git a/journal/importers/opml.py b/journal/importers/opml.py index 800afc75..33c51f0a 100644 --- a/journal/importers/opml.py +++ b/journal/importers/opml.py @@ -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( diff --git a/journal/mixins.py b/journal/mixins.py index 0454791f..8664df1d 100644 --- a/journal/mixins.py +++ b/journal/mixins.py @@ -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 ), diff --git a/journal/templates/_list_item.html b/journal/templates/_list_item.html index 12729309..91d34176 100644 --- a/journal/templates/_list_item.html +++ b/journal/templates/_list_item.html @@ -60,7 +60,7 @@ {{ mark.created_time|date }}
- {% comment %} {{ mark.owner.display_name }} {% endcomment %} + {% comment %} {{ mark.owner.display_name }} {% endcomment %} {{ mark.action_label }} {% if mark.rating_grade %}{{ mark.rating_grade|rating_star }}{% endif %} {% if mark.comment.focus_item %} diff --git a/journal/templates/collection.html b/journal/templates/collection.html index acf26988..170ce85c 100644 --- a/journal/templates/collection.html +++ b/journal/templates/collection.html @@ -19,7 +19,7 @@ + content="{{ collection.owner.display_name }}"> {{ site_name }} {% trans '收藏单' %} - {{ collection.title }} @@ -56,13 +56,13 @@
{{ collection.owner.username }} + alt="{{ collection.owner.display_name }}">

- {{ collection.owner.mastodon_account.display_name }} - @{{ collection.owner.mastodon_username }} + {{ collection.owner.mastodon_account.display_name }} + @{{ collection.owner.handler }}

{% for cat, count in collection.get_summary.items %} diff --git a/journal/templates/piece_delete.html b/journal/templates/piece_delete.html index 946931eb..7012bf72 100644 --- a/journal/templates/piece_delete.html +++ b/journal/templates/piece_delete.html @@ -22,7 +22,7 @@

{{ piece.title }}
{% if piece.visibility > 0 %}{% endif %} - {{ piece.owner.username }} + {{ piece.owner.display_name }} {{ piece.edited_time }}
diff --git a/journal/templates/profile.html b/journal/templates/profile.html index 5ad549ca..3d55a7f6 100644 --- a/journal/templates/profile.html +++ b/journal/templates/profile.html @@ -15,15 +15,14 @@ {% else %} {{ site_name }} - {{ user.display_name }} {% endif %} - + {% if user.preference.no_anonymous_view %}{% endif %} {% include "common_libs.html" with jquery=0 v2=1 %} @@ -49,7 +48,7 @@

@@ -63,7 +62,7 @@
{{ shelf.title }} - {{ shelf.count }} + {{ shelf.count }}
    @@ -90,7 +89,7 @@
    {% trans '创建的收藏单' %} - {{ collections_count }} + {{ collections_count }} {% if user == request.user %} @@ -118,7 +117,7 @@
    {% trans '关注的收藏单' %} - {{ liked_collections_count }} + {{ liked_collections_count }}
      diff --git a/journal/templates/review.html b/journal/templates/review.html index 6e457132..053fb74d 100644 --- a/journal/templates/review.html +++ b/journal/templates/review.html @@ -16,7 +16,8 @@ - + @@ -51,12 +52,12 @@
      {{ review.owner.username }} + alt="{{ review.owner.display_name }}">
      - {{ review.owner.display_name }} - @{{ review.owner.mastodon_username }} + {{ review.owner.display_name }} + @{{ review.owner.handler }}
      评论 {{ review.item.title }} diff --git a/journal/templates/user_collection_list.html b/journal/templates/user_collection_list.html index 9e75e0d4..9df3959f 100644 --- a/journal/templates/user_collection_list.html +++ b/journal/templates/user_collection_list.html @@ -13,7 +13,7 @@ - {{ site_name }} - {{ user.mastodon_username }} - + <title>{{ site_name }} - {{ user.display_name }} - {% if liked %}关注的{% endif %} 收藏单 {% include "common_libs.html" with jquery=0 v2=1 %} @@ -44,8 +44,8 @@ {{ collection.title }} {% if liked %} - - {{ collection.owner.display_name }} + {{ collection.owner.display_name }} {% endif %}

      {% empty %} diff --git a/journal/templates/user_item_list_base.html b/journal/templates/user_item_list_base.html index aa7aa1f4..9a3a56be 100644 --- a/journal/templates/user_item_list_base.html +++ b/journal/templates/user_item_list_base.html @@ -11,7 +11,7 @@ - {% block title %}{{ site_name }} - {{ user.mastodon_username }}{% endblock %} + {% block title %}{{ site_name }} - {{ user.display_name }}{% endblock %} {% include "common_libs.html" with jquery=0 v2=1 %} @@ -19,7 +19,7 @@
      - {% block head %}{{ user.mastodon_username }}{% endblock %} + {% block head %}{{ user.display_name }}{% endblock %}
      {% for member in members %} diff --git a/journal/templates/user_tag_list.html b/journal/templates/user_tag_list.html index 0e321f03..125f09a2 100644 --- a/journal/templates/user_tag_list.html +++ b/journal/templates/user_tag_list.html @@ -13,7 +13,7 @@ - {{ site_name }} - 我的标签 + {{ site_name }} - {{ user.display_name }} 的标签 {% include "common_libs.html" with jquery=0 v2=1 %} @@ -25,7 +25,7 @@ {% for v in tags %} - {{ v.title }} + {{ v.title }} ({{ v.total }}) diff --git a/journal/templates/user_tagmember_list.html b/journal/templates/user_tagmember_list.html index 1dd17df8..0122238c 100644 --- a/journal/templates/user_tagmember_list.html +++ b/journal/templates/user_tagmember_list.html @@ -1,14 +1,14 @@ {% extends "user_item_list_base.html" %} {% load i18n %} {% block title %} - {{ site_name }} - {{ user.mastodon_username }} - {{ tag.title }} {% trans '标签' %} + {{ site_name }} - {{ user.display_name }} - {{ tag.title }} {% trans '标签' %} {% endblock %} {% block head %} {{ tag.title }}
      {% if tag.visibility > 0 %}{% endif %} - {{ user.mastodon_username }}的{% trans '标签' %} + {{ user.display_name }}的{% trans '标签' %} {% if user == request.user %}
      diff --git a/social/templates/feed_data.html b/social/templates/feed_data.html index b347bcc2..a2c2511c 100644 --- a/social/templates/feed_data.html +++ b/social/templates/feed_data.html @@ -21,12 +21,10 @@ {% with "activity/"|add:activity.template|add:".html" as template %} diff --git a/social/tests.py b/social/tests.py index e7cf87cb..7c2ee48c 100644 --- a/social/tests.py +++ b/social/tests.py @@ -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 diff --git a/users/account.py b/users/account.py index 8837b2c0..3dc5ec59 100644 --- a/users/account.py +++ b/users/account.py @@ -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")) diff --git a/users/api.py b/users/api.py index 35034081..844d6084 100644 --- a/users/api.py +++ b/users/api.py @@ -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"), } diff --git a/users/management/commands/disable_user.py b/users/management/commands/disable_user.py index 67b3577e..f0556316 100644 --- a/users/management/commands/disable_user.py +++ b/users/management/commands/disable_user.py @@ -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") diff --git a/users/migrations/0005_add_dedicated_username.py b/users/migrations/0005_add_dedicated_username.py new file mode 100644 index 00000000..1f8066c2 --- /dev/null +++ b/users/migrations/0005_add_dedicated_username.py @@ -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" + ), + ), + ] diff --git a/users/migrations/0006_unique_email.py b/users/migrations/0006_unique_email.py new file mode 100644 index 00000000..b03656ab --- /dev/null +++ b/users/migrations/0006_unique_email.py @@ -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", + ), + ), + ] diff --git a/users/models.py b/users/models.py index 216006a3..2cab8197 100644 --- a/users/models.py +++ b/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="", ) diff --git a/users/tasks.py b/users/tasks.py index 7ba83a41..93f2df4c 100644 --- a/users/tasks.py +++ b/users/tasks.py @@ -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): diff --git a/users/templates/users/manage_report.html b/users/templates/users/manage_report.html index 9c2bda0e..670bcf5a 100644 --- a/users/templates/users/manage_report.html +++ b/users/templates/users/manage_report.html @@ -18,9 +18,9 @@ {% for report in reports %}
      - {{ report.submit_user.username }} + {{ report.submit_user.display_name }} {% trans '投诉了' %} - {{ report.reported_user.username }} + {{ report.reported_user.display_name }} @{{ report.submitted_time }}

      {{ report.message }}

      diff --git a/users/templates/users/relation_list.html b/users/templates/users/relation_list.html index 09535669..b929606e 100644 --- a/users/templates/users/relation_list.html +++ b/users/templates/users/relation_list.html @@ -58,7 +58,7 @@ {% else %} {% endif %} - +