diff --git a/journal/views.py b/journal/views.py index c7853316..d99c19e7 100644 --- a/journal/views.py +++ b/journal/views.py @@ -852,9 +852,11 @@ def profile_anonymous(request, id): def profile(request, user_name): if request.method != "GET": raise BadRequest() - user = User.get(user_name) + user = User.get(user_name, case_sensitive=True) if user is None or not user.is_active: return render_user_not_found(request) + if user.handler != user_name: + return redirect(user.url) if not request.user.is_authenticated and user.get_preference().no_anonymous_view: return profile_anonymous(request, user_name) # access one's own home page diff --git a/mastodon/api.py b/mastodon/api.py index 6272b3a0..89090d48 100644 --- a/mastodon/api.py +++ b/mastodon/api.py @@ -262,9 +262,9 @@ def detect_server_info(login_domain): def get_mastodon_application(login_domain): domain = login_domain - app = MastodonApplication.objects.filter(domain_name=domain).first() + app = MastodonApplication.objects.filter(domain_name__iexact=domain).first() if not app: - app = MastodonApplication.objects.filter(api_domain=domain).first() + app = MastodonApplication.objects.filter(api_domain__iexact=domain).first() if app: return app if domain == TWITTER_DOMAIN: @@ -274,7 +274,7 @@ def get_mastodon_application(login_domain): raise Exception("不支持其它实例登录") domain, api_domain, server_version = detect_server_info(login_domain) if login_domain != domain: - app = MastodonApplication.objects.filter(domain_name=domain).first() + app = MastodonApplication.objects.filter(domain_name__iexact=domain).first() if app: return app response = create_app(api_domain) @@ -289,8 +289,8 @@ def get_mastodon_application(login_domain): logger.error(f"Error creating app for {domain}: unable to parse response") raise Exception("实例注册应用失败,返回内容无法识别") app = MastodonApplication.objects.create( - domain_name=domain, - api_domain=api_domain, + domain_name=domain.lower(), + api_domain=api_domain.lower(), server_version=server_version, app_id=data["id"], client_id=data["client_id"], diff --git a/mastodon/auth.py b/mastodon/auth.py index b7e096ea..d8288a43 100644 --- a/mastodon/auth.py +++ b/mastodon/auth.py @@ -22,7 +22,7 @@ class OAuth2Backend(ModelBackend): return None try: user = UserModel._default_manager.get( - mastodon_id=mastodon_id, mastodon_site=site + mastodon_id__iexact=mastodon_id, mastodon_site__iexact=site ) return user if self.user_can_authenticate(user) else None except UserModel.DoesNotExist: diff --git a/users/account.py b/users/account.py index 58b1728d..54d470e3 100644 --- a/users/account.py +++ b/users/account.py @@ -75,7 +75,7 @@ def connect(request): "common/error.html", {"msg": _("无效的电子邮件地址")}, ) - user = User.objects.filter(email=login_email).first() + user = User.objects.filter(email__iexact=login_email).first() django_rq.get_queue("mastodon").enqueue( send_verification_link, user.pk if user else 0, @@ -236,13 +236,20 @@ class RegistrationForm(forms.ModelForm): username = self.cleaned_data.get("username") if username and self.instance and self.instance.username: username = self.instance.username + elif ( + username + and User.objects.filter(username__iexact=username) + .exclude(pk=self.instance.pk if self.instance else -1) + .exists() + ): + raise forms.ValidationError(_("This username is already in use.")) return username def clean_email(self): email = self.cleaned_data.get("email") if ( email - and User.objects.filter(email=email) + and User.objects.filter(email__iexact=email) .exclude(pk=self.instance.pk if self.instance else -1) .exists() ): @@ -317,7 +324,7 @@ def verify_email(request): else: error = _("电子邮件地址不匹配") elif action == "register": - user = User.objects.filter(email=email).first() + user = User.objects.filter(email__iexact=email).first() if user: error = _("此电子邮件地址已被注册") else: @@ -348,7 +355,9 @@ def register(request): if not form.is_valid(): return render(request, "users/register.html", {"form": form}) if request.user.username is None and form.cleaned_data["username"]: - if User.objects.filter(username=form.cleaned_data["username"]).exists(): + if User.objects.filter( + username__iexact=form.cleaned_data["username"] + ).exists(): return render( request, "users/register.html", @@ -360,8 +369,10 @@ def register(request): request.user.username = form.cleaned_data["username"] username_changed = True if form.cleaned_data["email"]: - if form.cleaned_data["email"] != request.user.email: - if User.objects.filter(email=form.cleaned_data["email"]).exists(): + if form.cleaned_data["email"].lower() != (request.user.email or "").lower(): + if User.objects.filter( + email__iexact=form.cleaned_data["email"] + ).exists(): return render( request, "users/register.html", @@ -412,7 +423,7 @@ def swap_login(request, token, site, refresh_token): else: try: existing_user = User.objects.get( - mastodon_username=username, mastodon_site=site + mastodon_username__iexact=username, mastodon_site__iexact=site ) messages.add_message( request, messages.ERROR, _(f"该身份 {username}@{site} 已被用于其它账号。") diff --git a/users/models.py b/users/models.py index 38763ad2..b7959b84 100644 --- a/users/models.py +++ b/users/models.py @@ -505,7 +505,7 @@ class User(AbstractUser): return unread_announcements @classmethod - def get(cls, name): + def get(cls, name, case_sensitive=False): if isinstance(name, str): sp = name.split("@") if name.startswith("~"): @@ -514,9 +514,18 @@ class User(AbstractUser): except: return None elif len(sp) == 1: - query_kwargs = {"username": name} + query_kwargs = { + "username__iexact" if case_sensitive else "username": name + } elif len(sp) == 2: - query_kwargs = {"mastodon_username": sp[0], "mastodon_site": sp[1]} + query_kwargs = { + "mastodon_username__iexact" + if case_sensitive + else "mastodon_username": sp[0], + "mastodon_site__iexact" + if case_sensitive + else "mastodon_site": sp[1], + } else: return None elif isinstance(name, int):