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

@ -198,11 +198,13 @@ MongoDBの時とは違い、findOneでレコードを取得する時に対象レ
MongoDBは`null`で返してきてたので、その感覚で`if (x === null)`とか書くとバグる。代わりに`if (x == null)`と書いてください MongoDBは`null`で返してきてたので、その感覚で`if (x === null)`とか書くとバグる。代わりに`if (x == null)`と書いてください
### Migration作成方法 ### Migration作成方法
``` packages/backendで:
npx ts-node ./node_modules/typeorm/cli.js migration:generate -n 変更の名前 -o ```sh
npx typeorm migration:generate -d ormconfig.js -o <migration name>
``` ```
作成されたスクリプトは不必要な変更を含むため除去してください。 - 生成後、ファイルをmigration下に移してください
- 作成されたスクリプトは不必要な変更を含むため除去してください
### コネクションには`markRaw`せよ ### コネクションには`markRaw`せよ
**Vueのコンポーネントのdataオプションとして**misskey.jsのコネクションを設定するとき、必ず`markRaw`でラップしてください。インスタンスが不必要にリアクティブ化されることで、misskey.js内の処理で不具合が発生するとともに、パフォーマンス上の問題にも繋がる。なお、Composition APIを使う場合はこの限りではない(リアクティブ化はマニュアルなため)。 **Vueのコンポーネントのdataオプションとして**misskey.jsのコネクションを設定するとき、必ず`markRaw`でラップしてください。インスタンスが不必要にリアクティブ化されることで、misskey.js内の処理で不具合が発生するとともに、パフォーマンス上の問題にも繋がる。なお、Composition APIを使う場合はこの限りではない(リアクティブ化はマニュアルなため)。

View File

@ -13,8 +13,7 @@
"start": "cd packages/backend && node --experimental-json-modules ./built/index.js", "start": "cd packages/backend && node --experimental-json-modules ./built/index.js",
"start:test": "cd packages/backend && cross-env NODE_ENV=test node --experimental-json-modules ./built/index.js", "start:test": "cd packages/backend && cross-env NODE_ENV=test node --experimental-json-modules ./built/index.js",
"init": "npm run migrate", "init": "npm run migrate",
"ormconfig": "node ./packages/backend/ormconfig.js", "migrate": "cd packages/backend && npx typeorm migration:run -d ormconfig.js",
"migrate": "cd packages/backend && npx typeorm migration:run",
"migrateandstart": "npm run migrate && npm run start", "migrateandstart": "npm run migrate && npm run start",
"gulp": "gulp build", "gulp": "gulp build",
"watch": "npm run dev", "watch": "npm run dev",

View File

