refactor: migrate to typeorm 3.0 (#8443)

* wip

* wip

* wip

* Update following.ts

* wip

* wip

* wip

* Update resolve-user.ts

* maxQueryExecutionTime

* wip

* wip
This commit is contained in:
syuilo 2022-03-26 15:34:00 +09:00 committed by GitHub
parent 41c87074e6
commit 1c67c26bd8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
325 changed files with 1314 additions and 1494 deletions

View file

@ -33,10 +33,10 @@ export async function addNoteToAntenna(antenna: Antenna, note: Note, noteUser: {
};
if (note.replyId != null) {
_note.reply = await Notes.findOneOrFail(note.replyId);
_note.reply = await Notes.findOneByOrFail({ id: note.replyId });
}
if (note.renoteId != null) {
_note.renote = await Notes.findOneOrFail(note.renoteId);
_note.renote = await Notes.findOneByOrFail({ id: note.renoteId });
}
if (isMutedUserRelated(_note, new Set<string>(mutings.map(x => x.muteeId)))) {
@ -45,7 +45,7 @@ export async function addNoteToAntenna(antenna: Antenna, note: Note, noteUser: {
// 2秒経っても既読にならなかったら通知
setTimeout(async () => {
const unread = await AntennaNotes.findOne({ antennaId: antenna.id, read: false });
const unread = await AntennaNotes.findOneBy({ antennaId: antenna.id, read: false });
if (unread) {
publishMainStream(antenna.userId, 'unreadAntenna', antenna);
}

View file

@ -34,7 +34,7 @@ export default async function(blocker: User, blockee: User) {
}
async function cancelRequest(follower: User, followee: User) {
const request = await FollowRequests.findOne({
const request = await FollowRequests.findOneBy({
followeeId: followee.id,
followerId: follower.id,
});
@ -77,7 +77,7 @@ async function cancelRequest(follower: User, followee: User) {
}
async function unFollow(follower: User, followee: User) {
const following = await Followings.findOne({
const following = await Followings.findOneBy({
followerId: follower.id,
followeeId: followee.id,
});
@ -116,7 +116,7 @@ async function unFollow(follower: User, followee: User) {
}
async function removeFromList(listOwner: User, user: User) {
const userLists = await UserLists.find({
const userLists = await UserLists.findBy({
userId: listOwner.id,
});

View file

@ -9,7 +9,7 @@ import { Blockings, Users } from '@/models/index.js';
const logger = new Logger('blocking/delete');
export default async function(blocker: User, blockee: User) {
const blocking = await Blockings.findOne({
const blocking = await Blockings.findOneBy({
blockerId: blocker.id,
blockeeId: blockee.id,
});

View file

@ -22,11 +22,11 @@ export default class InstanceChart extends Chart<typeof schema> {
followersCount,
driveFiles,
] = await Promise.all([
Notes.count({ userHost: group }),
Users.count({ host: group }),
Followings.count({ followerHost: group }),
Followings.count({ followeeHost: group }),
DriveFiles.count({ userHost: group }),
Notes.countBy({ userHost: group }),
Users.countBy({ host: group }),
Followings.countBy({ followerHost: group }),
Followings.countBy({ followeeHost: group }),
DriveFiles.countBy({ userHost: group }),
]);
return {

View file

@ -15,8 +15,8 @@ export default class NotesChart extends Chart<typeof schema> {
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
const [localCount, remoteCount] = await Promise.all([
Notes.count({ userHost: null }),
Notes.count({ userHost: Not(IsNull()) }),
Notes.countBy({ userHost: IsNull() }),
Notes.countBy({ userHost: Not(IsNull()) }),
]);
return {

View file

@ -14,7 +14,7 @@ export default class PerUserDriveChart extends Chart<typeof schema> {
protected async tickMajor(group: string): Promise<Partial<KVs<typeof schema>>> {
const [count, size] = await Promise.all([
DriveFiles.count({ userId: group }),
DriveFiles.countBy({ userId: group }),
DriveFiles.calcDriveUsageOf(group),
]);

View file

@ -20,10 +20,10 @@ export default class PerUserFollowingChart extends Chart<typeof schema> {
remoteFollowingsCount,
remoteFollowersCount,
] = await Promise.all([
Followings.count({ followerId: group, followeeHost: null }),
Followings.count({ followeeId: group, followerHost: null }),
Followings.count({ followerId: group, followeeHost: Not(IsNull()) }),
Followings.count({ followeeId: group, followerHost: Not(IsNull()) }),
Followings.countBy({ followerId: group, followeeHost: IsNull() }),
Followings.countBy({ followeeId: group, followerHost: IsNull() }),
Followings.countBy({ followerId: group, followeeHost: Not(IsNull()) }),
Followings.countBy({ followeeId: group, followerHost: Not(IsNull()) }),
]);
return {

View file

@ -15,7 +15,7 @@ export default class PerUserNotesChart extends Chart<typeof schema> {
protected async tickMajor(group: string): Promise<Partial<KVs<typeof schema>>> {
const [count] = await Promise.all([
Notes.count({ userId: group }),
Notes.countBy({ userId: group }),
]);
return {

View file

@ -15,8 +15,8 @@ export default class UsersChart extends Chart<typeof schema> {
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
const [localCount, remoteCount] = await Promise.all([
Users.count({ host: null }),
Users.count({ host: Not(IsNull()) }),
Users.countBy({ host: IsNull() }),
Users.countBy({ host: Not(IsNull()) }),
]);
return {

View file

@ -6,9 +6,10 @@
import * as nestedProperty from 'nested-property';
import Logger from '../logger.js';
import { EntitySchema, getRepository, Repository, LessThan, Between } from 'typeorm';
import { EntitySchema, Repository, LessThan, Between } from 'typeorm';
import { dateUTC, isTimeSame, isTimeBefore, subtractTime, addTime } from '@/prelude/time.js';
import { getChartInsertLock } from '@/misc/app-lock.js';
import { db } from '@/db/postgre.js';
const logger = new Logger('chart', 'white', process.env.NODE_ENV !== 'test');
@ -241,8 +242,8 @@ export default abstract class Chart<T extends Schema> {
this.schema = schema;
const { hour, day } = Chart.schemaToEntity(name, schema, grouped);
this.repositoryForHour = getRepository<{ id: number; group?: string | null; date: number; }>(hour);
this.repositoryForDay = getRepository<{ id: number; group?: string | null; date: number; }>(day);
this.repositoryForHour = db.getRepository<{ id: number; group?: string | null; date: number; }>(hour);
this.repositoryForDay = db.getRepository<{ id: number; group?: string | null; date: number; }>(day);
}
private convertRawRecord(x: RawRecord<T>): KVs<T> {
@ -271,9 +272,10 @@ export default abstract class Chart<T extends Schema> {
span === 'day' ? this.repositoryForDay :
new Error('not happen') as never;
return repository.findOne(group ? {
group: group,
} : {}, {
return repository.findOne({
where: group ? {
group: group,
} : {},
order: {
date: -1,
},
@ -297,7 +299,7 @@ export default abstract class Chart<T extends Schema> {
new Error('not happen') as never;
// 現在(=今のHour or Day)のログ
const currentLog = await repository.findOne({
const currentLog = await repository.findOneBy({
date: Chart.dateToTimestamp(current),
...(group ? { group: group } : {}),
}) as RawRecord<T> | undefined;
@ -337,7 +339,7 @@ export default abstract class Chart<T extends Schema> {
const unlock = await getChartInsertLock(lockKey);
try {
// ロック内でもう1回チェックする
const currentLog = await repository.findOne({
const currentLog = await repository.findOneBy({
date: date,
...(group ? { group: group } : {}),
}) as RawRecord<T> | undefined;
@ -356,7 +358,7 @@ export default abstract class Chart<T extends Schema> {
date: date,
...(group ? { group: group } : {}),
...columns,
}).then(x => repository.findOneOrFail(x.identifiers[0])) as RawRecord<T>;
}).then(x => repository.findOneByOrFail(x.identifiers[0])) as RawRecord<T>;
logger.info(`${this.name + (group ? `:${group}` : '')}(${span}): New commit created`);
@ -598,9 +600,10 @@ export default abstract class Chart<T extends Schema> {
if (logs.length === 0) {
// もっとも新しいログを持ってくる
// (すくなくともひとつログが無いと隙間埋めできないため)
const recentLog = await repository.findOne(group ? {
group: group,
} : {}, {
const recentLog = await repository.findOne({
where: group ? {
group: group,
} : {},
order: {
date: -1,
},
@ -615,9 +618,10 @@ export default abstract class Chart<T extends Schema> {
// 要求された範囲の最も古い箇所時点での最も新しいログを持ってきて末尾に追加する
// (隙間埋めできないため)
const outdatedLog = await repository.findOne({
date: LessThan(Chart.dateToTimestamp(gt)),
...(group ? { group: group } : {}),
}, {
where: {
date: LessThan(Chart.dateToTimestamp(gt)),
...(group ? { group: group } : {}),
},
order: {
date: -1,
},

View file

@ -15,7 +15,7 @@ export async function createNotification(
return null;
}
const profile = await UserProfiles.findOne({ userId: notifieeId });
const profile = await UserProfiles.findOneBy({ userId: notifieeId });
const isMuted = profile?.mutingNotificationTypes.includes(type);
@ -29,7 +29,7 @@ export async function createNotification(
isRead: isMuted,
...data,
} as Partial<Notification>)
.then(x => Notifications.findOneOrFail(x.identifiers[0]));
.then(x => Notifications.findOneByOrFail(x.identifiers[0]));
const packed = await Notifications.pack(notification, {});
@ -38,12 +38,12 @@ export async function createNotification(
// 2秒経っても(今回作成した)通知が既読にならなかったら「未読の通知がありますよ」イベントを発行する
setTimeout(async () => {
const fresh = await Notifications.findOne(notification.id);
const fresh = await Notifications.findOneBy({ id: notification.id });
if (fresh == null) return; // 既に削除されているかもしれない
if (fresh.isRead) return;
//#region ただしミュートしているユーザーからの通知なら無視
const mutings = await Mutings.find({
const mutings = await Mutings.findBy({
muterId: notifieeId,
});
if (data.notifierId && mutings.map(m => m.muteeId).includes(data.notifierId)) {
@ -54,8 +54,8 @@ export async function createNotification(
publishMainStream(notifieeId, 'unreadNotification', packed);
pushSw(notifieeId, 'notification', packed);
if (type === 'follow') sendEmailNotification.follow(notifieeId, await Users.findOneOrFail(data.notifierId!));
if (type === 'receiveFollowRequest') sendEmailNotification.receiveFollowRequest(notifieeId, await Users.findOneOrFail(data.notifierId!));
if (type === 'follow') sendEmailNotification.follow(notifieeId, await Users.findOneByOrFail({ id: data.notifierId! }));
if (type === 'receiveFollowRequest') sendEmailNotification.receiveFollowRequest(notifieeId, await Users.findOneByOrFail({ id: data.notifierId! }));
}, 2000);
return notification;

View file

@ -4,10 +4,11 @@ import generateNativeUserToken from '../server/api/common/generate-native-user-t
import { genRsaKeyPair } from '@/misc/gen-key-pair.js';
import { User } from '@/models/entities/user.js';
import { UserProfile } from '@/models/entities/user-profile.js';
import { getConnection, ObjectLiteral } from 'typeorm';
import { IsNull } from 'typeorm';
import { genId } from '@/misc/gen-id.js';
import { UserKeypair } from '@/models/entities/user-keypair.js';
import { UsedUsername } from '@/models/entities/used-username.js';
import { db } from '@/db/postgre.js';
export async function createSystemUser(username: string) {
const password = uuid();
@ -21,13 +22,13 @@ export async function createSystemUser(username: string) {
const keyPair = await genRsaKeyPair(4096);
let account!: User | ObjectLiteral;
let account!: User;
// Start transaction
await getConnection().transaction(async transactionalEntityManager => {
const exist = await transactionalEntityManager.findOne(User, {
await db.transaction(async transactionalEntityManager => {
const exist = await transactionalEntityManager.findOneBy(User, {
usernameLower: username.toLowerCase(),
host: null,
host: IsNull(),
});
if (exist) throw new Error('the user is already exists');
@ -43,7 +44,7 @@ export async function createSystemUser(username: string) {
isLocked: true,
isExplorable: false,
isBot: true,
}).then(x => transactionalEntityManager.findOneOrFail(User, x.identifiers[0]));
}).then(x => transactionalEntityManager.findOneByOrFail(User, x.identifiers[0]));
await transactionalEntityManager.insert(UserKeypair, {
publicKey: keyPair.publicKey,

View file

@ -21,6 +21,7 @@ import S3 from 'aws-sdk/clients/s3.js';
import { getS3 } from './s3.js';
import sharp from 'sharp';
import { FILE_TYPE_BROWSERSAFE } from '@/const.js';
import { IsNull } from 'typeorm';
const logger = driveLogger.createSubLogger('register', 'yellow');
@ -108,7 +109,7 @@ async function save(file: DriveFile, path: string, name: string, type: string, h
file.size = size;
file.storedInternal = false;
return await DriveFiles.insert(file).then(x => DriveFiles.findOneOrFail(x.identifiers[0]));
return await DriveFiles.insert(file).then(x => DriveFiles.findOneByOrFail(x.identifiers[0]));
} else { // use internal storage
const accessKey = uuid();
const thumbnailAccessKey = 'thumbnail-' + uuid();
@ -142,7 +143,7 @@ async function save(file: DriveFile, path: string, name: string, type: string, h
file.md5 = hash;
file.size = size;
return await DriveFiles.insert(file).then(x => DriveFiles.findOneOrFail(x.identifiers[0]));
return await DriveFiles.insert(file).then(x => DriveFiles.findOneByOrFail(x.identifiers[0]));
}
}
@ -344,7 +345,7 @@ export async function addFile({
if (user && !force) {
// Check if there is a file with the same hash
const much = await DriveFiles.findOne({
const much = await DriveFiles.findOneBy({
md5: info.md5,
userId: user.id,
});
@ -370,7 +371,7 @@ export async function addFile({
throw new Error('no-free-space');
} else {
// (アバターまたはバナーを含まず)最も古いファイルを削除する
deleteOldFile(await Users.findOneOrFail(user.id) as IRemoteUser);
deleteOldFile(await Users.findOneByOrFail({ id: user.id }) as IRemoteUser);
}
}
}
@ -381,9 +382,9 @@ export async function addFile({
return null;
}
const driveFolder = await DriveFolders.findOne({
const driveFolder = await DriveFolders.findOneBy({
id: folderId,
userId: user ? user.id : null,
userId: user ? user.id : IsNull(),
});
if (driveFolder == null) throw new Error('folder-not-found');
@ -405,7 +406,7 @@ export async function addFile({
properties['orientation'] = info.orientation;
}
const profile = user ? await UserProfiles.findOne(user.id) : null;
const profile = user ? await UserProfiles.findOneBy({ userId: user.id }) : null;
const folder = await fetchFolder();
@ -450,15 +451,15 @@ export async function addFile({
file.type = info.type.mime;
file.storedInternal = false;
file = await DriveFiles.insert(file).then(x => DriveFiles.findOneOrFail(x.identifiers[0]));
file = await DriveFiles.insert(file).then(x => DriveFiles.findOneByOrFail(x.identifiers[0]));
} catch (err) {
// duplicate key error (when already registered)
if (isDuplicateKeyValueError(err)) {
logger.info(`already registered ${file.uri}`);
file = await DriveFiles.findOne({
uri: file.uri,
userId: user ? user.id : null,
file = await DriveFiles.findOneBy({
uri: file.uri!,
userId: user ? user.id : IsNull(),
}) as DriveFile;
} else {
logger.error(err as Error);

View file

@ -13,7 +13,7 @@ export async function fetchInstanceMetadata(instance: Instance, force = false):
const unlock = await getFetchInstanceMetadataLock(instance.host);
if (!force) {
const _instance = await Instances.findOne({ host: instance.host });
const _instance = await Instances.findOneBy({ host: instance.host });
const now = Date.now();
if (_instance && _instance.infoUpdatedAt && (now - _instance.infoUpdatedAt.getTime() < 1000 * 60 * 60 * 24)) {
unlock();

View file

@ -45,7 +45,7 @@ export async function insertFollowingDoc(followee: { id: User['id']; host: User[
}
});
const req = await FollowRequests.findOne({
const req = await FollowRequests.findOneBy({
followeeId: followee.id,
followerId: follower.id,
});
@ -108,17 +108,17 @@ export async function insertFollowingDoc(followee: { id: User['id']; host: User[
export default async function(_follower: { id: User['id'] }, _followee: { id: User['id'] }, requestId?: string) {
const [follower, followee] = await Promise.all([
Users.findOneOrFail(_follower.id),
Users.findOneOrFail(_followee.id),
Users.findOneByOrFail({ id: _follower.id }),
Users.findOneByOrFail({ id: _followee.id }),
]);
// check blocking
const [blocking, blocked] = await Promise.all([
Blockings.findOne({
Blockings.findOneBy({
blockerId: follower.id,
blockeeId: followee.id,
}),
Blockings.findOne({
Blockings.findOneBy({
blockerId: followee.id,
blockeeId: follower.id,
}),
@ -138,7 +138,7 @@ export default async function(_follower: { id: User['id'] }, _followee: { id: Us
if (blocked != null) throw new IdentifiableError('3338392a-f764-498d-8855-db939dcf8c48', 'blocked');
}
const followeeProfile = await UserProfiles.findOneOrFail(followee.id);
const followeeProfile = await UserProfiles.findOneByOrFail({ userId: followee.id });
// フォロー対象が鍵アカウントである or
// フォロワーがBotであり、フォロー対象がBotからのフォローに慎重である or
@ -148,7 +148,7 @@ export default async function(_follower: { id: User['id'] }, _followee: { id: Us
let autoAccept = false;
// 鍵アカウントであっても、既にフォローされていた場合はスルー
const following = await Followings.findOne({
const following = await Followings.findOneBy({
followerId: follower.id,
followeeId: followee.id,
});
@ -158,7 +158,7 @@ export default async function(_follower: { id: User['id'] }, _followee: { id: Us
// フォローしているユーザーは自動承認オプション
if (!autoAccept && (Users.isLocalUser(followee) && followeeProfile.autoAcceptFollowed)) {
const followed = await Followings.findOne({
const followed = await Followings.findOneBy({
followerId: followee.id,
followeeId: follower.id,
});

View file

@ -13,7 +13,7 @@ import { instanceChart, perUserFollowingChart } from '@/services/chart/index.js'
const logger = new Logger('following/delete');
export default async function(follower: { id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox']; }, followee: { id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox']; }, silent = false) {
const following = await Followings.findOne({
const following = await Followings.findOneBy({
followerId: follower.id,
followeeId: followee.id,
});

View file

@ -63,7 +63,7 @@ export async function remoteReject(actor: Remote, follower: Local) {
* Remove follow request record
*/
async function removeFollowRequest(followee: Both, follower: Both) {
const request = await FollowRequests.findOne({
const request = await FollowRequests.findOneBy({
followeeId: followee.id,
followerId: follower.id,
});
@ -77,7 +77,7 @@ async function removeFollowRequest(followee: Both, follower: Both) {
* Remove follow record
*/
async function removeFollow(followee: Both, follower: Both) {
const following = await Followings.findOne({
const following = await Followings.findOneBy({
followeeId: followee.id,
followerId: follower.id,
});
@ -92,7 +92,7 @@ async function removeFollow(followee: Both, follower: Both) {
* Deliver Reject to remote
*/
async function deliverReject(followee: Local, follower: Remote) {
const request = await FollowRequests.findOne({
const request = await FollowRequests.findOneBy({
followeeId: followee.id,
followerId: follower.id,
});

View file

@ -7,12 +7,12 @@ import { FollowRequests, Users } from '@/models/index.js';
* @param user
*/
export default async function(user: { id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox']; }) {
const requests = await FollowRequests.find({
const requests = await FollowRequests.findBy({
followeeId: user.id,
});
for (const request of requests) {
const follower = await Users.findOneOrFail(request.followerId);
const follower = await Users.findOneByOrFail({ id: request.followerId });
accept(user, follower);
}
}

View file

@ -9,7 +9,7 @@ import { FollowRequests, Users } from '@/models/index.js';
import { IdentifiableError } from '@/misc/identifiable-error.js';
export default async function(followee: { id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox']; }, follower: User) {
const request = await FollowRequests.findOne({
const request = await FollowRequests.findOneBy({
followeeId: followee.id,
followerId: follower.id,
});

View file

@ -16,7 +16,7 @@ export default async function(followee: { id: User['id']; host: User['host']; ur
}
}
const request = await FollowRequests.findOne({
const request = await FollowRequests.findOneBy({
followeeId: followee.id,
followerId: follower.id,
});

View file

@ -12,11 +12,11 @@ export default async function(follower: { id: User['id']; host: User['host']; ur
// check blocking
const [blocking, blocked] = await Promise.all([
Blockings.findOne({
Blockings.findOneBy({
blockerId: follower.id,
blockeeId: followee.id,
}),
Blockings.findOne({
Blockings.findOneBy({
blockerId: followee.id,
blockeeId: follower.id,
}),
@ -39,7 +39,7 @@ export default async function(follower: { id: User['id']; host: User['host']; ur
followeeHost: followee.host,
followeeInbox: Users.isRemoteUser(followee) ? followee.inbox : undefined,
followeeSharedInbox: Users.isRemoteUser(followee) ? followee.sharedInbox : undefined,
}).then(x => FollowRequests.findOneOrFail(x.identifiers[0]));
}).then(x => FollowRequests.findOneByOrFail(x.identifiers[0]));
// Publish receiveRequest event
if (Users.isLocalUser(followee)) {

View file

@ -18,7 +18,7 @@ import { deliverToRelays } from '../relay.js';
*/
export async function addPinned(user: { id: User['id']; host: User['host']; }, noteId: Note['id']) {
// Fetch pinee
const note = await Notes.findOne({
const note = await Notes.findOneBy({
id: noteId,
userId: user.id,
});
@ -27,7 +27,7 @@ export async function addPinned(user: { id: User['id']; host: User['host']; }, n
throw new IdentifiableError('70c4e51f-5bea-449c-a030-53bee3cce202', 'No such note.');
}
const pinings = await UserNotePinings.find({ userId: user.id });
const pinings = await UserNotePinings.findBy({ userId: user.id });
if (pinings.length >= 5) {
throw new IdentifiableError('15a018eb-58e5-4da1-93be-330fcc5e4e1a', 'You can not pin notes any more.');
@ -57,7 +57,7 @@ export async function addPinned(user: { id: User['id']; host: User['host']; }, n
*/
export async function removePinned(user: { id: User['id']; host: User['host']; }, noteId: Note['id']) {
// Fetch unpinee
const note = await Notes.findOne({
const note = await Notes.findOneBy({
id: noteId,
userId: user.id,
});
@ -78,7 +78,7 @@ export async function removePinned(user: { id: User['id']; host: User['host']; }
}
export async function deliverPinnedChange(userId: User['id'], noteId: Note['id'], isAddition: boolean) {
const user = await Users.findOne(userId);
const user = await Users.findOneBy({ id: userId });
if (user == null) throw new Error('user not found');
if (!Users.isLocalUser(user)) return;

View file

@ -7,7 +7,7 @@ import { deliverToFollowers } from '@/remote/activitypub/deliver-manager.js';
import { deliverToRelays } from '../relay.js';
export async function publishToFollowers(userId: User['id']) {
const user = await Users.findOne(userId);
const user = await Users.findOneBy({ id: userId });
if (user == null) throw new Error('user not found');
// フォロワーがリモートユーザーかつ投稿者がローカルユーザーならUpdateを配信

View file

@ -2,6 +2,7 @@ import { createSystemUser } from './create-system-user.js';
import { ILocalUser } from '@/models/entities/user.js';
import { Users } from '@/models/index.js';
import { Cache } from '@/misc/cache.js';
import { IsNull } from 'typeorm';
const ACTOR_USERNAME = 'instance.actor' as const;
@ -11,8 +12,8 @@ export async function getInstanceActor(): Promise<ILocalUser> {
const cached = cache.get(null);
if (cached) return cached;
const user = await Users.findOne({
host: null,
const user = await Users.findOneBy({
host: IsNull(),
username: ACTOR_USERNAME,
}) as ILocalUser | undefined;

View file

@ -50,7 +50,7 @@ export async function createMessage(user: { id: User['id']; host: User['host'];
publishGroupMessagingStream(recipientGroup.id, 'message', messageObj);
// メンバーのストリーム
const joinings = await UserGroupJoinings.find({ userGroupId: recipientGroup.id });
const joinings = await UserGroupJoinings.findBy({ userGroupId: recipientGroup.id });
for (const joining of joinings) {
publishMessagingIndexStream(joining.userId, 'message', messageObj);
publishMainStream(joining.userId, 'messagingMessage', messageObj);
@ -59,14 +59,14 @@ export async function createMessage(user: { id: User['id']; host: User['host'];
// 2秒経っても(今回作成した)メッセージが既読にならなかったら「未読のメッセージがありますよ」イベントを発行する
setTimeout(async () => {
const freshMessage = await MessagingMessages.findOne(message.id);
const freshMessage = await MessagingMessages.findOneBy({ id: message.id });
if (freshMessage == null) return; // メッセージが削除されている場合もある
if (recipientUser && Users.isLocalUser(recipientUser)) {
if (freshMessage.isRead) return; // 既読
//#region ただしミュートされているなら発行しない
const mute = await Mutings.find({
const mute = await Mutings.findBy({
muterId: recipientUser.id,
});
if (mute.map(m => m.muteeId).includes(user.id)) return;
@ -75,7 +75,7 @@ export async function createMessage(user: { id: User['id']; host: User['host'];
publishMainStream(recipientUser.id, 'unreadMessagingMessage', messageObj);
pushNotification(recipientUser.id, 'unreadMessagingMessage', messageObj);
} else if (recipientGroup) {
const joinings = await UserGroupJoinings.find({ userGroupId: recipientGroup.id, userId: Not(user.id) });
const joinings = await UserGroupJoinings.findBy({ userGroupId: recipientGroup.id, userId: Not(user.id) });
for (const joining of joinings) {
if (freshMessage.reads.includes(joining.userId)) return; // 既読
publishMainStream(joining.userId, 'unreadMessagingMessage', messageObj);

View file

@ -14,8 +14,8 @@ export async function deleteMessage(message: MessagingMessage) {
async function postDeleteMessage(message: MessagingMessage) {
if (message.recipientId) {
const user = await Users.findOneOrFail(message.userId);
const recipient = await Users.findOneOrFail(message.recipientId);
const user = await Users.findOneByOrFail({ id: message.userId });
const recipient = await Users.findOneByOrFail({ id: message.recipientId });
if (Users.isLocalUser(user)) publishMessagingStream(message.userId, message.recipientId, 'deleted', message.id);
if (Users.isLocalUser(recipient)) publishMessagingStream(message.recipientId, message.userId, 'deleted', message.id);

View file

@ -19,7 +19,7 @@ import { Note, IMentionedRemoteUsers } from '@/models/entities/note.js';
import { Mutings, Users, NoteWatchings, Notes, Instances, UserProfiles, Antennas, Followings, MutedNotes, Channels, ChannelFollowings, Blockings, NoteThreadMutings } from '@/models/index.js';
import { DriveFile } from '@/models/entities/drive-file.js';
import { App } from '@/models/entities/app.js';
import { Not, getConnection, In } from 'typeorm';
import { Not, In } from 'typeorm';
import { User, ILocalUser, IRemoteUser } from '@/models/entities/user.js';
import { genId } from '@/misc/gen-id.js';
import { notesChart, perUserNotesChart, activeUsersChart, instanceChart } from '@/services/chart/index.js';
@ -37,6 +37,7 @@ import { getAntennas } from '@/misc/antenna-cache.js';
import { endedPollNotificationQueue } from '@/queue/queues.js';
import { Cache } from '@/misc/cache.js';
import { UserProfile } from '@/models/entities/user-profile.js';
import { db } from '@/db/postgre.js';
const mutedWordsCache = new Cache<{ userId: UserProfile['userId']; mutedWords: UserProfile['mutedWords']; }[]>(1000 * 60 * 5);
@ -78,7 +79,7 @@ class NotificationManager {
public async deliver() {
for (const x of this.queue) {
// ミュート情報を取得
const mentioneeMutes = await Mutings.find({
const mentioneeMutes = await Mutings.findBy({
muterId: x.target,
});
@ -128,7 +129,7 @@ export default async (user: { id: User['id']; username: User['username']; host:
// (クライアントサイドでやっても良い処理だと思うけどとりあえずサーバーサイドで)
if (data.reply && data.channel && data.reply.channelId !== data.channel.id) {
if (data.reply.channelId) {
data.channel = await Channels.findOne(data.reply.channelId);
data.channel = await Channels.findOneBy({ id: data.reply.channelId });
} else {
data.channel = null;
}
@ -137,7 +138,7 @@ export default async (user: { id: User['id']; username: User['username']; host:
// チャンネル内にリプライしたら対象のスコープに合わせる
// (クライアントサイドでやっても良い処理だと思うけどとりあえずサーバーサイドで)
if (data.reply && (data.channel == null) && data.reply.channelId) {
data.channel = await Channels.findOne(data.reply.channelId);
data.channel = await Channels.findOneBy({ id: data.reply.channelId });
}
if (data.createdAt == null) data.createdAt = new Date();
@ -210,7 +211,7 @@ export default async (user: { id: User['id']; username: User['username']; host:
tags = tags.filter(tag => Array.from(tag || '').length <= 128).splice(0, 32);
if (data.reply && (user.id !== data.reply.userId) && !mentionedUsers.some(u => u.id === data.reply!.userId)) {
mentionedUsers.push(await Users.findOneOrFail(data.reply!.userId));
mentionedUsers.push(await Users.findOneByOrFail({ id: data.reply!.userId }));
}
if (data.visibility === 'specified') {
@ -223,7 +224,7 @@ export default async (user: { id: User['id']; username: User['username']; host:
}
if (data.reply && !data.visibleUsers.some(x => x.id === data.reply!.userId)) {
data.visibleUsers.push(await Users.findOneOrFail(data.reply!.userId));
data.visibleUsers.push(await Users.findOneByOrFail({ id: data.reply!.userId }));
}
}
@ -283,7 +284,7 @@ export default async (user: { id: User['id']; username: User['username']; host:
// Channel
if (note.channelId) {
ChannelFollowings.find({ followeeId: note.channelId }).then(followings => {
ChannelFollowings.findBy({ followeeId: note.channelId }).then(followings => {
for (const following of followings) {
insertNoteUnread(following.followerId, note, {
isSpecified: false,
@ -356,7 +357,7 @@ export default async (user: { id: User['id']; username: User['username']; host:
// 通知
if (data.reply.userHost === null) {
const threadMuted = await NoteThreadMutings.findOne({
const threadMuted = await NoteThreadMutings.findOneBy({
userId: data.reply.userId,
threadId: data.reply.threadId || data.reply.id,
});
@ -403,13 +404,13 @@ export default async (user: { id: User['id']; username: User['username']; host:
// 投稿がリプライかつ投稿者がローカルユーザーかつリプライ先の投稿の投稿者がリモートユーザーなら配送
if (data.reply && data.reply.userHost !== null) {
const u = await Users.findOne(data.reply.userId);
const u = await Users.findOneBy({ id: data.reply.userId });
if (u && Users.isRemoteUser(u)) dm.addDirectRecipe(u);
}
// 投稿がRenoteかつ投稿者がローカルユーザーかつRenote元の投稿の投稿者がリモートユーザーなら配送
if (data.renote && data.renote.userHost !== null) {
const u = await Users.findOne(data.renote.userId);
const u = await Users.findOneBy({ id: data.renote.userId });
if (u && Users.isRemoteUser(u)) dm.addDirectRecipe(u);
}
@ -434,7 +435,7 @@ export default async (user: { id: User['id']; username: User['username']; host:
lastNotedAt: new Date(),
});
Notes.count({
Notes.countBy({
userId: user.id,
channelId: data.channel.id,
}).then(count => {
@ -514,7 +515,7 @@ async function insertNote(user: { id: User['id']; host: User['host']; }, data: O
// Append mentions data
if (mentionedUsers.length > 0) {
insert.mentions = mentionedUsers.map(u => u.id);
const profiles = await UserProfiles.find({ userId: In(insert.mentions) });
const profiles = await UserProfiles.findBy({ userId: In(insert.mentions) });
insert.mentionedRemoteUsers = JSON.stringify(mentionedUsers.filter(u => Users.isRemoteUser(u)).map(u => {
const profile = profiles.find(p => p.userId === u.id);
const url = profile != null ? profile.url : null;
@ -531,7 +532,7 @@ async function insertNote(user: { id: User['id']; host: User['host']; }, data: O
try {
if (insert.hasPoll) {
// Start transaction
await getConnection().transaction(async transactionalEntityManager => {
await db.transaction(async transactionalEntityManager => {
await transactionalEntityManager.insert(Note, insert);
const poll = new Poll({
@ -581,7 +582,7 @@ function index(note: Note) {
}
async function notifyToWatchersOfRenotee(renote: Note, user: { id: User['id']; }, nm: NotificationManager, type: NotificationType) {
const watchers = await NoteWatchings.find({
const watchers = await NoteWatchings.findBy({
noteId: renote.id,
userId: Not(user.id),
});
@ -592,7 +593,7 @@ async function notifyToWatchersOfRenotee(renote: Note, user: { id: User['id']; }
}
async function notifyToWatchersOfReplyee(reply: Note, user: { id: User['id']; }, nm: NotificationManager) {
const watchers = await NoteWatchings.find({
const watchers = await NoteWatchings.findBy({
noteId: reply.id,
userId: Not(user.id),
});
@ -604,7 +605,7 @@ async function notifyToWatchersOfReplyee(reply: Note, user: { id: User['id']; },
async function createMentionedEvents(mentionedUsers: MinimumUser[], note: Note, nm: NotificationManager) {
for (const u of mentionedUsers.filter(u => Users.isLocalUser(u))) {
const threadMuted = await NoteThreadMutings.findOne({
const threadMuted = await NoteThreadMutings.findOneBy({
userId: u.id,
threadId: note.threadId || note.id,
});

View file

@ -40,11 +40,11 @@ export default async function(user: { id: User['id']; uri: User['uri']; host: Us
//#region ローカルの投稿なら削除アクティビティを配送
if (Users.isLocalUser(user) && !note.localOnly) {
let renote: Note | undefined;
let renote: Note | null;
// if deletd note is renote
if (note.renoteId && note.text == null && !note.hasPoll && (note.fileIds == null || note.fileIds.length === 0)) {
renote = await Notes.findOne({
renote = await Notes.findOneBy({
id: note.renoteId,
});
}

View file

@ -7,10 +7,10 @@ import { deliverToFollowers } from '@/remote/activitypub/deliver-manager.js';
import { deliverToRelays } from '../../relay.js';
export async function deliverQuestionUpdate(noteId: Note['id']) {
const note = await Notes.findOne(noteId);
const note = await Notes.findOneBy({ id: noteId });
if (note == null) throw new Error('note not found');
const user = await Users.findOne(note.userId);
const user = await Users.findOneBy({ id: note.userId });
if (user == null) throw new Error('note not found');
if (Users.isLocalUser(user)) {

View file

@ -7,7 +7,7 @@ import { genId } from '@/misc/gen-id.js';
import { createNotification } from '../../create-notification.js';
export default async function(user: CacheableUser, note: Note, choice: number) {
const poll = await Polls.findOne(note.id);
const poll = await Polls.findOneBy({ noteId: note.id });
if (poll == null) throw new Error('poll not found');
@ -16,7 +16,7 @@ export default async function(user: CacheableUser, note: Note, choice: number) {
// Check blocking
if (note.userId !== user.id) {
const block = await Blockings.findOne({
const block = await Blockings.findOneBy({
blockerId: note.userId,
blockeeId: user.id,
});
@ -26,7 +26,7 @@ export default async function(user: CacheableUser, note: Note, choice: number) {
}
// if already voted
const exist = await PollVotes.find({
const exist = await PollVotes.findBy({
noteId: note.id,
userId: user.id,
});
@ -65,7 +65,7 @@ export default async function(user: CacheableUser, note: Note, choice: number) {
});
// Fetch watchers
NoteWatchings.find({
NoteWatchings.findBy({
noteId: note.id,
userId: Not(user.id),
})

View file

@ -6,7 +6,7 @@ import { toDbReaction, decodeReaction } from '@/misc/reaction-lib.js';
import { User, IRemoteUser } from '@/models/entities/user.js';
import { Note } from '@/models/entities/note.js';
import { NoteReactions, Users, NoteWatchings, Notes, Emojis, Blockings } from '@/models/index.js';
import { Not } from 'typeorm';
import { IsNull, Not } from 'typeorm';
import { perUserReactionsChart } from '@/services/chart/index.js';
import { genId } from '@/misc/gen-id.js';
import { createNotification } from '../../create-notification.js';
@ -18,7 +18,7 @@ import { IdentifiableError } from '@/misc/identifiable-error.js';
export default async (user: { id: User['id']; host: User['host']; }, note: Note, reaction?: string) => {
// Check blocking
if (note.userId !== user.id) {
const block = await Blockings.findOne({
const block = await Blockings.findOneBy({
blockerId: note.userId,
blockeeId: user.id,
});
@ -43,7 +43,7 @@ export default async (user: { id: User['id']; host: User['host']; }, note: Note,
await NoteReactions.insert(record);
} catch (e) {
if (isDuplicateKeyValueError(e)) {
const exists = await NoteReactions.findOneOrFail({
const exists = await NoteReactions.findOneByOrFail({
noteId: note.id,
userId: user.id,
});
@ -79,7 +79,7 @@ export default async (user: { id: User['id']; host: User['host']; }, note: Note,
const emoji = await Emojis.findOne({
where: {
name: decodedReaction.name,
host: decodedReaction.host,
host: decodedReaction.host ?? IsNull(),
},
select: ['name', 'host', 'originalUrl', 'publicUrl'],
});
@ -103,7 +103,7 @@ export default async (user: { id: User['id']; host: User['host']; }, note: Note,
}
// Fetch watchers
NoteWatchings.find({
NoteWatchings.findBy({
noteId: note.id,
userId: Not(user.id),
}).then(watchers => {
@ -121,7 +121,7 @@ export default async (user: { id: User['id']; host: User['host']; }, note: Note,
const content = renderActivity(await renderLike(record, note));
const dm = new DeliverManager(user, content);
if (note.userHost !== null) {
const reactee = await Users.findOne(note.userId);
const reactee = await Users.findOneBy({ id: note.userId });
dm.addDirectRecipe(reactee as IRemoteUser);
}
dm.addFollowersRecipe();

View file

@ -11,7 +11,7 @@ import { decodeReaction } from '@/misc/reaction-lib.js';
export default async (user: { id: User['id']; host: User['host']; }, note: Note) => {
// if already unreacted
const exist = await NoteReactions.findOne({
const exist = await NoteReactions.findOneBy({
noteId: note.id,
userId: user.id,
});
@ -48,7 +48,7 @@ export default async (user: { id: User['id']; host: User['host']; }, note: Note)
const content = renderActivity(renderUndo(await renderLike(exist, note), user));
const dm = new DeliverManager(user, content);
if (note.userHost !== null) {
const reactee = await Users.findOne(note.userId);
const reactee = await Users.findOneBy({ id: note.userId });
dm.addDirectRecipe(reactee as IRemoteUser);
}
dm.addFollowersRecipe();

View file

@ -68,7 +68,7 @@ export default async function(
// TODO: ↓まとめてクエリしたい
NoteUnreads.count({
NoteUnreads.countBy({
userId: userId,
isMentioned: true,
}).then(mentionsCount => {
@ -78,7 +78,7 @@ export default async function(
}
});
NoteUnreads.count({
NoteUnreads.countBy({
userId: userId,
isSpecified: true,
}).then(specifiedCount => {
@ -88,7 +88,7 @@ export default async function(
}
});
NoteUnreads.count({
NoteUnreads.countBy({
userId: userId,
noteChannelId: Not(IsNull()),
}).then(channelNoteCount => {
@ -113,7 +113,7 @@ export default async function(
// TODO: まとめてクエリしたい
for (const antenna of myAntennas) {
const count = await AntennaNotes.count({
const count = await AntennaNotes.countBy({
antennaId: antenna.id,
read: false,
});

View file

@ -11,14 +11,14 @@ export async function insertNoteUnread(userId: User['id'], note: Note, params: {
}) {
//#region ミュートしているなら無視
// TODO: 現在の仕様ではChannelにミュートは適用されないのでよしなにケアする
const mute = await Mutings.find({
const mute = await Mutings.findBy({
muterId: userId,
});
if (mute.map(m => m.muteeId).includes(note.userId)) return;
//#endregion
// スレッドミュート
const threadMute = await NoteThreadMutings.findOne({
const threadMute = await NoteThreadMutings.findOneBy({
userId: userId,
threadId: note.threadId || note.id,
});
@ -38,7 +38,7 @@ export async function insertNoteUnread(userId: User['id'], note: Note, params: {
// 2秒経っても既読にならなかったら「未読の投稿がありますよ」イベントを発行する
setTimeout(async () => {
const exist = await NoteUnreads.findOne(unread.id);
const exist = await NoteUnreads.findOneBy({ id: unread.id });
if (exist == null) return;

View file

@ -41,7 +41,7 @@ export default async function(userId: string, type: notificationType, body: noti
meta.swPrivateKey);
// Fetch
const subscriptions = await SwSubscriptions.find({
const subscriptions = await SwSubscriptions.findBy({
userId: userId,
});

View file

@ -12,7 +12,7 @@ export async function registerOrFetchInstanceDoc(host: string): Promise<Instance
const cached = cache.get(host);
if (cached) return cached;
const index = await Instances.findOne({ host });
const index = await Instances.findOneBy({ host });
if (index == null) {
const i = await Instances.insert({
@ -20,7 +20,7 @@ export async function registerOrFetchInstanceDoc(host: string): Promise<Instance
host,
caughtAt: new Date(),
lastCommunicatedAt: new Date(),
}).then(x => Instances.findOneOrFail(x.identifiers[0]));
}).then(x => Instances.findOneByOrFail(x.identifiers[0]));
cache.set(host, i);
return i;

View file

@ -8,14 +8,15 @@ import { Users, Relays } from '@/models/index.js';
import { genId } from '@/misc/gen-id.js';
import { Cache } from '@/misc/cache.js';
import { Relay } from '@/models/entities/relay.js';
import { IsNull } from 'typeorm';
const ACTOR_USERNAME = 'relay.actor' as const;
const relaysCache = new Cache<Relay[]>(1000 * 60 * 10);
export async function getRelayActor(): Promise<ILocalUser> {
const user = await Users.findOne({
host: null,
const user = await Users.findOneBy({
host: IsNull(),
username: ACTOR_USERNAME,
});
@ -30,7 +31,7 @@ export async function addRelay(inbox: string) {
id: genId(),
inbox,
status: 'requesting',
}).then(x => Relays.findOneOrFail(x.identifiers[0]));
}).then(x => Relays.findOneByOrFail(x.identifiers[0]));
const relayActor = await getRelayActor();
const follow = await renderFollowRelay(relay, relayActor);
@ -41,7 +42,7 @@ export async function addRelay(inbox: string) {
}
export async function removeRelay(inbox: string) {
const relay = await Relays.findOne({
const relay = await Relays.findOneBy({
inbox,
});
@ -82,7 +83,7 @@ export async function relayRejected(id: string) {
export async function deliverToRelays(user: { id: User['id']; host: null; }, activity: any) {
if (activity == null) return;
const relays = await relaysCache.fetch(null, () => Relays.find({
const relays = await relaysCache.fetch(null, () => Relays.findBy({
status: 'accepted',
}));
if (relays.length === 0) return;

View file

@ -10,7 +10,7 @@ import * as Acct from '@/misc/acct.js';
async function follow(userId: User['id'], follower: User) {
/*
const userProfile = await UserProfiles.findOneOrFail({ userId: userId });
const userProfile = await UserProfiles.findOneByOrFail({ userId: userId });
if (!userProfile.email || !userProfile.emailNotificationTypes.includes('follow')) return;
const locale = locales[userProfile.lang || 'ja-JP'];
const i18n = new I18n(locale);
@ -21,7 +21,7 @@ async function follow(userId: User['id'], follower: User) {
async function receiveFollowRequest(userId: User['id'], follower: User) {
/*
const userProfile = await UserProfiles.findOneOrFail({ userId: userId });
const userProfile = await UserProfiles.findOneByOrFail({ userId: userId });
if (!userProfile.email || !userProfile.emailNotificationTypes.includes('receiveFollowRequest')) return;
const locale = locales[userProfile.lang || 'ja-JP'];
const i18n = new I18n(locale);

View file

@ -24,7 +24,7 @@ export async function updateUsertags(user: User, tags: string[]) {
export async function updateHashtag(user: { id: User['id']; host: User['host']; }, tag: string, isUserAttached = false, inc = true) {
tag = normalizeForSearch(tag);
const index = await Hashtags.findOne({ name: tag });
const index = await Hashtags.findOneBy({ name: tag });
if (index == null && !inc) return;

View file

@ -18,7 +18,7 @@ subsdcriber.on('message', async (_, data) => {
case 'userChangeSilencedState':
case 'userChangeModeratorState':
case 'remoteUserUpdated': {
const user = await Users.findOneOrFail(body.id);
const user = await Users.findOneByOrFail({ id: body.id });
userByIdCache.set(user.id, user);
for (const [k, v] of uriPersonCache.cache.entries()) {
if (v.value?.id === user.id) {
@ -32,7 +32,7 @@ subsdcriber.on('message', async (_, data) => {
break;
}
case 'userTokenRegenerated': {
const user = await Users.findOneOrFail(body.id) as ILocalUser;
const user = await Users.findOneByOrFail({ id: body.id }) as ILocalUser;
localUserByNativeTokenCache.delete(body.oldToken);
localUserByNativeTokenCache.set(body.newToken, user);
break;

View file

@ -5,7 +5,7 @@ export async function validateEmailForAccount(emailAddress: string): Promise<{
available: boolean;
reason: null | 'used' | 'format' | 'disposable' | 'mx' | 'smtp';
}> {
const exist = await UserProfiles.count({
const exist = await UserProfiles.countBy({
emailVerified: true,
email: emailAddress,
});