remove 'ilike' for most case insensitive searches - too slow

This commit is contained in:
rimu 2024-02-09 14:58:51 +13:00
parent 321a95b59b
commit 45d8b042a5
3 changed files with 12 additions and 11 deletions

View file

@ -6,7 +6,7 @@ from datetime import timedelta
from random import randint from random import randint
from typing import Union, Tuple from typing import Union, Tuple
from flask import current_app, request, g, url_for from flask import current_app, request, g, url_for
from sqlalchemy import text from sqlalchemy import text, func
from app import db, cache, constants, celery from app import db, cache, constants, celery
from app.models import User, Post, Community, BannedInstances, File, PostReply, AllowedInstances, Instance, utcnow, \ from app.models import User, Post, Community, BannedInstances, File, PostReply, AllowedInstances, Instance, utcnow, \
PostVote, PostReplyVote, ActivityPubLog, Notification, Site, CommunityMember PostVote, PostReplyVote, ActivityPubLog, Notification, Site, CommunityMember
@ -189,10 +189,10 @@ def find_actor_or_create(actor: str) -> Union[User, Community, None]:
# Initially, check if the user exists in the local DB already # Initially, check if the user exists in the local DB already
if current_app.config['SERVER_NAME'] + '/c/' in actor: if current_app.config['SERVER_NAME'] + '/c/' in actor:
return Community.query.filter(Community.ap_profile_id.ilike(actor)).first() # finds communities formatted like https://localhost/c/* return Community.query.filter(func.lower(Community.ap_profile_id) == func.lower(actor)).first() # finds communities formatted like https://localhost/c/*
if current_app.config['SERVER_NAME'] + '/u/' in actor: if current_app.config['SERVER_NAME'] + '/u/' in actor:
user = User.query.filter(User.user_name.ilike(actor.split('/')[-1])).filter_by(ap_id=None, banned=False).first() # finds local users user = User.query.filter(func.lower(User.user_name) == func.lower(actor.split('/')[-1])).filter_by(ap_id=None, banned=False).first() # finds local users
if user is None: if user is None:
return None return None
elif actor.startswith('https://'): elif actor.startswith('https://'):
@ -203,11 +203,11 @@ def find_actor_or_create(actor: str) -> Union[User, Community, None]:
else: else:
if instance_blocked(server): if instance_blocked(server):
return None return None
user = User.query.filter(User.ap_profile_id.ilike(actor)).first() # finds users formatted like https://kbin.social/u/tables user = User.query.filter(func.lower(User.ap_profile_id) == func.lower(actor)).first() # finds users formatted like https://kbin.social/u/tables
if (user and user.banned) or (user and user.deleted) : if (user and user.banned) or (user and user.deleted) :
return None return None
if user is None: if user is None:
user = Community.query.filter(Community.ap_profile_id.ilike(actor)).first() user = Community.query.filter(func.lower(Community.ap_profile_id) == func.lower(actor)).first()
if user is not None: if user is not None:
if not user.is_local() and user.ap_fetched_at < utcnow() - timedelta(days=7): if not user.is_local() and user.ap_fetched_at < utcnow() - timedelta(days=7):

View file

@ -3,6 +3,7 @@ from wtforms import StringField, PasswordField, SubmitField, HiddenField, Boolea
from wtforms.validators import ValidationError, DataRequired, Email, EqualTo, Length from wtforms.validators import ValidationError, DataRequired, Email, EqualTo, Length
from flask_babel import _, lazy_gettext as _l from flask_babel import _, lazy_gettext as _l
from app.models import User, Community from app.models import User, Community
from sqlalchemy import func
class LoginForm(FlaskForm): class LoginForm(FlaskForm):
@ -26,18 +27,18 @@ class RegistrationForm(FlaskForm):
submit = SubmitField(_l('Register')) submit = SubmitField(_l('Register'))
def validate_real_email(self, email): def validate_real_email(self, email):
user = User.query.filter(User.email.ilike(email.data.strip())).first() user = User.query.filter(func.lower(User.email) == func.lower(email.data.strip())).first()
if user is not None: if user is not None:
raise ValidationError(_l('An account with this email address already exists.')) raise ValidationError(_l('An account with this email address already exists.'))
def validate_user_name(self, user_name): def validate_user_name(self, user_name):
user = User.query.filter(User.user_name.ilike(user_name.data.strip())).filter_by(ap_id=None).first() user = User.query.filter(func.lower(User.user_name) == func.lower(user_name.data.strip())).filter_by(ap_id=None).first()
if user is not None: if user is not None:
if user.deleted: if user.deleted:
raise ValidationError(_l('This username was used in the past and cannot be reused.')) raise ValidationError(_l('This username was used in the past and cannot be reused.'))
else: else:
raise ValidationError(_l('An account with this user name already exists.')) raise ValidationError(_l('An account with this user name already exists.'))
community = Community.query.filter(Community.name.ilike(user_name.data.strip())).first() community = Community.query.filter(func.lower(Community.name) == func.lower(user_name.data.strip())).first()
if community is not None: if community is not None:
raise ValidationError(_l('A community with this name exists so it cannot be used for a user.')) raise ValidationError(_l('A community with this name exists so it cannot be used for a user.'))

View file

@ -16,7 +16,7 @@ from app.models import Community, File, BannedInstances, PostReply, PostVote, Po
Instance, Notification, User Instance, Notification, User
from app.utils import get_request, gibberish, markdown_to_html, domain_from_url, allowlist_html, \ from app.utils import get_request, gibberish, markdown_to_html, domain_from_url, allowlist_html, \
html_to_markdown, is_image_url, ensure_directory_exists, inbox_domain, post_ranking, shorten_string, parse_page html_to_markdown, is_image_url, ensure_directory_exists, inbox_domain, post_ranking, shorten_string, parse_page
from sqlalchemy import desc, text from sqlalchemy import func
import os import os
@ -116,7 +116,7 @@ def retrieve_mods_and_backfill(community_id: int):
def community_url_exists(url) -> bool: def community_url_exists(url) -> bool:
community = Community.query.filter(Community.ap_profile_id.ilike(url)).first() community = Community.query.filter(func.lower(Community.ap_profile_id) == func.lower(url)).first()
return community is not None return community is not None
@ -125,7 +125,7 @@ def actor_to_community(actor) -> Community:
if '@' in actor: if '@' in actor:
community = Community.query.filter_by(banned=False, ap_id=actor).first() community = Community.query.filter_by(banned=False, ap_id=actor).first()
else: else:
community = Community.query.filter(Community.name.ilike(actor)).filter_by(banned=False, ap_id=None).first() community = Community.query.filter(func.lower(Community.name) == func.lower(actor)).filter_by(banned=False, ap_id=None).first()
return community return community