@ -1,7 +1,8 @@
import { DataSource } from 'typeorm';
import config from './built/config/index.js'; import config from './built/config/index.js';
import { entities } from './built/db/postgre.js'; import { entities } from './built/db/postgre.js';
export default { export default new DataSource({
type: 'postgres', type: 'postgres',
host: config.db.host, host: config.db.host,
port: config.db.port, port: config.db.port,
@ -11,7 +12,4 @@ export default {
extra: config.db.extra, extra: config.db.extra,
entities: entities, entities: entities,
migrations: ['migration/*.js'], migrations: ['migration/*.js'],
cli: { });
migrationsDir: 'migration'
}
};

View File

@ -3,7 +3,6 @@
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {
"init": "npm run migrate",
"build": "tsc -p tsconfig.json || echo done. && tsc-alias -p tsconfig.json", "build": "tsc -p tsconfig.json || echo done. && tsc-alias -p tsconfig.json",
"watch": "node watch.mjs", "watch": "node watch.mjs",
"lint": "eslint --quiet src/**/*.ts", "lint": "eslint --quiet src/**/*.ts",
@ -163,7 +162,7 @@
"tsc-alias": "1.4.1", "tsc-alias": "1.4.1",
"tsconfig-paths": "3.14.0", "tsconfig-paths": "3.14.0",
"twemoji-parser": "14.0.0", "twemoji-parser": "14.0.0",
"typeorm": "0.2.45", "typeorm": "0.3.3",
"typescript": "4.6.3", "typescript": "4.6.3",
"ulid": "2.3.0", "ulid": "2.3.0",
"unzipper": "0.10.11", "unzipper": "0.10.11",

View File

@ -7,7 +7,6 @@ import chalk from 'chalk';
import chalkTemplate from 'chalk-template'; import chalkTemplate from 'chalk-template';
import * as portscanner from 'portscanner'; import * as portscanner from 'portscanner';
import semver from 'semver'; import semver from 'semver';
import { getConnection } from 'typeorm';
import Logger from '@/services/logger.js'; import Logger from '@/services/logger.js';
import loadConfig from '@/config/load.js'; import loadConfig from '@/config/load.js';
@ -15,7 +14,7 @@ import { Config } from '@/config/types.js';
import { lessThan } from '@/prelude/array.js'; import { lessThan } from '@/prelude/array.js';
import { envOption } from '../env.js'; import { envOption } from '../env.js';
import { showMachineInfo } from '@/misc/show-machine-info.js'; import { showMachineInfo } from '@/misc/show-machine-info.js';
import { initDb } from '../db/postgre.js'; import { db, initDb } from '../db/postgre.js';
const _filename = fileURLToPath(import.meta.url); const _filename = fileURLToPath(import.meta.url);
const _dirname = dirname(_filename); const _dirname = dirname(_filename);
@ -144,7 +143,7 @@ async function connectDb(): Promise<void> {
try { try {
dbLogger.info('Connecting...'); dbLogger.info('Connecting...');
await initDb(); await initDb();
const v = await getConnection().query('SHOW server_version').then(x => x[0].server_version); const v = await db.query('SHOW server_version').then(x => x[0].server_version);
dbLogger.succ(`Connected: v${v}`); dbLogger.succ(`Connected: v${v}`);
} catch (e) { } catch (e) {
dbLogger.error('Cannot connect', null, true); dbLogger.error('Cannot connect', null, true);

View File

@ -2,9 +2,10 @@
import pg from 'pg'; import pg from 'pg';
pg.types.setTypeParser(20, Number); pg.types.setTypeParser(20, Number);
import { createConnection, Logger, getConnection } from 'typeorm'; import { Logger, DataSource } from 'typeorm';
import * as highlight from 'cli-highlight'; import * as highlight from 'cli-highlight';
import config from '@/config/index.js'; import config from '@/config/index.js';
import { envOption } from '../env.js';
import { dbLogger } from './logger.js'; import { dbLogger } from './logger.js';
@ -61,7 +62,6 @@ import { Antenna } from '@/models/entities/antenna.js';
import { AntennaNote } from '@/models/entities/antenna-note.js'; import { AntennaNote } from '@/models/entities/antenna-note.js';
import { PromoNote } from '@/models/entities/promo-note.js'; import { PromoNote } from '@/models/entities/promo-note.js';
import { PromoRead } from '@/models/entities/promo-read.js'; import { PromoRead } from '@/models/entities/promo-read.js';
import { envOption } from '../env.js';
import { Relay } from '@/models/entities/relay.js'; import { Relay } from '@/models/entities/relay.js';
import { MutedNote } from '@/models/entities/muted-note.js'; import { MutedNote } from '@/models/entities/muted-note.js';
import { Channel } from '@/models/entities/channel.js'; import { Channel } from '@/models/entities/channel.js';
@ -74,7 +74,7 @@ import { UserPending } from '@/models/entities/user-pending.js';
import { entities as charts } from '@/services/chart/entities.js'; import { entities as charts } from '@/services/chart/entities.js';
const sqlLogger = dbLogger.createSubLogger('sql', 'white', false); const sqlLogger = dbLogger.createSubLogger('sql', 'gray', false);
class MyCustomLogger implements Logger { class MyCustomLogger implements Logger {
private highlight(sql: string) { private highlight(sql: string) {
@ -84,10 +84,8 @@ class MyCustomLogger implements Logger {
} }
public logQuery(query: string, parameters?: any[]) { public logQuery(query: string, parameters?: any[]) {
if (envOption.verbose) {
sqlLogger.info(this.highlight(query).substring(0, 100)); sqlLogger.info(this.highlight(query).substring(0, 100));
} }
}
public logQueryError(error: string, query: string, parameters?: any[]) { public logQueryError(error: string, query: string, parameters?: any[]) {
sqlLogger.error(this.highlight(query)); sqlLogger.error(this.highlight(query));
@ -176,17 +174,9 @@ export const entities = [
...charts, ...charts,
]; ];
export function initDb(justBorrow = false, sync = false, forceRecreate = false) { const log = process.env.NODE_ENV !== 'production';
if (!forceRecreate) {
try {
const conn = getConnection();
return Promise.resolve(conn);
} catch (e) {}
}
const log = process.env.NODE_ENV !== 'production'; export const db = new DataSource({
return createConnection({
type: 'postgres', type: 'postgres',
host: config.db.host, host: config.db.host,
port: config.db.port, port: config.db.port,
@ -197,8 +187,8 @@ export function initDb(justBorrow = false, sync = false, forceRecreate = false)
statement_timeout: 1000 * 10, statement_timeout: 1000 * 10,
...config.db.extra, ...config.db.extra,
}, },
synchronize: process.env.NODE_ENV === 'test' || sync, synchronize: process.env.NODE_ENV === 'test',
dropSchema: process.env.NODE_ENV === 'test' && !justBorrow, dropSchema: process.env.NODE_ENV === 'test',
cache: !config.db.disableCache ? { cache: !config.db.disableCache ? {
type: 'redis', type: 'redis',
options: { options: {
@ -211,20 +201,24 @@ export function initDb(justBorrow = false, sync = false, forceRecreate = false)
} : false, } : false,
logging: log, logging: log,
logger: log ? new MyCustomLogger() : undefined, logger: log ? new MyCustomLogger() : undefined,
maxQueryExecutionTime: 300,
entities: entities, entities: entities,
}); migrations: ['../../migration/*.js'],
});
export async function initDb() {
await db.connect();
} }
export async function resetDb() { export async function resetDb() {
const reset = async () => { const reset = async () => {
const conn = await getConnection(); const tables = await db.query(`SELECT relname AS "table"
const tables = await conn.query(`SELECT relname AS "table"
FROM pg_class C LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) FROM pg_class C LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
WHERE nspname NOT IN ('pg_catalog', 'information_schema') WHERE nspname NOT IN ('pg_catalog', 'information_schema')
AND C.relkind = 'r' AND C.relkind = 'r'
AND nspname !~ '^pg_toast';`); AND nspname !~ '^pg_toast';`);
for (const table of tables) { for (const table of tables) {
await conn.query(`DELETE FROM "${table.table}" CASCADE`); await db.query(`DELETE FROM "${table.table}" CASCADE`);
} }
}; };

View File

@ -18,7 +18,7 @@ export async function checkHitAntenna(antenna: Antenna, note: (Note | Packed<'No
if (note.visibility === 'specified') return false; if (note.visibility === 'specified') return false;
// アンテナ作成者がノート作成者にブロックされていたらスキップ // アンテナ作成者がノート作成者にブロックされていたらスキップ
const blockings = await blockingCache.fetch(noteUser.id, () => Blockings.find({ blockerId: noteUser.id }).then(res => res.map(x => x.blockeeId))); const blockings = await blockingCache.fetch(noteUser.id, () => Blockings.findBy({ blockerId: noteUser.id }).then(res => res.map(x => x.blockeeId)));
if (blockings.some(blocking => blocking === antenna.userId)) return false; if (blockings.some(blocking => blocking === antenna.userId)) return false;
if (note.visibility === 'followers') { if (note.visibility === 'followers') {
@ -32,15 +32,15 @@ export async function checkHitAntenna(antenna: Antenna, note: (Note | Packed<'No
if (noteUserFollowers && !noteUserFollowers.includes(antenna.userId)) return false; if (noteUserFollowers && !noteUserFollowers.includes(antenna.userId)) return false;
if (antennaUserFollowing && !antennaUserFollowing.includes(note.userId)) return false; if (antennaUserFollowing && !antennaUserFollowing.includes(note.userId)) return false;
} else if (antenna.src === 'list') { } else if (antenna.src === 'list') {
const listUsers = (await UserListJoinings.find({ const listUsers = (await UserListJoinings.findBy({
userListId: antenna.userListId!, userListId: antenna.userListId!,
})).map(x => x.userId); })).map(x => x.userId);
if (!listUsers.includes(note.userId)) return false; if (!listUsers.includes(note.userId)) return false;
} else if (antenna.src === 'group') { } else if (antenna.src === 'group') {
const joining = await UserGroupJoinings.findOneOrFail(antenna.userGroupJoiningId!); const joining = await UserGroupJoinings.findOneByOrFail({ id: antenna.userGroupJoiningId! });
const groupUsers = (await UserGroupJoinings.find({ const groupUsers = (await UserGroupJoinings.findBy({
userGroupId: joining.userGroupId, userGroupId: joining.userGroupId,
})).map(x => x.userId); })).map(x => x.userId);

View File

@ -1,12 +1,12 @@
import { db } from '@/db/postgre.js';
import { Meta } from '@/models/entities/meta.js'; import { Meta } from '@/models/entities/meta.js';
import { getConnection } from 'typeorm';
let cache: Meta; let cache: Meta;
export async function fetchMeta(noCache = false): Promise<Meta> { export async function fetchMeta(noCache = false): Promise<Meta> {
if (!noCache && cache) return cache; if (!noCache && cache) return cache;
return await getConnection().transaction(async transactionalEntityManager => { return await db.transaction(async transactionalEntityManager => {
// 過去のバグでレコードが複数出来てしまっている可能性があるので新しいIDを優先する // 過去のバグでレコードが複数出来てしまっている可能性があるので新しいIDを優先する
const meta = await transactionalEntityManager.findOne(Meta, { const meta = await transactionalEntityManager.findOne(Meta, {
order: { order: {

View File

@ -5,5 +5,5 @@ import { Users } from '@/models/index.js';
export async function fetchProxyAccount(): Promise<ILocalUser | null> { export async function fetchProxyAccount(): Promise<ILocalUser | null> {
const meta = await fetchMeta(); const meta = await fetchMeta();
if (meta.proxyAccountId == null) return null; if (meta.proxyAccountId == null) return null;
return await Users.findOneOrFail(meta.proxyAccountId) as ILocalUser; return await Users.findOneByOrFail({ id: meta.proxyAccountId }) as ILocalUser;
} }

View File

@ -6,5 +6,5 @@ import { Cache } from './cache.js';
const cache = new Cache<UserKeypair>(Infinity); const cache = new Cache<UserKeypair>(Infinity);
export async function getUserKeypair(userId: User['id']): Promise<UserKeypair> { export async function getUserKeypair(userId: User['id']): Promise<UserKeypair> {
return await cache.fetch(userId, () => UserKeypairs.findOneOrFail(userId)); return await cache.fetch(userId, () => UserKeypairs.findOneByOrFail({ userId: userId }));
} }

View File

@ -1,4 +1,4 @@
import { In } from 'typeorm'; import { In, IsNull } from 'typeorm';
import { Emojis } from '@/models/index.js'; import { Emojis } from '@/models/index.js';
import { Emoji } from '@/models/entities/emoji.js'; import { Emoji } from '@/models/entities/emoji.js';
import { Note } from '@/models/entities/note.js'; import { Note } from '@/models/entities/note.js';
@ -52,9 +52,9 @@ export async function populateEmoji(emojiName: string, noteUserHost: string | nu
const { name, host } = parseEmojiStr(emojiName, noteUserHost); const { name, host } = parseEmojiStr(emojiName, noteUserHost);
if (name == null) return null; if (name == null) return null;
const queryOrNull = async () => (await Emojis.findOne({ const queryOrNull = async () => (await Emojis.findOneBy({
name, name,
host, host: host ?? IsNull(),
})) || null; })) || null;
const emoji = await cache.fetch(`${name} ${host}`, queryOrNull); const emoji = await cache.fetch(`${name} ${host}`, queryOrNull);
@ -112,7 +112,7 @@ export async function prefetchEmojis(emojis: { name: string; host: string | null
for (const host of hosts) { for (const host of hosts) {
emojisQuery.push({ emojisQuery.push({
name: In(notCachedEmojis.filter(e => e.host === host).map(e => e.name)), name: In(notCachedEmojis.filter(e => e.host === host).map(e => e.name)),
host: host, host: host ?? IsNull(),
}); });
} }
const _emojis = emojisQuery.length > 0 ? await Emojis.find({ const _emojis = emojisQuery.length > 0 ? await Emojis.find({

View File

@ -3,6 +3,7 @@ import { emojiRegex } from './emoji-regex.js';
import { fetchMeta } from './fetch-meta.js'; import { fetchMeta } from './fetch-meta.js';
import { Emojis } from '@/models/index.js'; import { Emojis } from '@/models/index.js';
import { toPunyNullable } from './convert-host.js'; import { toPunyNullable } from './convert-host.js';
import { IsNull } from 'typeorm';
const legacies: Record<string, string> = { const legacies: Record<string, string> = {
'like': '👍', 'like': '👍',
@ -74,8 +75,8 @@ export async function toDbReaction(reaction?: string | null, reacterHost?: strin
const custom = reaction.match(/^:([\w+-]+)(?:@\.)?:$/); const custom = reaction.match(/^:([\w+-]+)(?:@\.)?:$/);
if (custom) { if (custom) {
const name = custom[1]; const name = custom[1];
const emoji = await Emojis.findOne({ const emoji = await Emojis.findOneBy({
host: reacterHost || null, host: reacterHost ?? IsNull(),
name, name,
}); });

View File

@ -1,4 +1,6 @@
import { getRepository, getCustomRepository } from 'typeorm'; import { } from 'typeorm';
import { db } from '@/db/postgre.js';
import { Announcement } from './entities/announcement.js'; import { Announcement } from './entities/announcement.js';
import { AnnouncementRead } from './entities/announcement-read.js'; import { AnnouncementRead } from './entities/announcement-read.js';
import { Instance } from './entities/instance.js'; import { Instance } from './entities/instance.js';
@ -63,65 +65,65 @@ import { PasswordResetRequest } from './entities/password-reset-request.js';
import { UserPending } from './entities/user-pending.js'; import { UserPending } from './entities/user-pending.js';
import { InstanceRepository } from './repositories/instance.js'; import { InstanceRepository } from './repositories/instance.js';
export const Announcements = getRepository(Announcement); export const Announcements = db.getRepository(Announcement);
export const AnnouncementReads = getRepository(AnnouncementRead); export const AnnouncementReads = db.getRepository(AnnouncementRead);
export const Apps = getCustomRepository(AppRepository); export const Apps = (AppRepository);
export const Notes = getCustomRepository(NoteRepository); export const Notes = (NoteRepository);
export const NoteFavorites = getCustomRepository(NoteFavoriteRepository); export const NoteFavorites = (NoteFavoriteRepository);
export const NoteWatchings = getRepository(NoteWatching); export const NoteWatchings = db.getRepository(NoteWatching);
export const NoteThreadMutings = getRepository(NoteThreadMuting); export const NoteThreadMutings = db.getRepository(NoteThreadMuting);
export const NoteReactions = getCustomRepository(NoteReactionRepository); export const NoteReactions = (NoteReactionRepository);
export const NoteUnreads = getRepository(NoteUnread); export const NoteUnreads = db.getRepository(NoteUnread);
export const Polls = getRepository(Poll); export const Polls = db.getRepository(Poll);
export const PollVotes = getRepository(PollVote); export const PollVotes = db.getRepository(PollVote);
export const Users = getCustomRepository(UserRepository); export const Users = (UserRepository);
export const UserProfiles = getRepository(UserProfile); export const UserProfiles = db.getRepository(UserProfile);
export const UserKeypairs = getRepository(UserKeypair); export const UserKeypairs = db.getRepository(UserKeypair);
export const UserPendings = getRepository(UserPending); export const UserPendings = db.getRepository(UserPending);
export const AttestationChallenges = getRepository(AttestationChallenge); export const AttestationChallenges = db.getRepository(AttestationChallenge);
export const UserSecurityKeys = getRepository(UserSecurityKey); export const UserSecurityKeys = db.getRepository(UserSecurityKey);
export const UserPublickeys = getRepository(UserPublickey); export const UserPublickeys = db.getRepository(UserPublickey);
export const UserLists = getCustomRepository(UserListRepository); export const UserLists = (UserListRepository);
export const UserListJoinings = getRepository(UserListJoining); export const UserListJoinings = db.getRepository(UserListJoining);
export const UserGroups = getCustomRepository(UserGroupRepository); export const UserGroups = (UserGroupRepository);
export const UserGroupJoinings = getRepository(UserGroupJoining); export const UserGroupJoinings = db.getRepository(UserGroupJoining);
export const UserGroupInvitations = getCustomRepository(UserGroupInvitationRepository); export const UserGroupInvitations = (UserGroupInvitationRepository);
export const UserNotePinings = getRepository(UserNotePining); export const UserNotePinings = db.getRepository(UserNotePining);
export const UsedUsernames = getRepository(UsedUsername); export const UsedUsernames = db.getRepository(UsedUsername);
export const Followings = getCustomRepository(FollowingRepository); export const Followings = (FollowingRepository);
export const FollowRequests = getCustomRepository(FollowRequestRepository); export const FollowRequests = (FollowRequestRepository);
export const Instances = getCustomRepository(InstanceRepository); export const Instances = (InstanceRepository);
export const Emojis = getCustomRepository(EmojiRepository); export const Emojis = (EmojiRepository);
export const DriveFiles = getCustomRepository(DriveFileRepository); export const DriveFiles = (DriveFileRepository);
export const DriveFolders = getCustomRepository(DriveFolderRepository); export const DriveFolders = (DriveFolderRepository);
export const Notifications = getCustomRepository(NotificationRepository); export const Notifications = (NotificationRepository);
export const Metas = getRepository(Meta); export const Metas = db.getRepository(Meta);
export const Mutings = getCustomRepository(MutingRepository); export const Mutings = (MutingRepository);
export const Blockings = getCustomRepository(BlockingRepository); export const Blockings = (BlockingRepository);
export const SwSubscriptions = getRepository(SwSubscription); export const SwSubscriptions = db.getRepository(SwSubscription);
export const Hashtags = getCustomRepository(HashtagRepository); export const Hashtags = (HashtagRepository);
export const AbuseUserReports = getCustomRepository(AbuseUserReportRepository); export const AbuseUserReports = (AbuseUserReportRepository);
export const RegistrationTickets = getRepository(RegistrationTicket); export const RegistrationTickets = db.getRepository(RegistrationTicket);
export const AuthSessions = getCustomRepository(AuthSessionRepository); export const AuthSessions = (AuthSessionRepository);
export const AccessTokens = getRepository(AccessToken); export const AccessTokens = db.getRepository(AccessToken);
export const Signins = getCustomRepository(SigninRepository); export const Signins = (SigninRepository);
export const MessagingMessages = getCustomRepository(MessagingMessageRepository); export const MessagingMessages = (MessagingMessageRepository);
export const Pages = getCustomRepository(PageRepository); export const Pages = (PageRepository);
export const PageLikes = getCustomRepository(PageLikeRepository); export const PageLikes = (PageLikeRepository);
export const GalleryPosts = getCustomRepository(GalleryPostRepository); export const GalleryPosts = (GalleryPostRepository);
export const GalleryLikes = getCustomRepository(GalleryLikeRepository); export const GalleryLikes = (GalleryLikeRepository);
export const ModerationLogs = getCustomRepository(ModerationLogRepository); export const ModerationLogs = (ModerationLogRepository);
export const Clips = getCustomRepository(ClipRepository); export const Clips = (ClipRepository);
export const ClipNotes = getRepository(ClipNote); export const ClipNotes = db.getRepository(ClipNote);
export const Antennas = getCustomRepository(AntennaRepository); export const Antennas = (AntennaRepository);
export const AntennaNotes = getRepository(AntennaNote); export const AntennaNotes = db.getRepository(AntennaNote);
export const PromoNotes = getRepository(PromoNote); export const PromoNotes = db.getRepository(PromoNote);
export const PromoReads = getRepository(PromoRead); export const PromoReads = db.getRepository(PromoRead);
export const Relays = getCustomRepository(RelayRepository); export const Relays = (RelayRepository);
export const MutedNotes = getRepository(MutedNote); export const MutedNotes = db.getRepository(MutedNote);
export const Channels = getCustomRepository(ChannelRepository); export const Channels = (ChannelRepository);
export const ChannelFollowings = getRepository(ChannelFollowing); export const ChannelFollowings = db.getRepository(ChannelFollowing);
export const ChannelNotePinings = getRepository(ChannelNotePining); export const ChannelNotePinings = db.getRepository(ChannelNotePining);
export const RegistryItems = getRepository(RegistryItem); export const RegistryItems = db.getRepository(RegistryItem);
export const Ads = getRepository(Ad); export const Ads = db.getRepository(Ad);
export const PasswordResetRequests = getRepository(PasswordResetRequest); export const PasswordResetRequests = db.getRepository(PasswordResetRequest);

View File

@ -1,14 +1,13 @@
import { EntityRepository, Repository } from 'typeorm'; import { db } from '@/db/postgre.js';
import { Users } from '../index.js'; import { Users } from '../index.js';
import { AbuseUserReport } from '@/models/entities/abuse-user-report.js'; import { AbuseUserReport } from '@/models/entities/abuse-user-report.js';
import { awaitAll } from '@/prelude/await-all.js'; import { awaitAll } from '@/prelude/await-all.js';
@EntityRepository(AbuseUserReport) export const AbuseUserReportRepository = db.getRepository(AbuseUserReport).extend({
export class AbuseUserReportRepository extends Repository<AbuseUserReport> { async pack(
public async pack(
src: AbuseUserReport['id'] | AbuseUserReport, src: AbuseUserReport['id'] | AbuseUserReport,
) { ) {
const report = typeof src === 'object' ? src : await this.findOneOrFail(src); const report = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src });
return await awaitAll({ return await awaitAll({
id: report.id, id: report.id,
@ -29,11 +28,11 @@ export class AbuseUserReportRepository extends Repository<AbuseUserReport> {
}) : null, }) : null,
forwarded: report.forwarded, forwarded: report.forwarded,
}); });
} },
public packMany( packMany(
reports: any[], reports: any[],
) { ) {
return Promise.all(reports.map(x => this.pack(x))); return Promise.all(reports.map(x => this.pack(x)));
} },
} });

View File

@ -1,17 +1,16 @@
import { EntityRepository, Repository } from 'typeorm'; import { db } from '@/db/postgre.js';
import { Antenna } from '@/models/entities/antenna.js'; import { Antenna } from '@/models/entities/antenna.js';
import { Packed } from '@/misc/schema.js'; import { Packed } from '@/misc/schema.js';
import { AntennaNotes, UserGroupJoinings } from '../index.js'; import { AntennaNotes, UserGroupJoinings } from '../index.js';
@EntityRepository(Antenna) export const AntennaRepository = db.getRepository(Antenna).extend({
export class AntennaRepository extends Repository<Antenna> { async pack(
public async pack(
src: Antenna['id'] | Antenna, src: Antenna['id'] | Antenna,
): Promise<Packed<'Antenna'>> { ): Promise<Packed<'Antenna'>> {
const antenna = typeof src === 'object' ? src : await this.findOneOrFail(src); const antenna = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src });
const hasUnreadNote = (await AntennaNotes.findOne({ antennaId: antenna.id, read: false })) != null; const hasUnreadNote = (await AntennaNotes.findOneBy({ antennaId: antenna.id, read: false })) != null;
const userGroupJoining = antenna.userGroupJoiningId ? await UserGroupJoinings.findOne(antenna.userGroupJoiningId) : null; const userGroupJoining = antenna.userGroupJoiningId ? await UserGroupJoinings.findOneBy({ id: antenna.userGroupJoiningId }) : null;
return { return {
id: antenna.id, id: antenna.id,
@ -29,5 +28,5 @@ export class AntennaRepository extends Repository<Antenna> {
withFile: antenna.withFile, withFile: antenna.withFile,
hasUnreadNote, hasUnreadNote,
}; };
} },
} });

View File

@ -1,12 +1,11 @@
import { EntityRepository, Repository } from 'typeorm'; import { db } from '@/db/postgre.js';
import { App } from '@/models/entities/app.js'; import { App } from '@/models/entities/app.js';
import { AccessTokens } from '../index.js'; import { AccessTokens } from '../index.js';
import { Packed } from '@/misc/schema.js'; import { Packed } from '@/misc/schema.js';
import { User } from '../entities/user.js'; import { User } from '../entities/user.js';
@EntityRepository(App) export const AppRepository = db.getRepository(App).extend({
export class AppRepository extends Repository<App> { async pack(
public async pack(
src: App['id'] | App, src: App['id'] | App,
me?: { id: User['id'] } | null | undefined, me?: { id: User['id'] } | null | undefined,
options?: { options?: {
@ -21,7 +20,7 @@ export class AppRepository extends Repository<App> {
includeProfileImageIds: false, includeProfileImageIds: false,
}, options); }, options);
const app = typeof src === 'object' ? src : await this.findOneOrFail(src); const app = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src });
return { return {
id: app.id, id: app.id,
@ -30,11 +29,11 @@ export class AppRepository extends Repository<App> {
permission: app.permission, permission: app.permission,
...(opts.includeSecret ? { secret: app.secret } : {}), ...(opts.includeSecret ? { secret: app.secret } : {}),
...(me ? { ...(me ? {
isAuthorized: await AccessTokens.count({ isAuthorized: await AccessTokens.countBy({
appId: app.id, appId: app.id,
userId: me.id, userId: me.id,
}).then(count => count > 0), }).then(count => count > 0),
} : {}), } : {}),
}; };
} },
} });

View File

@ -1,21 +1,20 @@
import { EntityRepository, Repository } from 'typeorm'; import { db } from '@/db/postgre.js';
import { Apps } from '../index.js'; import { Apps } from '../index.js';
import { AuthSession } from '@/models/entities/auth-session.js'; import { AuthSession } from '@/models/entities/auth-session.js';
import { awaitAll } from '@/prelude/await-all.js'; import { awaitAll } from '@/prelude/await-all.js';
import { User } from '@/models/entities/user.js'; import { User } from '@/models/entities/user.js';
@EntityRepository(AuthSession) export const AuthSessionRepository = db.getRepository(AuthSession).extend({
export class AuthSessionRepository extends Repository<AuthSession> { async pack(
public async pack(
src: AuthSession['id'] | AuthSession, src: AuthSession['id'] | AuthSession,
me?: { id: User['id'] } | null | undefined me?: { id: User['id'] } | null | undefined
) { ) {
const session = typeof src === 'object' ? src : await this.findOneOrFail(src); const session = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src });
return await awaitAll({ return await awaitAll({
id: session.id, id: session.id,
app: Apps.pack(session.appId, me), app: Apps.pack(session.appId, me),
token: session.token, token: session.token,
}); });
} },
} });

View File

@ -1,17 +1,16 @@
import { EntityRepository, Repository } from 'typeorm'; import { db } from '@/db/postgre.js';
import { Users } from '../index.js'; import { Users } from '../index.js';
import { Blocking } from '@/models/entities/blocking.js'; import { Blocking } from '@/models/entities/blocking.js';
import { awaitAll } from '@/prelude/await-all.js'; import { awaitAll } from '@/prelude/await-all.js';
import { Packed } from '@/misc/schema.js'; import { Packed } from '@/misc/schema.js';
import { User } from '@/models/entities/user.js'; import { User } from '@/models/entities/user.js';
@EntityRepository(Blocking) export const BlockingRepository = db.getRepository(Blocking).extend({
export class BlockingRepository extends Repository<Blocking> { async pack(
public async pack(
src: Blocking['id'] | Blocking, src: Blocking['id'] | Blocking,
me?: { id: User['id'] } | null | undefined me?: { id: User['id'] } | null | undefined
): Promise<Packed<'Blocking'>> { ): Promise<Packed<'Blocking'>> {
const blocking = typeof src === 'object' ? src : await this.findOneOrFail(src); const blocking = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src });
return await awaitAll({ return await awaitAll({
id: blocking.id, id: blocking.id,
@ -21,12 +20,12 @@ export class BlockingRepository extends Repository<Blocking> {
detail: true, detail: true,
}), }),
}); });
} },
public packMany( packMany(
blockings: any[], blockings: any[],
me: { id: User['id'] } me: { id: User['id'] }
) { ) {
return Promise.all(blockings.map(x => this.pack(x, me))); return Promise.all(blockings.map(x => this.pack(x, me)));
} },
} });

View File

@ -1,23 +1,22 @@
import { EntityRepository, Repository } from 'typeorm'; import { db } from '@/db/postgre.js';
import { Channel } from '@/models/entities/channel.js'; import { Channel } from '@/models/entities/channel.js';
import { Packed } from '@/misc/schema.js'; import { Packed } from '@/misc/schema.js';
import { DriveFiles, ChannelFollowings, NoteUnreads } from '../index.js'; import { DriveFiles, ChannelFollowings, NoteUnreads } from '../index.js';
import { User } from '@/models/entities/user.js'; import { User } from '@/models/entities/user.js';
@EntityRepository(Channel) export const ChannelRepository = db.getRepository(Channel).extend({
export class ChannelRepository extends Repository<Channel> { async pack(
public async pack(
src: Channel['id'] | Channel, src: Channel['id'] | Channel,
me?: { id: User['id'] } | null | undefined, me?: { id: User['id'] } | null | undefined,
): Promise<Packed<'Channel'>> { ): Promise<Packed<'Channel'>> {
const channel = typeof src === 'object' ? src : await this.findOneOrFail(src); const channel = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src });
const meId = me ? me.id : null; const meId = me ? me.id : null;
const banner = channel.bannerId ? await DriveFiles.findOne(channel.bannerId) : null; const banner = channel.bannerId ? await DriveFiles.findOneBy({ id: channel.bannerId }) : null;
const hasUnreadNote = meId ? (await NoteUnreads.findOne({ noteChannelId: channel.id, userId: meId })) != null : undefined; const hasUnreadNote = meId ? (await NoteUnreads.findOneBy({ noteChannelId: channel.id, userId: meId })) != null : undefined;
const following = meId ? await ChannelFollowings.findOne({ const following = meId ? await ChannelFollowings.findOneBy({
followerId: meId, followerId: meId,
followeeId: channel.id, followeeId: channel.id,
}) : null; }) : null;
@ -38,5 +37,5 @@ export class ChannelRepository extends Repository<Channel> {
hasUnreadNote, hasUnreadNote,
} : {}), } : {}),
}; };
} },
} });

View File

@ -1,15 +1,14 @@
import { EntityRepository, Repository } from 'typeorm'; import { db } from '@/db/postgre.js';
import { Clip } from '@/models/entities/clip.js'; import { Clip } from '@/models/entities/clip.js';
import { Packed } from '@/misc/schema.js'; import { Packed } from '@/misc/schema.js';
import { Users } from '../index.js'; import { Users } from '../index.js';
import { awaitAll } from '@/prelude/await-all.js'; import { awaitAll } from '@/prelude/await-all.js';
@EntityRepository(Clip) export const ClipRepository = db.getRepository(Clip).extend({
export class ClipRepository extends Repository<Clip> { async pack(
public async pack(
src: Clip['id'] | Clip, src: Clip['id'] | Clip,
): Promise<Packed<'Clip'>> { ): Promise<Packed<'Clip'>> {
const clip = typeof src === 'object' ? src : await this.findOneOrFail(src); const clip = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src });
return await awaitAll({ return await awaitAll({
id: clip.id, id: clip.id,
@ -20,12 +19,12 @@ export class ClipRepository extends Repository<Clip> {
description: clip.description, description: clip.description,
isPublic: clip.isPublic, isPublic: clip.isPublic,
}); });
} },
public packMany( packMany(
clips: Clip[], clips: Clip[],
) { ) {
return Promise.all(clips.map(x => this.pack(x))); return Promise.all(clips.map(x => this.pack(x)));
} },
} });

View File

@ -1,4 +1,4 @@
import { EntityRepository, Repository } from 'typeorm'; import { db } from '@/db/postgre.js';
import { DriveFile } from '@/models/entities/drive-file.js'; import { DriveFile } from '@/models/entities/drive-file.js';
import { Users, DriveFolders } from '../index.js'; import { Users, DriveFolders } from '../index.js';
import { User } from '@/models/entities/user.js'; import { User } from '@/models/entities/user.js';
@ -16,9 +16,8 @@ type PackOptions = {
withUser?: boolean, withUser?: boolean,
}; };
@EntityRepository(DriveFile) export const DriveFileRepository = db.getRepository(DriveFile).extend({
export class DriveFileRepository extends Repository<DriveFile> { validateFileName(name: string): boolean {
public validateFileName(name: string): boolean {
return ( return (
(name.trim().length > 0) && (name.trim().length > 0) &&
(name.length <= 200) && (name.length <= 200) &&
@ -26,9 +25,9 @@ export class DriveFileRepository extends Repository<DriveFile> {
(name.indexOf('/') === -1) && (name.indexOf('/') === -1) &&
(name.indexOf('..') === -1) (name.indexOf('..') === -1)
); );
} },
public getPublicProperties(file: DriveFile): DriveFile['properties'] { getPublicProperties(file: DriveFile): DriveFile['properties'] {
if (file.properties.orientation != null) { if (file.properties.orientation != null) {
const properties = JSON.parse(JSON.stringify(file.properties)); const properties = JSON.parse(JSON.stringify(file.properties));
if (file.properties.orientation >= 5) { if (file.properties.orientation >= 5) {
@ -39,9 +38,9 @@ export class DriveFileRepository extends Repository<DriveFile> {
} }
return file.properties; return file.properties;
} },
public getPublicUrl(file: DriveFile, thumbnail = false): string | null { getPublicUrl(file: DriveFile, thumbnail = false): string | null {
// リモートかつメディアプロキシ // リモートかつメディアプロキシ
if (file.uri != null && file.userHost != null && config.mediaProxy != null) { if (file.uri != null && file.userHost != null && config.mediaProxy != null) {
return appendQuery(config.mediaProxy, query({ return appendQuery(config.mediaProxy, query({
@ -62,9 +61,9 @@ export class DriveFileRepository extends Repository<DriveFile> {
const isImage = file.type && ['image/png', 'image/apng', 'image/gif', 'image/jpeg', 'image/webp', 'image/svg+xml'].includes(file.type); const isImage = file.type && ['image/png', 'image/apng', 'image/gif', 'image/jpeg', 'image/webp', 'image/svg+xml'].includes(file.type);
return thumbnail ? (file.thumbnailUrl || (isImage ? (file.webpublicUrl || file.url) : null)) : (file.webpublicUrl || file.url); return thumbnail ? (file.thumbnailUrl || (isImage ? (file.webpublicUrl || file.url) : null)) : (file.webpublicUrl || file.url);
} },
public async calcDriveUsageOf(user: User['id'] | { id: User['id'] }): Promise<number> { async calcDriveUsageOf(user: User['id'] | { id: User['id'] }): Promise<number> {
const id = typeof user === 'object' ? user.id : user; const id = typeof user === 'object' ? user.id : user;
const { sum } = await this const { sum } = await this
@ -75,9 +74,9 @@ export class DriveFileRepository extends Repository<DriveFile> {
.getRawOne(); .getRawOne();
return parseInt(sum, 10) || 0; return parseInt(sum, 10) || 0;
} },
public async calcDriveUsageOfHost(host: string): Promise<number> { async calcDriveUsageOfHost(host: string): Promise<number> {
const { sum } = await this const { sum } = await this
.createQueryBuilder('file') .createQueryBuilder('file')
.where('file.userHost = :host', { host: toPuny(host) }) .where('file.userHost = :host', { host: toPuny(host) })
@ -86,9 +85,9 @@ export class DriveFileRepository extends Repository<DriveFile> {
.getRawOne(); .getRawOne();
return parseInt(sum, 10) || 0; return parseInt(sum, 10) || 0;
} },
public async calcDriveUsageOfLocal(): Promise<number> { async calcDriveUsageOfLocal(): Promise<number> {
const { sum } = await this const { sum } = await this
.createQueryBuilder('file') .createQueryBuilder('file')
.where('file.userHost IS NULL') .where('file.userHost IS NULL')
@ -97,9 +96,9 @@ export class DriveFileRepository extends Repository<DriveFile> {
.getRawOne(); .getRawOne();
return parseInt(sum, 10) || 0; return parseInt(sum, 10) || 0;
} },
public async calcDriveUsageOfRemote(): Promise<number> { async calcDriveUsageOfRemote(): Promise<number> {
const { sum } = await this const { sum } = await this
.createQueryBuilder('file') .createQueryBuilder('file')
.where('file.userHost IS NOT NULL') .where('file.userHost IS NOT NULL')
@ -108,11 +107,9 @@ export class DriveFileRepository extends Repository<DriveFile> {
.getRawOne(); .getRawOne();
return parseInt(sum, 10) || 0; return parseInt(sum, 10) || 0;
} },
public async pack(src: DriveFile['id'], options?: PackOptions): Promise<Packed<'DriveFile'> | null>; async pack(
public async pack(src: DriveFile, options?: PackOptions): Promise<Packed<'DriveFile'>>;
public async pack(
src: DriveFile['id'] | DriveFile, src: DriveFile['id'] | DriveFile,
options?: PackOptions options?: PackOptions
): Promise<Packed<'DriveFile'> | null> { ): Promise<Packed<'DriveFile'> | null> {
@ -121,11 +118,9 @@ export class DriveFileRepository extends Repository<DriveFile> {
self: false, self: false,
}, options); }, options);
const file = typeof src === 'object' ? src : await this.findOne(src); const file = typeof src === 'object' ? src : await this.findOneBy({ id: src });
if (file == null) return null; if (file == null) return null;
const meta = await fetchMeta();
return await awaitAll<Packed<'DriveFile'>>({ return await awaitAll<Packed<'DriveFile'>>({
id: file.id, id: file.id,
createdAt: file.createdAt.toISOString(), createdAt: file.createdAt.toISOString(),
@ -146,13 +141,13 @@ export class DriveFileRepository extends Repository<DriveFile> {
userId: opts.withUser ? file.userId : null, userId: opts.withUser ? file.userId : null,
user: (opts.withUser && file.userId) ? Users.pack(file.userId) : null, user: (opts.withUser && file.userId) ? Users.pack(file.userId) : null,
}); });
} },
public async packMany( async packMany(
files: (DriveFile['id'] | DriveFile)[], files: (DriveFile['id'] | DriveFile)[],
options?: PackOptions options?: PackOptions
) { ) {
const items = await Promise.all(files.map(f => this.pack(f, options))); const items = await Promise.all(files.map(f => this.pack(f, options)));
return items.filter(x => x != null); return items.filter(x => x != null);
} },
} });

View File

@ -1,12 +1,11 @@
import { EntityRepository, Repository } from 'typeorm'; import { db } from '@/db/postgre.js';
import { DriveFolders, DriveFiles } from '../index.js'; import { DriveFolders, DriveFiles } from '../index.js';
import { DriveFolder } from '@/models/entities/drive-folder.js'; import { DriveFolder } from '@/models/entities/drive-folder.js';
import { awaitAll } from '@/prelude/await-all.js'; import { awaitAll } from '@/prelude/await-all.js';
import { Packed } from '@/misc/schema.js'; import { Packed } from '@/misc/schema.js';
@EntityRepository(DriveFolder) export const DriveFolderRepository = db.getRepository(DriveFolder).extend({
export class DriveFolderRepository extends Repository<DriveFolder> { async pack(
public async pack(
src: DriveFolder['id'] | DriveFolder, src: DriveFolder['id'] | DriveFolder,
options?: { options?: {
detail: boolean detail: boolean
@ -16,7 +15,7 @@ export class DriveFolderRepository extends Repository<DriveFolder> {
detail: false, detail: false,
}, options); }, options);
const folder = typeof src === 'object' ? src : await this.findOneOrFail(src); const folder = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src });
return await awaitAll({ return await awaitAll({
id: folder.id, id: folder.id,
@ -25,10 +24,10 @@ export class DriveFolderRepository extends Repository<DriveFolder> {
parentId: folder.parentId, parentId: folder.parentId,
...(opts.detail ? { ...(opts.detail ? {
foldersCount: DriveFolders.count({ foldersCount: DriveFolders.countBy({
parentId: folder.id, parentId: folder.id,
}), }),
filesCount: DriveFiles.count({ filesCount: DriveFiles.countBy({
folderId: folder.id, folderId: folder.id,
}), }),
@ -39,5 +38,5 @@ export class DriveFolderRepository extends Repository<DriveFolder> {
} : {}), } : {}),
} : {}), } : {}),
}); });
} },
} });

View File

@ -1,13 +1,12 @@
import { EntityRepository, Repository } from 'typeorm'; import { db } from '@/db/postgre.js';
import { Emoji } from '@/models/entities/emoji.js'; import { Emoji } from '@/models/entities/emoji.js';
import { Packed } from '@/misc/schema.js'; import { Packed } from '@/misc/schema.js';
@EntityRepository(Emoji) export const EmojiRepository = db.getRepository(Emoji).extend({
export class EmojiRepository extends Repository<Emoji> { async pack(
public async pack(
src: Emoji['id'] | Emoji, src: Emoji['id'] | Emoji,
): Promise<Packed<'Emoji'>> { ): Promise<Packed<'Emoji'>> {
const emoji = typeof src === 'object' ? src : await this.findOneOrFail(src); const emoji = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src });
return { return {
id: emoji.id, id: emoji.id,
@ -18,11 +17,11 @@ export class EmojiRepository extends Repository<Emoji> {
// || emoji.originalUrl してるのは後方互換性のため // || emoji.originalUrl してるのは後方互換性のため
url: emoji.publicUrl || emoji.originalUrl, url: emoji.publicUrl || emoji.originalUrl,
}; };
} },
public packMany( packMany(
emojis: any[], emojis: any[],
) { ) {
return Promise.all(emojis.map(x => this.pack(x))); return Promise.all(emojis.map(x => this.pack(x)));
} },
} });

View File

@ -1,20 +1,19 @@
import { EntityRepository, Repository } from 'typeorm'; import { db } from '@/db/postgre.js';
import { FollowRequest } from '@/models/entities/follow-request.js'; import { FollowRequest } from '@/models/entities/follow-request.js';
import { Users } from '../index.js'; import { Users } from '../index.js';
import { User } from '@/models/entities/user.js'; import { User } from '@/models/entities/user.js';
@EntityRepository(FollowRequest) export const FollowRequestRepository = db.getRepository(FollowRequest).extend({
export class FollowRequestRepository extends Repository<FollowRequest> { async pack(
public async pack(
src: FollowRequest['id'] | FollowRequest, src: FollowRequest['id'] | FollowRequest,
me?: { id: User['id'] } | null | undefined me?: { id: User['id'] } | null | undefined
) { ) {
const request = typeof src === 'object' ? src : await this.findOneOrFail(src); const request = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src });
return { return {
id: request.id, id: request.id,
follower: await Users.pack(request.followerId, me), follower: await Users.pack(request.followerId, me),
followee: await Users.pack(request.followeeId, me), followee: await Users.pack(request.followeeId, me),
}; };
} },
} });

View File

@ -1,4 +1,4 @@
import { EntityRepository, Repository } from 'typeorm'; import { db } from '@/db/postgre.js';
import { Users } from '../index.js'; import { Users } from '../index.js';
import { Following } from '@/models/entities/following.js'; import { Following } from '@/models/entities/following.js';
import { awaitAll } from '@/prelude/await-all.js'; import { awaitAll } from '@/prelude/await-all.js';
@ -29,25 +29,24 @@ type RemoteFolloweeFollowing = Following & {
followeeSharedInbox: string; followeeSharedInbox: string;
}; };
@EntityRepository(Following) export const FollowingRepository = db.getRepository(Following).extend({
export class FollowingRepository extends Repository<Following> { isLocalFollower(following: Following): following is LocalFollowerFollowing {
public isLocalFollower(following: Following): following is LocalFollowerFollowing {
return following.followerHost == null; return following.followerHost == null;
} },
public isRemoteFollower(following: Following): following is RemoteFollowerFollowing { isRemoteFollower(following: Following): following is RemoteFollowerFollowing {
return following.followerHost != null; return following.followerHost != null;
} },
public isLocalFollowee(following: Following): following is LocalFolloweeFollowing { isLocalFollowee(following: Following): following is LocalFolloweeFollowing {
return following.followeeHost == null; return following.followeeHost == null;
} },
public isRemoteFollowee(following: Following): following is RemoteFolloweeFollowing { isRemoteFollowee(following: Following): following is RemoteFolloweeFollowing {
return following.followeeHost != null; return following.followeeHost != null;
} },
public async pack( async pack(
src: Following['id'] | Following, src: Following['id'] | Following,
me?: { id: User['id'] } | null | undefined, me?: { id: User['id'] } | null | undefined,
opts?: { opts?: {
@ -55,7 +54,7 @@ export class FollowingRepository extends Repository<Following> {
populateFollower?: boolean; populateFollower?: boolean;
} }
): Promise<Packed<'Following'>> { ): Promise<Packed<'Following'>> {
const following = typeof src === 'object' ? src : await this.findOneOrFail(src); const following = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src });
if (opts == null) opts = {}; if (opts == null) opts = {};
@ -71,9 +70,9 @@ export class FollowingRepository extends Repository<Following> {
detail: true, detail: true,
}) : undefined, }) : undefined,
}); });
} },
public packMany( packMany(
followings: any[], followings: any[],
me?: { id: User['id'] } | null | undefined, me?: { id: User['id'] } | null | undefined,
opts?: { opts?: {
@ -82,5 +81,5 @@ export class FollowingRepository extends Repository<Following> {
} }
) { ) {
return Promise.all(followings.map(x => this.pack(x, me, opts))); return Promise.all(followings.map(x => this.pack(x, me, opts)));
} },
} });

View File

@ -1,25 +1,24 @@
import { EntityRepository, Repository } from 'typeorm'; import { db } from '@/db/postgre.js';
import { GalleryLike } from '@/models/entities/gallery-like.js'; import { GalleryLike } from '@/models/entities/gallery-like.js';
import { GalleryPosts } from '../index.js'; import { GalleryPosts } from '../index.js';
@EntityRepository(GalleryLike) export const GalleryLikeRepository = db.getRepository(GalleryLike).extend({
export class GalleryLikeRepository extends Repository<GalleryLike> { async pack(
public async pack(
src: GalleryLike['id'] | GalleryLike, src: GalleryLike['id'] | GalleryLike,
me?: any me?: any
) { ) {
const like = typeof src === 'object' ? src : await this.findOneOrFail(src); const like = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src });
return { return {
id: like.id, id: like.id,
post: await GalleryPosts.pack(like.post || like.postId, me), post: await GalleryPosts.pack(like.post || like.postId, me),
}; };
} },
public packMany( packMany(
likes: any[], likes: any[],
me: any me: any
) { ) {
return Promise.all(likes.map(x => this.pack(x, me))); return Promise.all(likes.map(x => this.pack(x, me)));
} },
} });

View File

@ -1,18 +1,17 @@
import { EntityRepository, Repository } from 'typeorm'; import { db } from '@/db/postgre.js';
import { GalleryPost } from '@/models/entities/gallery-post.js'; import { GalleryPost } from '@/models/entities/gallery-post.js';
import { Packed } from '@/misc/schema.js'; import { Packed } from '@/misc/schema.js';
import { Users, DriveFiles, GalleryLikes } from '../index.js'; import { Users, DriveFiles, GalleryLikes } from '../index.js';
import { awaitAll } from '@/prelude/await-all.js'; import { awaitAll } from '@/prelude/await-all.js';
import { User } from '@/models/entities/user.js'; import { User } from '@/models/entities/user.js';
@EntityRepository(GalleryPost) export const GalleryPostRepository = db.getRepository(GalleryPost).extend({
export class GalleryPostRepository extends Repository<GalleryPost> { async pack(
public async pack(
src: GalleryPost['id'] | GalleryPost, src: GalleryPost['id'] | GalleryPost,
me?: { id: User['id'] } | null | undefined, me?: { id: User['id'] } | null | undefined,
): Promise<Packed<'GalleryPost'>> { ): Promise<Packed<'GalleryPost'>> {
const meId = me ? me.id : null; const meId = me ? me.id : null;
const post = typeof src === 'object' ? src : await this.findOneOrFail(src); const post = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src });
return await awaitAll({ return await awaitAll({
id: post.id, id: post.id,
@ -27,14 +26,14 @@ export class GalleryPostRepository extends Repository<GalleryPost> {
tags: post.tags.length > 0 ? post.tags : undefined, tags: post.tags.length > 0 ? post.tags : undefined,
isSensitive: post.isSensitive, isSensitive: post.isSensitive,
likedCount: post.likedCount, likedCount: post.likedCount,
isLiked: meId ? await GalleryLikes.findOne({ postId: post.id, userId: meId }).then(x => x != null) : undefined, isLiked: meId ? await GalleryLikes.findOneBy({ postId: post.id, userId: meId }).then(x => x != null) : undefined,
}); });
} },
public packMany( packMany(
posts: GalleryPost[], posts: GalleryPost[],
me?: { id: User['id'] } | null | undefined, me?: { id: User['id'] } | null | undefined,
) { ) {
return Promise.all(posts.map(x => this.pack(x, me))); return Promise.all(posts.map(x => this.pack(x, me)));
} },
} });

View File

@ -1,10 +1,9 @@
import { EntityRepository, Repository } from 'typeorm'; import { db } from '@/db/postgre.js';
import { Hashtag } from '@/models/entities/hashtag.js'; import { Hashtag } from '@/models/entities/hashtag.js';
import { Packed } from '@/misc/schema.js'; import { Packed } from '@/misc/schema.js';
@EntityRepository(Hashtag) export const HashtagRepository = db.getRepository(Hashtag).extend({
export class HashtagRepository extends Repository<Hashtag> { async pack(
public async pack(
src: Hashtag, src: Hashtag,
): Promise<Packed<'Hashtag'>> { ): Promise<Packed<'Hashtag'>> {
return { return {
@ -16,11 +15,11 @@ export class HashtagRepository extends Repository<Hashtag> {
attachedLocalUsersCount: src.attachedLocalUsersCount, attachedLocalUsersCount: src.attachedLocalUsersCount,
attachedRemoteUsersCount: src.attachedRemoteUsersCount, attachedRemoteUsersCount: src.attachedRemoteUsersCount,
}; };
} },
public packMany( packMany(
hashtags: Hashtag[], hashtags: Hashtag[],
) { ) {
return Promise.all(hashtags.map(x => this.pack(x))); return Promise.all(hashtags.map(x => this.pack(x)));
} },
} });

View File

@ -1,10 +1,9 @@
import { EntityRepository, Repository } from 'typeorm'; import { db } from '@/db/postgre.js';
import { Instance } from '@/models/entities/instance.js'; import { Instance } from '@/models/entities/instance.js';
import { Packed } from '@/misc/schema.js'; import { Packed } from '@/misc/schema.js';
@EntityRepository(Instance) export const InstanceRepository = db.getRepository(Instance).extend({
export class InstanceRepository extends Repository<Instance> { async pack(
public async pack(
instance: Instance, instance: Instance,
): Promise<Packed<'FederationInstance'>> { ): Promise<Packed<'FederationInstance'>> {
return { return {
@ -29,11 +28,11 @@ export class InstanceRepository extends Repository<Instance> {
iconUrl: instance.iconUrl, iconUrl: instance.iconUrl,
infoUpdatedAt: instance.infoUpdatedAt ? instance.infoUpdatedAt.toISOString() : null, infoUpdatedAt: instance.infoUpdatedAt ? instance.infoUpdatedAt.toISOString() : null,
}; };
} },
public packMany( packMany(
instances: Instance[], instances: Instance[],
) { ) {
return Promise.all(instances.map(x => this.pack(x))); return Promise.all(instances.map(x => this.pack(x)));
} },
} });

View File

@ -1,12 +1,11 @@
import { EntityRepository, Repository } from 'typeorm'; import { db } from '@/db/postgre.js';
import { MessagingMessage } from '@/models/entities/messaging-message.js'; import { MessagingMessage } from '@/models/entities/messaging-message.js';
import { Users, DriveFiles, UserGroups } from '../index.js'; import { Users, DriveFiles, UserGroups } from '../index.js';
import { Packed } from '@/misc/schema.js'; import { Packed } from '@/misc/schema.js';
import { User } from '@/models/entities/user.js'; import { User } from '@/models/entities/user.js';
@EntityRepository(MessagingMessage) export const MessagingMessageRepository = db.getRepository(MessagingMessage).extend({
export class MessagingMessageRepository extends Repository<MessagingMessage> { async pack(
public async pack(
src: MessagingMessage['id'] | MessagingMessage, src: MessagingMessage['id'] | MessagingMessage,
me?: { id: User['id'] } | null | undefined, me?: { id: User['id'] } | null | undefined,
options?: { options?: {
@ -19,7 +18,7 @@ export class MessagingMessageRepository extends Repository<MessagingMessage> {
populateGroup: true, populateGroup: true,
}; };
const message = typeof src === 'object' ? src : await this.findOneOrFail(src); const message = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src });
return { return {
id: message.id, id: message.id,
@ -36,5 +35,5 @@ export class MessagingMessageRepository extends Repository<MessagingMessage> {
isRead: message.isRead, isRead: message.isRead,
reads: message.reads, reads: message.reads,
}; };
} },
} });

View File

@ -1,14 +1,13 @@
import { EntityRepository, Repository } from 'typeorm'; import { db } from '@/db/postgre.js';
import { Users } from '../index.js'; import { Users } from '../index.js';
import { ModerationLog } from '@/models/entities/moderation-log.js'; import { ModerationLog } from '@/models/entities/moderation-log.js';
import { awaitAll } from '@/prelude/await-all.js'; import { awaitAll } from '@/prelude/await-all.js';
@EntityRepository(ModerationLog) export const ModerationLogRepository = db.getRepository(ModerationLog).extend({
export class ModerationLogRepository extends Repository<ModerationLog> { async pack(
public async pack(
src: ModerationLog['id'] | ModerationLog, src: ModerationLog['id'] | ModerationLog,
) { ) {
const log = typeof src === 'object' ? src : await this.findOneOrFail(src); const log = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src });
return await awaitAll({ return await awaitAll({
id: log.id, id: log.id,
@ -20,11 +19,11 @@ export class ModerationLogRepository extends Repository<ModerationLog> {
detail: true, detail: true,
}), }),
}); });
} },
public packMany( packMany(
reports: any[], reports: any[],
) { ) {
return Promise.all(reports.map(x => this.pack(x))); return Promise.all(reports.map(x => this.pack(x)));
} },
} });

View File

@ -1,17 +1,16 @@
import { EntityRepository, Repository } from 'typeorm'; import { db } from '@/db/postgre.js';
import { Users } from '../index.js'; import { Users } from '../index.js';
import { Muting } from '@/models/entities/muting.js'; import { Muting } from '@/models/entities/muting.js';
import { awaitAll } from '@/prelude/await-all.js'; import { awaitAll } from '@/prelude/await-all.js';
import { Packed } from '@/misc/schema.js'; import { Packed } from '@/misc/schema.js';
import { User } from '@/models/entities/user.js'; import { User } from '@/models/entities/user.js';
@EntityRepository(Muting) export const MutingRepository = db.getRepository(Muting).extend({
export class MutingRepository extends Repository<Muting> { async pack(
public async pack(
src: Muting['id'] | Muting, src: Muting['id'] | Muting,
me?: { id: User['id'] } | null | undefined me?: { id: User['id'] } | null | undefined
): Promise<Packed<'Muting'>> { ): Promise<Packed<'Muting'>> {
const muting = typeof src === 'object' ? src : await this.findOneOrFail(src); const muting = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src });
return await awaitAll({ return await awaitAll({
id: muting.id, id: muting.id,
@ -22,12 +21,12 @@ export class MutingRepository extends Repository<Muting> {
detail: true, detail: true,
}), }),
}); });
} },
public packMany( packMany(
mutings: any[], mutings: any[],
me: { id: User['id'] } me: { id: User['id'] }
) { ) {
return Promise.all(mutings.map(x => this.pack(x, me))); return Promise.all(mutings.map(x => this.pack(x, me)));
} },
} });

View File

@ -1,15 +1,14 @@
import { EntityRepository, Repository } from 'typeorm'; import { db } from '@/db/postgre.js';
import { NoteFavorite } from '@/models/entities/note-favorite.js'; import { NoteFavorite } from '@/models/entities/note-favorite.js';
import { Notes } from '../index.js'; import { Notes } from '../index.js';
import { User } from '@/models/entities/user.js'; import { User } from '@/models/entities/user.js';
@EntityRepository(NoteFavorite) export const NoteFavoriteRepository = db.getRepository(NoteFavorite).extend({
export class NoteFavoriteRepository extends Repository<NoteFavorite> { async pack(
public async pack(
src: NoteFavorite['id'] | NoteFavorite, src: NoteFavorite['id'] | NoteFavorite,
me?: { id: User['id'] } | null | undefined me?: { id: User['id'] } | null | undefined
) { ) {
const favorite = typeof src === 'object' ? src : await this.findOneOrFail(src); const favorite = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src });
return { return {
id: favorite.id, id: favorite.id,
@ -17,12 +16,12 @@ export class NoteFavoriteRepository extends Repository<NoteFavorite> {
noteId: favorite.noteId, noteId: favorite.noteId,
note: await Notes.pack(favorite.note || favorite.noteId, me), note: await Notes.pack(favorite.note || favorite.noteId, me),
}; };
} },
public packMany( packMany(
favorites: any[], favorites: any[],
me: { id: User['id'] } me: { id: User['id'] }
) { ) {
return Promise.all(favorites.map(x => this.pack(x, me))); return Promise.all(favorites.map(x => this.pack(x, me)));
} },
} });

View File

@ -1,13 +1,12 @@
import { EntityRepository, Repository } from 'typeorm'; import { db } from '@/db/postgre.js';
import { NoteReaction } from '@/models/entities/note-reaction.js'; import { NoteReaction } from '@/models/entities/note-reaction.js';
import { Notes, Users } from '../index.js'; import { Notes, Users } from '../index.js';
import { Packed } from '@/misc/schema.js'; import { Packed } from '@/misc/schema.js';
import { convertLegacyReaction } from '@/misc/reaction-lib.js'; import { convertLegacyReaction } from '@/misc/reaction-lib.js';
import { User } from '@/models/entities/user.js'; import { User } from '@/models/entities/user.js';
@EntityRepository(NoteReaction) export const NoteReactionRepository = db.getRepository(NoteReaction).extend({
export class NoteReactionRepository extends Repository<NoteReaction> { async pack(
public async pack(
src: NoteReaction['id'] | NoteReaction, src: NoteReaction['id'] | NoteReaction,
me?: { id: User['id'] } | null | undefined, me?: { id: User['id'] } | null | undefined,
options?: { options?: {
@ -18,7 +17,7 @@ export class NoteReactionRepository extends Repository<NoteReaction> {
withNote: false, withNote: false,
}, options); }, options);
const reaction = typeof src === 'object' ? src : await this.findOneOrFail(src); const reaction = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src });
return { return {
id: reaction.id, id: reaction.id,
@ -29,5 +28,5 @@ export class NoteReactionRepository extends Repository<NoteReaction> {
note: await Notes.pack(reaction.note ?? reaction.noteId, me), note: await Notes.pack(reaction.note ?? reaction.noteId, me),
} : {}), } : {}),
}; };
} },
} });

