mirror of https://github.com/Chocobozzz/PeerTube
				
				
				
			Set actor preferred name case insensitive
							parent
							
								
									823c34c07f
								
							
						
					
					
						commit
						85c20aaeb9
					
				|  | @ -99,7 +99,7 @@ async function areSubscriptionsExist (req: express.Request, res: express.Respons | |||
|     const obj = results.find(r => { | ||||
|       const server = r.ActorFollowing.Server | ||||
| 
 | ||||
|       return r.ActorFollowing.preferredUsername === sanitizedHandle.name && | ||||
|       return r.ActorFollowing.preferredUsername.toLowerCase() === sanitizedHandle.name.toLowerCase() && | ||||
|         ( | ||||
|           (!server && !sanitizedHandle.host) || | ||||
|           (server.host === sanitizedHandle.host) | ||||
|  |  | |||
|  | @ -27,7 +27,7 @@ import { CONFIG, registerConfigChangedHandler } from './config' | |||
| 
 | ||||
| // ---------------------------------------------------------------------------
 | ||||
| 
 | ||||
| const LAST_MIGRATION_VERSION = 765 | ||||
| const LAST_MIGRATION_VERSION = 770 | ||||
| 
 | ||||
| // ---------------------------------------------------------------------------
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1,44 @@ | |||
| import * as Sequelize from 'sequelize' | ||||
| 
 | ||||
| async function up (utils: { | ||||
|   transaction: Sequelize.Transaction | ||||
|   queryInterface: Sequelize.QueryInterface | ||||
|   sequelize: Sequelize.Sequelize | ||||
|   db: any | ||||
| }): Promise<void> { | ||||
|   const { transaction } = utils | ||||
| 
 | ||||
|   await utils.sequelize.query('drop index if exists "actor_preferred_username"', { transaction }) | ||||
|   await utils.sequelize.query('drop index if exists "actor_preferred_username_server_id"', { transaction }) | ||||
| 
 | ||||
|   await utils.sequelize.query( | ||||
|     'DELETE FROM "actor" v1 USING (' + | ||||
|       'SELECT MIN(id) as id, lower("preferredUsername") AS "lowerPreferredUsername", "serverId" ' + | ||||
|       'FROM "actor" ' + | ||||
|       'GROUP BY "lowerPreferredUsername", "serverId" HAVING COUNT(*) > 1 AND "serverId" IS NOT NULL' + | ||||
|     ') v2 ' + | ||||
|     'WHERE lower(v1."preferredUsername") = v2."lowerPreferredUsername" AND v1."serverId" = v2."serverId" AND v1.id <> v2.id', | ||||
|     { transaction } | ||||
|   ) | ||||
| 
 | ||||
|   await utils.sequelize.query( | ||||
|     'DELETE FROM "actor" v1 USING (' + | ||||
|       'SELECT MIN(id) as id, lower("preferredUsername") AS "lowerPreferredUsername", "serverId" ' + | ||||
|       'FROM "actor" ' + | ||||
|       'GROUP BY "lowerPreferredUsername", "serverId" HAVING COUNT(*) > 1 AND "serverId" IS NULL' + | ||||
|     ') v2 ' + | ||||
|     'WHERE lower(v1."preferredUsername") = v2."lowerPreferredUsername" AND v1."serverId" IS NULL AND v1.id <> v2.id', | ||||
|     { transaction } | ||||
|   ) | ||||
| } | ||||
| 
 | ||||
| async function down (utils: { | ||||
|   queryInterface: Sequelize.QueryInterface | ||||
|   transaction: Sequelize.Transaction | ||||
| }) { | ||||
| } | ||||
| 
 | ||||
| export { | ||||
|   up, | ||||
|   down | ||||
| } | ||||
|  | @ -189,8 +189,10 @@ export class AccountVideoRateModel extends Model<Partial<AttributesOnly<AccountV | |||
|               model: ActorModel.unscoped(), | ||||
|               required: true, | ||||
|               where: { | ||||
|                 preferredUsername: accountName, | ||||
|                 serverId: null | ||||
|                 [Op.and]: [ | ||||
|                   ActorModel.wherePreferredUsername(accountName), | ||||
|                   { serverId: null } | ||||
|                 ] | ||||
|               } | ||||
|             } | ||||
|           ] | ||||
|  |  | |||
|  | @ -37,8 +37,8 @@ import { ActorImageModel } from '../actor/actor-image' | |||
| import { ApplicationModel } from '../application/application' | ||||
| import { ServerModel } from '../server/server' | ||||
| import { ServerBlocklistModel } from '../server/server-blocklist' | ||||
| import { UserModel } from '../user/user' | ||||
| import { buildSQLAttributes, getSort, throwIfNotValid } from '../shared' | ||||
| import { UserModel } from '../user/user' | ||||
| import { VideoModel } from '../video/video' | ||||
| import { VideoChannelModel } from '../video/video-channel' | ||||
| import { VideoCommentModel } from '../video/video-comment' | ||||
|  | @ -296,9 +296,7 @@ export class AccountModel extends Model<Partial<AttributesOnly<AccountModel>>> { | |||
|           { | ||||
|             model: ActorModel, | ||||
|             required: true, | ||||
|             where: { | ||||
|               preferredUsername: name | ||||
|             } | ||||
|             where: ActorModel.wherePreferredUsername(name) | ||||
|           } | ||||
|         ] | ||||
|       } | ||||
|  | @ -321,9 +319,7 @@ export class AccountModel extends Model<Partial<AttributesOnly<AccountModel>>> { | |||
|         { | ||||
|           model: ActorModel, | ||||
|           required: true, | ||||
|           where: { | ||||
|             preferredUsername: name | ||||
|           }, | ||||
|           where: ActorModel.wherePreferredUsername(name), | ||||
|           include: [ | ||||
|             { | ||||
|               model: ServerModel, | ||||
|  |  | |||
|  | @ -37,8 +37,8 @@ import { logger } from '../../helpers/logger' | |||
| import { ACTOR_FOLLOW_SCORE, CONSTRAINTS_FIELDS, FOLLOW_STATES, SERVER_ACTOR_NAME, SORTABLE_COLUMNS } from '../../initializers/constants' | ||||
| import { AccountModel } from '../account/account' | ||||
| import { ServerModel } from '../server/server' | ||||
| import { doesExist } from '../shared/query' | ||||
| import { buildSQLAttributes, createSafeIn, getSort, searchAttribute, throwIfNotValid } from '../shared' | ||||
| import { doesExist } from '../shared/query' | ||||
| import { VideoChannelModel } from '../video/video-channel' | ||||
| import { ActorModel, unusedActorAttributesForAPI } from './actor' | ||||
| import { InstanceListFollowersQueryBuilder, ListFollowersOptions } from './sql/instance-list-followers-query-builder' | ||||
|  | @ -265,9 +265,7 @@ export class ActorFollowModel extends Model<Partial<AttributesOnly<ActorFollowMo | |||
|       model: ActorModel, | ||||
|       required: true, | ||||
|       as: 'ActorFollowing', | ||||
|       where: { | ||||
|         preferredUsername: targetName | ||||
|       }, | ||||
|       where: ActorModel.wherePreferredUsername(targetName), | ||||
|       include: [ | ||||
|         { | ||||
|           model: VideoChannelModel.unscoped(), | ||||
|  | @ -313,24 +311,16 @@ export class ActorFollowModel extends Model<Partial<AttributesOnly<ActorFollowMo | |||
|         if (t.host) { | ||||
|           return { | ||||
|             [Op.and]: [ | ||||
|               { | ||||
|                 $preferredUsername$: t.name | ||||
|               }, | ||||
|               { | ||||
|                 $host$: t.host | ||||
|               } | ||||
|               ActorModel.wherePreferredUsername(t.name, '$preferredUsername$'), | ||||
|               { $host$: t.host } | ||||
|             ] | ||||
|           } | ||||
|         } | ||||
| 
 | ||||
|         return { | ||||
|           [Op.and]: [ | ||||
|             { | ||||
|               $preferredUsername$: t.name | ||||
|             }, | ||||
|             { | ||||
|               $serverId$: null | ||||
|             } | ||||
|             ActorModel.wherePreferredUsername(t.name, '$preferredUsername$'), | ||||
|             { $serverId$: null } | ||||
|           ] | ||||
|         } | ||||
|       }) | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| import { literal, Op, QueryTypes, Transaction } from 'sequelize' | ||||
| import { col, fn, literal, Op, QueryTypes, Transaction, where } from 'sequelize' | ||||
| import { | ||||
|   AllowNull, | ||||
|   BelongsTo, | ||||
|  | @ -130,7 +130,8 @@ export const unusedActorAttributesForAPI: (keyof AttributesOnly<ActorModel>)[] = | |||
|       unique: true | ||||
|     }, | ||||
|     { | ||||
|       fields: [ 'preferredUsername', 'serverId' ], | ||||
|       fields: [ fn('lower', col('preferredUsername')), 'serverId' ], | ||||
|       name: 'actor_preferred_username_lower_server_id', | ||||
|       unique: true, | ||||
|       where: { | ||||
|         serverId: { | ||||
|  | @ -139,7 +140,8 @@ export const unusedActorAttributesForAPI: (keyof AttributesOnly<ActorModel>)[] = | |||
|       } | ||||
|     }, | ||||
|     { | ||||
|       fields: [ 'preferredUsername' ], | ||||
|       fields: [ fn('lower', col('preferredUsername')) ], | ||||
|       name: 'actor_preferred_username_lower', | ||||
|       unique: true, | ||||
|       where: { | ||||
|         serverId: null | ||||
|  | @ -327,6 +329,12 @@ export class ActorModel extends Model<Partial<AttributesOnly<ActorModel>>> { | |||
| 
 | ||||
|   // ---------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   static wherePreferredUsername (preferredUsername: string, colName = 'preferredUsername') { | ||||
|     return where(fn('lower', col(colName)), preferredUsername.toLowerCase()) | ||||
|   } | ||||
| 
 | ||||
|   // ---------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   static async load (id: number): Promise<MActor> { | ||||
|     const actorServer = await getServerActor() | ||||
|     if (id === actorServer.id) return actorServer | ||||
|  | @ -372,8 +380,12 @@ export class ActorModel extends Model<Partial<AttributesOnly<ActorModel>>> { | |||
|     const fun = () => { | ||||
|       const query = { | ||||
|         where: { | ||||
|           preferredUsername, | ||||
|           serverId: null | ||||
|           [Op.and]: [ | ||||
|             this.wherePreferredUsername(preferredUsername), | ||||
|             { | ||||
|               serverId: null | ||||
|             } | ||||
|           ] | ||||
|         }, | ||||
|         transaction | ||||
|       } | ||||
|  | @ -395,8 +407,12 @@ export class ActorModel extends Model<Partial<AttributesOnly<ActorModel>>> { | |||
|       const query = { | ||||
|         attributes: [ 'url' ], | ||||
|         where: { | ||||
|           preferredUsername, | ||||
|           serverId: null | ||||
|           [Op.and]: [ | ||||
|             this.wherePreferredUsername(preferredUsername), | ||||
|             { | ||||
|               serverId: null | ||||
|             } | ||||
|           ] | ||||
|         }, | ||||
|         transaction | ||||
|       } | ||||
|  | @ -405,7 +421,7 @@ export class ActorModel extends Model<Partial<AttributesOnly<ActorModel>>> { | |||
|     } | ||||
| 
 | ||||
|     return ModelCache.Instance.doCache({ | ||||
|       cacheType: 'local-actor-name', | ||||
|       cacheType: 'local-actor-url', | ||||
|       key: preferredUsername, | ||||
|       // The server actor never change, so we can easily cache it
 | ||||
|       whitelist: () => preferredUsername === SERVER_ACTOR_NAME, | ||||
|  | @ -415,9 +431,7 @@ export class ActorModel extends Model<Partial<AttributesOnly<ActorModel>>> { | |||
| 
 | ||||
|   static loadByNameAndHost (preferredUsername: string, host: string): Promise<MActorFull> { | ||||
|     const query = { | ||||
|       where: { | ||||
|         preferredUsername | ||||
|       }, | ||||
|       where: this.wherePreferredUsername(preferredUsername), | ||||
|       include: [ | ||||
|         { | ||||
|           model: ServerModel, | ||||
|  |  | |||
|  | @ -130,13 +130,16 @@ export type SummaryOptions = { | |||
|       for (const handle of options.handles || []) { | ||||
|         const [ preferredUsername, host ] = handle.split('@') | ||||
| 
 | ||||
|         const sanitizedPreferredUsername = VideoChannelModel.sequelize.escape(preferredUsername.toLowerCase()) | ||||
|         const sanitizedHost = VideoChannelModel.sequelize.escape(host) | ||||
| 
 | ||||
|         if (!host || host === WEBSERVER.HOST) { | ||||
|           or.push(`("preferredUsername" = ${VideoChannelModel.sequelize.escape(preferredUsername)} AND "serverId" IS NULL)`) | ||||
|           or.push(`(LOWER("preferredUsername") = ${sanitizedPreferredUsername} AND "serverId" IS NULL)`) | ||||
|         } else { | ||||
|           or.push( | ||||
|             `(` + | ||||
|               `"preferredUsername" = ${VideoChannelModel.sequelize.escape(preferredUsername)} ` + | ||||
|               `AND "host" = ${VideoChannelModel.sequelize.escape(host)}` + | ||||
|               `LOWER("preferredUsername") = ${sanitizedPreferredUsername} ` + | ||||
|               `AND "host" = ${sanitizedHost}` + | ||||
|             `)` | ||||
|           ) | ||||
|         } | ||||
|  | @ -698,8 +701,10 @@ export class VideoChannelModel extends Model<Partial<AttributesOnly<VideoChannel | |||
|           model: ActorModel, | ||||
|           required: true, | ||||
|           where: { | ||||
|             preferredUsername: name, | ||||
|             serverId: null | ||||
|             [Op.and]: [ | ||||
|               ActorModel.wherePreferredUsername(name), | ||||
|               { serverId: null } | ||||
|             ] | ||||
|           }, | ||||
|           include: [ | ||||
|             { | ||||
|  | @ -723,9 +728,7 @@ export class VideoChannelModel extends Model<Partial<AttributesOnly<VideoChannel | |||
|         { | ||||
|           model: ActorModel, | ||||
|           required: true, | ||||
|           where: { | ||||
|             preferredUsername: name | ||||
|           }, | ||||
|           where: ActorModel.wherePreferredUsername(name), | ||||
|           include: [ | ||||
|             { | ||||
|               model: ServerModel, | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Chocobozzz
						Chocobozzz