View File

@ -1,4 +1,4 @@
import { EntityRepository, Repository, In } from 'typeorm'; import { In } from 'typeorm';
import * as mfm from 'mfm-js'; import * as mfm from 'mfm-js';
import { Note } from '@/models/entities/note.js'; import { Note } from '@/models/entities/note.js';
import { User } from '@/models/entities/user.js'; import { User } from '@/models/entities/user.js';
@ -9,59 +9,9 @@ import { awaitAll } from '@/prelude/await-all.js';
import { convertLegacyReaction, convertLegacyReactions, decodeReaction } from '@/misc/reaction-lib.js'; import { convertLegacyReaction, convertLegacyReactions, decodeReaction } from '@/misc/reaction-lib.js';
import { NoteReaction } from '@/models/entities/note-reaction.js'; import { NoteReaction } from '@/models/entities/note-reaction.js';
import { aggregateNoteEmojis, populateEmojis, prefetchEmojis } from '@/misc/populate-emojis.js'; import { aggregateNoteEmojis, populateEmojis, prefetchEmojis } from '@/misc/populate-emojis.js';
import { db } from '@/db/postgre.js';
@EntityRepository(Note) async function hideNote(packedNote: Packed<'Note'>, meId: User['id'] | null) {
export class NoteRepository extends Repository<Note> {
public async isVisibleForMe(note: Note, meId: User['id'] | null): Promise<boolean> {
// visibility が specified かつ自分が指定されていなかったら非表示
if (note.visibility === 'specified') {
if (meId == null) {
return false;
} else if (meId === note.userId) {
return true;
} else {
// 指定されているかどうか
const specified = note.visibleUserIds.some((id: any) => meId === id);
if (specified) {
return true;
} else {
return false;
}
}
}
// visibility が followers かつ自分が投稿者のフォロワーでなかったら非表示
if (note.visibility === 'followers') {
if (meId == null) {
return false;
} else if (meId === note.userId) {
return true;
} else if (note.reply && (meId === note.reply.userId)) {
// 自分の投稿に対するリプライ
return true;
} else if (note.mentions && note.mentions.some(id => meId === id)) {
// 自分へのメンション
return true;
} else {
// フォロワーかどうか
const following = await Followings.findOne({
followeeId: note.userId,
followerId: meId,
});
if (following == null) {
return false;
} else {
return true;
}
}
}
return true;
}
private async hideNote(packedNote: Packed<'Note'>, meId: User['id'] | null) {
// TODO: isVisibleForMe を使うようにしても良さそう(型違うけど) // TODO: isVisibleForMe を使うようにしても良さそう(型違うけど)
let hide = false; let hide = false;
@ -97,7 +47,7 @@ export class NoteRepository extends Repository<Note> {
hide = false; hide = false;
} else { } else {
// フォロワーかどうか // フォロワーかどうか
const following = await Followings.findOne({ const following = await Followings.findOneBy({
followeeId: packedNote.userId, followeeId: packedNote.userId,
followerId: meId, followerId: meId,
}); });
@ -119,9 +69,59 @@ export class NoteRepository extends Repository<Note> {
packedNote.cw = null; packedNote.cw = null;
packedNote.isHidden = true; packedNote.isHidden = true;
} }
}
export const NoteRepository = db.getRepository(Note).extend({
async isVisibleForMe(note: Note, meId: User['id'] | null): Promise<boolean> {
// visibility が specified かつ自分が指定されていなかったら非表示
if (note.visibility === 'specified') {
if (meId == null) {
return false;
} else if (meId === note.userId) {
return true;
} else {
// 指定されているかどうか
const specified = note.visibleUserIds.some((id: any) => meId === id);
if (specified) {
return true;
} else {
return false;
}
}
} }
public async pack( // visibility が followers かつ自分が投稿者のフォロワーでなかったら非表示
if (note.visibility === 'followers') {
if (meId == null) {
return false;
} else if (meId === note.userId) {
return true;
} else if (note.reply && (meId === note.reply.userId)) {
// 自分の投稿に対するリプライ
return true;
} else if (note.mentions && note.mentions.some(id => meId === id)) {
// 自分へのメンション
return true;
} else {
// フォロワーかどうか
const following = await Followings.findOneBy({
followeeId: note.userId,
followerId: meId,
});
if (following == null) {
return false;
} else {
return true;
}
}
}
return true;
},
async pack(
src: Note['id'] | Note, src: Note['id'] | Note,
me?: { id: User['id'] } | null | undefined, me?: { id: User['id'] } | null | undefined,
options?: { options?: {
@ -138,11 +138,11 @@ export class NoteRepository extends Repository<Note> {
}, options); }, options);
const meId = me ? me.id : null; const meId = me ? me.id : null;
const note = typeof src === 'object' ? src : await this.findOneOrFail(src); const note = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src });
const host = note.userHost; const host = note.userHost;
async function populatePoll() { async function populatePoll() {
const poll = await Polls.findOneOrFail(note.id); const poll = await Polls.findOneByOrFail({ noteId: note.id });
const choices = poll.choices.map(c => ({ const choices = poll.choices.map(c => ({
text: c, text: c,
votes: poll.votes[poll.choices.indexOf(c)], votes: poll.votes[poll.choices.indexOf(c)],
@ -150,7 +150,7 @@ export class NoteRepository extends Repository<Note> {
})); }));
if (poll.multiple) { if (poll.multiple) {
const votes = await PollVotes.find({ const votes = await PollVotes.findBy({
userId: meId!, userId: meId!,
noteId: note.id, noteId: note.id,
}); });
@ -160,7 +160,7 @@ export class NoteRepository extends Repository<Note> {
choices[myChoice].isVoted = true; choices[myChoice].isVoted = true;
} }
} else { } else {
const vote = await PollVotes.findOne({ const vote = await PollVotes.findOneBy({
userId: meId!, userId: meId!,
noteId: note.id, noteId: note.id,
}); });
@ -188,7 +188,7 @@ export class NoteRepository extends Repository<Note> {
// 実装上抜けがあるだけかもしれないので、「ヒントに含まれてなかったら(=undefinedなら)return」のようにはしない // 実装上抜けがあるだけかもしれないので、「ヒントに含まれてなかったら(=undefinedなら)return」のようにはしない
} }
const reaction = await NoteReactions.findOne({ const reaction = await NoteReactions.findOneBy({
userId: meId!, userId: meId!,
noteId: note.id, noteId: note.id,
}); });
@ -209,7 +209,7 @@ export class NoteRepository extends Repository<Note> {
const channel = note.channelId const channel = note.channelId
? note.channel ? note.channel
? note.channel ? note.channel
: await Channels.findOne(note.channelId) : await Channels.findOneBy({ id: note.channelId })
: null; : null;
const reactionEmojiNames = Object.keys(note.reactions).filter(x => x?.startsWith(':')).map(x => decodeReaction(x).reaction).map(x => x.replace(/:/g, '')); const reactionEmojiNames = Object.keys(note.reactions).filter(x => x?.startsWith(':')).map(x => decodeReaction(x).reaction).map(x => x.replace(/:/g, ''));
@ -275,13 +275,13 @@ export class NoteRepository extends Repository<Note> {
} }
if (!opts.skipHide) { if (!opts.skipHide) {
await this.hideNote(packed, meId); await hideNote(packed, meId);
} }
return packed; return packed;
} },
public async packMany( async packMany(
notes: Note[], notes: Note[],
me?: { id: User['id'] } | null | undefined, me?: { id: User['id'] } | null | undefined,
options?: { options?: {
@ -296,7 +296,7 @@ export class NoteRepository extends Repository<Note> {
if (meId) { if (meId) {
const renoteIds = notes.filter(n => n.renoteId != null).map(n => n.renoteId!); const renoteIds = notes.filter(n => n.renoteId != null).map(n => n.renoteId!);
const targets = [...notes.map(n => n.id), ...renoteIds]; const targets = [...notes.map(n => n.id), ...renoteIds];
const myReactions = await NoteReactions.find({ const myReactions = await NoteReactions.findBy({
userId: meId, userId: meId,
noteId: In(targets), noteId: In(targets),
}); });
@ -314,5 +314,5 @@ export class NoteRepository extends Repository<Note> {
myReactions: myReactionsMap, myReactions: myReactionsMap,
}, },
}))); })));
} },
} });

View File

@ -1,4 +1,4 @@
import { EntityRepository, In, Repository } from 'typeorm'; import { In, Repository } from 'typeorm';
import { Users, Notes, UserGroupInvitations, AccessTokens, NoteReactions } from '../index.js'; import { Users, Notes, UserGroupInvitations, AccessTokens, NoteReactions } from '../index.js';
import { Notification } from '@/models/entities/notification.js'; import { Notification } from '@/models/entities/notification.js';
import { awaitAll } from '@/prelude/await-all.js'; import { awaitAll } from '@/prelude/await-all.js';
@ -8,10 +8,10 @@ import { NoteReaction } from '@/models/entities/note-reaction.js';
import { User } from '@/models/entities/user.js'; import { User } from '@/models/entities/user.js';
import { aggregateNoteEmojis, prefetchEmojis } from '@/misc/populate-emojis.js'; import { aggregateNoteEmojis, prefetchEmojis } from '@/misc/populate-emojis.js';
import { notificationTypes } from '@/types.js'; import { notificationTypes } from '@/types.js';
import { db } from '@/db/postgre.js';
@EntityRepository(Notification) export const NotificationRepository = db.getRepository(Notification).extend({
export class NotificationRepository extends Repository<Notification> { async pack(
public async pack(
src: Notification['id'] | Notification, src: Notification['id'] | Notification,
options: { options: {
_hintForEachNotes_?: { _hintForEachNotes_?: {
@ -19,8 +19,8 @@ export class NotificationRepository extends Repository<Notification> {
}; };
} }
): Promise<Packed<'Notification'>> { ): Promise<Packed<'Notification'>> {
const notification = typeof src === 'object' ? src : await this.findOneOrFail(src); const notification = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src });
const token = notification.appAccessTokenId ? await AccessTokens.findOneOrFail(notification.appAccessTokenId) : null; const token = notification.appAccessTokenId ? await AccessTokens.findOneByOrFail({ id: notification.appAccessTokenId }) : null;
return await awaitAll({ return await awaitAll({
id: notification.id, id: notification.id,
@ -82,9 +82,9 @@ export class NotificationRepository extends Repository<Notification> {
icon: notification.customIcon || token?.iconUrl, icon: notification.customIcon || token?.iconUrl,
} : {}), } : {}),
}); });
} },
public async packMany( async packMany(
notifications: Notification[], notifications: Notification[],
meId: User['id'] meId: User['id']
) { ) {
@ -95,7 +95,7 @@ export class NotificationRepository extends Repository<Notification> {
const myReactionsMap = new Map<Note['id'], NoteReaction | null>(); const myReactionsMap = new Map<Note['id'], NoteReaction | null>();
const renoteIds = notes.filter(n => n.renoteId != null).map(n => n.renoteId!); const renoteIds = notes.filter(n => n.renoteId != null).map(n => n.renoteId!);
const targets = [...noteIds, ...renoteIds]; const targets = [...noteIds, ...renoteIds];
const myReactions = await NoteReactions.find({ const myReactions = await NoteReactions.findBy({
userId: meId, userId: meId,
noteId: In(targets), noteId: In(targets),
}); });
@ -111,5 +111,5 @@ export class NotificationRepository extends Repository<Notification> {
myReactions: myReactionsMap, myReactions: myReactionsMap,
}, },
}))); })));
} },
} });

View File

@ -1,26 +1,25 @@
import { EntityRepository, Repository } from 'typeorm'; import { db } from '@/db/postgre.js';
import { PageLike } from '@/models/entities/page-like.js'; import { PageLike } from '@/models/entities/page-like.js';
import { Pages } from '../index.js'; import { Pages } from '../index.js';
import { User } from '@/models/entities/user.js'; import { User } from '@/models/entities/user.js';
@EntityRepository(PageLike) export const PageLikeRepository = db.getRepository(PageLike).extend({
export class PageLikeRepository extends Repository<PageLike> { async pack(
public async pack(
src: PageLike['id'] | PageLike, src: PageLike['id'] | PageLike,
me?: { id: User['id'] } | null | undefined me?: { id: User['id'] } | null | undefined
) { ) {
const like = typeof src === 'object' ? src : await this.findOneOrFail(src); const like = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src });
return { return {
id: like.id, id: like.id,
page: await Pages.pack(like.page || like.pageId, me), page: await Pages.pack(like.page || like.pageId, me),
}; };
} },
public packMany( packMany(
likes: any[], likes: any[],
me: { id: User['id'] } me: { id: User['id'] }
) { ) {
return Promise.all(likes.map(x => this.pack(x, me))); return Promise.all(likes.map(x => this.pack(x, me)));
} },
} });

View File

@ -1,4 +1,4 @@
import { EntityRepository, Repository } from 'typeorm'; import { db } from '@/db/postgre.js';
import { Page } from '@/models/entities/page.js'; import { Page } from '@/models/entities/page.js';
import { Packed } from '@/misc/schema.js'; import { Packed } from '@/misc/schema.js';
import { Users, DriveFiles, PageLikes } from '../index.js'; import { Users, DriveFiles, PageLikes } from '../index.js';
@ -6,20 +6,19 @@ import { awaitAll } from '@/prelude/await-all.js';
import { DriveFile } from '@/models/entities/drive-file.js'; import { DriveFile } from '@/models/entities/drive-file.js';
import { User } from '@/models/entities/user.js'; import { User } from '@/models/entities/user.js';
@EntityRepository(Page) export const PageRepository = db.getRepository(Page).extend({
export class PageRepository extends Repository<Page> { async pack(
public async pack(
src: Page['id'] | Page, src: Page['id'] | Page,
me?: { id: User['id'] } | null | undefined, me?: { id: User['id'] } | null | undefined,
): Promise<Packed<'Page'>> { ): Promise<Packed<'Page'>> {
const meId = me ? me.id : null; const meId = me ? me.id : null;
const page = typeof src === 'object' ? src : await this.findOneOrFail(src); const page = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src });
const attachedFiles: Promise<DriveFile | undefined>[] = []; const attachedFiles: Promise<DriveFile | undefined>[] = [];
const collectFile = (xs: any[]) => { const collectFile = (xs: any[]) => {
for (const x of xs) { for (const x of xs) {
if (x.type === 'image') { if (x.type === 'image') {
attachedFiles.push(DriveFiles.findOne({ attachedFiles.push(DriveFiles.findOneBy({
id: x.fileId, id: x.fileId,
userId: page.userId, userId: page.userId,
})); }));
@ -76,14 +75,14 @@ export class PageRepository extends Repository<Page> {
eyeCatchingImage: page.eyeCatchingImageId ? await DriveFiles.pack(page.eyeCatchingImageId) : null, eyeCatchingImage: page.eyeCatchingImageId ? await DriveFiles.pack(page.eyeCatchingImageId) : null,
attachedFiles: DriveFiles.packMany(await Promise.all(attachedFiles)), attachedFiles: DriveFiles.packMany(await Promise.all(attachedFiles)),
likedCount: page.likedCount, likedCount: page.likedCount,
isLiked: meId ? await PageLikes.findOne({ pageId: page.id, userId: meId }).then(x => x != null) : undefined, isLiked: meId ? await PageLikes.findOneBy({ pageId: page.id, userId: meId }).then(x => x != null) : undefined,
}); });
} },
public packMany( packMany(
pages: Page[], pages: Page[],
me?: { id: User['id'] } | null | undefined, me?: { id: User['id'] } | null | undefined,
) { ) {
return Promise.all(pages.map(x => this.pack(x, me))); return Promise.all(pages.map(x => this.pack(x, me)));
} },
} });

View File

@ -1,6 +1,5 @@
import { EntityRepository, Repository } from 'typeorm'; import { db } from '@/db/postgre.js';
import { Relay } from '@/models/entities/relay.js'; import { Relay } from '@/models/entities/relay.js';
@EntityRepository(Relay) export const RelayRepository = db.getRepository(Relay).extend({
export class RelayRepository extends Repository<Relay> { });
}

View File

@ -1,11 +1,10 @@
import { EntityRepository, Repository } from 'typeorm'; import { db } from '@/db/postgre.js';
import { Signin } from '@/models/entities/signin.js'; import { Signin } from '@/models/entities/signin.js';
@EntityRepository(Signin) export const SigninRepository = db.getRepository(Signin).extend({
export class SigninRepository extends Repository<Signin> { async pack(
public async pack(
src: Signin, src: Signin,
) { ) {
return src; return src;
} },
} });

View File

@ -1,23 +1,22 @@
import { EntityRepository, Repository } from 'typeorm'; import { db } from '@/db/postgre.js';
import { UserGroupInvitation } from '@/models/entities/user-group-invitation.js'; import { UserGroupInvitation } from '@/models/entities/user-group-invitation.js';
import { UserGroups } from '../index.js'; import { UserGroups } from '../index.js';
@EntityRepository(UserGroupInvitation) export const UserGroupInvitationRepository = db.getRepository(UserGroupInvitation).extend({
export class UserGroupInvitationRepository extends Repository<UserGroupInvitation> { async pack(
public async pack(
src: UserGroupInvitation['id'] | UserGroupInvitation, src: UserGroupInvitation['id'] | UserGroupInvitation,
) { ) {
const invitation = typeof src === 'object' ? src : await this.findOneOrFail(src); const invitation = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src });
return { return {
id: invitation.id, id: invitation.id,
group: await UserGroups.pack(invitation.userGroup || invitation.userGroupId), group: await UserGroups.pack(invitation.userGroup || invitation.userGroupId),
}; };
} },
public packMany( packMany(
invitations: any[], invitations: any[],
) { ) {
return Promise.all(invitations.map(x => this.pack(x))); return Promise.all(invitations.map(x => this.pack(x)));
} },
} });

View File

@ -1,16 +1,15 @@
import { EntityRepository, Repository } from 'typeorm'; import { db } from '@/db/postgre.js';
import { UserGroup } from '@/models/entities/user-group.js'; import { UserGroup } from '@/models/entities/user-group.js';
import { UserGroupJoinings } from '../index.js'; import { UserGroupJoinings } from '../index.js';
import { Packed } from '@/misc/schema.js'; import { Packed } from '@/misc/schema.js';
@EntityRepository(UserGroup) export const UserGroupRepository = db.getRepository(UserGroup).extend({
export class UserGroupRepository extends Repository<UserGroup> { async pack(
public async pack(
src: UserGroup['id'] | UserGroup, src: UserGroup['id'] | UserGroup,
): Promise<Packed<'UserGroup'>> { ): Promise<Packed<'UserGroup'>> {
const userGroup = typeof src === 'object' ? src : await this.findOneOrFail(src); const userGroup = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src });
const users = await UserGroupJoinings.find({ const users = await UserGroupJoinings.findBy({
userGroupId: userGroup.id, userGroupId: userGroup.id,
}); });
@ -21,5 +20,5 @@ export class UserGroupRepository extends Repository<UserGroup> {
ownerId: userGroup.userId, ownerId: userGroup.userId,
userIds: users.map(x => x.userId), userIds: users.map(x => x.userId),
}; };
} },
} });

View File

@ -1,16 +1,15 @@
import { EntityRepository, Repository } from 'typeorm'; import { db } from '@/db/postgre.js';
import { UserList } from '@/models/entities/user-list.js'; import { UserList } from '@/models/entities/user-list.js';
import { UserListJoinings } from '../index.js'; import { UserListJoinings } from '../index.js';
import { Packed } from '@/misc/schema.js'; import { Packed } from '@/misc/schema.js';
@EntityRepository(UserList) export const UserListRepository = db.getRepository(UserList).extend({
export class UserListRepository extends Repository<UserList> { async pack(
public async pack(
src: UserList['id'] | UserList, src: UserList['id'] | UserList,
): Promise<Packed<'UserList'>> { ): Promise<Packed<'UserList'>> {
const userList = typeof src === 'object' ? src : await this.findOneOrFail(src); const userList = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src });
const users = await UserListJoinings.find({ const users = await UserListJoinings.findBy({
userListId: userList.id, userListId: userList.id,
}); });
@ -20,5 +19,5 @@ export class UserListRepository extends Repository<UserList> {
name: userList.name, name: userList.name,
userIds: users.map(x => x.userId), userIds: users.map(x => x.userId),
}; };
} },
} });

View File

@ -10,6 +10,7 @@ import { getAntennas } from '@/misc/antenna-cache.js';
import { USER_ACTIVE_THRESHOLD, USER_ONLINE_THRESHOLD } from '@/const.js'; import { USER_ACTIVE_THRESHOLD, USER_ONLINE_THRESHOLD } from '@/const.js';
import { Cache } from '@/misc/cache.js'; import { Cache } from '@/misc/cache.js';
import { Instance } from '../entities/instance.js'; import { Instance } from '../entities/instance.js';
import { db } from '@/db/postgre.js';
const userInstanceCache = new Cache<Instance | null>(1000 * 60 * 60 * 3); const userInstanceCache = new Cache<Instance | null>(1000 * 60 * 60 * 3);
@ -23,51 +24,69 @@ type IsMeAndIsUserDetailed<ExpectsMe extends boolean | null, Detailed extends bo
const ajv = new Ajv(); const ajv = new Ajv();
@EntityRepository(User) const localUsernameSchema = { type: 'string', pattern: /^\w{1,20}$/.toString().slice(1, -1) } as const;
export class UserRepository extends Repository<User> { const passwordSchema = { type: 'string', minLength: 1 } as const;
public localUsernameSchema = { type: 'string', pattern: /^\w{1,20}$/.toString().slice(1, -1) } as const; const nameSchema = { type: 'string', minLength: 1, maxLength: 50 } as const;
public passwordSchema = { type: 'string', minLength: 1 } as const; const descriptionSchema = { type: 'string', minLength: 1, maxLength: 500 } as const;
public nameSchema = { type: 'string', minLength: 1, maxLength: 50 } as const; const locationSchema = { type: 'string', minLength: 1, maxLength: 50 } as const;
public descriptionSchema = { type: 'string', minLength: 1, maxLength: 500 } as const; const birthdaySchema = { type: 'string', pattern: /^([0-9]{4})-([0-9]{2})-([0-9]{2})$/.toString().slice(1, -1) } as const;
public locationSchema = { type: 'string', minLength: 1, maxLength: 50 } as const;
public birthdaySchema = { type: 'string', pattern: /^([0-9]{4})-([0-9]{2})-([0-9]{2})$/.toString().slice(1, -1) } as const; function isLocalUser(user: User): user is ILocalUser;
function isLocalUser<T extends { host: User['host'] }>(user: T): user is T & { host: null; };
function isLocalUser(user: User | { host: User['host'] }): boolean {
return user.host == null;
}
function isRemoteUser(user: User): user is IRemoteUser;
function isRemoteUser<T extends { host: User['host'] }>(user: T): user is T & { host: string; };
function isRemoteUser(user: User | { host: User['host'] }): boolean {
return !isLocalUser(user);
}
export const UserRepository = db.getRepository(User).extend({
localUsernameSchema,
passwordSchema,
nameSchema,
descriptionSchema,
locationSchema,
birthdaySchema,
//#region Validators //#region Validators
public validateLocalUsername = ajv.compile(this.localUsernameSchema); validateLocalUsername: ajv.compile(localUsernameSchema),
public validatePassword = ajv.compile(this.passwordSchema); validatePassword: ajv.compile(passwordSchema),
public validateName = ajv.compile(this.nameSchema); validateName: ajv.compile(nameSchema),
public validateDescription = ajv.compile(this.descriptionSchema); validateDescription: ajv.compile(descriptionSchema),
public validateLocation = ajv.compile(this.locationSchema); validateLocation: ajv.compile(locationSchema),
public validateBirthday = ajv.compile(this.birthdaySchema); validateBirthday: ajv.compile(birthdaySchema),
//#endregion //#endregion
public async getRelation(me: User['id'], target: User['id']) { async getRelation(me: User['id'], target: User['id']) {
const [following1, following2, followReq1, followReq2, toBlocking, fromBlocked, mute] = await Promise.all([ const [following1, following2, followReq1, followReq2, toBlocking, fromBlocked, mute] = await Promise.all([
Followings.findOne({ Followings.findOneBy({
followerId: me, followerId: me,
followeeId: target, followeeId: target,
}), }),
Followings.findOne({ Followings.findOneBy({
followerId: target, followerId: target,
followeeId: me, followeeId: me,
}), }),
FollowRequests.findOne({ FollowRequests.findOneBy({
followerId: me, followerId: me,
followeeId: target, followeeId: target,
}), }),
FollowRequests.findOne({ FollowRequests.findOneBy({
followerId: target, followerId: target,
followeeId: me, followeeId: me,
}), }),
Blockings.findOne({ Blockings.findOneBy({
blockerId: me, blockerId: me,
blockeeId: target, blockeeId: target,
}), }),
Blockings.findOne({ Blockings.findOneBy({
blockerId: target, blockerId: target,
blockeeId: me, blockeeId: me,
}), }),
Mutings.findOne({ Mutings.findOneBy({
muterId: me, muterId: me,
muteeId: target, muteeId: target,
}), }),
@ -83,14 +102,14 @@ export class UserRepository extends Repository<User> {
isBlocked: fromBlocked != null, isBlocked: fromBlocked != null,
isMuted: mute != null, isMuted: mute != null,
}; };
} },
public async getHasUnreadMessagingMessage(userId: User['id']): Promise<boolean> { async getHasUnreadMessagingMessage(userId: User['id']): Promise<boolean> {
const mute = await Mutings.find({ const mute = await Mutings.findBy({
muterId: userId, muterId: userId,
}); });
const joinings = await UserGroupJoinings.find({ userId: userId }); const joinings = await UserGroupJoinings.findBy({ userId: userId });
const groupQs = Promise.all(joinings.map(j => MessagingMessages.createQueryBuilder('message') const groupQs = Promise.all(joinings.map(j => MessagingMessages.createQueryBuilder('message')
.where(`message.groupId = :groupId`, { groupId: j.userGroupId }) .where(`message.groupId = :groupId`, { groupId: j.userGroupId })
@ -112,44 +131,44 @@ export class UserRepository extends Repository<User> {
]); ]);
return withUser || withGroups.some(x => x); return withUser || withGroups.some(x => x);
} },
public async getHasUnreadAnnouncement(userId: User['id']): Promise<boolean> { async getHasUnreadAnnouncement(userId: User['id']): Promise<boolean> {
const reads = await AnnouncementReads.find({ const reads = await AnnouncementReads.findBy({
userId: userId, userId: userId,
}); });
const count = await Announcements.count(reads.length > 0 ? { const count = await Announcements.countBy(reads.length > 0 ? {
id: Not(In(reads.map(read => read.announcementId))), id: Not(In(reads.map(read => read.announcementId))),
} : {}); } : {});
return count > 0; return count > 0;
} },
public async getHasUnreadAntenna(userId: User['id']): Promise<boolean> { async getHasUnreadAntenna(userId: User['id']): Promise<boolean> {
const myAntennas = (await getAntennas()).filter(a => a.userId === userId); const myAntennas = (await getAntennas()).filter(a => a.userId === userId);
const unread = myAntennas.length > 0 ? await AntennaNotes.findOne({ const unread = myAntennas.length > 0 ? await AntennaNotes.findOneBy({
antennaId: In(myAntennas.map(x => x.id)), antennaId: In(myAntennas.map(x => x.id)),
read: false, read: false,
}) : null; }) : null;
return unread != null; return unread != null;
} },
public async getHasUnreadChannel(userId: User['id']): Promise<boolean> { async getHasUnreadChannel(userId: User['id']): Promise<boolean> {
const channels = await ChannelFollowings.find({ followerId: userId }); const channels = await ChannelFollowings.findBy({ followerId: userId });
const unread = channels.length > 0 ? await NoteUnreads.findOne({ const unread = channels.length > 0 ? await NoteUnreads.findOneBy({
userId: userId, userId: userId,
noteChannelId: In(channels.map(x => x.followeeId)), noteChannelId: In(channels.map(x => x.followeeId)),
}) : null; }) : null;
return unread != null; return unread != null;
} },
public async getHasUnreadNotification(userId: User['id']): Promise<boolean> { async getHasUnreadNotification(userId: User['id']): Promise<boolean> {
const mute = await Mutings.find({ const mute = await Mutings.findBy({
muterId: userId, muterId: userId,
}); });
const mutedUserIds = mute.map(m => m.muteeId); const mutedUserIds = mute.map(m => m.muteeId);
@ -164,17 +183,17 @@ export class UserRepository extends Repository<User> {
}); });
return count > 0; return count > 0;
} },
public async getHasPendingReceivedFollowRequest(userId: User['id']): Promise<boolean> { async getHasPendingReceivedFollowRequest(userId: User['id']): Promise<boolean> {
const count = await FollowRequests.count({ const count = await FollowRequests.countBy({
followeeId: userId, followeeId: userId,
}); });
return count > 0; return count > 0;
} },
public getOnlineStatus(user: User): 'unknown' | 'online' | 'active' | 'offline' { getOnlineStatus(user: User): 'unknown' | 'online' | 'active' | 'offline' {
if (user.hideOnlineStatus) return 'unknown'; if (user.hideOnlineStatus) return 'unknown';
if (user.lastActiveDate == null) return 'unknown'; if (user.lastActiveDate == null) return 'unknown';
const elapsed = Date.now() - user.lastActiveDate.getTime(); const elapsed = Date.now() - user.lastActiveDate.getTime();
@ -183,22 +202,22 @@ export class UserRepository extends Repository<User> {
elapsed < USER_ACTIVE_THRESHOLD ? 'active' : elapsed < USER_ACTIVE_THRESHOLD ? 'active' :
'offline' 'offline'
); );
} },
public getAvatarUrl(user: User): string { getAvatarUrl(user: User): string {
// TODO: avatarIdがあるがavatarがない(JOINされてない)場合のハンドリング // TODO: avatarIdがあるがavatarがない(JOINされてない)場合のハンドリング
if (user.avatar) { if (user.avatar) {
return DriveFiles.getPublicUrl(user.avatar, true) || this.getIdenticonUrl(user.id); return DriveFiles.getPublicUrl(user.avatar, true) || this.getIdenticonUrl(user.id);
} else { } else {
return this.getIdenticonUrl(user.id); return this.getIdenticonUrl(user.id);
} }
} },
public getIdenticonUrl(userId: User['id']): string { getIdenticonUrl(userId: User['id']): string {
return `${config.url}/identicon/${userId}`; return `${config.url}/identicon/${userId}`;
} },
public async pack<ExpectsMe extends boolean | null = null, D extends boolean = false>( async pack<ExpectsMe extends boolean | null = null, D extends boolean = false>(
src: User['id'] | User, src: User['id'] | User,
me?: { id: User['id'] } | null | undefined, me?: { id: User['id'] } | null | undefined,
options?: { options?: {
@ -215,11 +234,15 @@ export class UserRepository extends Repository<User> {
if (typeof src === 'object') { if (typeof src === 'object') {
user = src; user = src;
if (src.avatar === undefined && src.avatarId) src.avatar = await DriveFiles.findOne(src.avatarId) ?? null; if (src.avatar === undefined && src.avatarId) src.avatar = await DriveFiles.findOneBy({ id: src.avatarId }) ?? null;
if (src.banner === undefined && src.bannerId) src.banner = await DriveFiles.findOne(src.bannerId) ?? null; if (src.banner === undefined && src.bannerId) src.banner = await DriveFiles.findOneBy({ id: src.bannerId }) ?? null;
} else { } else {
user = await this.findOneOrFail(src, { user = await this.findOneOrFail({
relations: ['avatar', 'banner'], where: { id: src },
relations: {
avatar: true,
banner: true,
},
}); });
} }
@ -232,7 +255,7 @@ export class UserRepository extends Repository<User> {
.innerJoinAndSelect('pin.note', 'note') .innerJoinAndSelect('pin.note', 'note')
.orderBy('pin.id', 'DESC') .orderBy('pin.id', 'DESC')
.getMany() : []; .getMany() : [];
const profile = opts.detail ? await UserProfiles.findOneOrFail(user.id) : null; const profile = opts.detail ? await UserProfiles.findOneByOrFail({ userId: user.id }) : null;
const followingCount = profile == null ? null : const followingCount = profile == null ? null :
(profile.ffVisibility === 'public') || isMe ? user.followingCount : (profile.ffVisibility === 'public') || isMe ? user.followingCount :
@ -258,9 +281,8 @@ export class UserRepository extends Repository<User> {
isModerator: user.isModerator || falsy, isModerator: user.isModerator || falsy,
isBot: user.isBot || falsy, isBot: user.isBot || falsy,
isCat: user.isCat || falsy, isCat: user.isCat || falsy,
// TODO: typeorm 3.0にしたら .then(x => x || null) は消せる
instance: user.host ? userInstanceCache.fetch(user.host, instance: user.host ? userInstanceCache.fetch(user.host,
() => Instances.findOne({ host: user.host }).then(x => x || null), () => Instances.findOneBy({ host: user.host! }),
v => v != null v => v != null
).then(instance => instance ? { ).then(instance => instance ? {
name: instance.name, name: instance.name,
@ -304,7 +326,7 @@ export class UserRepository extends Repository<User> {
twoFactorEnabled: profile!.twoFactorEnabled, twoFactorEnabled: profile!.twoFactorEnabled,
usePasswordLessLogin: profile!.usePasswordLessLogin, usePasswordLessLogin: profile!.usePasswordLessLogin,
securityKeys: profile!.twoFactorEnabled securityKeys: profile!.twoFactorEnabled
? UserSecurityKeys.count({ ? UserSecurityKeys.countBy({
userId: user.id, userId: user.id,
}).then(result => result >= 1) }).then(result => result >= 1)
: false, : false,
@ -352,7 +374,11 @@ export class UserRepository extends Repository<User> {
where: { where: {
userId: user.id, userId: user.id,
}, },
select: ['id', 'name', 'lastUsed'], select: {
id: true,
name: true,
lastUsed: true,
},
}) })
: [], : [],
} : {}), } : {}),
@ -369,9 +395,9 @@ export class UserRepository extends Repository<User> {
} as Promiseable<Packed<'User'>> as Promiseable<IsMeAndIsUserDetailed<ExpectsMe, D>>; } as Promiseable<Packed<'User'>> as Promiseable<IsMeAndIsUserDetailed<ExpectsMe, D>>;
return await awaitAll(packed); return await awaitAll(packed);
} },
public packMany<D extends boolean = false>( packMany<D extends boolean = false>(
users: (User['id'] | User)[], users: (User['id'] | User)[],
me?: { id: User['id'] } | null | undefined, me?: { id: User['id'] } | null | undefined,
options?: { options?: {
@ -380,17 +406,8 @@ export class UserRepository extends Repository<User> {
} }
): Promise<IsUserDetailed<D>[]> { ): Promise<IsUserDetailed<D>[]> {
return Promise.all(users.map(u => this.pack(u, me, options))); return Promise.all(users.map(u => this.pack(u, me, options)));
} },
public isLocalUser(user: User): user is ILocalUser; isLocalUser,
public isLocalUser<T extends { host: User['host'] }>(user: T): user is T & { host: null; }; isRemoteUser,
public isLocalUser(user: User | { host: User['host'] }): boolean { });
return user.host == null;
}
public isRemoteUser(user: User): user is IRemoteUser;
public isRemoteUser<T extends { host: User['host'] }>(user: T): user is T & { host: string; };
public isRemoteUser(user: User | { host: User['host'] }): boolean {
return !this.isLocalUser(user);
}
}

View File

@ -13,7 +13,7 @@ const logger = queueLogger.createSubLogger('delete-account');
export async function deleteAccount(job: Bull.Job<DbUserDeleteJobData>): Promise<string | void> { export async function deleteAccount(job: Bull.Job<DbUserDeleteJobData>): Promise<string | void> {
logger.info(`Deleting account of ${job.data.user.id} ...`); logger.info(`Deleting account of ${job.data.user.id} ...`);
const user = await Users.findOne(job.data.user.id); const user = await Users.findOneBy({ id: job.data.user.id });
if (user == null) { if (user == null) {
return; return;
} }
@ -75,7 +75,7 @@ export async function deleteAccount(job: Bull.Job<DbUserDeleteJobData>): Promise
} }
{ // Send email notification { // Send email notification
const profile = await UserProfiles.findOneOrFail(user.id); const profile = await UserProfiles.findOneByOrFail({ userId: user.id });
if (profile.email && profile.emailVerified) { if (profile.email && profile.emailVerified) {
sendEmail(profile.email, 'Account deleted', sendEmail(profile.email, 'Account deleted',
`Your account has been deleted.`, `Your account has been deleted.`,

View File

@ -11,7 +11,7 @@ const logger = queueLogger.createSubLogger('delete-drive-files');
export async function deleteDriveFiles(job: Bull.Job<DbUserJobData>, done: any): Promise<void> { export async function deleteDriveFiles(job: Bull.Job<DbUserJobData>, done: any): Promise<void> {
logger.info(`Deleting drive files of ${job.data.user.id} ...`); logger.info(`Deleting drive files of ${job.data.user.id} ...`);
const user = await Users.findOne(job.data.user.id); const user = await Users.findOneBy({ id: job.data.user.id });
if (user == null) { if (user == null) {
done(); done();
return; return;
@ -44,7 +44,7 @@ export async function deleteDriveFiles(job: Bull.Job<DbUserJobData>, done: any):
deletedCount++; deletedCount++;
} }
const total = await DriveFiles.count({ const total = await DriveFiles.countBy({
userId: user.id, userId: user.id,
}); });

View File

@ -15,7 +15,7 @@ const logger = queueLogger.createSubLogger('export-blocking');
export async function exportBlocking(job: Bull.Job<DbUserJobData>, done: any): Promise<void> { export async function exportBlocking(job: Bull.Job<DbUserJobData>, done: any): Promise<void> {
logger.info(`Exporting blocking of ${job.data.user.id} ...`); logger.info(`Exporting blocking of ${job.data.user.id} ...`);
const user = await Users.findOne(job.data.user.id); const user = await Users.findOneBy({ id: job.data.user.id });
if (user == null) { if (user == null) {
done(); done();
return; return;
@ -56,7 +56,7 @@ export async function exportBlocking(job: Bull.Job<DbUserJobData>, done: any): P
cursor = blockings[blockings.length - 1].id; cursor = blockings[blockings.length - 1].id;
for (const block of blockings) { for (const block of blockings) {
const u = await Users.findOne({ id: block.blockeeId }); const u = await Users.findOneBy({ id: block.blockeeId });
if (u == null) { if (u == null) {
exportedCount++; continue; exportedCount++; continue;
} }
@ -75,7 +75,7 @@ export async function exportBlocking(job: Bull.Job<DbUserJobData>, done: any): P
exportedCount++; exportedCount++;
} }
const total = await Blockings.count({ const total = await Blockings.countBy({
blockerId: user.id, blockerId: user.id,
}); });

View File

@ -12,13 +12,14 @@ import { Users, Emojis } from '@/models/index.js';
import { } from '@/queue/types.js'; import { } from '@/queue/types.js';
import { downloadUrl } from '@/misc/download-url.js'; import { downloadUrl } from '@/misc/download-url.js';
import config from '@/config/index.js'; import config from '@/config/index.js';
import { IsNull } from 'typeorm';
const logger = queueLogger.createSubLogger('export-custom-emojis'); const logger = queueLogger.createSubLogger('export-custom-emojis');
export async function exportCustomEmojis(job: Bull.Job, done: () => void): Promise<void> { export async function exportCustomEmojis(job: Bull.Job, done: () => void): Promise<void> {
logger.info(`Exporting custom emojis ...`); logger.info(`Exporting custom emojis ...`);
const user = await Users.findOne(job.data.user.id); const user = await Users.findOneBy({ id: job.data.user.id });
if (user == null) { if (user == null) {
done(); done();
return; return;
@ -57,7 +58,7 @@ export async function exportCustomEmojis(job: Bull.Job, done: () => void): Promi
const customEmojis = await Emojis.find({ const customEmojis = await Emojis.find({
where: { where: {
host: null, host: IsNull(),
}, },
order: { order: {
id: 'ASC', id: 'ASC',

View File

@ -16,7 +16,7 @@ const logger = queueLogger.createSubLogger('export-following');
export async function exportFollowing(job: Bull.Job<DbUserJobData>, done: () => void): Promise<void> { export async function exportFollowing(job: Bull.Job<DbUserJobData>, done: () => void): Promise<void> {
logger.info(`Exporting following of ${job.data.user.id} ...`); logger.info(`Exporting following of ${job.data.user.id} ...`);
const user = await Users.findOne(job.data.user.id); const user = await Users.findOneBy({ id: job.data.user.id });
if (user == null) { if (user == null) {
done(); done();
return; return;
@ -36,7 +36,7 @@ export async function exportFollowing(job: Bull.Job<DbUserJobData>, done: () =>
let cursor: Following['id'] | null = null; let cursor: Following['id'] | null = null;
const mutings = job.data.excludeMuting ? await Mutings.find({ const mutings = job.data.excludeMuting ? await Mutings.findBy({
muterId: user.id, muterId: user.id,
}) : []; }) : [];
@ -60,7 +60,7 @@ export async function exportFollowing(job: Bull.Job<DbUserJobData>, done: () =>
cursor = followings[followings.length - 1].id; cursor = followings[followings.length - 1].id;
for (const following of followings) { for (const following of followings) {
const u = await Users.findOne({ id: following.followeeId }); const u = await Users.findOneBy({ id: following.followeeId });
if (u == null) { if (u == null) {
continue; continue;
} }

View File

@ -15,7 +15,7 @@ const logger = queueLogger.createSubLogger('export-mute');
export async function exportMute(job: Bull.Job<DbUserJobData>, done: any): Promise<void> { export async function exportMute(job: Bull.Job<DbUserJobData>, done: any): Promise<void> {
logger.info(`Exporting mute of ${job.data.user.id} ...`); logger.info(`Exporting mute of ${job.data.user.id} ...`);
const user = await Users.findOne(job.data.user.id); const user = await Users.findOneBy({ id: job.data.user.id });
if (user == null) { if (user == null) {
done(); done();
return; return;
@ -57,7 +57,7 @@ export async function exportMute(job: Bull.Job<DbUserJobData>, done: any): Promi
cursor = mutes[mutes.length - 1].id; cursor = mutes[mutes.length - 1].id;
for (const mute of mutes) { for (const mute of mutes) {
const u = await Users.findOne({ id: mute.muteeId }); const u = await Users.findOneBy({ id: mute.muteeId });
if (u == null) { if (u == null) {
exportedCount++; continue; exportedCount++; continue;
} }
@ -76,7 +76,7 @@ export async function exportMute(job: Bull.Job<DbUserJobData>, done: any): Promi
exportedCount++; exportedCount++;
} }
const total = await Mutings.count({ const total = await Mutings.countBy({
muterId: user.id, muterId: user.id,
}); });

View File

@ -16,7 +16,7 @@ const logger = queueLogger.createSubLogger('export-notes');
export async function exportNotes(job: Bull.Job<DbUserJobData>, done: any): Promise<void> { export async function exportNotes(job: Bull.Job<DbUserJobData>, done: any): Promise<void> {
logger.info(`Exporting notes of ${job.data.user.id} ...`); logger.info(`Exporting notes of ${job.data.user.id} ...`);
const user = await Users.findOne(job.data.user.id); const user = await Users.findOneBy({ id: job.data.user.id });
if (user == null) { if (user == null) {
done(); done();
return; return;
@ -74,7 +74,7 @@ export async function exportNotes(job: Bull.Job<DbUserJobData>, done: any): Prom
for (const note of notes) { for (const note of notes) {
let poll: Poll | undefined; let poll: Poll | undefined;
if (note.hasPoll) { if (note.hasPoll) {
poll = await Polls.findOneOrFail({ noteId: note.id }); poll = await Polls.findOneByOrFail({ noteId: note.id });
} }
const content = JSON.stringify(serialize(note, poll)); const content = JSON.stringify(serialize(note, poll));
const isFirst = exportedNotesCount === 0; const isFirst = exportedNotesCount === 0;
@ -82,7 +82,7 @@ export async function exportNotes(job: Bull.Job<DbUserJobData>, done: any): Prom
exportedNotesCount++; exportedNotesCount++;
} }
const total = await Notes.count({ const total = await Notes.countBy({
userId: user.id, userId: user.id,
}); });

View File

@ -15,13 +15,13 @@ const logger = queueLogger.createSubLogger('export-user-lists');
export async function exportUserLists(job: Bull.Job<DbUserJobData>, done: any): Promise<void> { export async function exportUserLists(job: Bull.Job<DbUserJobData>, done: any): Promise<void> {
logger.info(`Exporting user lists of ${job.data.user.id} ...`); logger.info(`Exporting user lists of ${job.data.user.id} ...`);
const user = await Users.findOne(job.data.user.id); const user = await Users.findOneBy({ id: job.data.user.id });
if (user == null) { if (user == null) {
done(); done();
return; return;
} }
const lists = await UserLists.find({ const lists = await UserLists.findBy({
userId: user.id, userId: user.id,
}); });
@ -38,8 +38,8 @@ export async function exportUserLists(job: Bull.Job<DbUserJobData>, done: any):
const stream = fs.createWriteStream(path, { flags: 'a' }); const stream = fs.createWriteStream(path, { flags: 'a' });
for (const list of lists) { for (const list of lists) {
const joinings = await UserListJoinings.find({ userListId: list.id }); const joinings = await UserListJoinings.findBy({ userListId: list.id });
const users = await Users.find({ const users = await Users.findBy({
id: In(joinings.map(j => j.userId)), id: In(joinings.map(j => j.userId)),
}); });

View File

@ -8,19 +8,20 @@ import { isSelfHost, toPuny } from '@/misc/convert-host.js';
import { Users, DriveFiles, Blockings } from '@/models/index.js'; import { Users, DriveFiles, Blockings } from '@/models/index.js';
import { DbUserImportJobData } from '@/queue/types.js'; import { DbUserImportJobData } from '@/queue/types.js';
import block from '@/services/blocking/create.js'; import block from '@/services/blocking/create.js';
import { IsNull } from 'typeorm';
const logger = queueLogger.createSubLogger('import-blocking'); const logger = queueLogger.createSubLogger('import-blocking');
export async function importBlocking(job: Bull.Job<DbUserImportJobData>, done: any): Promise<void> { export async function importBlocking(job: Bull.Job<DbUserImportJobData>, done: any): Promise<void> {
logger.info(`Importing blocking of ${job.data.user.id} ...`); logger.info(`Importing blocking of ${job.data.user.id} ...`);
const user = await Users.findOne(job.data.user.id); const user = await Users.findOneBy({ id: job.data.user.id });
if (user == null) { if (user == null) {
done(); done();
return; return;
} }
const file = await DriveFiles.findOne({ const file = await DriveFiles.findOneBy({
id: job.data.fileId, id: job.data.fileId,
}); });
if (file == null) { if (file == null) {
@ -39,10 +40,10 @@ export async function importBlocking(job: Bull.Job<DbUserImportJobData>, done: a
const acct = line.split(',')[0].trim(); const acct = line.split(',')[0].trim();
const { username, host } = Acct.parse(acct); const { username, host } = Acct.parse(acct);
let target = isSelfHost(host!) ? await Users.findOne({ let target = isSelfHost(host!) ? await Users.findOneBy({
host: null, host: IsNull(),
usernameLower: username.toLowerCase(), usernameLower: username.toLowerCase(),
}) : await Users.findOne({ }) : await Users.findOneBy({
host: toPuny(host!), host: toPuny(host!),
usernameLower: username.toLowerCase(), usernameLower: username.toLowerCase(),
}); });

View File

@ -2,7 +2,6 @@ import Bull from 'bull';
import * as tmp from 'tmp'; import * as tmp from 'tmp';
import * as fs from 'node:fs'; import * as fs from 'node:fs';
import unzipper from 'unzipper'; import unzipper from 'unzipper';
import { getConnection } from 'typeorm';
import { queueLogger } from '../../logger.js'; import { queueLogger } from '../../logger.js';
import { downloadUrl } from '@/misc/download-url.js'; import { downloadUrl } from '@/misc/download-url.js';
@ -10,6 +9,7 @@ import { DriveFiles, Emojis } from '@/models/index.js';
import { DbUserImportJobData } from '@/queue/types.js'; import { DbUserImportJobData } from '@/queue/types.js';
import { addFile } from '@/services/drive/add-file.js'; import { addFile } from '@/services/drive/add-file.js';
import { genId } from '@/misc/gen-id.js'; import { genId } from '@/misc/gen-id.js';
import { db } from '@/db/postgre.js';
const logger = queueLogger.createSubLogger('import-custom-emojis'); const logger = queueLogger.createSubLogger('import-custom-emojis');
@ -17,7 +17,7 @@ const logger = queueLogger.createSubLogger('import-custom-emojis');
export async function importCustomEmojis(job: Bull.Job<DbUserImportJobData>, done: any): Promise<void> { export async function importCustomEmojis(job: Bull.Job<DbUserImportJobData>, done: any): Promise<void> {
logger.info(`Importing custom emojis ...`); logger.info(`Importing custom emojis ...`);
const file = await DriveFiles.findOne({ const file = await DriveFiles.findOneBy({
id: job.data.fileId, id: job.data.fileId,
}); });
if (file == null) { if (file == null) {
@ -72,10 +72,10 @@ export async function importCustomEmojis(job: Bull.Job<DbUserImportJobData>, don
originalUrl: driveFile.url, originalUrl: driveFile.url,
publicUrl: driveFile.webpublicUrl ?? driveFile.url, publicUrl: driveFile.webpublicUrl ?? driveFile.url,
type: driveFile.webpublicType ?? driveFile.type, type: driveFile.webpublicType ?? driveFile.type,
}).then(x => Emojis.findOneOrFail(x.identifiers[0])); }).then(x => Emojis.findOneByOrFail(x.identifiers[0]));
} }
await getConnection().queryResultCache!.remove(['meta_emojis']); await db.queryResultCache!.remove(['meta_emojis']);
cleanup(); cleanup();

View File

@ -8,19 +8,20 @@ import { downloadTextFile } from '@/misc/download-text-file.js';
import { isSelfHost, toPuny } from '@/misc/convert-host.js'; import { isSelfHost, toPuny } from '@/misc/convert-host.js';
import { Users, DriveFiles } from '@/models/index.js'; import { Users, DriveFiles } from '@/models/index.js';
import { DbUserImportJobData } from '@/queue/types.js'; import { DbUserImportJobData } from '@/queue/types.js';
import { IsNull } from 'typeorm';
const logger = queueLogger.createSubLogger('import-following'); const logger = queueLogger.createSubLogger('import-following');
export async function importFollowing(job: Bull.Job<DbUserImportJobData>, done: any): Promise<void> { export async function importFollowing(job: Bull.Job<DbUserImportJobData>, done: any): Promise<void> {
logger.info(`Importing following of ${job.data.user.id} ...`); logger.info(`Importing following of ${job.data.user.id} ...`);
const user = await Users.findOne(job.data.user.id); const user = await Users.findOneBy({ id: job.data.user.id });
if (user == null) { if (user == null) {
done(); done();
return; return;
} }
const file = await DriveFiles.findOne({ const file = await DriveFiles.findOneBy({
id: job.data.fileId, id: job.data.fileId,
}); });
if (file == null) { if (file == null) {
@ -39,10 +40,10 @@ export async function importFollowing(job: Bull.Job<DbUserImportJobData>, done:
const acct = line.split(',')[0].trim(); const acct = line.split(',')[0].trim();
const { username, host } = Acct.parse(acct); const { username, host } = Acct.parse(acct);
let target = isSelfHost(host!) ? await Users.findOne({ let target = isSelfHost(host!) ? await Users.findOneBy({
host: null, host: IsNull(),
usernameLower: username.toLowerCase(), usernameLower: username.toLowerCase(),
}) : await Users.findOne({ }) : await Users.findOneBy({
host: toPuny(host!), host: toPuny(host!),
usernameLower: username.toLowerCase(), usernameLower: username.toLowerCase(),
}); });

View File

@ -9,19 +9,20 @@ import { Users, DriveFiles, Mutings } from '@/models/index.js';
import { DbUserImportJobData } from '@/queue/types.js'; import { DbUserImportJobData } from '@/queue/types.js';
import { User } from '@/models/entities/user.js'; import { User } from '@/models/entities/user.js';
import { genId } from '@/misc/gen-id.js'; import { genId } from '@/misc/gen-id.js';
import { IsNull } from 'typeorm';
const logger = queueLogger.createSubLogger('import-muting'); const logger = queueLogger.createSubLogger('import-muting');
export async function importMuting(job: Bull.Job<DbUserImportJobData>, done: any): Promise<void> { export async function importMuting(job: Bull.Job<DbUserImportJobData>, done: any): Promise<void> {
logger.info(`Importing muting of ${job.data.user.id} ...`); logger.info(`Importing muting of ${job.data.user.id} ...`);
const user = await Users.findOne(job.data.user.id); const user = await Users.findOneBy({ id: job.data.user.id });
if (user == null) { if (user == null) {
done(); done();
return; return;
} }
const file = await DriveFiles.findOne({ const file = await DriveFiles.findOneBy({
id: job.data.fileId, id: job.data.fileId,
}); });
if (file == null) { if (file == null) {
@ -40,10 +41,10 @@ export async function importMuting(job: Bull.Job<DbUserImportJobData>, done: any
const acct = line.split(',')[0].trim(); const acct = line.split(',')[0].trim();
const { username, host } = Acct.parse(acct); const { username, host } = Acct.parse(acct);
let target = isSelfHost(host!) ? await Users.findOne({ let target = isSelfHost(host!) ? await Users.findOneBy({
host: null, host: IsNull(),
usernameLower: username.toLowerCase(), usernameLower: username.toLowerCase(),
}) : await Users.findOne({ }) : await Users.findOneBy({
host: toPuny(host!), host: toPuny(host!),
usernameLower: username.toLowerCase(), usernameLower: username.toLowerCase(),
}); });

View File

@ -9,19 +9,20 @@ import { isSelfHost, toPuny } from '@/misc/convert-host.js';
import { DriveFiles, Users, UserLists, UserListJoinings } from '@/models/index.js'; import { DriveFiles, Users, UserLists, UserListJoinings } from '@/models/index.js';
import { genId } from '@/misc/gen-id.js'; import { genId } from '@/misc/gen-id.js';
import { DbUserImportJobData } from '@/queue/types.js'; import { DbUserImportJobData } from '@/queue/types.js';
import { IsNull } from 'typeorm';
const logger = queueLogger.createSubLogger('import-user-lists'); const logger = queueLogger.createSubLogger('import-user-lists');
export async function importUserLists(job: Bull.Job<DbUserImportJobData>, done: any): Promise<void> { export async function importUserLists(job: Bull.Job<DbUserImportJobData>, done: any): Promise<void> {
logger.info(`Importing user lists of ${job.data.user.id} ...`); logger.info(`Importing user lists of ${job.data.user.id} ...`);
const user = await Users.findOne(job.data.user.id); const user = await Users.findOneBy({ id: job.data.user.id });
if (user == null) { if (user == null) {
done(); done();
return; return;
} }
const file = await DriveFiles.findOne({ const file = await DriveFiles.findOneBy({
id: job.data.fileId, id: job.data.fileId,
}); });
if (file == null) { if (file == null) {
@ -40,7 +41,7 @@ export async function importUserLists(job: Bull.Job<DbUserImportJobData>, done:
const listName = line.split(',')[0].trim(); const listName = line.split(',')[0].trim();
const { username, host } = Acct.parse(line.split(',')[1].trim()); const { username, host } = Acct.parse(line.split(',')[1].trim());
let list = await UserLists.findOne({ let list = await UserLists.findOneBy({
userId: user.id, userId: user.id,
name: listName, name: listName,
}); });
@ -51,13 +52,13 @@ export async function importUserLists(job: Bull.Job<DbUserImportJobData>, done:
createdAt: new Date(), createdAt: new Date(),
userId: user.id, userId: user.id,
name: listName, name: listName,
}).then(x => UserLists.findOneOrFail(x.identifiers[0])); }).then(x => UserLists.findOneByOrFail(x.identifiers[0]));
} }
let target = isSelfHost(host!) ? await Users.findOne({ let target = isSelfHost(host!) ? await Users.findOneBy({
host: null, host: IsNull(),
usernameLower: username.toLowerCase(), usernameLower: username.toLowerCase(),
}) : await Users.findOne({ }) : await Users.findOneBy({
host: toPuny(host!), host: toPuny(host!),
usernameLower: username.toLowerCase(), usernameLower: username.toLowerCase(),
}); });
@ -66,7 +67,7 @@ export async function importUserLists(job: Bull.Job<DbUserImportJobData>, done:
target = await resolveUser(username, host); target = await resolveUser(username, host);
} }
if (await UserListJoinings.findOne({ userListId: list!.id, userId: target.id }) != null) continue; if (await UserListJoinings.findOneBy({ userListId: list!.id, userId: target.id }) != null) continue;
pushUserToUserList(target, list!); pushUserToUserList(target, list!);
} catch (e) { } catch (e) {

View File

@ -8,7 +8,7 @@ import { createNotification } from '@/services/create-notification.js';
const logger = queueLogger.createSubLogger('ended-poll-notification'); const logger = queueLogger.createSubLogger('ended-poll-notification');
export async function endedPollNotification(job: Bull.Job<EndedPollNotificationJobData>, done: any): Promise<void> { export async function endedPollNotification(job: Bull.Job<EndedPollNotificationJobData>, done: any): Promise<void> {
const note = await Notes.findOne(job.data.noteId); const note = await Notes.findOneBy({ id: job.data.noteId });
if (note == null || !note.hasPoll) { if (note == null || !note.hasPoll) {
done(); done();
return; return;

View File

@ -37,7 +37,7 @@ export default async function cleanRemoteFiles(job: Bull.Job<Record<string, unkn
deletedCount += 8; deletedCount += 8;
const total = await DriveFiles.count({ const total = await DriveFiles.countBy({
userHost: Not(IsNull()), userHost: Not(IsNull()),
isLink: false, isLink: false,
}); });

View File

@ -24,13 +24,13 @@ export default class DbResolver {
const parsed = this.parseUri(value); const parsed = this.parseUri(value);
if (parsed.id) { if (parsed.id) {
return (await Notes.findOne({ return (await Notes.findOneBy({
id: parsed.id, id: parsed.id,
})) || null; })) || null;
} }
if (parsed.uri) { if (parsed.uri) {
return (await Notes.findOne({ return (await Notes.findOneBy({
uri: parsed.uri, uri: parsed.uri,
})) || null; })) || null;
} }
@ -42,13 +42,13 @@ export default class DbResolver {
const parsed = this.parseUri(value); const parsed = this.parseUri(value);
if (parsed.id) { if (parsed.id) {
return (await MessagingMessages.findOne({ return (await MessagingMessages.findOneBy({
id: parsed.id, id: parsed.id,
})) || null; })) || null;
} }
if (parsed.uri) { if (parsed.uri) {
return (await MessagingMessages.findOne({ return (await MessagingMessages.findOneBy({
uri: parsed.uri, uri: parsed.uri,
})) || null; })) || null;
} }
@ -63,13 +63,13 @@ export default class DbResolver {
const parsed = this.parseUri(value); const parsed = this.parseUri(value);
if (parsed.id) { if (parsed.id) {
return (await Users.findOne({ return (await Users.findOneBy({
id: parsed.id, id: parsed.id,
})) || null; })) || null;
} }
if (parsed.uri) { if (parsed.uri) {
return (await Users.findOne({ return (await Users.findOneBy({
uri: parsed.uri, uri: parsed.uri,
})) || null; })) || null;
} }
@ -85,7 +85,7 @@ export default class DbResolver {
key: UserPublickey; key: UserPublickey;
} | null> { } | null> {
const key = await publicKeyCache.fetch(keyId, async () => { const key = await publicKeyCache.fetch(keyId, async () => {
const key = await UserPublickeys.findOne({ const key = await UserPublickeys.findOneBy({
keyId, keyId,
}); });
@ -97,7 +97,7 @@ export default class DbResolver {
if (key == null) return null; if (key == null) return null;
return { return {
user: await userByIdCache.fetch(key.userId, () => Users.findOneOrFail(key.userId)) as CacheableRemoteUser, user: await userByIdCache.fetch(key.userId, () => Users.findOneByOrFail({ id: key.userId })) as CacheableRemoteUser,
key, key,
}; };
} }
@ -113,7 +113,7 @@ export default class DbResolver {
if (user == null) return null; if (user == null) return null;
const key = await publicKeyByUserIdCache.fetch(user.id, () => UserPublickeys.findOne(user.id).then(x => x || null), v => v != null); // TODO: typeorm 3.0 にしたら.then(x => x || null)は消せる const key = await publicKeyByUserIdCache.fetch(user.id, () => UserPublickeys.findOneBy({ userId: user.id }), v => v != null);
return { return {
user, user,

View File

@ -82,7 +82,7 @@ export default class DeliverManager {
for (const recipe of this.recipes) { for (const recipe of this.recipes) {
if (isFollowers(recipe)) { if (isFollowers(recipe)) {
// followers deliver // followers deliver
const followers = await Followings.find({ const followers = await Followings.findBy({
followeeId: this.actor.id, followeeId: this.actor.id,
}); });

View File

@ -18,6 +18,6 @@ export default async (actor: CacheableRemoteUser, activity: IBlock): Promise<str
return `skip: ブロックしようとしているユーザーはローカルユーザーではありません`; return `skip: ブロックしようとしているユーザーはローカルユーザーではありません`;
} }
await block(await Users.findOneOrFail(actor.id), blockee); await block(await Users.findOneByOrFail({ id: actor.id }), blockee);
return `ok`; return `ok`;
}; };

View File

@ -12,7 +12,7 @@ export async function deleteActor(actor: CacheableRemoteUser, uri: string): Prom
return `skip: delete actor ${actor.uri} !== ${uri}`; return `skip: delete actor ${actor.uri} !== ${uri}`;
} }
const user = await Users.findOneOrFail(actor.id); const user = await Users.findOneByOrFail({ id: actor.id });
if (user.isDeleted) { if (user.isDeleted) {
logger.info(`skip: already deleted`); logger.info(`skip: already deleted`);
} }

View File

@ -11,7 +11,7 @@ export default async (actor: CacheableRemoteUser, activity: IFlag): Promise<stri
const uris = getApIds(activity.object); const uris = getApIds(activity.object);
const userIds = uris.filter(uri => uri.startsWith(config.url + '/users/')).map(uri => uri.split('/').pop()!); const userIds = uris.filter(uri => uri.startsWith(config.url + '/users/')).map(uri => uri.split('/').pop()!);
const users = await Users.find({ const users = await Users.findBy({
id: In(userIds), id: In(userIds),
}); });
if (users.length < 1) return `skip`; if (users.length < 1) return `skip`;

View File

@ -13,7 +13,7 @@ export const performReadActivity = async (actor: CacheableRemoteUser, activity:
const messageId = id.split('/').pop(); const messageId = id.split('/').pop();
const message = await MessagingMessages.findOne(messageId); const message = await MessagingMessages.findOneBy({ id: messageId });
if (message == null) { if (message == null) {
return `skip: message not found`; return `skip: message not found`;
} }

View File

@ -13,7 +13,7 @@ export default async (actor: CacheableRemoteUser, activity: IAccept): Promise<st
return `skip: follower not found`; return `skip: follower not found`;
} }
const following = await Followings.findOne({ const following = await Followings.findOneBy({
followerId: follower.id, followerId: follower.id,
followeeId: actor.id, followeeId: actor.id,
}); });

View File

@ -6,7 +6,7 @@ import deleteNote from '@/services/note/delete.js';
export const undoAnnounce = async (actor: CacheableRemoteUser, activity: IAnnounce): Promise<string> => { export const undoAnnounce = async (actor: CacheableRemoteUser, activity: IAnnounce): Promise<string> => {
const uri = getApId(activity); const uri = getApId(activity);
const note = await Notes.findOne({ const note = await Notes.findOneBy({
uri, uri,
}); });

View File

@ -16,6 +16,6 @@ export default async (actor: CacheableRemoteUser, activity: IBlock): Promise<str
return `skip: ブロック解除しようとしているユーザーはローカルユーザーではありません`; return `skip: ブロック解除しようとしているユーザーはローカルユーザーではありません`;
} }
await unblock(await Users.findOneOrFail(actor.id), blockee); await unblock(await Users.findOneByOrFail({ id: actor.id }), blockee);
return `ok`; return `ok`;
}; };

View File

@ -17,12 +17,12 @@ export default async (actor: CacheableRemoteUser, activity: IFollow): Promise<st
return `skip: フォロー解除しようとしているユーザーはローカルユーザーではありません`; return `skip: フォロー解除しようとしているユーザーはローカルユーザーではありません`;
} }
const req = await FollowRequests.findOne({ const req = await FollowRequests.findOneBy({
followerId: actor.id, followerId: actor.id,
followeeId: followee.id, followeeId: followee.id,
}); });
const following = await Followings.findOne({ const following = await Followings.findOneBy({
followerId: actor.id, followerId: actor.id,
followeeId: followee.id, followeeId: followee.id,
}); });

View File

@ -47,7 +47,7 @@ export async function createImage(actor: CacheableRemoteUser, value: any): Promi
uri: image.url, uri: image.url,
}); });
file = await DriveFiles.findOneOrFail(file.id); file = await DriveFiles.findOneByOrFail({ id: file.id });
} }
} }

View File

@ -141,7 +141,7 @@ export async function createNote(value: string | IObject, resolver?: Resolver, s
const uri = getApId(note.inReplyTo); const uri = getApId(note.inReplyTo);
if (uri.startsWith(config.url + '/')) { if (uri.startsWith(config.url + '/')) {
const id = uri.split('/').pop(); const id = uri.split('/').pop();
const talk = await MessagingMessages.findOne(id); const talk = await MessagingMessages.findOneBy({ id });
if (talk) { if (talk) {
isTalk = true; isTalk = true;
return null; return null;
@ -201,7 +201,7 @@ export async function createNote(value: string | IObject, resolver?: Resolver, s
// vote // vote
if (reply && reply.hasPoll) { if (reply && reply.hasPoll) {
const poll = await Polls.findOneOrFail(reply.id); const poll = await Polls.findOneByOrFail({ noteId: reply.id });
const tryCreateVote = async (name: string, index: number): Promise<null> => { const tryCreateVote = async (name: string, index: number): Promise<null> => {
if (poll.expiresAt && Date.now() > new Date(poll.expiresAt).getTime()) { if (poll.expiresAt && Date.now() > new Date(poll.expiresAt).getTime()) {
@ -306,7 +306,7 @@ export async function extractEmojis(tags: IObject | IObject[], host: string): Pr
const name = tag.name!.replace(/^:/, '').replace(/:$/, ''); const name = tag.name!.replace(/^:/, '').replace(/:$/, '');
tag.icon = toSingle(tag.icon); tag.icon = toSingle(tag.icon);
const exists = await Emojis.findOne({ const exists = await Emojis.findOneBy({
host, host,
name, name,
}); });
@ -327,7 +327,7 @@ export async function extractEmojis(tags: IObject | IObject[], host: string): Pr
updatedAt: new Date(), updatedAt: new Date(),
}); });
return await Emojis.findOne({ return await Emojis.findOneBy({
host, host,
name, name,
}) as Emoji; }) as Emoji;
@ -347,6 +347,6 @@ export async function extractEmojis(tags: IObject | IObject[], host: string): Pr
publicUrl: tag.icon!.url, publicUrl: tag.icon!.url,
updatedAt: new Date(), updatedAt: new Date(),
aliases: [], aliases: [],
} as Partial<Emoji>).then(x => Emojis.findOneOrFail(x.identifiers[0])); } as Partial<Emoji>).then(x => Emojis.findOneByOrFail(x.identifiers[0]));
})); }));
} }

View File

@ -24,7 +24,6 @@ import { UserPublickey } from '@/models/entities/user-publickey.js';
import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js'; import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js';
import { toPuny } from '@/misc/convert-host.js'; import { toPuny } from '@/misc/convert-host.js';
import { UserProfile } from '@/models/entities/user-profile.js'; import { UserProfile } from '@/models/entities/user-profile.js';
import { getConnection } from 'typeorm';
import { toArray } from '@/prelude/array.js'; import { toArray } from '@/prelude/array.js';
import { fetchInstanceMetadata } from '@/services/fetch-instance-metadata.js'; import { fetchInstanceMetadata } from '@/services/fetch-instance-metadata.js';
import { normalizeForSearch } from '@/misc/normalize-for-search.js'; import { normalizeForSearch } from '@/misc/normalize-for-search.js';
@ -32,6 +31,7 @@ import { truncate } from '@/misc/truncate.js';
import { StatusError } from '@/misc/fetch.js'; import { StatusError } from '@/misc/fetch.js';
import { uriPersonCache } from '@/services/user-cache.js'; import { uriPersonCache } from '@/services/user-cache.js';
import { publishInternalEvent } from '@/services/stream.js'; import { publishInternalEvent } from '@/services/stream.js';
import { db } from '@/db/postgre.js';
const logger = apLogger; const logger = apLogger;
@ -102,13 +102,13 @@ export async function fetchPerson(uri: string, resolver?: Resolver): Promise<Cac
// URIがこのサーバーを指しているならデータベースからフェッチ // URIがこのサーバーを指しているならデータベースからフェッチ
if (uri.startsWith(config.url + '/')) { if (uri.startsWith(config.url + '/')) {
const id = uri.split('/').pop(); const id = uri.split('/').pop();
const u = await Users.findOne(id).then(x => x || null); // TODO: typeorm 3.0 にしたら .then(x => x || null) を消す const u = await Users.findOneBy({ id });
if (u) uriPersonCache.set(uri, u); if (u) uriPersonCache.set(uri, u);
return u; return u;
} }
//#region このサーバーに既に登録されていたらそれを返す //#region このサーバーに既に登録されていたらそれを返す
const exist = await Users.findOne({ uri }); const exist = await Users.findOneBy({ uri });
if (exist) { if (exist) {
uriPersonCache.set(uri, exist); uriPersonCache.set(uri, exist);
@ -151,7 +151,7 @@ export async function createPerson(uri: string, resolver?: Resolver): Promise<Us
let user: IRemoteUser; let user: IRemoteUser;
try { try {
// Start transaction // Start transaction
await getConnection().transaction(async transactionalEntityManager => { await db.transaction(async transactionalEntityManager => {
user = await transactionalEntityManager.save(new User({ user = await transactionalEntityManager.save(new User({
id: genId(), id: genId(),
avatarId: null, avatarId: null,
@ -197,7 +197,7 @@ export async function createPerson(uri: string, resolver?: Resolver): Promise<Us
// duplicate key error // duplicate key error
if (isDuplicateKeyValueError(e)) { if (isDuplicateKeyValueError(e)) {
// /users/@a => /users/:id のように入力がaliasなときにエラーになることがあるのを対応 // /users/@a => /users/:id のように入力がaliasなときにエラーになることがあるのを対応
const u = await Users.findOne({ const u = await Users.findOneBy({
uri: person.id, uri: person.id,
}); });
@ -280,7 +280,7 @@ export async function updatePerson(uri: string, resolver?: Resolver | null, hint
} }
//#region このサーバーに既に登録されているか //#region このサーバーに既に登録されているか
const exist = await Users.findOne({ uri }) as IRemoteUser; const exist = await Users.findOneBy({ uri }) as IRemoteUser;
if (exist == null) { if (exist == null) {
return; return;
@ -451,7 +451,7 @@ export function analyzeAttachments(attachments: IObject | IObject[] | undefined)
} }
export async function updateFeatured(userId: User['id']) { export async function updateFeatured(userId: User['id']) {
const user = await Users.findOneOrFail(userId); const user = await Users.findOneByOrFail({ id: userId });
if (!Users.isRemoteUser(user)) return; if (!Users.isRemoteUser(user)) return;
if (!user.featured) return; if (!user.featured) return;
@ -474,7 +474,7 @@ export async function updateFeatured(userId: User['id']) {
.slice(0, 5) .slice(0, 5)
.map(item => limit(() => resolveNote(item, resolver)))); .map(item => limit(() => resolveNote(item, resolver))));
await getConnection().transaction(async transactionalEntityManager => { await db.transaction(async transactionalEntityManager => {
await transactionalEntityManager.delete(UserNotePining, { userId: user.id }); await transactionalEntityManager.delete(UserNotePining, { userId: user.id });
// とりあえずidを別の時間で生成して順番を維持 // とりあえずidを別の時間で生成して順番を維持

View File

@ -47,10 +47,10 @@ export async function updateQuestion(value: any) {
if (uri.startsWith(config.url + '/')) throw new Error('uri points local'); if (uri.startsWith(config.url + '/')) throw new Error('uri points local');
//#region このサーバーに既に登録されているか //#region このサーバーに既に登録されているか
const note = await Notes.findOne({ uri }); const note = await Notes.findOneBy({ uri });
if (note == null) throw new Error('Question is not registed'); if (note == null) throw new Error('Question is not registed');
const poll = await Polls.findOne({ noteId: note.id }); const poll = await Polls.findOneBy({ noteId: note.id });
if (poll == null) throw new Error('Question is not registed'); if (poll == null) throw new Error('Question is not registed');
//#endregion //#endregion

View File

@ -7,6 +7,6 @@ import { User } from '@/models/entities/user.js';
* @param id Follower|Followee ID * @param id Follower|Followee ID
*/ */
export default async function renderFollowUser(id: User['id']): Promise<any> { export default async function renderFollowUser(id: User['id']): Promise<any> {
const user = await Users.findOneOrFail(id); const user = await Users.findOneByOrFail({ id: id });
return Users.isLocalUser(user) ? `${config.url}/users/${user.id}` : user.uri; return Users.isLocalUser(user) ? `${config.url}/users/${user.id}` : user.uri;
} }

View File

@ -2,6 +2,7 @@ import config from '@/config/index.js';
import { NoteReaction } from '@/models/entities/note-reaction.js'; import { NoteReaction } from '@/models/entities/note-reaction.js';
import { Note } from '@/models/entities/note.js'; import { Note } from '@/models/entities/note.js';
import { Emojis } from '@/models/index.js'; import { Emojis } from '@/models/index.js';
import { IsNull } from 'typeorm';
import renderEmoji from './emoji.js'; import renderEmoji from './emoji.js';
export const renderLike = async (noteReaction: NoteReaction, note: Note) => { export const renderLike = async (noteReaction: NoteReaction, note: Note) => {
@ -18,9 +19,9 @@ export const renderLike = async (noteReaction: NoteReaction, note: Note) => {
if (reaction.startsWith(':')) { if (reaction.startsWith(':')) {
const name = reaction.replace(/:/g, ''); const name = reaction.replace(/:/g, '');
const emoji = await Emojis.findOne({ const emoji = await Emojis.findOneBy({
name, name,
host: null, host: IsNull(),
}); });
if (emoji) object.tag = [ renderEmoji(emoji) ]; if (emoji) object.tag = [ renderEmoji(emoji) ];

View File

@ -7,25 +7,25 @@ import toHtml from '../misc/get-note-html.js';
import { Note, IMentionedRemoteUsers } from '@/models/entities/note.js'; import { Note, IMentionedRemoteUsers } from '@/models/entities/note.js';
import { DriveFile } from '@/models/entities/drive-file.js'; import { DriveFile } from '@/models/entities/drive-file.js';
import { DriveFiles, Notes, Users, Emojis, Polls } from '@/models/index.js'; import { DriveFiles, Notes, Users, Emojis, Polls } from '@/models/index.js';
import { In } from 'typeorm'; import { In, IsNull } from 'typeorm';
import { Emoji } from '@/models/entities/emoji.js'; import { Emoji } from '@/models/entities/emoji.js';
import { Poll } from '@/models/entities/poll.js'; import { Poll } from '@/models/entities/poll.js';
export default async function renderNote(note: Note, dive = true, isTalk = false): Promise<Record<string, unknown>> { export default async function renderNote(note: Note, dive = true, isTalk = false): Promise<Record<string, unknown>> {
const getPromisedFiles = async (ids: string[]) => { const getPromisedFiles = async (ids: string[]) => {
if (!ids || ids.length === 0) return []; if (!ids || ids.length === 0) return [];
const items = await DriveFiles.find({ id: In(ids) }); const items = await DriveFiles.findBy({ id: In(ids) });
return ids.map(id => items.find(item => item.id === id)).filter(item => item != null) as DriveFile[]; return ids.map(id => items.find(item => item.id === id)).filter(item => item != null) as DriveFile[];
}; };
let inReplyTo; let inReplyTo;
let inReplyToNote: Note | undefined; let inReplyToNote: Note | null;
if (note.replyId) { if (note.replyId) {
inReplyToNote = await Notes.findOne(note.replyId); inReplyToNote = await Notes.findOneBy({ id: note.replyId });
if (inReplyToNote != null) { if (inReplyToNote != null) {
const inReplyToUser = await Users.findOne(inReplyToNote.userId); const inReplyToUser = await Users.findOneBy({ id: inReplyToNote.userId });
if (inReplyToUser != null) { if (inReplyToUser != null) {
if (inReplyToNote.uri) { if (inReplyToNote.uri) {
@ -46,7 +46,7 @@ export default async function renderNote(note: Note, dive = true, isTalk = false
let quote; let quote;
if (note.renoteId) { if (note.renoteId) {
const renote = await Notes.findOne(note.renoteId); const renote = await Notes.findOneBy({ id: note.renoteId });
if (renote) { if (renote) {
quote = renote.uri ? renote.uri : `${config.url}/notes/${renote.id}`; quote = renote.uri ? renote.uri : `${config.url}/notes/${renote.id}`;
@ -73,7 +73,7 @@ export default async function renderNote(note: Note, dive = true, isTalk = false
to = mentions; to = mentions;
} }
const mentionedUsers = note.mentions.length > 0 ? await Users.find({ const mentionedUsers = note.mentions.length > 0 ? await Users.findBy({
id: In(note.mentions), id: In(note.mentions),
}) : []; }) : [];
@ -83,10 +83,10 @@ export default async function renderNote(note: Note, dive = true, isTalk = false
const files = await getPromisedFiles(note.fileIds); const files = await getPromisedFiles(note.fileIds);
const text = note.text; const text = note.text;
let poll: Poll | undefined; let poll: Poll | null;
if (note.hasPoll) { if (note.hasPoll) {
poll = await Polls.findOne({ noteId: note.id }); poll = await Polls.findOneBy({ noteId: note.id });
} }
let apText = text; let apText = text;
@ -156,9 +156,9 @@ export async function getEmojis(names: string[]): Promise<Emoji[]> {
if (names == null || names.length === 0) return []; if (names == null || names.length === 0) return [];
const emojis = await Promise.all( const emojis = await Promise.all(
names.map(name => Emojis.findOne({ names.map(name => Emojis.findOneBy({
name, name,
host: null, host: IsNull(),
})) }))
); );

View File

@ -17,9 +17,9 @@ export async function renderPerson(user: ILocalUser) {
const isSystem = !!user.username.match(/\./); const isSystem = !!user.username.match(/\./);
const [avatar, banner, profile] = await Promise.all([ const [avatar, banner, profile] = await Promise.all([
user.avatarId ? DriveFiles.findOne(user.avatarId) : Promise.resolve(undefined), user.avatarId ? DriveFiles.findOneBy({ id: user.avatarId }) : Promise.resolve(undefined),
user.bannerId ? DriveFiles.findOne(user.bannerId) : Promise.resolve(undefined), user.bannerId ? DriveFiles.findOneBy({ id: user.bannerId }) : Promise.resolve(undefined),
UserProfiles.findOneOrFail(user.id), UserProfiles.findOneByOrFail({ userId: user.id }),
]); ]);
const attachment: { const attachment: {

View File

@ -7,15 +7,16 @@ import chalk from 'chalk';
import { User, IRemoteUser } from '@/models/entities/user.js'; import { User, IRemoteUser } from '@/models/entities/user.js';
import { Users } from '@/models/index.js'; import { Users } from '@/models/index.js';
import { toPuny } from '@/misc/convert-host.js'; import { toPuny } from '@/misc/convert-host.js';
import { IsNull } from 'typeorm';
const logger = remoteLogger.createSubLogger('resolve-user'); const logger = remoteLogger.createSubLogger('resolve-user');
export async function resolveUser(username: string, host: string | null, option?: any, resync = false): Promise<User> { export async function resolveUser(username: string, host: string | null): Promise<User> {
const usernameLower = username.toLowerCase(); const usernameLower = username.toLowerCase();
if (host == null) { if (host == null) {
logger.info(`return local user: ${usernameLower}`); logger.info(`return local user: ${usernameLower}`);
return await Users.findOne({ usernameLower, host: null }).then(u => { return await Users.findOneBy({ usernameLower, host: IsNull() }).then(u => {
if (u == null) { if (u == null) {
throw new Error('user not found'); throw new Error('user not found');
} else { } else {
@ -28,7 +29,7 @@ export async function resolveUser(username: string, host: string | null, option?
if (config.host === host) { if (config.host === host) {
logger.info(`return local user: ${usernameLower}`); logger.info(`return local user: ${usernameLower}`);
return await Users.findOne({ usernameLower, host: null }).then(u => { return await Users.findOneBy({ usernameLower, host: IsNull() }).then(u => {
if (u == null) { if (u == null) {
throw new Error('user not found'); throw new Error('user not found');
} else { } else {
@ -37,7 +38,7 @@ export async function resolveUser(username: string, host: string | null, option?
}); });
} }
const user = await Users.findOne({ usernameLower, host }, option) as IRemoteUser | null; const user = await Users.findOneBy({ usernameLower, host }) as IRemoteUser | null;
const acctLower = `${usernameLower}@${host}`; const acctLower = `${usernameLower}@${host}`;
@ -48,8 +49,8 @@ export async function resolveUser(username: string, host: string | null, option?
return await createPerson(self.href); return await createPerson(self.href);
} }
// resyncオプション OR ユーザー情報が古い場合は、WebFilgerからやりなおして返す // ユーザー情報が古い場合は、WebFilgerからやりなおして返す
if (resync || user.lastFetchedAt == null || Date.now() - user.lastFetchedAt.getTime() > 1000 * 60 * 60 * 24) { if (user.lastFetchedAt == null || Date.now() - user.lastFetchedAt.getTime() > 1000 * 60 * 60 * 24) {
// 繋がらないインスタンスに何回も試行するのを防ぐ, 後続の同様処理の連続試行を防ぐ ため 試行前にも更新する // 繋がらないインスタンスに何回も試行するのを防ぐ, 後続の同様処理の連続試行を防ぐ ため 試行前にも更新する
await Users.update(user.id, { await Users.update(user.id, {
lastFetchedAt: new Date(), lastFetchedAt: new Date(),
@ -82,7 +83,7 @@ export async function resolveUser(username: string, host: string | null, option?
await updatePerson(self.href); await updatePerson(self.href);
logger.info(`return resynced remote user: ${acctLower}`); logger.info(`return resynced remote user: ${acctLower}`);
return await Users.findOne({ uri: self.href }).then(u => { return await Users.findOneBy({ uri: self.href }).then(u => {
if (u == null) { if (u == null) {
throw new Error('user not found'); throw new Error('user not found');
} else { } else {

View File

@ -15,7 +15,7 @@ import { inbox as processInbox } from '@/queue/index.js';
import { isSelfHost } from '@/misc/convert-host.js'; import { isSelfHost } from '@/misc/convert-host.js';
import { Notes, Users, Emojis, NoteReactions } from '@/models/index.js'; import { Notes, Users, Emojis, NoteReactions } from '@/models/index.js';
import { ILocalUser, User } from '@/models/entities/user.js'; import { ILocalUser, User } from '@/models/entities/user.js';
import { In } from 'typeorm'; import { In, IsNull } from 'typeorm';
import { renderLike } from '@/remote/activitypub/renderer/like.js'; import { renderLike } from '@/remote/activitypub/renderer/like.js';
import { getUserKeypair } from '@/misc/keypair-store.js'; import { getUserKeypair } from '@/misc/keypair-store.js';
@ -65,7 +65,7 @@ router.post('/users/:user/inbox', json(), inbox);
router.get('/notes/:note', async (ctx, next) => { router.get('/notes/:note', async (ctx, next) => {
if (!isActivityPubReq(ctx)) return await next(); if (!isActivityPubReq(ctx)) return await next();
const note = await Notes.findOne({ const note = await Notes.findOneBy({
id: ctx.params.note, id: ctx.params.note,
visibility: In(['public' as const, 'home' as const]), visibility: In(['public' as const, 'home' as const]),
localOnly: false, localOnly: false,
@ -93,9 +93,9 @@ router.get('/notes/:note', async (ctx, next) => {
// note activity // note activity
router.get('/notes/:note/activity', async ctx => { router.get('/notes/:note/activity', async ctx => {
const note = await Notes.findOne({ const note = await Notes.findOneBy({
id: ctx.params.note, id: ctx.params.note,
userHost: null, userHost: IsNull(),
visibility: In(['public' as const, 'home' as const]), visibility: In(['public' as const, 'home' as const]),
localOnly: false, localOnly: false,
}); });
@ -126,9 +126,9 @@ router.get('/users/:user/collections/featured', Featured);
router.get('/users/:user/publickey', async ctx => { router.get('/users/:user/publickey', async ctx => {
const userId = ctx.params.user; const userId = ctx.params.user;
const user = await Users.findOne({ const user = await Users.findOneBy({
id: userId, id: userId,
host: null, host: IsNull(),
}); });
if (user == null) { if (user == null) {
@ -164,9 +164,9 @@ router.get('/users/:user', async (ctx, next) => {
const userId = ctx.params.user; const userId = ctx.params.user;
const user = await Users.findOne({ const user = await Users.findOneBy({
id: userId, id: userId,
host: null, host: IsNull(),
isSuspended: false, isSuspended: false,
}); });
@ -176,9 +176,9 @@ router.get('/users/:user', async (ctx, next) => {
router.get('/@:user', async (ctx, next) => { router.get('/@:user', async (ctx, next) => {
if (!isActivityPubReq(ctx)) return await next(); if (!isActivityPubReq(ctx)) return await next();
const user = await Users.findOne({ const user = await Users.findOneBy({
usernameLower: ctx.params.user.toLowerCase(), usernameLower: ctx.params.user.toLowerCase(),
host: null, host: IsNull(),
isSuspended: false, isSuspended: false,
}); });
@ -188,8 +188,8 @@ router.get('/@:user', async (ctx, next) => {
// emoji // emoji
router.get('/emojis/:emoji', async ctx => { router.get('/emojis/:emoji', async ctx => {
const emoji = await Emojis.findOne({ const emoji = await Emojis.findOneBy({
host: null, host: IsNull(),
name: ctx.params.emoji, name: ctx.params.emoji,
}); });
@ -205,14 +205,14 @@ router.get('/emojis/:emoji', async ctx => {
// like // like
router.get('/likes/:like', async ctx => { router.get('/likes/:like', async ctx => {
const reaction = await NoteReactions.findOne(ctx.params.like); const reaction = await NoteReactions.findOneBy({ id: ctx.params.like });
if (reaction == null) { if (reaction == null) {
ctx.status = 404; ctx.status = 404;
return; return;
} }
const note = await Notes.findOne(reaction.noteId); const note = await Notes.findOneBy({ id: reaction.noteId });
if (note == null) { if (note == null) {
ctx.status = 404; ctx.status = 404;

View File

@ -5,13 +5,14 @@ import renderOrderedCollection from '@/remote/activitypub/renderer/ordered-colle
import { setResponseType } from '../activitypub.js'; import { setResponseType } from '../activitypub.js';
import renderNote from '@/remote/activitypub/renderer/note.js'; import renderNote from '@/remote/activitypub/renderer/note.js';
import { Users, Notes, UserNotePinings } from '@/models/index.js'; import { Users, Notes, UserNotePinings } from '@/models/index.js';
import { IsNull } from 'typeorm';
export default async (ctx: Router.RouterContext) => { export default async (ctx: Router.RouterContext) => {
const userId = ctx.params.user; const userId = ctx.params.user;
const user = await Users.findOne({ const user = await Users.findOneBy({
id: userId, id: userId,
host: null, host: IsNull(),
}); });
if (user == null) { if (user == null) {
@ -25,7 +26,7 @@ export default async (ctx: Router.RouterContext) => {
}); });
const pinnedNotes = await Promise.all(pinings.map(pining => const pinnedNotes = await Promise.all(pinings.map(pining =>
Notes.findOneOrFail(pining.noteId))); Notes.findOneByOrFail({ id: pining.noteId })));
const renderedNotes = await Promise.all(pinnedNotes.map(note => renderNote(note))); const renderedNotes = await Promise.all(pinnedNotes.map(note => renderNote(note)));

View File

@ -9,7 +9,7 @@ import renderOrderedCollectionPage from '@/remote/activitypub/renderer/ordered-c
import renderFollowUser from '@/remote/activitypub/renderer/follow-user.js'; import renderFollowUser from '@/remote/activitypub/renderer/follow-user.js';
import { setResponseType } from '../activitypub.js'; import { setResponseType } from '../activitypub.js';
import { Users, Followings, UserProfiles } from '@/models/index.js'; import { Users, Followings, UserProfiles } from '@/models/index.js';
import { LessThan } from 'typeorm'; import { IsNull, LessThan } from 'typeorm';
export default async (ctx: Router.RouterContext) => { export default async (ctx: Router.RouterContext) => {
const userId = ctx.params.user; const userId = ctx.params.user;
@ -27,9 +27,9 @@ export default async (ctx: Router.RouterContext) => {
return; return;
} }
const user = await Users.findOne({ const user = await Users.findOneBy({
id: userId, id: userId,
host: null, host: IsNull(),
}); });
if (user == null) { if (user == null) {
@ -38,7 +38,7 @@ export default async (ctx: Router.RouterContext) => {
} }
//#region Check ff visibility //#region Check ff visibility
const profile = await UserProfiles.findOneOrFail(user.id); const profile = await UserProfiles.findOneByOrFail({ userId: user.id });
if (profile.ffVisibility === 'private') { if (profile.ffVisibility === 'private') {
ctx.status = 403; ctx.status = 403;

View File

@ -9,7 +9,7 @@ import renderOrderedCollectionPage from '@/remote/activitypub/renderer/ordered-c
import renderFollowUser from '@/remote/activitypub/renderer/follow-user.js'; import renderFollowUser from '@/remote/activitypub/renderer/follow-user.js';
import { setResponseType } from '../activitypub.js'; import { setResponseType } from '../activitypub.js';
import { Users, Followings, UserProfiles } from '@/models/index.js'; import { Users, Followings, UserProfiles } from '@/models/index.js';
import { LessThan, FindConditions } from 'typeorm'; import { LessThan, IsNull, FindOptionsWhere } from 'typeorm';
import { Following } from '@/models/entities/following.js'; import { Following } from '@/models/entities/following.js';
export default async (ctx: Router.RouterContext) => { export default async (ctx: Router.RouterContext) => {
@ -28,9 +28,9 @@ export default async (ctx: Router.RouterContext) => {
return; return;
} }
const user = await Users.findOne({ const user = await Users.findOneBy({
id: userId, id: userId,
host: null, host: IsNull(),
}); });
if (user == null) { if (user == null) {
@ -39,7 +39,7 @@ export default async (ctx: Router.RouterContext) => {
} }
//#region Check ff visibility //#region Check ff visibility
const profile = await UserProfiles.findOneOrFail(user.id); const profile = await UserProfiles.findOneByOrFail({ userId: user.id });
if (profile.ffVisibility === 'private') { if (profile.ffVisibility === 'private') {
ctx.status = 403; ctx.status = 403;
@ -58,7 +58,7 @@ export default async (ctx: Router.RouterContext) => {
if (page) { if (page) {
const query = { const query = {
followerId: user.id, followerId: user.id,
} as FindConditions<Following>; } as FindOptionsWhere<Following>;
// カーソルが指定されている場合 // カーソルが指定されている場合
if (cursor) { if (cursor) {

View File

@ -13,7 +13,7 @@ import { countIf } from '@/prelude/array.js';
import * as url from '@/prelude/url.js'; import * as url from '@/prelude/url.js';
import { Users, Notes } from '@/models/index.js'; import { Users, Notes } from '@/models/index.js';
import { makePaginationQuery } from '../api/common/make-pagination-query.js'; import { makePaginationQuery } from '../api/common/make-pagination-query.js';
import { Brackets } from 'typeorm'; import { Brackets, IsNull } from 'typeorm';
import { Note } from '@/models/entities/note.js'; import { Note } from '@/models/entities/note.js';
export default async (ctx: Router.RouterContext) => { export default async (ctx: Router.RouterContext) => {
@ -35,9 +35,9 @@ export default async (ctx: Router.RouterContext) => {
return; return;
} }
const user = await Users.findOne({ const user = await Users.findOneBy({
id: userId, id: userId,
host: null, host: IsNull(),
}); });
if (user == null) { if (user == null) {
@ -99,7 +99,7 @@ export default async (ctx: Router.RouterContext) => {
*/ */
export async function packActivity(note: Note): Promise<any> { export async function packActivity(note: Note): Promise<any> {
if (note.renoteId && note.text == null && !note.hasPoll && (note.fileIds == null || note.fileIds.length === 0)) { if (note.renoteId && note.text == null && !note.hasPoll && (note.fileIds == null || note.fileIds.length === 0)) {
const renote = await Notes.findOneOrFail(note.renoteId); const renote = await Notes.findOneByOrFail({ id: note.renoteId });
return renderAnnounce(renote.uri ? renote.uri : `${config.url}/notes/${renote.id}`, note); return renderAnnounce(renote.uri ? renote.uri : `${config.url}/notes/${renote.id}`, note);
} }

View File

@ -21,9 +21,8 @@ export default async (token: string | null): Promise<[CacheableLocalUser | null
} }
if (isNativeToken(token)) { if (isNativeToken(token)) {
// TODO: typeorm 3.0にしたら .then(x => x || null) は消せる
const user = await localUserByNativeTokenCache.fetch(token, const user = await localUserByNativeTokenCache.fetch(token,
() => Users.findOne({ token }).then(x => x || null) as Promise<ILocalUser | null>); () => Users.findOneBy({ token }) as Promise<ILocalUser | null>);
if (user == null) { if (user == null) {
throw new AuthenticationError('user not found'); throw new AuthenticationError('user not found');
@ -48,13 +47,13 @@ export default async (token: string | null): Promise<[CacheableLocalUser | null
}); });
const user = await localUserByIdCache.fetch(accessToken.userId, const user = await localUserByIdCache.fetch(accessToken.userId,
() => Users.findOne({ () => Users.findOneBy({
id: accessToken.userId, // findOne(accessToken.userId) のように書かないのは後方互換性のため id: accessToken.userId,
}) as Promise<ILocalUser>); }) as Promise<ILocalUser>);
if (accessToken.appId) { if (accessToken.appId) {
const app = await appCache.fetch(accessToken.appId, const app = await appCache.fetch(accessToken.appId,
() => Apps.findOneOrFail(accessToken.appId!)); () => Apps.findOneByOrFail({ id: accessToken.appId! }));
return [user, { return [user, {
id: accessToken.id, id: accessToken.id,

View File

@ -7,7 +7,7 @@ import { Notes, Users } from '@/models/index.js';
* Get note for API processing * Get note for API processing
*/ */
export async function getNote(noteId: Note['id']) { export async function getNote(noteId: Note['id']) {
const note = await Notes.findOne(noteId); const note = await Notes.findOneBy({ id: noteId });
if (note == null) { if (note == null) {
throw new IdentifiableError('9725d0ce-ba28-4dde-95a7-2cbb2c15de24', 'No such note.'); throw new IdentifiableError('9725d0ce-ba28-4dde-95a7-2cbb2c15de24', 'No such note.');
@ -20,7 +20,7 @@ export async function getNote(noteId: Note['id']) {
* Get user for API processing * Get user for API processing
*/ */
export async function getUser(userId: User['id']) { export async function getUser(userId: User['id']) {
const user = await Users.findOne(userId); const user = await Users.findOneBy({ id: userId });
if (user == null) { if (user == null) {
throw new IdentifiableError('15348ddd-432d-49c2-8a5a-8069753becff', 'No such user.'); throw new IdentifiableError('15348ddd-432d-49c2-8a5a-8069753becff', 'No such user.');

View File

@ -11,7 +11,7 @@ export async function injectFeatured(timeline: Note[], user?: User | null) {
if (timeline.length < 5) return; if (timeline.length < 5) return;
if (user) { if (user) {
const profile = await UserProfiles.findOneOrFail(user.id); const profile = await UserProfiles.findOneByOrFail({ userId: user.id });
if (!profile.injectFeaturedNote) return; if (!profile.injectFeaturedNote) return;
} }

View File

@ -8,7 +8,7 @@ export async function injectPromo(timeline: Note[], user?: User | null) {
// TODO: readやexpireフィルタはクエリ側でやる // TODO: readやexpireフィルタはクエリ側でやる
const reads = user ? await PromoReads.find({ const reads = user ? await PromoReads.findBy({
userId: user.id, userId: user.id,
}) : []; }) : [];
@ -22,10 +22,10 @@ export async function injectPromo(timeline: Note[], user?: User | null) {
// Pick random promo // Pick random promo
const promo = promos[Math.floor(Math.random() * promos.length)]; const promo = promos[Math.floor(Math.random() * promos.length)];
const note = await Notes.findOneOrFail(promo.noteId); const note = await Notes.findOneByOrFail({ id: promo.noteId });
// Join // Join
note.user = await Users.findOneOrFail(note.userId); note.user = await Users.findOneByOrFail({ id: note.userId });
(note as any)._prId_ = rndstr('a-z0-9', 8); (note as any)._prId_ = rndstr('a-z0-9', 8);

View File

@ -23,7 +23,7 @@ export async function readUserMessagingMessage(
) { ) {
if (messageIds.length === 0) return; if (messageIds.length === 0) return;
const messages = await MessagingMessages.find({ const messages = await MessagingMessages.findBy({
id: In(messageIds), id: In(messageIds),
}); });
@ -64,7 +64,7 @@ export async function readGroupMessagingMessage(
if (messageIds.length === 0) return; if (messageIds.length === 0) return;
// check joined // check joined
const joining = await UserGroupJoinings.findOne({ const joining = await UserGroupJoinings.findOneBy({
userId: userId, userId: userId,
userGroupId: groupId, userGroupId: groupId,
}); });
@ -73,7 +73,7 @@ export async function readGroupMessagingMessage(
throw new IdentifiableError('930a270c-714a-46b2-b776-ad27276dc569', 'Access denied (group).'); throw new IdentifiableError('930a270c-714a-46b2-b776-ad27276dc569', 'Access denied (group).');
} }
const messages = await MessagingMessages.find({ const messages = await MessagingMessages.findBy({
id: In(messageIds), id: In(messageIds),
}); });

View File

@ -36,7 +36,7 @@ export default function(ctx: Koa.Context, user: ILocalUser, redirect = false) {
ip: ctx.ip, ip: ctx.ip,
headers: ctx.headers, headers: ctx.headers,
success: true, success: true,
}).then(x => Signins.findOneOrFail(x.identifiers[0])); }).then(x => Signins.findOneByOrFail(x.identifiers[0]));
// Publish signin event // Publish signin event
publishMainStream(user.id, 'signin', await Signins.pack(record)); publishMainStream(user.id, 'signin', await Signins.pack(record));

View File

@ -4,12 +4,13 @@ import generateUserToken from './generate-native-user-token.js';
import { User } from '@/models/entities/user.js'; import { User } from '@/models/entities/user.js';
import { Users, UsedUsernames } from '@/models/index.js'; import { Users, UsedUsernames } from '@/models/index.js';
import { UserProfile } from '@/models/entities/user-profile.js'; import { UserProfile } from '@/models/entities/user-profile.js';
import { getConnection } from 'typeorm'; import { IsNull } from 'typeorm';
import { genId } from '@/misc/gen-id.js'; import { genId } from '@/misc/gen-id.js';
import { toPunyNullable } from '@/misc/convert-host.js'; import { toPunyNullable } from '@/misc/convert-host.js';
import { UserKeypair } from '@/models/entities/user-keypair.js'; import { UserKeypair } from '@/models/entities/user-keypair.js';
import { usersChart } from '@/services/chart/index.js'; import { usersChart } from '@/services/chart/index.js';
import { UsedUsername } from '@/models/entities/used-username.js'; import { UsedUsername } from '@/models/entities/used-username.js';
import { db } from '@/db/postgre.js';
export async function signup(opts: { export async function signup(opts: {
username: User['username']; username: User['username'];
@ -40,12 +41,12 @@ export async function signup(opts: {
const secret = generateUserToken(); const secret = generateUserToken();
// Check username duplication // Check username duplication
if (await Users.findOne({ usernameLower: username.toLowerCase(), host: null })) { if (await Users.findOneBy({ usernameLower: username.toLowerCase(), host: IsNull() })) {
throw new Error('DUPLICATED_USERNAME'); throw new Error('DUPLICATED_USERNAME');
} }
// Check deleted username duplication // Check deleted username duplication
if (await UsedUsernames.findOne({ username: username.toLowerCase() })) { if (await UsedUsernames.findOneBy({ username: username.toLowerCase() })) {
throw new Error('USED_USERNAME'); throw new Error('USED_USERNAME');
} }
@ -69,10 +70,10 @@ export async function signup(opts: {
let account!: User; let account!: User;
// Start transaction // Start transaction
await getConnection().transaction(async transactionalEntityManager => { await db.transaction(async transactionalEntityManager => {
const exist = await transactionalEntityManager.findOne(User, { const exist = await transactionalEntityManager.findOneBy(User, {
usernameLower: username.toLowerCase(), usernameLower: username.toLowerCase(),
host: null, host: IsNull(),
}); });
if (exist) throw new Error(' the username is already used'); if (exist) throw new Error(' the username is already used');
@ -84,8 +85,8 @@ export async function signup(opts: {
usernameLower: username.toLowerCase(), usernameLower: username.toLowerCase(),
host: toPunyNullable(host), host: toPunyNullable(host),
token: secret, token: secret,
isAdmin: (await Users.count({ isAdmin: (await Users.countBy({
host: null, host: IsNull(),
})) === 0, })) === 0,
})); }));

View File

@ -1,6 +1,7 @@
import define from '../../../define.js'; import define from '../../../define.js';
import { Users } from '@/models/index.js'; import { Users } from '@/models/index.js';
import { signup } from '../../../common/signup.js'; import { signup } from '../../../common/signup.js';
import { IsNull } from 'typeorm';
export const meta = { export const meta = {
tags: ['admin'], tags: ['admin'],
@ -29,9 +30,9 @@ export const paramDef = {
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default define(meta, paramDef, async (ps, _me) => { export default define(meta, paramDef, async (ps, _me) => {
const me = _me ? await Users.findOneOrFail(_me.id) : null; const me = _me ? await Users.findOneByOrFail({ id: _me.id }) : null;
const noUsers = (await Users.count({ const noUsers = (await Users.countBy({
host: null, host: IsNull(),
})) === 0; })) === 0;
if (!noUsers && !me?.isAdmin) throw new Error('access denied'); if (!noUsers && !me?.isAdmin) throw new Error('access denied');

View File

@ -21,7 +21,7 @@ export const paramDef = {
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default define(meta, paramDef, async (ps, me) => { export default define(meta, paramDef, async (ps, me) => {
const user = await Users.findOne(ps.userId); const user = await Users.findOneBy({ id: ps.userId });
if (user == null) { if (user == null) {
throw new Error('user not found'); throw new Error('user not found');

View File

@ -27,7 +27,7 @@ export const paramDef = {
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default define(meta, paramDef, async (ps, me) => { export default define(meta, paramDef, async (ps, me) => {
const ad = await Ads.findOne(ps.id); const ad = await Ads.findOneBy({ id: ps.id });
if (ad == null) throw new ApiError(meta.errors.noSuchAd); if (ad == null) throw new ApiError(meta.errors.noSuchAd);

View File

@ -34,7 +34,7 @@ export const paramDef = {
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default define(meta, paramDef, async (ps, me) => { export default define(meta, paramDef, async (ps, me) => {
const ad = await Ads.findOne(ps.id); const ad = await Ads.findOneBy({ id: ps.id });
if (ad == null) throw new ApiError(meta.errors.noSuchAd); if (ad == null) throw new ApiError(meta.errors.noSuchAd);

View File

@ -63,7 +63,7 @@ export default define(meta, paramDef, async (ps) => {
title: ps.title, title: ps.title,
text: ps.text, text: ps.text,
imageUrl: ps.imageUrl, imageUrl: ps.imageUrl,
}).then(x => Announcements.findOneOrFail(x.identifiers[0])); }).then(x => Announcements.findOneByOrFail(x.identifiers[0]));
return Object.assign({}, announcement, { createdAt: announcement.createdAt.toISOString(), updatedAt: null }); return Object.assign({}, announcement, { createdAt: announcement.createdAt.toISOString(), updatedAt: null });
}); });

View File

@ -27,7 +27,7 @@ export const paramDef = {
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default define(meta, paramDef, async (ps, me) => { export default define(meta, paramDef, async (ps, me) => {
const announcement = await Announcements.findOne(ps.id); const announcement = await Announcements.findOneBy({ id: ps.id });
if (announcement == null) throw new ApiError(meta.errors.noSuchAnnouncement); if (announcement == null) throw new ApiError(meta.errors.noSuchAnnouncement);

View File

@ -69,7 +69,7 @@ export default define(meta, paramDef, async (ps) => {
const announcements = await query.take(ps.limit).getMany(); const announcements = await query.take(ps.limit).getMany();
for (const announcement of announcements) { for (const announcement of announcements) {
(announcement as any).reads = await AnnouncementReads.count({ (announcement as any).reads = await AnnouncementReads.countBy({
announcementId: announcement.id, announcementId: announcement.id,
}); });
} }

View File

@ -30,7 +30,7 @@ export const paramDef = {
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default define(meta, paramDef, async (ps, me) => { export default define(meta, paramDef, async (ps, me) => {
const announcement = await Announcements.findOne(ps.id); const announcement = await Announcements.findOneBy({ id: ps.id });
if (announcement == null) throw new ApiError(meta.errors.noSuchAnnouncement); if (announcement == null) throw new ApiError(meta.errors.noSuchAnnouncement);

View File

@ -19,7 +19,7 @@ export const paramDef = {
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default define(meta, paramDef, async (ps, me) => { export default define(meta, paramDef, async (ps, me) => {
const files = await DriveFiles.find({ const files = await DriveFiles.findBy({
userId: ps.userId, userId: ps.userId,
}); });

View File

@ -18,7 +18,7 @@ export const paramDef = {
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default define(meta, paramDef, async (ps, me) => { export default define(meta, paramDef, async (ps, me) => {
const files = await DriveFiles.find({ const files = await DriveFiles.findBy({
userId: IsNull(), userId: IsNull(),
}); });

Some files were not shown because too many files have changed in this diff Show More