diff --git a/CHANGELOG.md b/CHANGELOG.md index 015374e2db..ec50b1fc2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ You should also include the user name that made the change. ### Improvements - Bull Dashboardを組み込み、ジョブキューの確認や操作を行えるように @syuilo - Check that installed Node.js version fulfills version requirement @ThatOneCalculator +- Server: performance improvements @syuilo ### Bugfixes - API: fix endpoint endpoint @Johann150 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6e0f500be5..a696bc5ceb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,6 +6,9 @@ Also, you might receive comments on your Issue/PR in Japanese, but you do not ne The accuracy of machine translation into Japanese is not high, so it will be easier for us to understand if you write it in the original language. It will also allow the reader to use the translation tool of their preference if necessary. +## Roadmap +See [ROADMAP.md](./ROADMAP.md) + ## Issues Before creating an issue, please check the following: - To avoid duplication, please search for similar issues before creating a new issue. @@ -198,11 +201,13 @@ MongoDBの時とは違い、findOneでレコードを取得する時に対象レ MongoDBは`null`で返してきてたので、その感覚で`if (x === null)`とか書くとバグる。代わりに`if (x == null)`と書いてください ### Migration作成方法 -``` -npx ts-node ./node_modules/typeorm/cli.js migration:generate -n 変更の名前 -o +packages/backendで: +```sh +npx typeorm migration:generate -d ormconfig.js -o ``` -作成されたスクリプトは不必要な変更を含むため除去してください。 +- 生成後、ファイルをmigration下に移してください +- 作成されたスクリプトは不必要な変更を含むため除去してください ### コネクションには`markRaw`せよ **Vueのコンポーネントのdataオプションとして**misskey.jsのコネクションを設定するとき、必ず`markRaw`でラップしてください。インスタンスが不必要にリアクティブ化されることで、misskey.js内の処理で不具合が発生するとともに、パフォーマンス上の問題にも繋がる。なお、Composition APIを使う場合はこの限りではない(リアクティブ化はマニュアルなため)。 diff --git a/ROADMAP.md b/ROADMAP.md new file mode 100644 index 0000000000..c12526bbce --- /dev/null +++ b/ROADMAP.md @@ -0,0 +1,28 @@ +# Roadmap +The order of individual tasks is a guide only and is subject to change depending on the situation. +Also, the later tasks are more indefinite and are subject to change as development progresses. + +## (1) Improve maintainability \ +This is the phase we are at now. We need to make a high-maintenance environment that can withstand future development. + +- Make the number of type errors zero (backend) + - Probably need to switch some libraries to others that make it difficult to reduce type errors + - e.g. koa to fastify https://github.com/misskey-dev/misskey/issues/7537 +- Improve CI + - Fix tests + - mocha, jest, etc. do not support the combination of `TypeScript + ESM + Path alias`, and the tests currently do not work. + - Fix random test failures - https://github.com/misskey-dev/misskey/issues/7985 and https://github.com/misskey-dev/misskey/issues/7986 + - Add more tests + - May need to implement a mechanism that allows for DI +- Improve documentation + +## (2) Improve functionality +Once Phase 1 is complete and an environment conducive to the development of a stable system is in place, the implementation of new functions can begin gradually. + +- OAuth2 support https://github.com/misskey-dev/misskey/issues/8262 +- GraphQL support? + +## (3) Improve scalability +Once the development of the feature has settled down, this may be an opportunity to make larger modifications. + +- Rewriting in Rust? diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 2ee312a306..4d04cd28c8 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -841,6 +841,7 @@ oneHour: "1時間" oneDay: "1日" oneWeek: "1週間" reflectMayTakeTime: "反映されるまで時間がかかる場合があります。" +failedToFetchAccountInformation: "アカウント情報の取得に失敗しました" _emailUnavailable: used: "既に使用されています" diff --git a/package.json b/package.json index ea691dec50..cc49d1ffa4 100644 --- a/package.json +++ b/package.json @@ -13,8 +13,7 @@ "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", "init": "npm run migrate", - "ormconfig": "node ./packages/backend/ormconfig.js", - "migrate": "cd packages/backend && npx typeorm migration:run", + "migrate": "cd packages/backend && npx typeorm migration:run -d ormconfig.js", "migrateandstart": "npm run migrate && npm run start", "gulp": "gulp build", "watch": "npm run dev", @@ -42,10 +41,10 @@ "js-yaml": "4.1.0" }, "devDependencies": { - "@typescript-eslint/parser": "5.15.0", + "@typescript-eslint/parser": "5.16.0", "cross-env": "7.0.3", "cypress": "9.5.2", "start-server-and-test": "1.14.0", - "typescript": "4.6.2" + "typescript": "4.6.3" } } diff --git a/packages/backend/ormconfig.js b/packages/backend/ormconfig.js index b8150f7014..a4e903abad 100644 --- a/packages/backend/ormconfig.js +++ b/packages/backend/ormconfig.js @@ -1,7 +1,8 @@ +import { DataSource } from 'typeorm'; import config from './built/config/index.js'; import { entities } from './built/db/postgre.js'; -export default { +export default new DataSource({ type: 'postgres', host: config.db.host, port: config.db.port, @@ -11,7 +12,4 @@ export default { extra: config.db.extra, entities: entities, migrations: ['migration/*.js'], - cli: { - migrationsDir: 'migration' - } -}; +}); diff --git a/packages/backend/package.json b/packages/backend/package.json index 07904098f9..91c099e9f2 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -3,7 +3,6 @@ "private": true, "type": "module", "scripts": { - "init": "npm run migrate", "build": "tsc -p tsconfig.json || echo done. && tsc-alias -p tsconfig.json", "watch": "node watch.mjs", "lint": "eslint --quiet src/**/*.ts", @@ -31,7 +30,7 @@ "@types/jsdom": "16.2.14", "@types/jsonld": "1.5.6", "@types/koa": "2.13.4", - "@types/koa-bodyparser": "4.3.6", + "@types/koa-bodyparser": "4.3.7", "@types/koa-cors": "0.0.2", "@types/koa-favicon": "2.0.21", "@types/koa-logger": "3.1.2", @@ -42,7 +41,7 @@ "@types/koa__multer": "2.0.4", "@types/koa__router": "8.0.11", "@types/mocha": "9.1.0", - "@types/node": "17.0.21", + "@types/node": "17.0.23", "@types/node-fetch": "3.0.3", "@types/nodemailer": "6.4.4", "@types/oauth": "0.9.1", @@ -57,7 +56,7 @@ "@types/rename": "1.0.4", "@types/sanitize-html": "2.6.2", "@types/sharp": "0.30.0", - "@types/sinonjs__fake-timers": "8.1.1", + "@types/sinonjs__fake-timers": "8.1.2", "@types/speakeasy": "2.0.7", "@types/throttle-debounce": "2.1.0", "@types/tinycolor2": "1.4.3", @@ -66,19 +65,19 @@ "@types/web-push": "3.3.2", "@types/websocket": "1.0.5", "@types/ws": "8.5.3", - "@typescript-eslint/eslint-plugin": "5.15.0", - "@typescript-eslint/parser": "5.15.0", - "@bull-board/koa": "3.10.0", + "@typescript-eslint/eslint-plugin": "5.16.0", + "@typescript-eslint/parser": "5.16.0", + "@bull-board/koa": "3.10.1", "abort-controller": "3.0.0", - "ajv": "8.10.0", + "ajv": "8.11.0", "archiver": "5.3.0", "autobind-decorator": "2.4.0", "autwh": "0.1.0", - "aws-sdk": "2.1096.0", + "aws-sdk": "2.1100.0", "bcryptjs": "2.4.3", "blurhash": "1.1.5", "broadcast-channel": "4.10.0", - "bull": "4.7.0", + "bull": "4.8.1", "cacheable-lookup": "6.0.4", "cafy": "15.2.1", "cbor": "8.1.0", @@ -90,19 +89,19 @@ "date-fns": "2.28.0", "deep-email-validator": "0.1.21", "escape-regexp": "0.0.1", - "eslint": "8.11.0", + "eslint": "8.12.0", "eslint-plugin-import": "2.25.4", "feed": "4.2.2", "file-type": "17.1.1", "fluent-ffmpeg": "2.1.2", - "got": "12.0.2", + "got": "12.0.3", "hpagent": "0.1.2", "http-signature": "1.3.6", "ip-cidr": "3.0.4", "is-svg": "4.3.2", "js-yaml": "4.1.0", "jsdom": "19.0.0", - "json5": "2.2.0", + "json5": "2.2.1", "json5-loader": "4.0.1", "jsonld": "5.2.0", "jsrsasign": "8.0.20", @@ -123,7 +122,7 @@ "multer": "1.4.4", "nested-property": "4.0.0", "node-fetch": "3.2.3", - "nodemailer": "6.7.2", + "nodemailer": "6.7.3", "os-utils": "0.0.14", "parse5": "6.0.1", "pg": "8.7.3", @@ -154,17 +153,17 @@ "style-loader": "3.3.1", "summaly": "2.5.0", "syslog-pro": "1.0.0", - "systeminformation": "5.11.8", + "systeminformation": "5.11.9", "throttle-debounce": "3.0.1", "tinycolor2": "1.4.2", "tmp": "0.2.1", "ts-loader": "9.2.8", "ts-node": "10.7.0", "tsc-alias": "1.4.1", - "tsconfig-paths": "3.14.0", + "tsconfig-paths": "3.14.1", "twemoji-parser": "14.0.0", - "typeorm": "0.2.45", - "typescript": "4.6.2", + "typeorm": "0.3.4", + "typescript": "4.6.3", "ulid": "2.3.0", "unzipper": "0.10.11", "uuid": "8.3.2", @@ -174,7 +173,7 @@ "xev": "2.0.1" }, "devDependencies": { - "@redocly/openapi-core": "1.0.0-beta.88", + "@redocly/openapi-core": "1.0.0-beta.90", "@types/fluent-ffmpeg": "2.1.20", "cross-env": "7.0.3", "execa": "6.1.0" diff --git a/packages/backend/src/boot/master.ts b/packages/backend/src/boot/master.ts index 48f0f81564..09d20f9361 100644 --- a/packages/backend/src/boot/master.ts +++ b/packages/backend/src/boot/master.ts @@ -7,7 +7,6 @@ import chalk from 'chalk'; import chalkTemplate from 'chalk-template'; import * as portscanner from 'portscanner'; import semver from 'semver'; -import { getConnection } from 'typeorm'; import Logger from '@/services/logger.js'; import loadConfig from '@/config/load.js'; @@ -15,7 +14,7 @@ import { Config } from '@/config/types.js'; import { lessThan } from '@/prelude/array.js'; import { envOption } from '../env.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 _dirname = dirname(_filename); @@ -144,7 +143,7 @@ async function connectDb(): Promise { try { dbLogger.info('Connecting...'); 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}`); } catch (e) { dbLogger.error('Cannot connect', null, true); diff --git a/packages/backend/src/db/postgre.ts b/packages/backend/src/db/postgre.ts index 5fd1f95cca..491c1a174f 100644 --- a/packages/backend/src/db/postgre.ts +++ b/packages/backend/src/db/postgre.ts @@ -2,9 +2,10 @@ import pg from 'pg'; pg.types.setTypeParser(20, Number); -import { createConnection, Logger, getConnection } from 'typeorm'; +import { Logger, DataSource } from 'typeorm'; import * as highlight from 'cli-highlight'; import config from '@/config/index.js'; +import { envOption } from '../env.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 { PromoNote } from '@/models/entities/promo-note.js'; import { PromoRead } from '@/models/entities/promo-read.js'; -import { envOption } from '../env.js'; import { Relay } from '@/models/entities/relay.js'; import { MutedNote } from '@/models/entities/muted-note.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'; -const sqlLogger = dbLogger.createSubLogger('sql', 'white', false); +const sqlLogger = dbLogger.createSubLogger('sql', 'gray', false); class MyCustomLogger implements Logger { private highlight(sql: string) { @@ -84,9 +84,7 @@ class MyCustomLogger implements Logger { } 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[]) { @@ -176,55 +174,51 @@ export const entities = [ ...charts, ]; -export function initDb(justBorrow = false, sync = false, forceRecreate = false) { - if (!forceRecreate) { - try { - const conn = getConnection(); - return Promise.resolve(conn); - } catch (e) {} - } +const log = process.env.NODE_ENV !== 'production'; - const log = process.env.NODE_ENV !== 'production'; - - return createConnection({ - type: 'postgres', - host: config.db.host, - port: config.db.port, - username: config.db.user, - password: config.db.pass, - database: config.db.db, - extra: { - statement_timeout: 1000 * 10, - ...config.db.extra, +export const db = new DataSource({ + type: 'postgres', + host: config.db.host, + port: config.db.port, + username: config.db.user, + password: config.db.pass, + database: config.db.db, + extra: { + statement_timeout: 1000 * 10, + ...config.db.extra, + }, + synchronize: process.env.NODE_ENV === 'test', + dropSchema: process.env.NODE_ENV === 'test', + cache: !config.db.disableCache ? { + type: 'redis', + options: { + host: config.redis.host, + port: config.redis.port, + password: config.redis.pass, + prefix: `${config.redis.prefix}:query:`, + db: config.redis.db || 0, }, - synchronize: process.env.NODE_ENV === 'test' || sync, - dropSchema: process.env.NODE_ENV === 'test' && !justBorrow, - cache: !config.db.disableCache ? { - type: 'redis', - options: { - host: config.redis.host, - port: config.redis.port, - password: config.redis.pass, - prefix: `${config.redis.prefix}:query:`, - db: config.redis.db || 0, - }, - } : false, - logging: log, - logger: log ? new MyCustomLogger() : undefined, - entities: entities, - }); + } : false, + logging: log, + logger: log ? new MyCustomLogger() : undefined, + maxQueryExecutionTime: 300, + entities: entities, + migrations: ['../../migration/*.js'], +}); + +export async function initDb() { + await db.connect(); } export async function resetDb() { const reset = async () => { - const conn = await getConnection(); - const tables = await conn.query(`SELECT relname AS "table" + const tables = await db.query(`SELECT relname AS "table" FROM pg_class C LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) WHERE nspname NOT IN ('pg_catalog', 'information_schema') AND C.relkind = 'r' AND nspname !~ '^pg_toast';`); for (const table of tables) { - await conn.query(`DELETE FROM "${table.table}" CASCADE`); + await db.query(`DELETE FROM "${table.table}" CASCADE`); } }; diff --git a/packages/backend/src/misc/cache.ts b/packages/backend/src/misc/cache.ts index e9966b7785..01bbe98a85 100644 --- a/packages/backend/src/misc/cache.ts +++ b/packages/backend/src/misc/cache.ts @@ -1,5 +1,5 @@ export class Cache { - private cache: Map; + public cache: Map; private lifetime: number; constructor(lifetime: Cache['lifetime']) { @@ -48,7 +48,32 @@ export class Cache { // Cache MISS const value = await fetcher(); - this.set(key, value); + return value; + } + + /** + * キャッシュがあればそれを返し、無ければfetcherを呼び出して結果をキャッシュ&返します + * optional: キャッシュが存在してもvalidatorでfalseを返すとキャッシュ無効扱いにします + */ + public async fetchMaybe(key: string | null, fetcher: () => Promise, validator?: (cachedValue: T) => boolean): Promise { + const cachedValue = this.get(key); + if (cachedValue !== undefined) { + if (validator) { + if (validator(cachedValue)) { + // Cache HIT + return cachedValue; + } + } else { + // Cache HIT + return cachedValue; + } + } + + // Cache MISS + const value = await fetcher(); + if (value !== undefined) { + this.set(key, value); + } return value; } } diff --git a/packages/backend/src/misc/check-hit-antenna.ts b/packages/backend/src/misc/check-hit-antenna.ts index 745db391a4..d9cedee7df 100644 --- a/packages/backend/src/misc/check-hit-antenna.ts +++ b/packages/backend/src/misc/check-hit-antenna.ts @@ -18,7 +18,7 @@ export async function checkHitAntenna(antenna: Antenna, note: (Note | Packed<'No 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 (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 (antennaUserFollowing && !antennaUserFollowing.includes(note.userId)) return false; } else if (antenna.src === 'list') { - const listUsers = (await UserListJoinings.find({ + const listUsers = (await UserListJoinings.findBy({ userListId: antenna.userListId!, })).map(x => x.userId); if (!listUsers.includes(note.userId)) return false; } 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, })).map(x => x.userId); diff --git a/packages/backend/src/misc/fetch-meta.ts b/packages/backend/src/misc/fetch-meta.ts index 9f85d3d1db..5417c10962 100644 --- a/packages/backend/src/misc/fetch-meta.ts +++ b/packages/backend/src/misc/fetch-meta.ts @@ -1,19 +1,21 @@ +import { db } from '@/db/postgre.js'; import { Meta } from '@/models/entities/meta.js'; -import { getConnection } from 'typeorm'; let cache: Meta; export async function fetchMeta(noCache = false): Promise { if (!noCache && cache) return cache; - return await getConnection().transaction(async transactionalEntityManager => { + return await db.transaction(async transactionalEntityManager => { // 過去のバグでレコードが複数出来てしまっている可能性があるので新しいIDを優先する - const meta = await transactionalEntityManager.findOne(Meta, { + const metas = await transactionalEntityManager.find(Meta, { order: { id: 'DESC', }, }); + const meta = metas[0]; + if (meta) { cache = meta; return meta; diff --git a/packages/backend/src/misc/fetch-proxy-account.ts b/packages/backend/src/misc/fetch-proxy-account.ts index ed8a4c794d..b61bba264b 100644 --- a/packages/backend/src/misc/fetch-proxy-account.ts +++ b/packages/backend/src/misc/fetch-proxy-account.ts @@ -5,5 +5,5 @@ import { Users } from '@/models/index.js'; export async function fetchProxyAccount(): Promise { const meta = await fetchMeta(); if (meta.proxyAccountId == null) return null; - return await Users.findOneOrFail(meta.proxyAccountId) as ILocalUser; + return await Users.findOneByOrFail({ id: meta.proxyAccountId }) as ILocalUser; } diff --git a/packages/backend/src/misc/keypair-store.ts b/packages/backend/src/misc/keypair-store.ts index 3d505c0abb..1183b9a781 100644 --- a/packages/backend/src/misc/keypair-store.ts +++ b/packages/backend/src/misc/keypair-store.ts @@ -6,5 +6,5 @@ import { Cache } from './cache.js'; const cache = new Cache(Infinity); export async function getUserKeypair(userId: User['id']): Promise { - return await cache.fetch(userId, () => UserKeypairs.findOneOrFail(userId)); + return await cache.fetch(userId, () => UserKeypairs.findOneByOrFail({ userId: userId })); } diff --git a/packages/backend/src/misc/populate-emojis.ts b/packages/backend/src/misc/populate-emojis.ts index 4953c6890b..86f1356c31 100644 --- a/packages/backend/src/misc/populate-emojis.ts +++ b/packages/backend/src/misc/populate-emojis.ts @@ -1,4 +1,4 @@ -import { In } from 'typeorm'; +import { In, IsNull } from 'typeorm'; import { Emojis } from '@/models/index.js'; import { Emoji } from '@/models/entities/emoji.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); if (name == null) return null; - const queryOrNull = async () => (await Emojis.findOne({ + const queryOrNull = async () => (await Emojis.findOneBy({ name, - host, + host: host ?? IsNull(), })) || null; 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) { emojisQuery.push({ 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({ diff --git a/packages/backend/src/misc/reaction-lib.ts b/packages/backend/src/misc/reaction-lib.ts index 086944ccfb..fefc2781f3 100644 --- a/packages/backend/src/misc/reaction-lib.ts +++ b/packages/backend/src/misc/reaction-lib.ts @@ -3,6 +3,7 @@ import { emojiRegex } from './emoji-regex.js'; import { fetchMeta } from './fetch-meta.js'; import { Emojis } from '@/models/index.js'; import { toPunyNullable } from './convert-host.js'; +import { IsNull } from 'typeorm'; const legacies: Record = { 'like': '👍', @@ -74,8 +75,8 @@ export async function toDbReaction(reaction?: string | null, reacterHost?: strin const custom = reaction.match(/^:([\w+-]+)(?:@\.)?:$/); if (custom) { const name = custom[1]; - const emoji = await Emojis.findOne({ - host: reacterHost || null, + const emoji = await Emojis.findOneBy({ + host: reacterHost ?? IsNull(), name, }); diff --git a/packages/backend/src/models/entities/user.ts b/packages/backend/src/models/entities/user.ts index 9d5db10eb3..c76824c977 100644 --- a/packages/backend/src/models/entities/user.ts +++ b/packages/backend/src/models/entities/user.ts @@ -234,3 +234,9 @@ export interface ILocalUser extends User { export interface IRemoteUser extends User { host: string; } + +export type CacheableLocalUser = ILocalUser; + +export type CacheableRemoteUser = IRemoteUser; + +export type CacheableUser = CacheableLocalUser | CacheableRemoteUser; diff --git a/packages/backend/src/models/index.ts b/packages/backend/src/models/index.ts index e7b6854886..54582347c7 100644 --- a/packages/backend/src/models/index.ts +++ b/packages/backend/src/models/index.ts @@ -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 { AnnouncementRead } from './entities/announcement-read.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 { InstanceRepository } from './repositories/instance.js'; -export const Announcements = getRepository(Announcement); -export const AnnouncementReads = getRepository(AnnouncementRead); -export const Apps = getCustomRepository(AppRepository); -export const Notes = getCustomRepository(NoteRepository); -export const NoteFavorites = getCustomRepository(NoteFavoriteRepository); -export const NoteWatchings = getRepository(NoteWatching); -export const NoteThreadMutings = getRepository(NoteThreadMuting); -export const NoteReactions = getCustomRepository(NoteReactionRepository); -export const NoteUnreads = getRepository(NoteUnread); -export const Polls = getRepository(Poll); -export const PollVotes = getRepository(PollVote); -export const Users = getCustomRepository(UserRepository); -export const UserProfiles = getRepository(UserProfile); -export const UserKeypairs = getRepository(UserKeypair); -export const UserPendings = getRepository(UserPending); -export const AttestationChallenges = getRepository(AttestationChallenge); -export const UserSecurityKeys = getRepository(UserSecurityKey); -export const UserPublickeys = getRepository(UserPublickey); -export const UserLists = getCustomRepository(UserListRepository); -export const UserListJoinings = getRepository(UserListJoining); -export const UserGroups = getCustomRepository(UserGroupRepository); -export const UserGroupJoinings = getRepository(UserGroupJoining); -export const UserGroupInvitations = getCustomRepository(UserGroupInvitationRepository); -export const UserNotePinings = getRepository(UserNotePining); -export const UsedUsernames = getRepository(UsedUsername); -export const Followings = getCustomRepository(FollowingRepository); -export const FollowRequests = getCustomRepository(FollowRequestRepository); -export const Instances = getCustomRepository(InstanceRepository); -export const Emojis = getCustomRepository(EmojiRepository); -export const DriveFiles = getCustomRepository(DriveFileRepository); -export const DriveFolders = getCustomRepository(DriveFolderRepository); -export const Notifications = getCustomRepository(NotificationRepository); -export const Metas = getRepository(Meta); -export const Mutings = getCustomRepository(MutingRepository); -export const Blockings = getCustomRepository(BlockingRepository); -export const SwSubscriptions = getRepository(SwSubscription); -export const Hashtags = getCustomRepository(HashtagRepository); -export const AbuseUserReports = getCustomRepository(AbuseUserReportRepository); -export const RegistrationTickets = getRepository(RegistrationTicket); -export const AuthSessions = getCustomRepository(AuthSessionRepository); -export const AccessTokens = getRepository(AccessToken); -export const Signins = getCustomRepository(SigninRepository); -export const MessagingMessages = getCustomRepository(MessagingMessageRepository); -export const Pages = getCustomRepository(PageRepository); -export const PageLikes = getCustomRepository(PageLikeRepository); -export const GalleryPosts = getCustomRepository(GalleryPostRepository); -export const GalleryLikes = getCustomRepository(GalleryLikeRepository); -export const ModerationLogs = getCustomRepository(ModerationLogRepository); -export const Clips = getCustomRepository(ClipRepository); -export const ClipNotes = getRepository(ClipNote); -export const Antennas = getCustomRepository(AntennaRepository); -export const AntennaNotes = getRepository(AntennaNote); -export const PromoNotes = getRepository(PromoNote); -export const PromoReads = getRepository(PromoRead); -export const Relays = getCustomRepository(RelayRepository); -export const MutedNotes = getRepository(MutedNote); -export const Channels = getCustomRepository(ChannelRepository); -export const ChannelFollowings = getRepository(ChannelFollowing); -export const ChannelNotePinings = getRepository(ChannelNotePining); -export const RegistryItems = getRepository(RegistryItem); -export const Ads = getRepository(Ad); -export const PasswordResetRequests = getRepository(PasswordResetRequest); +export const Announcements = db.getRepository(Announcement); +export const AnnouncementReads = db.getRepository(AnnouncementRead); +export const Apps = (AppRepository); +export const Notes = (NoteRepository); +export const NoteFavorites = (NoteFavoriteRepository); +export const NoteWatchings = db.getRepository(NoteWatching); +export const NoteThreadMutings = db.getRepository(NoteThreadMuting); +export const NoteReactions = (NoteReactionRepository); +export const NoteUnreads = db.getRepository(NoteUnread); +export const Polls = db.getRepository(Poll); +export const PollVotes = db.getRepository(PollVote); +export const Users = (UserRepository); +export const UserProfiles = db.getRepository(UserProfile); +export const UserKeypairs = db.getRepository(UserKeypair); +export const UserPendings = db.getRepository(UserPending); +export const AttestationChallenges = db.getRepository(AttestationChallenge); +export const UserSecurityKeys = db.getRepository(UserSecurityKey); +export const UserPublickeys = db.getRepository(UserPublickey); +export const UserLists = (UserListRepository); +export const UserListJoinings = db.getRepository(UserListJoining); +export const UserGroups = (UserGroupRepository); +export const UserGroupJoinings = db.getRepository(UserGroupJoining); +export const UserGroupInvitations = (UserGroupInvitationRepository); +export const UserNotePinings = db.getRepository(UserNotePining); +export const UsedUsernames = db.getRepository(UsedUsername); +export const Followings = (FollowingRepository); +export const FollowRequests = (FollowRequestRepository); +export const Instances = (InstanceRepository); +export const Emojis = (EmojiRepository); +export const DriveFiles = (DriveFileRepository); +export const DriveFolders = (DriveFolderRepository); +export const Notifications = (NotificationRepository); +export const Metas = db.getRepository(Meta); +export const Mutings = (MutingRepository); +export const Blockings = (BlockingRepository); +export const SwSubscriptions = db.getRepository(SwSubscription); +export const Hashtags = (HashtagRepository); +export const AbuseUserReports = (AbuseUserReportRepository); +export const RegistrationTickets = db.getRepository(RegistrationTicket); +export const AuthSessions = (AuthSessionRepository); +export const AccessTokens = db.getRepository(AccessToken); +export const Signins = (SigninRepository); +export const MessagingMessages = (MessagingMessageRepository); +export const Pages = (PageRepository); +export const PageLikes = (PageLikeRepository); +export const GalleryPosts = (GalleryPostRepository); +export const GalleryLikes = (GalleryLikeRepository); +export const ModerationLogs = (ModerationLogRepository); +export const Clips = (ClipRepository); +export const ClipNotes = db.getRepository(ClipNote); +export const Antennas = (AntennaRepository); +export const AntennaNotes = db.getRepository(AntennaNote); +export const PromoNotes = db.getRepository(PromoNote); +export const PromoReads = db.getRepository(PromoRead); +export const Relays = (RelayRepository); +export const MutedNotes = db.getRepository(MutedNote); +export const Channels = (ChannelRepository); +export const ChannelFollowings = db.getRepository(ChannelFollowing); +export const ChannelNotePinings = db.getRepository(ChannelNotePining); +export const RegistryItems = db.getRepository(RegistryItem); +export const Ads = db.getRepository(Ad); +export const PasswordResetRequests = db.getRepository(PasswordResetRequest); diff --git a/packages/backend/src/models/repositories/abuse-user-report.ts b/packages/backend/src/models/repositories/abuse-user-report.ts index 348f88b3a2..36d7ab90c5 100644 --- a/packages/backend/src/models/repositories/abuse-user-report.ts +++ b/packages/backend/src/models/repositories/abuse-user-report.ts @@ -1,14 +1,13 @@ -import { EntityRepository, Repository } from 'typeorm'; +import { db } from '@/db/postgre.js'; import { Users } from '../index.js'; import { AbuseUserReport } from '@/models/entities/abuse-user-report.js'; import { awaitAll } from '@/prelude/await-all.js'; -@EntityRepository(AbuseUserReport) -export class AbuseUserReportRepository extends Repository { - public async pack( +export const AbuseUserReportRepository = db.getRepository(AbuseUserReport).extend({ + async pack( 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({ id: report.id, @@ -29,11 +28,11 @@ export class AbuseUserReportRepository extends Repository { }) : null, forwarded: report.forwarded, }); - } + }, - public packMany( + packMany( reports: any[], ) { return Promise.all(reports.map(x => this.pack(x))); - } -} + }, +}); diff --git a/packages/backend/src/models/repositories/antenna.ts b/packages/backend/src/models/repositories/antenna.ts index 3440ca1871..70180e2dec 100644 --- a/packages/backend/src/models/repositories/antenna.ts +++ b/packages/backend/src/models/repositories/antenna.ts @@ -1,17 +1,16 @@ -import { EntityRepository, Repository } from 'typeorm'; +import { db } from '@/db/postgre.js'; import { Antenna } from '@/models/entities/antenna.js'; import { Packed } from '@/misc/schema.js'; import { AntennaNotes, UserGroupJoinings } from '../index.js'; -@EntityRepository(Antenna) -export class AntennaRepository extends Repository { - public async pack( +export const AntennaRepository = db.getRepository(Antenna).extend({ + async pack( src: Antenna['id'] | Antenna, ): Promise> { - 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 userGroupJoining = antenna.userGroupJoiningId ? await UserGroupJoinings.findOne(antenna.userGroupJoiningId) : null; + const hasUnreadNote = (await AntennaNotes.findOneBy({ antennaId: antenna.id, read: false })) != null; + const userGroupJoining = antenna.userGroupJoiningId ? await UserGroupJoinings.findOneBy({ id: antenna.userGroupJoiningId }) : null; return { id: antenna.id, @@ -29,5 +28,5 @@ export class AntennaRepository extends Repository { withFile: antenna.withFile, hasUnreadNote, }; - } -} + }, +}); diff --git a/packages/backend/src/models/repositories/app.ts b/packages/backend/src/models/repositories/app.ts index 4c3c488da0..e08dd6f0e3 100644 --- a/packages/backend/src/models/repositories/app.ts +++ b/packages/backend/src/models/repositories/app.ts @@ -1,12 +1,11 @@ -import { EntityRepository, Repository } from 'typeorm'; +import { db } from '@/db/postgre.js'; import { App } from '@/models/entities/app.js'; import { AccessTokens } from '../index.js'; import { Packed } from '@/misc/schema.js'; import { User } from '../entities/user.js'; -@EntityRepository(App) -export class AppRepository extends Repository { - public async pack( +export const AppRepository = db.getRepository(App).extend({ + async pack( src: App['id'] | App, me?: { id: User['id'] } | null | undefined, options?: { @@ -21,7 +20,7 @@ export class AppRepository extends Repository { includeProfileImageIds: false, }, options); - const app = typeof src === 'object' ? src : await this.findOneOrFail(src); + const app = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); return { id: app.id, @@ -30,11 +29,11 @@ export class AppRepository extends Repository { permission: app.permission, ...(opts.includeSecret ? { secret: app.secret } : {}), ...(me ? { - isAuthorized: await AccessTokens.count({ + isAuthorized: await AccessTokens.countBy({ appId: app.id, userId: me.id, }).then(count => count > 0), } : {}), }; - } -} + }, +}); diff --git a/packages/backend/src/models/repositories/auth-session.ts b/packages/backend/src/models/repositories/auth-session.ts index 7a7bd3a1ed..3f1f6f4897 100644 --- a/packages/backend/src/models/repositories/auth-session.ts +++ b/packages/backend/src/models/repositories/auth-session.ts @@ -1,21 +1,20 @@ -import { EntityRepository, Repository } from 'typeorm'; +import { db } from '@/db/postgre.js'; import { Apps } from '../index.js'; import { AuthSession } from '@/models/entities/auth-session.js'; import { awaitAll } from '@/prelude/await-all.js'; import { User } from '@/models/entities/user.js'; -@EntityRepository(AuthSession) -export class AuthSessionRepository extends Repository { - public async pack( +export const AuthSessionRepository = db.getRepository(AuthSession).extend({ + async pack( src: AuthSession['id'] | AuthSession, 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({ id: session.id, app: Apps.pack(session.appId, me), token: session.token, }); - } -} + }, +}); diff --git a/packages/backend/src/models/repositories/blocking.ts b/packages/backend/src/models/repositories/blocking.ts index b155bf944b..1d569fb875 100644 --- a/packages/backend/src/models/repositories/blocking.ts +++ b/packages/backend/src/models/repositories/blocking.ts @@ -1,17 +1,16 @@ -import { EntityRepository, Repository } from 'typeorm'; +import { db } from '@/db/postgre.js'; import { Users } from '../index.js'; import { Blocking } from '@/models/entities/blocking.js'; import { awaitAll } from '@/prelude/await-all.js'; import { Packed } from '@/misc/schema.js'; import { User } from '@/models/entities/user.js'; -@EntityRepository(Blocking) -export class BlockingRepository extends Repository { - public async pack( +export const BlockingRepository = db.getRepository(Blocking).extend({ + async pack( src: Blocking['id'] | Blocking, me?: { id: User['id'] } | null | undefined ): Promise> { - const blocking = typeof src === 'object' ? src : await this.findOneOrFail(src); + const blocking = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); return await awaitAll({ id: blocking.id, @@ -21,12 +20,12 @@ export class BlockingRepository extends Repository { detail: true, }), }); - } + }, - public packMany( + packMany( blockings: any[], me: { id: User['id'] } ) { return Promise.all(blockings.map(x => this.pack(x, me))); - } -} + }, +}); diff --git a/packages/backend/src/models/repositories/channel.ts b/packages/backend/src/models/repositories/channel.ts index cc13d7c1e6..213ac3671a 100644 --- a/packages/backend/src/models/repositories/channel.ts +++ b/packages/backend/src/models/repositories/channel.ts @@ -1,23 +1,22 @@ -import { EntityRepository, Repository } from 'typeorm'; +import { db } from '@/db/postgre.js'; import { Channel } from '@/models/entities/channel.js'; import { Packed } from '@/misc/schema.js'; import { DriveFiles, ChannelFollowings, NoteUnreads } from '../index.js'; import { User } from '@/models/entities/user.js'; -@EntityRepository(Channel) -export class ChannelRepository extends Repository { - public async pack( +export const ChannelRepository = db.getRepository(Channel).extend({ + async pack( src: Channel['id'] | Channel, me?: { id: User['id'] } | null | undefined, ): Promise> { - 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 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, followeeId: channel.id, }) : null; @@ -38,5 +37,5 @@ export class ChannelRepository extends Repository { hasUnreadNote, } : {}), }; - } -} + }, +}); diff --git a/packages/backend/src/models/repositories/clip.ts b/packages/backend/src/models/repositories/clip.ts index 9e1979729a..b4a342905e 100644 --- a/packages/backend/src/models/repositories/clip.ts +++ b/packages/backend/src/models/repositories/clip.ts @@ -1,15 +1,14 @@ -import { EntityRepository, Repository } from 'typeorm'; +import { db } from '@/db/postgre.js'; import { Clip } from '@/models/entities/clip.js'; import { Packed } from '@/misc/schema.js'; import { Users } from '../index.js'; import { awaitAll } from '@/prelude/await-all.js'; -@EntityRepository(Clip) -export class ClipRepository extends Repository { - public async pack( +export const ClipRepository = db.getRepository(Clip).extend({ + async pack( src: Clip['id'] | Clip, ): Promise> { - const clip = typeof src === 'object' ? src : await this.findOneOrFail(src); + const clip = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); return await awaitAll({ id: clip.id, @@ -20,12 +19,12 @@ export class ClipRepository extends Repository { description: clip.description, isPublic: clip.isPublic, }); - } + }, - public packMany( + packMany( clips: Clip[], ) { return Promise.all(clips.map(x => this.pack(x))); - } -} + }, +}); diff --git a/packages/backend/src/models/repositories/drive-file.ts b/packages/backend/src/models/repositories/drive-file.ts index 6452632db7..69dc1721c2 100644 --- a/packages/backend/src/models/repositories/drive-file.ts +++ b/packages/backend/src/models/repositories/drive-file.ts @@ -1,4 +1,4 @@ -import { EntityRepository, Repository } from 'typeorm'; +import { db } from '@/db/postgre.js'; import { DriveFile } from '@/models/entities/drive-file.js'; import { Users, DriveFolders } from '../index.js'; import { User } from '@/models/entities/user.js'; @@ -16,9 +16,8 @@ type PackOptions = { withUser?: boolean, }; -@EntityRepository(DriveFile) -export class DriveFileRepository extends Repository { - public validateFileName(name: string): boolean { +export const DriveFileRepository = db.getRepository(DriveFile).extend({ + validateFileName(name: string): boolean { return ( (name.trim().length > 0) && (name.length <= 200) && @@ -26,9 +25,9 @@ export class DriveFileRepository extends Repository { (name.indexOf('/') === -1) && (name.indexOf('..') === -1) ); - } + }, - public getPublicProperties(file: DriveFile): DriveFile['properties'] { + getPublicProperties(file: DriveFile): DriveFile['properties'] { if (file.properties.orientation != null) { const properties = JSON.parse(JSON.stringify(file.properties)); if (file.properties.orientation >= 5) { @@ -39,9 +38,9 @@ export class DriveFileRepository extends Repository { } 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) { return appendQuery(config.mediaProxy, query({ @@ -62,9 +61,9 @@ export class DriveFileRepository extends Repository { 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); - } + }, - public async calcDriveUsageOf(user: User['id'] | { id: User['id'] }): Promise { + async calcDriveUsageOf(user: User['id'] | { id: User['id'] }): Promise { const id = typeof user === 'object' ? user.id : user; const { sum } = await this @@ -75,9 +74,9 @@ export class DriveFileRepository extends Repository { .getRawOne(); return parseInt(sum, 10) || 0; - } + }, - public async calcDriveUsageOfHost(host: string): Promise { + async calcDriveUsageOfHost(host: string): Promise { const { sum } = await this .createQueryBuilder('file') .where('file.userHost = :host', { host: toPuny(host) }) @@ -86,9 +85,9 @@ export class DriveFileRepository extends Repository { .getRawOne(); return parseInt(sum, 10) || 0; - } + }, - public async calcDriveUsageOfLocal(): Promise { + async calcDriveUsageOfLocal(): Promise { const { sum } = await this .createQueryBuilder('file') .where('file.userHost IS NULL') @@ -97,9 +96,9 @@ export class DriveFileRepository extends Repository { .getRawOne(); return parseInt(sum, 10) || 0; - } + }, - public async calcDriveUsageOfRemote(): Promise { + async calcDriveUsageOfRemote(): Promise { const { sum } = await this .createQueryBuilder('file') .where('file.userHost IS NOT NULL') @@ -108,11 +107,9 @@ export class DriveFileRepository extends Repository { .getRawOne(); return parseInt(sum, 10) || 0; - } + }, - public async pack(src: DriveFile['id'], options?: PackOptions): Promise | null>; - public async pack(src: DriveFile, options?: PackOptions): Promise>; - public async pack( + async pack( src: DriveFile['id'] | DriveFile, options?: PackOptions ): Promise | null> { @@ -121,11 +118,9 @@ export class DriveFileRepository extends Repository { self: false, }, 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; - const meta = await fetchMeta(); - return await awaitAll>({ id: file.id, createdAt: file.createdAt.toISOString(), @@ -146,13 +141,13 @@ export class DriveFileRepository extends Repository { userId: opts.withUser ? file.userId : null, user: (opts.withUser && file.userId) ? Users.pack(file.userId) : null, }); - } + }, - public async packMany( + async packMany( files: (DriveFile['id'] | DriveFile)[], options?: PackOptions ) { const items = await Promise.all(files.map(f => this.pack(f, options))); return items.filter(x => x != null); - } -} + }, +}); diff --git a/packages/backend/src/models/repositories/drive-folder.ts b/packages/backend/src/models/repositories/drive-folder.ts index b0e09eedf5..ab5f3dab63 100644 --- a/packages/backend/src/models/repositories/drive-folder.ts +++ b/packages/backend/src/models/repositories/drive-folder.ts @@ -1,12 +1,11 @@ -import { EntityRepository, Repository } from 'typeorm'; +import { db } from '@/db/postgre.js'; import { DriveFolders, DriveFiles } from '../index.js'; import { DriveFolder } from '@/models/entities/drive-folder.js'; import { awaitAll } from '@/prelude/await-all.js'; import { Packed } from '@/misc/schema.js'; -@EntityRepository(DriveFolder) -export class DriveFolderRepository extends Repository { - public async pack( +export const DriveFolderRepository = db.getRepository(DriveFolder).extend({ + async pack( src: DriveFolder['id'] | DriveFolder, options?: { detail: boolean @@ -16,7 +15,7 @@ export class DriveFolderRepository extends Repository { detail: false, }, 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({ id: folder.id, @@ -25,10 +24,10 @@ export class DriveFolderRepository extends Repository { parentId: folder.parentId, ...(opts.detail ? { - foldersCount: DriveFolders.count({ + foldersCount: DriveFolders.countBy({ parentId: folder.id, }), - filesCount: DriveFiles.count({ + filesCount: DriveFiles.countBy({ folderId: folder.id, }), @@ -39,5 +38,5 @@ export class DriveFolderRepository extends Repository { } : {}), } : {}), }); - } -} + }, +}); diff --git a/packages/backend/src/models/repositories/emoji.ts b/packages/backend/src/models/repositories/emoji.ts index 3b13832a35..a0d390d793 100644 --- a/packages/backend/src/models/repositories/emoji.ts +++ b/packages/backend/src/models/repositories/emoji.ts @@ -1,13 +1,12 @@ -import { EntityRepository, Repository } from 'typeorm'; +import { db } from '@/db/postgre.js'; import { Emoji } from '@/models/entities/emoji.js'; import { Packed } from '@/misc/schema.js'; -@EntityRepository(Emoji) -export class EmojiRepository extends Repository { - public async pack( +export const EmojiRepository = db.getRepository(Emoji).extend({ + async pack( src: Emoji['id'] | Emoji, ): Promise> { - const emoji = typeof src === 'object' ? src : await this.findOneOrFail(src); + const emoji = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); return { id: emoji.id, @@ -18,11 +17,11 @@ export class EmojiRepository extends Repository { // || emoji.originalUrl してるのは後方互換性のため url: emoji.publicUrl || emoji.originalUrl, }; - } + }, - public packMany( + packMany( emojis: any[], ) { return Promise.all(emojis.map(x => this.pack(x))); - } -} + }, +}); diff --git a/packages/backend/src/models/repositories/follow-request.ts b/packages/backend/src/models/repositories/follow-request.ts index 1da1f875ea..c4a7203aa1 100644 --- a/packages/backend/src/models/repositories/follow-request.ts +++ b/packages/backend/src/models/repositories/follow-request.ts @@ -1,20 +1,19 @@ -import { EntityRepository, Repository } from 'typeorm'; +import { db } from '@/db/postgre.js'; import { FollowRequest } from '@/models/entities/follow-request.js'; import { Users } from '../index.js'; import { User } from '@/models/entities/user.js'; -@EntityRepository(FollowRequest) -export class FollowRequestRepository extends Repository { - public async pack( +export const FollowRequestRepository = db.getRepository(FollowRequest).extend({ + async pack( src: FollowRequest['id'] | FollowRequest, 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 { id: request.id, follower: await Users.pack(request.followerId, me), followee: await Users.pack(request.followeeId, me), }; - } -} + }, +}); diff --git a/packages/backend/src/models/repositories/following.ts b/packages/backend/src/models/repositories/following.ts index f25289d19c..46109244fa 100644 --- a/packages/backend/src/models/repositories/following.ts +++ b/packages/backend/src/models/repositories/following.ts @@ -1,4 +1,4 @@ -import { EntityRepository, Repository } from 'typeorm'; +import { db } from '@/db/postgre.js'; import { Users } from '../index.js'; import { Following } from '@/models/entities/following.js'; import { awaitAll } from '@/prelude/await-all.js'; @@ -29,25 +29,24 @@ type RemoteFolloweeFollowing = Following & { followeeSharedInbox: string; }; -@EntityRepository(Following) -export class FollowingRepository extends Repository { - public isLocalFollower(following: Following): following is LocalFollowerFollowing { +export const FollowingRepository = db.getRepository(Following).extend({ + isLocalFollower(following: Following): following is LocalFollowerFollowing { return following.followerHost == null; - } + }, - public isRemoteFollower(following: Following): following is RemoteFollowerFollowing { + isRemoteFollower(following: Following): following is RemoteFollowerFollowing { return following.followerHost != null; - } + }, - public isLocalFollowee(following: Following): following is LocalFolloweeFollowing { + isLocalFollowee(following: Following): following is LocalFolloweeFollowing { return following.followeeHost == null; - } + }, - public isRemoteFollowee(following: Following): following is RemoteFolloweeFollowing { + isRemoteFollowee(following: Following): following is RemoteFolloweeFollowing { return following.followeeHost != null; - } + }, - public async pack( + async pack( src: Following['id'] | Following, me?: { id: User['id'] } | null | undefined, opts?: { @@ -55,7 +54,7 @@ export class FollowingRepository extends Repository { populateFollower?: boolean; } ): Promise> { - 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 = {}; @@ -71,9 +70,9 @@ export class FollowingRepository extends Repository { detail: true, }) : undefined, }); - } + }, - public packMany( + packMany( followings: any[], me?: { id: User['id'] } | null | undefined, opts?: { @@ -82,5 +81,5 @@ export class FollowingRepository extends Repository { } ) { return Promise.all(followings.map(x => this.pack(x, me, opts))); - } -} + }, +}); diff --git a/packages/backend/src/models/repositories/gallery-like.ts b/packages/backend/src/models/repositories/gallery-like.ts index 545186fa19..08ca4962b8 100644 --- a/packages/backend/src/models/repositories/gallery-like.ts +++ b/packages/backend/src/models/repositories/gallery-like.ts @@ -1,25 +1,24 @@ -import { EntityRepository, Repository } from 'typeorm'; +import { db } from '@/db/postgre.js'; import { GalleryLike } from '@/models/entities/gallery-like.js'; import { GalleryPosts } from '../index.js'; -@EntityRepository(GalleryLike) -export class GalleryLikeRepository extends Repository { - public async pack( +export const GalleryLikeRepository = db.getRepository(GalleryLike).extend({ + async pack( src: GalleryLike['id'] | GalleryLike, me?: any ) { - const like = typeof src === 'object' ? src : await this.findOneOrFail(src); + const like = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); return { id: like.id, post: await GalleryPosts.pack(like.post || like.postId, me), }; - } + }, - public packMany( + packMany( likes: any[], me: any ) { return Promise.all(likes.map(x => this.pack(x, me))); - } -} + }, +}); diff --git a/packages/backend/src/models/repositories/gallery-post.ts b/packages/backend/src/models/repositories/gallery-post.ts index bbb036dd09..bb8d40b75e 100644 --- a/packages/backend/src/models/repositories/gallery-post.ts +++ b/packages/backend/src/models/repositories/gallery-post.ts @@ -1,18 +1,17 @@ -import { EntityRepository, Repository } from 'typeorm'; +import { db } from '@/db/postgre.js'; import { GalleryPost } from '@/models/entities/gallery-post.js'; import { Packed } from '@/misc/schema.js'; import { Users, DriveFiles, GalleryLikes } from '../index.js'; import { awaitAll } from '@/prelude/await-all.js'; import { User } from '@/models/entities/user.js'; -@EntityRepository(GalleryPost) -export class GalleryPostRepository extends Repository { - public async pack( +export const GalleryPostRepository = db.getRepository(GalleryPost).extend({ + async pack( src: GalleryPost['id'] | GalleryPost, me?: { id: User['id'] } | null | undefined, ): Promise> { 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({ id: post.id, @@ -27,14 +26,14 @@ export class GalleryPostRepository extends Repository { tags: post.tags.length > 0 ? post.tags : undefined, isSensitive: post.isSensitive, 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[], me?: { id: User['id'] } | null | undefined, ) { return Promise.all(posts.map(x => this.pack(x, me))); - } -} + }, +}); diff --git a/packages/backend/src/models/repositories/hashtag.ts b/packages/backend/src/models/repositories/hashtag.ts index 0548e19ee3..e6c0e36f00 100644 --- a/packages/backend/src/models/repositories/hashtag.ts +++ b/packages/backend/src/models/repositories/hashtag.ts @@ -1,10 +1,9 @@ -import { EntityRepository, Repository } from 'typeorm'; +import { db } from '@/db/postgre.js'; import { Hashtag } from '@/models/entities/hashtag.js'; import { Packed } from '@/misc/schema.js'; -@EntityRepository(Hashtag) -export class HashtagRepository extends Repository { - public async pack( +export const HashtagRepository = db.getRepository(Hashtag).extend({ + async pack( src: Hashtag, ): Promise> { return { @@ -16,11 +15,11 @@ export class HashtagRepository extends Repository { attachedLocalUsersCount: src.attachedLocalUsersCount, attachedRemoteUsersCount: src.attachedRemoteUsersCount, }; - } + }, - public packMany( + packMany( hashtags: Hashtag[], ) { return Promise.all(hashtags.map(x => this.pack(x))); - } -} + }, +}); diff --git a/packages/backend/src/models/repositories/instance.ts b/packages/backend/src/models/repositories/instance.ts index 358e055aaa..4ddf717098 100644 --- a/packages/backend/src/models/repositories/instance.ts +++ b/packages/backend/src/models/repositories/instance.ts @@ -1,10 +1,9 @@ -import { EntityRepository, Repository } from 'typeorm'; +import { db } from '@/db/postgre.js'; import { Instance } from '@/models/entities/instance.js'; import { Packed } from '@/misc/schema.js'; -@EntityRepository(Instance) -export class InstanceRepository extends Repository { - public async pack( +export const InstanceRepository = db.getRepository(Instance).extend({ + async pack( instance: Instance, ): Promise> { return { @@ -29,11 +28,11 @@ export class InstanceRepository extends Repository { iconUrl: instance.iconUrl, infoUpdatedAt: instance.infoUpdatedAt ? instance.infoUpdatedAt.toISOString() : null, }; - } + }, - public packMany( + packMany( instances: Instance[], ) { return Promise.all(instances.map(x => this.pack(x))); - } -} + }, +}); diff --git a/packages/backend/src/models/repositories/messaging-message.ts b/packages/backend/src/models/repositories/messaging-message.ts index 3f51707008..6c51c93ff7 100644 --- a/packages/backend/src/models/repositories/messaging-message.ts +++ b/packages/backend/src/models/repositories/messaging-message.ts @@ -1,12 +1,11 @@ -import { EntityRepository, Repository } from 'typeorm'; +import { db } from '@/db/postgre.js'; import { MessagingMessage } from '@/models/entities/messaging-message.js'; import { Users, DriveFiles, UserGroups } from '../index.js'; import { Packed } from '@/misc/schema.js'; import { User } from '@/models/entities/user.js'; -@EntityRepository(MessagingMessage) -export class MessagingMessageRepository extends Repository { - public async pack( +export const MessagingMessageRepository = db.getRepository(MessagingMessage).extend({ + async pack( src: MessagingMessage['id'] | MessagingMessage, me?: { id: User['id'] } | null | undefined, options?: { @@ -19,7 +18,7 @@ export class MessagingMessageRepository extends Repository { populateGroup: true, }; - const message = typeof src === 'object' ? src : await this.findOneOrFail(src); + const message = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); return { id: message.id, @@ -36,5 +35,5 @@ export class MessagingMessageRepository extends Repository { isRead: message.isRead, reads: message.reads, }; - } -} + }, +}); diff --git a/packages/backend/src/models/repositories/moderation-logs.ts b/packages/backend/src/models/repositories/moderation-logs.ts index ea78104960..1488b1eabe 100644 --- a/packages/backend/src/models/repositories/moderation-logs.ts +++ b/packages/backend/src/models/repositories/moderation-logs.ts @@ -1,14 +1,13 @@ -import { EntityRepository, Repository } from 'typeorm'; +import { db } from '@/db/postgre.js'; import { Users } from '../index.js'; import { ModerationLog } from '@/models/entities/moderation-log.js'; import { awaitAll } from '@/prelude/await-all.js'; -@EntityRepository(ModerationLog) -export class ModerationLogRepository extends Repository { - public async pack( +export const ModerationLogRepository = db.getRepository(ModerationLog).extend({ + async pack( 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({ id: log.id, @@ -20,11 +19,11 @@ export class ModerationLogRepository extends Repository { detail: true, }), }); - } + }, - public packMany( + packMany( reports: any[], ) { return Promise.all(reports.map(x => this.pack(x))); - } -} + }, +}); diff --git a/packages/backend/src/models/repositories/muting.ts b/packages/backend/src/models/repositories/muting.ts index 643e0b68ee..7891b10fb0 100644 --- a/packages/backend/src/models/repositories/muting.ts +++ b/packages/backend/src/models/repositories/muting.ts @@ -1,17 +1,16 @@ -import { EntityRepository, Repository } from 'typeorm'; +import { db } from '@/db/postgre.js'; import { Users } from '../index.js'; import { Muting } from '@/models/entities/muting.js'; import { awaitAll } from '@/prelude/await-all.js'; import { Packed } from '@/misc/schema.js'; import { User } from '@/models/entities/user.js'; -@EntityRepository(Muting) -export class MutingRepository extends Repository { - public async pack( +export const MutingRepository = db.getRepository(Muting).extend({ + async pack( src: Muting['id'] | Muting, me?: { id: User['id'] } | null | undefined ): Promise> { - const muting = typeof src === 'object' ? src : await this.findOneOrFail(src); + const muting = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); return await awaitAll({ id: muting.id, @@ -22,12 +21,12 @@ export class MutingRepository extends Repository { detail: true, }), }); - } + }, - public packMany( + packMany( mutings: any[], me: { id: User['id'] } ) { return Promise.all(mutings.map(x => this.pack(x, me))); - } -} + }, +}); diff --git a/packages/backend/src/models/repositories/note-favorite.ts b/packages/backend/src/models/repositories/note-favorite.ts index d7a7925ebc..9bd97f9880 100644 --- a/packages/backend/src/models/repositories/note-favorite.ts +++ b/packages/backend/src/models/repositories/note-favorite.ts @@ -1,15 +1,14 @@ -import { EntityRepository, Repository } from 'typeorm'; +import { db } from '@/db/postgre.js'; import { NoteFavorite } from '@/models/entities/note-favorite.js'; import { Notes } from '../index.js'; import { User } from '@/models/entities/user.js'; -@EntityRepository(NoteFavorite) -export class NoteFavoriteRepository extends Repository { - public async pack( +export const NoteFavoriteRepository = db.getRepository(NoteFavorite).extend({ + async pack( src: NoteFavorite['id'] | NoteFavorite, 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 { id: favorite.id, @@ -17,12 +16,12 @@ export class NoteFavoriteRepository extends Repository { noteId: favorite.noteId, note: await Notes.pack(favorite.note || favorite.noteId, me), }; - } + }, - public packMany( + packMany( favorites: any[], me: { id: User['id'] } ) { return Promise.all(favorites.map(x => this.pack(x, me))); - } -} + }, +}); diff --git a/packages/backend/src/models/repositories/note-reaction.ts b/packages/backend/src/models/repositories/note-reaction.ts index a212b0d3e9..4deae51c93 100644 --- a/packages/backend/src/models/repositories/note-reaction.ts +++ b/packages/backend/src/models/repositories/note-reaction.ts @@ -1,13 +1,12 @@ -import { EntityRepository, Repository } from 'typeorm'; +import { db } from '@/db/postgre.js'; import { NoteReaction } from '@/models/entities/note-reaction.js'; import { Notes, Users } from '../index.js'; import { Packed } from '@/misc/schema.js'; import { convertLegacyReaction } from '@/misc/reaction-lib.js'; import { User } from '@/models/entities/user.js'; -@EntityRepository(NoteReaction) -export class NoteReactionRepository extends Repository { - public async pack( +export const NoteReactionRepository = db.getRepository(NoteReaction).extend({ + async pack( src: NoteReaction['id'] | NoteReaction, me?: { id: User['id'] } | null | undefined, options?: { @@ -18,7 +17,7 @@ export class NoteReactionRepository extends Repository { withNote: false, }, options); - const reaction = typeof src === 'object' ? src : await this.findOneOrFail(src); + const reaction = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); return { id: reaction.id, @@ -29,5 +28,5 @@ export class NoteReactionRepository extends Repository { note: await Notes.pack(reaction.note ?? reaction.noteId, me), } : {}), }; - } -} + }, +}); diff --git a/packages/backend/src/models/repositories/note.ts b/packages/backend/src/models/repositories/note.ts index 418d6e2346..cf5fcb1787 100644 --- a/packages/backend/src/models/repositories/note.ts +++ b/packages/backend/src/models/repositories/note.ts @@ -1,4 +1,4 @@ -import { EntityRepository, Repository, In } from 'typeorm'; +import { In } from 'typeorm'; import * as mfm from 'mfm-js'; import { Note } from '@/models/entities/note.js'; import { User } from '@/models/entities/user.js'; @@ -9,10 +9,133 @@ import { awaitAll } from '@/prelude/await-all.js'; import { convertLegacyReaction, convertLegacyReactions, decodeReaction } from '@/misc/reaction-lib.js'; import { NoteReaction } from '@/models/entities/note-reaction.js'; import { aggregateNoteEmojis, populateEmojis, prefetchEmojis } from '@/misc/populate-emojis.js'; +import { db } from '@/db/postgre.js'; -@EntityRepository(Note) -export class NoteRepository extends Repository { - public async isVisibleForMe(note: Note, meId: User['id'] | null): Promise { +async function hideNote(packedNote: Packed<'Note'>, meId: User['id'] | null) { + // TODO: isVisibleForMe を使うようにしても良さそう(型違うけど) + let hide = false; + + // visibility が specified かつ自分が指定されていなかったら非表示 + if (packedNote.visibility === 'specified') { + if (meId == null) { + hide = true; + } else if (meId === packedNote.userId) { + hide = false; + } else { + // 指定されているかどうか + const specified = packedNote.visibleUserIds!.some((id: any) => meId === id); + + if (specified) { + hide = false; + } else { + hide = true; + } + } + } + + // visibility が followers かつ自分が投稿者のフォロワーでなかったら非表示 + if (packedNote.visibility === 'followers') { + if (meId == null) { + hide = true; + } else if (meId === packedNote.userId) { + hide = false; + } else if (packedNote.reply && (meId === packedNote.reply.userId)) { + // 自分の投稿に対するリプライ + hide = false; + } else if (packedNote.mentions && packedNote.mentions.some(id => meId === id)) { + // 自分へのメンション + hide = false; + } else { + // フォロワーかどうか + const following = await Followings.findOneBy({ + followeeId: packedNote.userId, + followerId: meId, + }); + + if (following == null) { + hide = true; + } else { + hide = false; + } + } + } + + if (hide) { + packedNote.visibleUserIds = undefined; + packedNote.fileIds = []; + packedNote.files = []; + packedNote.text = null; + packedNote.poll = undefined; + packedNote.cw = null; + packedNote.isHidden = true; + } +} + +async function populatePoll(note: Note, meId: User['id'] | null) { + const poll = await Polls.findOneByOrFail({ noteId: note.id }); + const choices = poll.choices.map(c => ({ + text: c, + votes: poll.votes[poll.choices.indexOf(c)], + isVoted: false, + })); + + if (meId) { + if (poll.multiple) { + const votes = await PollVotes.findBy({ + userId: meId, + noteId: note.id, + }); + + const myChoices = votes.map(v => v.choice); + for (const myChoice of myChoices) { + choices[myChoice].isVoted = true; + } + } else { + const vote = await PollVotes.findOneBy({ + userId: meId, + noteId: note.id, + }); + + if (vote) { + choices[vote.choice].isVoted = true; + } + } + } + + return { + multiple: poll.multiple, + expiresAt: poll.expiresAt, + choices, + }; +} + +async function populateMyReaction(note: Note, meId: User['id'], _hint_?: { + myReactions: Map; +}) { + if (_hint_?.myReactions) { + const reaction = _hint_.myReactions.get(note.id); + if (reaction) { + return convertLegacyReaction(reaction.reaction); + } else if (reaction === null) { + return undefined; + } + // 実装上抜けがあるだけかもしれないので、「ヒントに含まれてなかったら(=undefinedなら)return」のようにはしない + } + + const reaction = await NoteReactions.findOneBy({ + userId: meId, + noteId: note.id, + }); + + if (reaction) { + return convertLegacyReaction(reaction.reaction); + } + + return undefined; +} + +export const NoteRepository = db.getRepository(Note).extend({ + async isVisibleForMe(note: Note, meId: User['id'] | null): Promise { // visibility が specified かつ自分が指定されていなかったら非表示 if (note.visibility === 'specified') { if (meId == null) { @@ -45,7 +168,7 @@ export class NoteRepository extends Repository { return true; } else { // フォロワーかどうか - const following = await Followings.findOne({ + const following = await Followings.findOneBy({ followeeId: note.userId, followerId: meId, }); @@ -59,69 +182,9 @@ export class NoteRepository extends Repository { } return true; - } + }, - private async hideNote(packedNote: Packed<'Note'>, meId: User['id'] | null) { - // TODO: isVisibleForMe を使うようにしても良さそう(型違うけど) - let hide = false; - - // visibility が specified かつ自分が指定されていなかったら非表示 - if (packedNote.visibility === 'specified') { - if (meId == null) { - hide = true; - } else if (meId === packedNote.userId) { - hide = false; - } else { - // 指定されているかどうか - const specified = packedNote.visibleUserIds!.some((id: any) => meId === id); - - if (specified) { - hide = false; - } else { - hide = true; - } - } - } - - // visibility が followers かつ自分が投稿者のフォロワーでなかったら非表示 - if (packedNote.visibility === 'followers') { - if (meId == null) { - hide = true; - } else if (meId === packedNote.userId) { - hide = false; - } else if (packedNote.reply && (meId === packedNote.reply.userId)) { - // 自分の投稿に対するリプライ - hide = false; - } else if (packedNote.mentions && packedNote.mentions.some(id => meId === id)) { - // 自分へのメンション - hide = false; - } else { - // フォロワーかどうか - const following = await Followings.findOne({ - followeeId: packedNote.userId, - followerId: meId, - }); - - if (following == null) { - hide = true; - } else { - hide = false; - } - } - } - - if (hide) { - packedNote.visibleUserIds = undefined; - packedNote.fileIds = []; - packedNote.files = []; - packedNote.text = null; - packedNote.poll = undefined; - packedNote.cw = null; - packedNote.isHidden = true; - } - } - - public async pack( + async pack( src: Note['id'] | Note, me?: { id: User['id'] } | null | undefined, options?: { @@ -138,68 +201,9 @@ export class NoteRepository extends Repository { }, options); 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; - async function populatePoll() { - const poll = await Polls.findOneOrFail(note.id); - const choices = poll.choices.map(c => ({ - text: c, - votes: poll.votes[poll.choices.indexOf(c)], - isVoted: false, - })); - - if (poll.multiple) { - const votes = await PollVotes.find({ - userId: meId!, - noteId: note.id, - }); - - const myChoices = votes.map(v => v.choice); - for (const myChoice of myChoices) { - choices[myChoice].isVoted = true; - } - } else { - const vote = await PollVotes.findOne({ - userId: meId!, - noteId: note.id, - }); - - if (vote) { - choices[vote.choice].isVoted = true; - } - } - - return { - multiple: poll.multiple, - expiresAt: poll.expiresAt, - choices, - }; - } - - async function populateMyReaction() { - if (options?._hint_?.myReactions) { - const reaction = options._hint_.myReactions.get(note.id); - if (reaction) { - return convertLegacyReaction(reaction.reaction); - } else if (reaction === null) { - return undefined; - } - // 実装上抜けがあるだけかもしれないので、「ヒントに含まれてなかったら(=undefinedなら)return」のようにはしない - } - - const reaction = await NoteReactions.findOne({ - userId: meId!, - noteId: note.id, - }); - - if (reaction) { - return convertLegacyReaction(reaction.reaction); - } - - return undefined; - } - let text = note.text; if (note.name && (note.url ?? note.uri)) { @@ -209,7 +213,7 @@ export class NoteRepository extends Repository { const channel = note.channelId ? note.channel ? note.channel - : await Channels.findOne(note.channelId) + : await Channels.findOneBy({ id: note.channelId }) : null; const reactionEmojiNames = Object.keys(note.reactions).filter(x => x?.startsWith(':')).map(x => decodeReaction(x).reaction).map(x => x.replace(/:/g, '')); @@ -255,10 +259,10 @@ export class NoteRepository extends Repository { _hint_: options?._hint_, }) : undefined, - poll: note.hasPoll ? populatePoll() : undefined, + poll: note.hasPoll ? populatePoll(note, meId) : undefined, ...(meId ? { - myReaction: populateMyReaction(), + myReaction: populateMyReaction(note, meId, options?._hint_), } : {}), } : {}), }); @@ -275,13 +279,13 @@ export class NoteRepository extends Repository { } if (!opts.skipHide) { - await this.hideNote(packed, meId); + await hideNote(packed, meId); } return packed; - } + }, - public async packMany( + async packMany( notes: Note[], me?: { id: User['id'] } | null | undefined, options?: { @@ -296,7 +300,7 @@ export class NoteRepository extends Repository { if (meId) { const renoteIds = notes.filter(n => n.renoteId != null).map(n => n.renoteId!); const targets = [...notes.map(n => n.id), ...renoteIds]; - const myReactions = await NoteReactions.find({ + const myReactions = await NoteReactions.findBy({ userId: meId, noteId: In(targets), }); @@ -314,5 +318,5 @@ export class NoteRepository extends Repository { myReactions: myReactionsMap, }, }))); - } -} + }, +}); diff --git a/packages/backend/src/models/repositories/notification.ts b/packages/backend/src/models/repositories/notification.ts index 8e72d8aabd..42b47ab150 100644 --- a/packages/backend/src/models/repositories/notification.ts +++ b/packages/backend/src/models/repositories/notification.ts @@ -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 { Notification } from '@/models/entities/notification.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 { aggregateNoteEmojis, prefetchEmojis } from '@/misc/populate-emojis.js'; import { notificationTypes } from '@/types.js'; +import { db } from '@/db/postgre.js'; -@EntityRepository(Notification) -export class NotificationRepository extends Repository { - public async pack( +export const NotificationRepository = db.getRepository(Notification).extend({ + async pack( src: Notification['id'] | Notification, options: { _hintForEachNotes_?: { @@ -19,8 +19,8 @@ export class NotificationRepository extends Repository { }; } ): Promise> { - const notification = typeof src === 'object' ? src : await this.findOneOrFail(src); - const token = notification.appAccessTokenId ? await AccessTokens.findOneOrFail(notification.appAccessTokenId) : null; + const notification = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); + const token = notification.appAccessTokenId ? await AccessTokens.findOneByOrFail({ id: notification.appAccessTokenId }) : null; return await awaitAll({ id: notification.id, @@ -82,9 +82,9 @@ export class NotificationRepository extends Repository { icon: notification.customIcon || token?.iconUrl, } : {}), }); - } + }, - public async packMany( + async packMany( notifications: Notification[], meId: User['id'] ) { @@ -95,7 +95,7 @@ export class NotificationRepository extends Repository { const myReactionsMap = new Map(); const renoteIds = notes.filter(n => n.renoteId != null).map(n => n.renoteId!); const targets = [...noteIds, ...renoteIds]; - const myReactions = await NoteReactions.find({ + const myReactions = await NoteReactions.findBy({ userId: meId, noteId: In(targets), }); @@ -111,5 +111,5 @@ export class NotificationRepository extends Repository { myReactions: myReactionsMap, }, }))); - } -} + }, +}); diff --git a/packages/backend/src/models/repositories/page-like.ts b/packages/backend/src/models/repositories/page-like.ts index 66d780584f..87d6accc34 100644 --- a/packages/backend/src/models/repositories/page-like.ts +++ b/packages/backend/src/models/repositories/page-like.ts @@ -1,26 +1,25 @@ -import { EntityRepository, Repository } from 'typeorm'; +import { db } from '@/db/postgre.js'; import { PageLike } from '@/models/entities/page-like.js'; import { Pages } from '../index.js'; import { User } from '@/models/entities/user.js'; -@EntityRepository(PageLike) -export class PageLikeRepository extends Repository { - public async pack( +export const PageLikeRepository = db.getRepository(PageLike).extend({ + async pack( src: PageLike['id'] | PageLike, 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 { id: like.id, page: await Pages.pack(like.page || like.pageId, me), }; - } + }, - public packMany( + packMany( likes: any[], me: { id: User['id'] } ) { return Promise.all(likes.map(x => this.pack(x, me))); - } -} + }, +}); diff --git a/packages/backend/src/models/repositories/page.ts b/packages/backend/src/models/repositories/page.ts index 037c13c434..1bffb23fa2 100644 --- a/packages/backend/src/models/repositories/page.ts +++ b/packages/backend/src/models/repositories/page.ts @@ -1,4 +1,4 @@ -import { EntityRepository, Repository } from 'typeorm'; +import { db } from '@/db/postgre.js'; import { Page } from '@/models/entities/page.js'; import { Packed } from '@/misc/schema.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 { User } from '@/models/entities/user.js'; -@EntityRepository(Page) -export class PageRepository extends Repository { - public async pack( +export const PageRepository = db.getRepository(Page).extend({ + async pack( src: Page['id'] | Page, me?: { id: User['id'] } | null | undefined, ): Promise> { 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[] = []; const collectFile = (xs: any[]) => { for (const x of xs) { if (x.type === 'image') { - attachedFiles.push(DriveFiles.findOne({ + attachedFiles.push(DriveFiles.findOneBy({ id: x.fileId, userId: page.userId, })); @@ -76,14 +75,14 @@ export class PageRepository extends Repository { eyeCatchingImage: page.eyeCatchingImageId ? await DriveFiles.pack(page.eyeCatchingImageId) : null, attachedFiles: DriveFiles.packMany(await Promise.all(attachedFiles)), 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[], me?: { id: User['id'] } | null | undefined, ) { return Promise.all(pages.map(x => this.pack(x, me))); - } -} + }, +}); diff --git a/packages/backend/src/models/repositories/relay.ts b/packages/backend/src/models/repositories/relay.ts index 160ca60f7b..fa1c8f4d8d 100644 --- a/packages/backend/src/models/repositories/relay.ts +++ b/packages/backend/src/models/repositories/relay.ts @@ -1,6 +1,5 @@ -import { EntityRepository, Repository } from 'typeorm'; +import { db } from '@/db/postgre.js'; import { Relay } from '@/models/entities/relay.js'; -@EntityRepository(Relay) -export class RelayRepository extends Repository { -} +export const RelayRepository = db.getRepository(Relay).extend({ +}); diff --git a/packages/backend/src/models/repositories/signin.ts b/packages/backend/src/models/repositories/signin.ts index a0e2ce1526..94410ec58a 100644 --- a/packages/backend/src/models/repositories/signin.ts +++ b/packages/backend/src/models/repositories/signin.ts @@ -1,11 +1,10 @@ -import { EntityRepository, Repository } from 'typeorm'; +import { db } from '@/db/postgre.js'; import { Signin } from '@/models/entities/signin.js'; -@EntityRepository(Signin) -export class SigninRepository extends Repository { - public async pack( +export const SigninRepository = db.getRepository(Signin).extend({ + async pack( src: Signin, ) { return src; - } -} + }, +}); diff --git a/packages/backend/src/models/repositories/user-group-invitation.ts b/packages/backend/src/models/repositories/user-group-invitation.ts index e338242c64..79ad019c99 100644 --- a/packages/backend/src/models/repositories/user-group-invitation.ts +++ b/packages/backend/src/models/repositories/user-group-invitation.ts @@ -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 { UserGroups } from '../index.js'; -@EntityRepository(UserGroupInvitation) -export class UserGroupInvitationRepository extends Repository { - public async pack( +export const UserGroupInvitationRepository = db.getRepository(UserGroupInvitation).extend({ + async pack( 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 { id: invitation.id, group: await UserGroups.pack(invitation.userGroup || invitation.userGroupId), }; - } + }, - public packMany( + packMany( invitations: any[], ) { return Promise.all(invitations.map(x => this.pack(x))); - } -} + }, +}); diff --git a/packages/backend/src/models/repositories/user-group.ts b/packages/backend/src/models/repositories/user-group.ts index a9ffe7369e..6eb9234244 100644 --- a/packages/backend/src/models/repositories/user-group.ts +++ b/packages/backend/src/models/repositories/user-group.ts @@ -1,16 +1,15 @@ -import { EntityRepository, Repository } from 'typeorm'; +import { db } from '@/db/postgre.js'; import { UserGroup } from '@/models/entities/user-group.js'; import { UserGroupJoinings } from '../index.js'; import { Packed } from '@/misc/schema.js'; -@EntityRepository(UserGroup) -export class UserGroupRepository extends Repository { - public async pack( +export const UserGroupRepository = db.getRepository(UserGroup).extend({ + async pack( src: UserGroup['id'] | UserGroup, ): Promise> { - 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, }); @@ -21,5 +20,5 @@ export class UserGroupRepository extends Repository { ownerId: userGroup.userId, userIds: users.map(x => x.userId), }; - } -} + }, +}); diff --git a/packages/backend/src/models/repositories/user-list.ts b/packages/backend/src/models/repositories/user-list.ts index 0ea26427fe..2b6f411ef6 100644 --- a/packages/backend/src/models/repositories/user-list.ts +++ b/packages/backend/src/models/repositories/user-list.ts @@ -1,16 +1,15 @@ -import { EntityRepository, Repository } from 'typeorm'; +import { db } from '@/db/postgre.js'; import { UserList } from '@/models/entities/user-list.js'; import { UserListJoinings } from '../index.js'; import { Packed } from '@/misc/schema.js'; -@EntityRepository(UserList) -export class UserListRepository extends Repository { - public async pack( +export const UserListRepository = db.getRepository(UserList).extend({ + async pack( src: UserList['id'] | UserList, ): Promise> { - 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, }); @@ -20,5 +19,5 @@ export class UserListRepository extends Repository { name: userList.name, userIds: users.map(x => x.userId), }; - } -} + }, +}); diff --git a/packages/backend/src/models/repositories/user.ts b/packages/backend/src/models/repositories/user.ts index 17b7987a4e..2f4b7d6787 100644 --- a/packages/backend/src/models/repositories/user.ts +++ b/packages/backend/src/models/repositories/user.ts @@ -10,6 +10,7 @@ import { getAntennas } from '@/misc/antenna-cache.js'; import { USER_ACTIVE_THRESHOLD, USER_ONLINE_THRESHOLD } from '@/const.js'; import { Cache } from '@/misc/cache.js'; import { Instance } from '../entities/instance.js'; +import { db } from '@/db/postgre.js'; const userInstanceCache = new Cache(1000 * 60 * 60 * 3); @@ -23,51 +24,69 @@ type IsMeAndIsUserDetailed { - public localUsernameSchema = { type: 'string', pattern: /^\w{1,20}$/.toString().slice(1, -1) } as const; - public passwordSchema = { type: 'string', minLength: 1 } as const; - public nameSchema = { type: 'string', minLength: 1, maxLength: 50 } as const; - public descriptionSchema = { type: 'string', minLength: 1, maxLength: 500 } 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; +const localUsernameSchema = { type: 'string', pattern: /^\w{1,20}$/.toString().slice(1, -1) } as const; +const passwordSchema = { type: 'string', minLength: 1 } as const; +const nameSchema = { type: 'string', minLength: 1, maxLength: 50 } as const; +const descriptionSchema = { type: 'string', minLength: 1, maxLength: 500 } as const; +const locationSchema = { type: 'string', minLength: 1, maxLength: 50 } as const; +const 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(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(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 - public validateLocalUsername = ajv.compile(this.localUsernameSchema); - public validatePassword = ajv.compile(this.passwordSchema); - public validateName = ajv.compile(this.nameSchema); - public validateDescription = ajv.compile(this.descriptionSchema); - public validateLocation = ajv.compile(this.locationSchema); - public validateBirthday = ajv.compile(this.birthdaySchema); + validateLocalUsername: ajv.compile(localUsernameSchema), + validatePassword: ajv.compile(passwordSchema), + validateName: ajv.compile(nameSchema), + validateDescription: ajv.compile(descriptionSchema), + validateLocation: ajv.compile(locationSchema), + validateBirthday: ajv.compile(birthdaySchema), //#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([ - Followings.findOne({ + Followings.findOneBy({ followerId: me, followeeId: target, }), - Followings.findOne({ + Followings.findOneBy({ followerId: target, followeeId: me, }), - FollowRequests.findOne({ + FollowRequests.findOneBy({ followerId: me, followeeId: target, }), - FollowRequests.findOne({ + FollowRequests.findOneBy({ followerId: target, followeeId: me, }), - Blockings.findOne({ + Blockings.findOneBy({ blockerId: me, blockeeId: target, }), - Blockings.findOne({ + Blockings.findOneBy({ blockerId: target, blockeeId: me, }), - Mutings.findOne({ + Mutings.findOneBy({ muterId: me, muteeId: target, }), @@ -83,14 +102,14 @@ export class UserRepository extends Repository { isBlocked: fromBlocked != null, isMuted: mute != null, }; - } + }, - public async getHasUnreadMessagingMessage(userId: User['id']): Promise { - const mute = await Mutings.find({ + async getHasUnreadMessagingMessage(userId: User['id']): Promise { + const mute = await Mutings.findBy({ 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') .where(`message.groupId = :groupId`, { groupId: j.userGroupId }) @@ -112,44 +131,44 @@ export class UserRepository extends Repository { ]); return withUser || withGroups.some(x => x); - } + }, - public async getHasUnreadAnnouncement(userId: User['id']): Promise { - const reads = await AnnouncementReads.find({ + async getHasUnreadAnnouncement(userId: User['id']): Promise { + const reads = await AnnouncementReads.findBy({ 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))), } : {}); return count > 0; - } + }, - public async getHasUnreadAntenna(userId: User['id']): Promise { + async getHasUnreadAntenna(userId: User['id']): Promise { 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)), read: false, }) : null; return unread != null; - } + }, - public async getHasUnreadChannel(userId: User['id']): Promise { - const channels = await ChannelFollowings.find({ followerId: userId }); + async getHasUnreadChannel(userId: User['id']): Promise { + 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, noteChannelId: In(channels.map(x => x.followeeId)), }) : null; return unread != null; - } + }, - public async getHasUnreadNotification(userId: User['id']): Promise { - const mute = await Mutings.find({ + async getHasUnreadNotification(userId: User['id']): Promise { + const mute = await Mutings.findBy({ muterId: userId, }); const mutedUserIds = mute.map(m => m.muteeId); @@ -164,17 +183,17 @@ export class UserRepository extends Repository { }); return count > 0; - } + }, - public async getHasPendingReceivedFollowRequest(userId: User['id']): Promise { - const count = await FollowRequests.count({ + async getHasPendingReceivedFollowRequest(userId: User['id']): Promise { + const count = await FollowRequests.countBy({ followeeId: userId, }); 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.lastActiveDate == null) return 'unknown'; const elapsed = Date.now() - user.lastActiveDate.getTime(); @@ -183,22 +202,22 @@ export class UserRepository extends Repository { elapsed < USER_ACTIVE_THRESHOLD ? 'active' : 'offline' ); - } + }, - public getAvatarUrl(user: User): string { + getAvatarUrl(user: User): string { // TODO: avatarIdがあるがavatarがない(JOINされてない)場合のハンドリング if (user.avatar) { return DriveFiles.getPublicUrl(user.avatar, true) || this.getIdenticonUrl(user.id); } else { return this.getIdenticonUrl(user.id); } - } + }, - public getIdenticonUrl(userId: User['id']): string { + getIdenticonUrl(userId: User['id']): string { return `${config.url}/identicon/${userId}`; - } + }, - public async pack( + async pack( src: User['id'] | User, me?: { id: User['id'] } | null | undefined, options?: { @@ -215,11 +234,15 @@ export class UserRepository extends Repository { if (typeof src === 'object') { user = src; - if (src.avatar === undefined && src.avatarId) src.avatar = await DriveFiles.findOne(src.avatarId) ?? null; - if (src.banner === undefined && src.bannerId) src.banner = await DriveFiles.findOne(src.bannerId) ?? 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.findOneBy({ id: src.bannerId }) ?? null; } else { - user = await this.findOneOrFail(src, { - relations: ['avatar', 'banner'], + user = await this.findOneOrFail({ + where: { id: src }, + relations: { + avatar: true, + banner: true, + }, }); } @@ -232,7 +255,7 @@ export class UserRepository extends Repository { .innerJoinAndSelect('pin.note', 'note') .orderBy('pin.id', 'DESC') .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 : (profile.ffVisibility === 'public') || isMe ? user.followingCount : @@ -258,9 +281,8 @@ export class UserRepository extends Repository { isModerator: user.isModerator || falsy, isBot: user.isBot || falsy, isCat: user.isCat || falsy, - // TODO: typeorm 3.0にしたら .then(x => x || null) は消せる instance: user.host ? userInstanceCache.fetch(user.host, - () => Instances.findOne({ host: user.host }).then(x => x || null), + () => Instances.findOneBy({ host: user.host! }), v => v != null ).then(instance => instance ? { name: instance.name, @@ -304,7 +326,7 @@ export class UserRepository extends Repository { twoFactorEnabled: profile!.twoFactorEnabled, usePasswordLessLogin: profile!.usePasswordLessLogin, securityKeys: profile!.twoFactorEnabled - ? UserSecurityKeys.count({ + ? UserSecurityKeys.countBy({ userId: user.id, }).then(result => result >= 1) : false, @@ -352,7 +374,11 @@ export class UserRepository extends Repository { where: { userId: user.id, }, - select: ['id', 'name', 'lastUsed'], + select: { + id: true, + name: true, + lastUsed: true, + }, }) : [], } : {}), @@ -369,9 +395,9 @@ export class UserRepository extends Repository { } as Promiseable> as Promiseable>; return await awaitAll(packed); - } + }, - public packMany( + packMany( users: (User['id'] | User)[], me?: { id: User['id'] } | null | undefined, options?: { @@ -380,17 +406,8 @@ export class UserRepository extends Repository { } ): Promise[]> { return Promise.all(users.map(u => this.pack(u, me, options))); - } + }, - public isLocalUser(user: User): user is ILocalUser; - public isLocalUser(user: T): user is T & { host: null; }; - public isLocalUser(user: User | { host: User['host'] }): boolean { - return user.host == null; - } - - public isRemoteUser(user: User): user is IRemoteUser; - public isRemoteUser(user: T): user is T & { host: string; }; - public isRemoteUser(user: User | { host: User['host'] }): boolean { - return !this.isLocalUser(user); - } -} + isLocalUser, + isRemoteUser, +}); diff --git a/packages/backend/src/queue/processors/db/delete-account.ts b/packages/backend/src/queue/processors/db/delete-account.ts index dbc1f16a46..c1657b4be6 100644 --- a/packages/backend/src/queue/processors/db/delete-account.ts +++ b/packages/backend/src/queue/processors/db/delete-account.ts @@ -13,7 +13,7 @@ const logger = queueLogger.createSubLogger('delete-account'); export async function deleteAccount(job: Bull.Job): Promise { 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) { return; } @@ -75,7 +75,7 @@ export async function deleteAccount(job: Bull.Job): Promise } { // Send email notification - const profile = await UserProfiles.findOneOrFail(user.id); + const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); if (profile.email && profile.emailVerified) { sendEmail(profile.email, 'Account deleted', `Your account has been deleted.`, diff --git a/packages/backend/src/queue/processors/db/delete-drive-files.ts b/packages/backend/src/queue/processors/db/delete-drive-files.ts index f6a8699855..b3832d9f04 100644 --- a/packages/backend/src/queue/processors/db/delete-drive-files.ts +++ b/packages/backend/src/queue/processors/db/delete-drive-files.ts @@ -11,7 +11,7 @@ const logger = queueLogger.createSubLogger('delete-drive-files'); export async function deleteDriveFiles(job: Bull.Job, done: any): Promise { 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) { done(); return; @@ -44,7 +44,7 @@ export async function deleteDriveFiles(job: Bull.Job, done: any): deletedCount++; } - const total = await DriveFiles.count({ + const total = await DriveFiles.countBy({ userId: user.id, }); diff --git a/packages/backend/src/queue/processors/db/export-blocking.ts b/packages/backend/src/queue/processors/db/export-blocking.ts index 83f1ec8fd6..166c9e4cd3 100644 --- a/packages/backend/src/queue/processors/db/export-blocking.ts +++ b/packages/backend/src/queue/processors/db/export-blocking.ts @@ -15,7 +15,7 @@ const logger = queueLogger.createSubLogger('export-blocking'); export async function exportBlocking(job: Bull.Job, done: any): Promise { 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) { done(); return; @@ -56,7 +56,7 @@ export async function exportBlocking(job: Bull.Job, done: any): P cursor = blockings[blockings.length - 1].id; for (const block of blockings) { - const u = await Users.findOne({ id: block.blockeeId }); + const u = await Users.findOneBy({ id: block.blockeeId }); if (u == null) { exportedCount++; continue; } @@ -75,7 +75,7 @@ export async function exportBlocking(job: Bull.Job, done: any): P exportedCount++; } - const total = await Blockings.count({ + const total = await Blockings.countBy({ blockerId: user.id, }); diff --git a/packages/backend/src/queue/processors/db/export-custom-emojis.ts b/packages/backend/src/queue/processors/db/export-custom-emojis.ts index a65b46cc00..c2467fb5f0 100644 --- a/packages/backend/src/queue/processors/db/export-custom-emojis.ts +++ b/packages/backend/src/queue/processors/db/export-custom-emojis.ts @@ -12,13 +12,14 @@ import { Users, Emojis } from '@/models/index.js'; import { } from '@/queue/types.js'; import { downloadUrl } from '@/misc/download-url.js'; import config from '@/config/index.js'; +import { IsNull } from 'typeorm'; const logger = queueLogger.createSubLogger('export-custom-emojis'); export async function exportCustomEmojis(job: Bull.Job, done: () => void): Promise { 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) { done(); return; @@ -57,7 +58,7 @@ export async function exportCustomEmojis(job: Bull.Job, done: () => void): Promi const customEmojis = await Emojis.find({ where: { - host: null, + host: IsNull(), }, order: { id: 'ASC', diff --git a/packages/backend/src/queue/processors/db/export-following.ts b/packages/backend/src/queue/processors/db/export-following.ts index 162862180b..965500ac27 100644 --- a/packages/backend/src/queue/processors/db/export-following.ts +++ b/packages/backend/src/queue/processors/db/export-following.ts @@ -16,7 +16,7 @@ const logger = queueLogger.createSubLogger('export-following'); export async function exportFollowing(job: Bull.Job, done: () => void): Promise { 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) { done(); return; @@ -36,7 +36,7 @@ export async function exportFollowing(job: Bull.Job, done: () => 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, }) : []; @@ -60,7 +60,7 @@ export async function exportFollowing(job: Bull.Job, done: () => cursor = followings[followings.length - 1].id; for (const following of followings) { - const u = await Users.findOne({ id: following.followeeId }); + const u = await Users.findOneBy({ id: following.followeeId }); if (u == null) { continue; } diff --git a/packages/backend/src/queue/processors/db/export-mute.ts b/packages/backend/src/queue/processors/db/export-mute.ts index 9fb144abb2..0ef81971f1 100644 --- a/packages/backend/src/queue/processors/db/export-mute.ts +++ b/packages/backend/src/queue/processors/db/export-mute.ts @@ -15,7 +15,7 @@ const logger = queueLogger.createSubLogger('export-mute'); export async function exportMute(job: Bull.Job, done: any): Promise { 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) { done(); return; @@ -57,7 +57,7 @@ export async function exportMute(job: Bull.Job, done: any): Promi cursor = mutes[mutes.length - 1].id; for (const mute of mutes) { - const u = await Users.findOne({ id: mute.muteeId }); + const u = await Users.findOneBy({ id: mute.muteeId }); if (u == null) { exportedCount++; continue; } @@ -76,7 +76,7 @@ export async function exportMute(job: Bull.Job, done: any): Promi exportedCount++; } - const total = await Mutings.count({ + const total = await Mutings.countBy({ muterId: user.id, }); diff --git a/packages/backend/src/queue/processors/db/export-notes.ts b/packages/backend/src/queue/processors/db/export-notes.ts index c79679366c..7e12a6fac2 100644 --- a/packages/backend/src/queue/processors/db/export-notes.ts +++ b/packages/backend/src/queue/processors/db/export-notes.ts @@ -16,7 +16,7 @@ const logger = queueLogger.createSubLogger('export-notes'); export async function exportNotes(job: Bull.Job, done: any): Promise { 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) { done(); return; @@ -74,7 +74,7 @@ export async function exportNotes(job: Bull.Job, done: any): Prom for (const note of notes) { let poll: Poll | undefined; 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 isFirst = exportedNotesCount === 0; @@ -82,7 +82,7 @@ export async function exportNotes(job: Bull.Job, done: any): Prom exportedNotesCount++; } - const total = await Notes.count({ + const total = await Notes.countBy({ userId: user.id, }); diff --git a/packages/backend/src/queue/processors/db/export-user-lists.ts b/packages/backend/src/queue/processors/db/export-user-lists.ts index 1c04c36789..45852a6038 100644 --- a/packages/backend/src/queue/processors/db/export-user-lists.ts +++ b/packages/backend/src/queue/processors/db/export-user-lists.ts @@ -15,13 +15,13 @@ const logger = queueLogger.createSubLogger('export-user-lists'); export async function exportUserLists(job: Bull.Job, done: any): Promise { 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) { done(); return; } - const lists = await UserLists.find({ + const lists = await UserLists.findBy({ userId: user.id, }); @@ -38,8 +38,8 @@ export async function exportUserLists(job: Bull.Job, done: any): const stream = fs.createWriteStream(path, { flags: 'a' }); for (const list of lists) { - const joinings = await UserListJoinings.find({ userListId: list.id }); - const users = await Users.find({ + const joinings = await UserListJoinings.findBy({ userListId: list.id }); + const users = await Users.findBy({ id: In(joinings.map(j => j.userId)), }); diff --git a/packages/backend/src/queue/processors/db/import-blocking.ts b/packages/backend/src/queue/processors/db/import-blocking.ts index 857c2629e3..8bddf34bc2 100644 --- a/packages/backend/src/queue/processors/db/import-blocking.ts +++ b/packages/backend/src/queue/processors/db/import-blocking.ts @@ -8,19 +8,20 @@ import { isSelfHost, toPuny } from '@/misc/convert-host.js'; import { Users, DriveFiles, Blockings } from '@/models/index.js'; import { DbUserImportJobData } from '@/queue/types.js'; import block from '@/services/blocking/create.js'; +import { IsNull } from 'typeorm'; const logger = queueLogger.createSubLogger('import-blocking'); export async function importBlocking(job: Bull.Job, done: any): Promise { 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) { done(); return; } - const file = await DriveFiles.findOne({ + const file = await DriveFiles.findOneBy({ id: job.data.fileId, }); if (file == null) { @@ -39,10 +40,10 @@ export async function importBlocking(job: Bull.Job, done: a const acct = line.split(',')[0].trim(); const { username, host } = Acct.parse(acct); - let target = isSelfHost(host!) ? await Users.findOne({ - host: null, + let target = isSelfHost(host!) ? await Users.findOneBy({ + host: IsNull(), usernameLower: username.toLowerCase(), - }) : await Users.findOne({ + }) : await Users.findOneBy({ host: toPuny(host!), usernameLower: username.toLowerCase(), }); diff --git a/packages/backend/src/queue/processors/db/import-custom-emojis.ts b/packages/backend/src/queue/processors/db/import-custom-emojis.ts index f862276b47..28e0b867a4 100644 --- a/packages/backend/src/queue/processors/db/import-custom-emojis.ts +++ b/packages/backend/src/queue/processors/db/import-custom-emojis.ts @@ -2,7 +2,6 @@ import Bull from 'bull'; import * as tmp from 'tmp'; import * as fs from 'node:fs'; import unzipper from 'unzipper'; -import { getConnection } from 'typeorm'; import { queueLogger } from '../../logger.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 { addFile } from '@/services/drive/add-file.js'; import { genId } from '@/misc/gen-id.js'; +import { db } from '@/db/postgre.js'; 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, done: any): Promise { logger.info(`Importing custom emojis ...`); - const file = await DriveFiles.findOne({ + const file = await DriveFiles.findOneBy({ id: job.data.fileId, }); if (file == null) { @@ -72,10 +72,10 @@ export async function importCustomEmojis(job: Bull.Job, don originalUrl: driveFile.url, publicUrl: driveFile.webpublicUrl ?? driveFile.url, 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(); diff --git a/packages/backend/src/queue/processors/db/import-following.ts b/packages/backend/src/queue/processors/db/import-following.ts index 235fc28394..8ce2c367d6 100644 --- a/packages/backend/src/queue/processors/db/import-following.ts +++ b/packages/backend/src/queue/processors/db/import-following.ts @@ -8,19 +8,20 @@ import { downloadTextFile } from '@/misc/download-text-file.js'; import { isSelfHost, toPuny } from '@/misc/convert-host.js'; import { Users, DriveFiles } from '@/models/index.js'; import { DbUserImportJobData } from '@/queue/types.js'; +import { IsNull } from 'typeorm'; const logger = queueLogger.createSubLogger('import-following'); export async function importFollowing(job: Bull.Job, done: any): Promise { 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) { done(); return; } - const file = await DriveFiles.findOne({ + const file = await DriveFiles.findOneBy({ id: job.data.fileId, }); if (file == null) { @@ -39,10 +40,10 @@ export async function importFollowing(job: Bull.Job, done: const acct = line.split(',')[0].trim(); const { username, host } = Acct.parse(acct); - let target = isSelfHost(host!) ? await Users.findOne({ - host: null, + let target = isSelfHost(host!) ? await Users.findOneBy({ + host: IsNull(), usernameLower: username.toLowerCase(), - }) : await Users.findOne({ + }) : await Users.findOneBy({ host: toPuny(host!), usernameLower: username.toLowerCase(), }); diff --git a/packages/backend/src/queue/processors/db/import-muting.ts b/packages/backend/src/queue/processors/db/import-muting.ts index 32f5f6bbee..8552b797be 100644 --- a/packages/backend/src/queue/processors/db/import-muting.ts +++ b/packages/backend/src/queue/processors/db/import-muting.ts @@ -9,19 +9,20 @@ import { Users, DriveFiles, Mutings } from '@/models/index.js'; import { DbUserImportJobData } from '@/queue/types.js'; import { User } from '@/models/entities/user.js'; import { genId } from '@/misc/gen-id.js'; +import { IsNull } from 'typeorm'; const logger = queueLogger.createSubLogger('import-muting'); export async function importMuting(job: Bull.Job, done: any): Promise { 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) { done(); return; } - const file = await DriveFiles.findOne({ + const file = await DriveFiles.findOneBy({ id: job.data.fileId, }); if (file == null) { @@ -40,10 +41,10 @@ export async function importMuting(job: Bull.Job, done: any const acct = line.split(',')[0].trim(); const { username, host } = Acct.parse(acct); - let target = isSelfHost(host!) ? await Users.findOne({ - host: null, + let target = isSelfHost(host!) ? await Users.findOneBy({ + host: IsNull(), usernameLower: username.toLowerCase(), - }) : await Users.findOne({ + }) : await Users.findOneBy({ host: toPuny(host!), usernameLower: username.toLowerCase(), }); diff --git a/packages/backend/src/queue/processors/db/import-user-lists.ts b/packages/backend/src/queue/processors/db/import-user-lists.ts index ae263e19b0..9919b7c53c 100644 --- a/packages/backend/src/queue/processors/db/import-user-lists.ts +++ b/packages/backend/src/queue/processors/db/import-user-lists.ts @@ -9,19 +9,20 @@ import { isSelfHost, toPuny } from '@/misc/convert-host.js'; import { DriveFiles, Users, UserLists, UserListJoinings } from '@/models/index.js'; import { genId } from '@/misc/gen-id.js'; import { DbUserImportJobData } from '@/queue/types.js'; +import { IsNull } from 'typeorm'; const logger = queueLogger.createSubLogger('import-user-lists'); export async function importUserLists(job: Bull.Job, done: any): Promise { 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) { done(); return; } - const file = await DriveFiles.findOne({ + const file = await DriveFiles.findOneBy({ id: job.data.fileId, }); if (file == null) { @@ -40,7 +41,7 @@ export async function importUserLists(job: Bull.Job, done: const listName = line.split(',')[0].trim(); const { username, host } = Acct.parse(line.split(',')[1].trim()); - let list = await UserLists.findOne({ + let list = await UserLists.findOneBy({ userId: user.id, name: listName, }); @@ -51,13 +52,13 @@ export async function importUserLists(job: Bull.Job, done: createdAt: new Date(), userId: user.id, name: listName, - }).then(x => UserLists.findOneOrFail(x.identifiers[0])); + }).then(x => UserLists.findOneByOrFail(x.identifiers[0])); } - let target = isSelfHost(host!) ? await Users.findOne({ - host: null, + let target = isSelfHost(host!) ? await Users.findOneBy({ + host: IsNull(), usernameLower: username.toLowerCase(), - }) : await Users.findOne({ + }) : await Users.findOneBy({ host: toPuny(host!), usernameLower: username.toLowerCase(), }); @@ -66,7 +67,7 @@ export async function importUserLists(job: Bull.Job, done: 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!); } catch (e) { diff --git a/packages/backend/src/queue/processors/ended-poll-notification.ts b/packages/backend/src/queue/processors/ended-poll-notification.ts index afac27921f..6151c96ad6 100644 --- a/packages/backend/src/queue/processors/ended-poll-notification.ts +++ b/packages/backend/src/queue/processors/ended-poll-notification.ts @@ -8,7 +8,7 @@ import { createNotification } from '@/services/create-notification.js'; const logger = queueLogger.createSubLogger('ended-poll-notification'); export async function endedPollNotification(job: Bull.Job, done: any): Promise { - const note = await Notes.findOne(job.data.noteId); + const note = await Notes.findOneBy({ id: job.data.noteId }); if (note == null || !note.hasPoll) { done(); return; diff --git a/packages/backend/src/queue/processors/inbox.ts b/packages/backend/src/queue/processors/inbox.ts index 1b3f94b700..4fbfdb234f 100644 --- a/packages/backend/src/queue/processors/inbox.ts +++ b/packages/backend/src/queue/processors/inbox.ts @@ -15,6 +15,8 @@ import DbResolver from '@/remote/activitypub/db-resolver.js'; import { resolvePerson } from '@/remote/activitypub/models/person.js'; import { LdSignature } from '@/remote/activitypub/misc/ld-signature.js'; import { StatusError } from '@/misc/fetch.js'; +import { CacheableRemoteUser } from '@/models/entities/user.js'; +import { UserPublickey } from '@/models/entities/user-publickey.js'; const logger = new Logger('inbox'); @@ -42,11 +44,13 @@ export default async (job: Bull.Job): Promise => { return `Old keyId is no longer supported. ${keyIdLower}`; } - // TDOO: キャッシュ const dbResolver = new DbResolver(); // HTTP-Signature keyIdを元にDBから取得 - let authUser = await dbResolver.getAuthUserFromKeyId(signature.keyId); + let authUser: { + user: CacheableRemoteUser; + key: UserPublickey | null; + } | null = await dbResolver.getAuthUserFromKeyId(signature.keyId); // keyIdでわからなければ、activity.actorを元にDBから取得 || activity.actorを元にリモートから取得 if (authUser == null) { diff --git a/packages/backend/src/queue/processors/object-storage/clean-remote-files.ts b/packages/backend/src/queue/processors/object-storage/clean-remote-files.ts index 7d71a20adb..77da162f6e 100644 --- a/packages/backend/src/queue/processors/object-storage/clean-remote-files.ts +++ b/packages/backend/src/queue/processors/object-storage/clean-remote-files.ts @@ -37,7 +37,7 @@ export default async function cleanRemoteFiles(job: Bull.Job { +export async function parseAudience(actor: CacheableRemoteUser, to?: ApObject, cc?: ApObject, resolver?: Resolver): Promise { const toGroups = groupingAudience(getApIds(to), actor); const ccGroups = groupingAudience(getApIds(cc), actor); const others = unique(concat([toGroups.other, ccGroups.other])); - const limit = promiseLimit(2); + const limit = promiseLimit(2); const mentionedUsers = (await Promise.all( others.map(id => limit(() => resolvePerson(id, resolver).catch(() => null))) - )).filter((x): x is User => x != null); + )).filter((x): x is CacheableUser => x != null); if (toGroups.public.length > 0) { return { @@ -55,7 +55,7 @@ export async function parseAudience(actor: IRemoteUser, to?: ApObject, cc?: ApOb }; } -function groupingAudience(ids: string[], actor: IRemoteUser) { +function groupingAudience(ids: string[], actor: CacheableRemoteUser) { const groups = { public: [] as string[], followers: [] as string[], @@ -85,7 +85,7 @@ function isPublic(id: string) { ].includes(id); } -function isFollowers(id: string, actor: IRemoteUser) { +function isFollowers(id: string, actor: CacheableRemoteUser) { return ( id === (actor.followersUri || `${actor.uri}/followers`) ); diff --git a/packages/backend/src/remote/activitypub/db-resolver.ts b/packages/backend/src/remote/activitypub/db-resolver.ts index 3f16c5f56d..ef07966e42 100644 --- a/packages/backend/src/remote/activitypub/db-resolver.ts +++ b/packages/backend/src/remote/activitypub/db-resolver.ts @@ -1,12 +1,17 @@ +import escapeRegexp from 'escape-regexp'; import config from '@/config/index.js'; import { Note } from '@/models/entities/note.js'; -import { User, IRemoteUser } from '@/models/entities/user.js'; +import { User, IRemoteUser, CacheableRemoteUser, CacheableUser } from '@/models/entities/user.js'; import { UserPublickey } from '@/models/entities/user-publickey.js'; import { MessagingMessage } from '@/models/entities/messaging-message.js'; import { Notes, Users, UserPublickeys, MessagingMessages } from '@/models/index.js'; import { IObject, getApId } from './type.js'; import { resolvePerson } from './models/person.js'; -import escapeRegexp from 'escape-regexp'; +import { Cache } from '@/misc/cache.js'; +import { uriPersonCache, userByIdCache } from '@/services/user-cache.js'; + +const publicKeyCache = new Cache(Infinity); +const publicKeyByUserIdCache = new Cache(Infinity); export default class DbResolver { constructor() { @@ -19,15 +24,15 @@ export default class DbResolver { const parsed = this.parseUri(value); if (parsed.id) { - return (await Notes.findOne({ + return await Notes.findOneBy({ id: parsed.id, - })) || null; + }); } if (parsed.uri) { - return (await Notes.findOne({ + return await Notes.findOneBy({ uri: parsed.uri, - })) || null; + }); } return null; @@ -37,15 +42,15 @@ export default class DbResolver { const parsed = this.parseUri(value); if (parsed.id) { - return (await MessagingMessages.findOne({ + return await MessagingMessages.findOneBy({ id: parsed.id, - })) || null; + }); } if (parsed.uri) { - return (await MessagingMessages.findOne({ + return await MessagingMessages.findOneBy({ uri: parsed.uri, - })) || null; + }); } return null; @@ -54,19 +59,19 @@ export default class DbResolver { /** * AP Person => Misskey User in DB */ - public async getUserFromApId(value: string | IObject): Promise { + public async getUserFromApId(value: string | IObject): Promise { const parsed = this.parseUri(value); if (parsed.id) { - return (await Users.findOne({ + return await userByIdCache.fetchMaybe(parsed.id, () => Users.findOneBy({ id: parsed.id, - })) || null; + }).then(x => x ?? undefined)) ?? null; } if (parsed.uri) { - return (await Users.findOne({ + return await uriPersonCache.fetch(parsed.uri, () => Users.findOneBy({ uri: parsed.uri, - })) || null; + })); } return null; @@ -75,17 +80,24 @@ export default class DbResolver { /** * AP KeyId => Misskey User and Key */ - public async getAuthUserFromKeyId(keyId: string): Promise { - const key = await UserPublickeys.findOne({ - keyId, - }, { - relations: ['user'], - }); + public async getAuthUserFromKeyId(keyId: string): Promise<{ + user: CacheableRemoteUser; + key: UserPublickey; + } | null> { + const key = await publicKeyCache.fetch(keyId, async () => { + const key = await UserPublickeys.findOneBy({ + keyId, + }); + + if (key == null) return null; + + return key; + }, key => key != null); if (key == null) return null; return { - user: key.user as IRemoteUser, + user: await userByIdCache.fetch(key.userId, () => Users.findOneByOrFail({ id: key.userId })) as CacheableRemoteUser, key, }; } @@ -93,12 +105,15 @@ export default class DbResolver { /** * AP Actor id => Misskey User and Key */ - public async getAuthUserFromApId(uri: string): Promise { - const user = await resolvePerson(uri) as IRemoteUser; + public async getAuthUserFromApId(uri: string): Promise<{ + user: CacheableRemoteUser; + key: UserPublickey | null; + } | null> { + const user = await resolvePerson(uri) as CacheableRemoteUser; if (user == null) return null; - const key = await UserPublickeys.findOne(user.id); + const key = await publicKeyByUserIdCache.fetch(user.id, () => UserPublickeys.findOneBy({ userId: user.id }), v => v != null); return { user, @@ -125,11 +140,6 @@ export default class DbResolver { } } -export type AuthUser = { - user: IRemoteUser; - key?: UserPublickey; -}; - type UriParseResult = { /** id in DB (local object only) */ id?: string; diff --git a/packages/backend/src/remote/activitypub/deliver-manager.ts b/packages/backend/src/remote/activitypub/deliver-manager.ts index 9c4e3418ff..9f21dc4cc6 100644 --- a/packages/backend/src/remote/activitypub/deliver-manager.ts +++ b/packages/backend/src/remote/activitypub/deliver-manager.ts @@ -1,6 +1,7 @@ import { Users, Followings } from '@/models/index.js'; import { ILocalUser, IRemoteUser, User } from '@/models/entities/user.js'; import { deliver } from '@/queue/index.js'; +import { IsNull, Not } from 'typeorm'; //#region types interface IRecipe { @@ -82,15 +83,25 @@ export default class DeliverManager { for (const recipe of this.recipes) { if (isFollowers(recipe)) { // followers deliver + // TODO: SELECT DISTINCT ON ("followerSharedInbox") "followerSharedInbox" みたいな問い合わせにすればよりパフォーマンス向上できそう + // ただ、sharedInboxがnullなリモートユーザーも稀におり、その対応ができなさそう? const followers = await Followings.find({ - followeeId: this.actor.id, - }); + where: { + followeeId: this.actor.id, + followerHost: Not(IsNull()), + }, + select: { + followerSharedInbox: true, + followerInbox: true, + }, + }) as { + followerSharedInbox: string | null; + followerInbox: string; + }[]; for (const following of followers) { - if (Followings.isRemoteFollower(following)) { - const inbox = following.followerSharedInbox || following.followerInbox; - inboxes.add(inbox); - } + const inbox = following.followerSharedInbox || following.followerInbox; + inboxes.add(inbox); } } else if (isDirect(recipe)) { // direct deliver @@ -112,7 +123,7 @@ export default class DeliverManager { * @param activity Activity * @param from Followee */ -export async function deliverToFollowers(actor: ILocalUser, activity: any) { +export async function deliverToFollowers(actor: { id: ILocalUser['id']; host: null; }, activity: any) { const manager = new DeliverManager(actor, activity); manager.addFollowersRecipe(); await manager.execute(); @@ -123,7 +134,7 @@ export async function deliverToFollowers(actor: ILocalUser, activity: any) { * @param activity Activity * @param to Target user */ -export async function deliverToUser(actor: ILocalUser, activity: any, to: IRemoteUser) { +export async function deliverToUser(actor: { id: ILocalUser['id']; host: null; }, activity: any, to: IRemoteUser) { const manager = new DeliverManager(actor, activity); manager.addDirectRecipe(to); await manager.execute(); diff --git a/packages/backend/src/remote/activitypub/kernel/accept/follow.ts b/packages/backend/src/remote/activitypub/kernel/accept/follow.ts index 393516addf..4350ef1333 100644 --- a/packages/backend/src/remote/activitypub/kernel/accept/follow.ts +++ b/packages/backend/src/remote/activitypub/kernel/accept/follow.ts @@ -1,10 +1,10 @@ -import { IRemoteUser } from '@/models/entities/user.js'; +import { CacheableRemoteUser } from '@/models/entities/user.js'; import accept from '@/services/following/requests/accept.js'; import { IFollow } from '../../type.js'; import DbResolver from '../../db-resolver.js'; import { relayAccepted } from '@/services/relay.js'; -export default async (actor: IRemoteUser, activity: IFollow): Promise => { +export default async (actor: CacheableRemoteUser, activity: IFollow): Promise => { // ※ activityはこっちから投げたフォローリクエストなので、activity.actorは存在するローカルユーザーである必要がある const dbResolver = new DbResolver(); diff --git a/packages/backend/src/remote/activitypub/kernel/accept/index.ts b/packages/backend/src/remote/activitypub/kernel/accept/index.ts index 354bd4f6e1..78ef75ade3 100644 --- a/packages/backend/src/remote/activitypub/kernel/accept/index.ts +++ b/packages/backend/src/remote/activitypub/kernel/accept/index.ts @@ -1,12 +1,12 @@ import Resolver from '../../resolver.js'; -import { IRemoteUser } from '@/models/entities/user.js'; +import { CacheableRemoteUser } from '@/models/entities/user.js'; import acceptFollow from './follow.js'; import { IAccept, isFollow, getApType } from '../../type.js'; import { apLogger } from '../../logger.js'; const logger = apLogger; -export default async (actor: IRemoteUser, activity: IAccept): Promise => { +export default async (actor: CacheableRemoteUser, activity: IAccept): Promise => { const uri = activity.id || activity; logger.info(`Accept: ${uri}`); diff --git a/packages/backend/src/remote/activitypub/kernel/add/index.ts b/packages/backend/src/remote/activitypub/kernel/add/index.ts index 9a2fac1e74..c813414f93 100644 --- a/packages/backend/src/remote/activitypub/kernel/add/index.ts +++ b/packages/backend/src/remote/activitypub/kernel/add/index.ts @@ -1,9 +1,9 @@ -import { IRemoteUser } from '@/models/entities/user.js'; +import { CacheableRemoteUser } from '@/models/entities/user.js'; import { IAdd } from '../../type.js'; import { resolveNote } from '../../models/note.js'; import { addPinned } from '@/services/i/pin.js'; -export default async (actor: IRemoteUser, activity: IAdd): Promise => { +export default async (actor: CacheableRemoteUser, activity: IAdd): Promise => { if ('actor' in activity && actor.uri !== activity.actor) { throw new Error('invalid actor'); } diff --git a/packages/backend/src/remote/activitypub/kernel/announce/index.ts b/packages/backend/src/remote/activitypub/kernel/announce/index.ts index 7e2e73bdd5..ae7e507c99 100644 --- a/packages/backend/src/remote/activitypub/kernel/announce/index.ts +++ b/packages/backend/src/remote/activitypub/kernel/announce/index.ts @@ -1,12 +1,12 @@ import Resolver from '../../resolver.js'; -import { IRemoteUser } from '@/models/entities/user.js'; +import { CacheableRemoteUser } from '@/models/entities/user.js'; import announceNote from './note.js'; import { IAnnounce, getApId } from '../../type.js'; import { apLogger } from '../../logger.js'; const logger = apLogger; -export default async (actor: IRemoteUser, activity: IAnnounce): Promise => { +export default async (actor: CacheableRemoteUser, activity: IAnnounce): Promise => { const uri = getApId(activity); logger.info(`Announce: ${uri}`); diff --git a/packages/backend/src/remote/activitypub/kernel/announce/note.ts b/packages/backend/src/remote/activitypub/kernel/announce/note.ts index f6068fac79..680749f4d8 100644 --- a/packages/backend/src/remote/activitypub/kernel/announce/note.ts +++ b/packages/backend/src/remote/activitypub/kernel/announce/note.ts @@ -1,6 +1,6 @@ import Resolver from '../../resolver.js'; import post from '@/services/note/create.js'; -import { IRemoteUser } from '@/models/entities/user.js'; +import { CacheableRemoteUser } from '@/models/entities/user.js'; import { IAnnounce, getApId } from '../../type.js'; import { fetchNote, resolveNote } from '../../models/note.js'; import { apLogger } from '../../logger.js'; @@ -15,10 +15,9 @@ const logger = apLogger; /** * アナウンスアクティビティを捌きます */ -export default async function(resolver: Resolver, actor: IRemoteUser, activity: IAnnounce, targetUri: string): Promise { +export default async function(resolver: Resolver, actor: CacheableRemoteUser, activity: IAnnounce, targetUri: string): Promise { const uri = getApId(activity); - // アナウンサーが凍結されていたらスキップ if (actor.isSuspended) { return; } diff --git a/packages/backend/src/remote/activitypub/kernel/block/index.ts b/packages/backend/src/remote/activitypub/kernel/block/index.ts index 9e4f1b316e..5e230ad7b7 100644 --- a/packages/backend/src/remote/activitypub/kernel/block/index.ts +++ b/packages/backend/src/remote/activitypub/kernel/block/index.ts @@ -1,9 +1,10 @@ import { IBlock } from '../../type.js'; import block from '@/services/blocking/create.js'; -import { IRemoteUser } from '@/models/entities/user.js'; +import { CacheableRemoteUser } from '@/models/entities/user.js'; import DbResolver from '../../db-resolver.js'; +import { Users } from '@/models/index.js'; -export default async (actor: IRemoteUser, activity: IBlock): Promise => { +export default async (actor: CacheableRemoteUser, activity: IBlock): Promise => { // ※ activity.objectにブロック対象があり、それは存在するローカルユーザーのはず const dbResolver = new DbResolver(); @@ -17,6 +18,6 @@ export default async (actor: IRemoteUser, activity: IBlock): Promise => return `skip: ブロックしようとしているユーザーはローカルユーザーではありません`; } - await block(actor, blockee); + await block(await Users.findOneByOrFail({ id: actor.id }), await Users.findOneByOrFail({ id: blockee.id })); return `ok`; }; diff --git a/packages/backend/src/remote/activitypub/kernel/create/index.ts b/packages/backend/src/remote/activitypub/kernel/create/index.ts index 1187b95ac6..c253f9f667 100644 --- a/packages/backend/src/remote/activitypub/kernel/create/index.ts +++ b/packages/backend/src/remote/activitypub/kernel/create/index.ts @@ -1,5 +1,5 @@ import Resolver from '../../resolver.js'; -import { IRemoteUser } from '@/models/entities/user.js'; +import { CacheableRemoteUser } from '@/models/entities/user.js'; import createNote from './note.js'; import { ICreate, getApId, isPost, getApType } from '../../type.js'; import { apLogger } from '../../logger.js'; @@ -7,7 +7,7 @@ import { toArray, concat, unique } from '@/prelude/array.js'; const logger = apLogger; -export default async (actor: IRemoteUser, activity: ICreate): Promise => { +export default async (actor: CacheableRemoteUser, activity: ICreate): Promise => { const uri = getApId(activity); logger.info(`Create: ${uri}`); diff --git a/packages/backend/src/remote/activitypub/kernel/create/note.ts b/packages/backend/src/remote/activitypub/kernel/create/note.ts index b5c47990aa..f8dabe06e2 100644 --- a/packages/backend/src/remote/activitypub/kernel/create/note.ts +++ b/packages/backend/src/remote/activitypub/kernel/create/note.ts @@ -1,5 +1,5 @@ import Resolver from '../../resolver.js'; -import { IRemoteUser } from '@/models/entities/user.js'; +import { CacheableRemoteUser } from '@/models/entities/user.js'; import { createNote, fetchNote } from '../../models/note.js'; import { getApId, IObject, ICreate } from '../../type.js'; import { getApLock } from '@/misc/app-lock.js'; @@ -9,7 +9,7 @@ import { StatusError } from '@/misc/fetch.js'; /** * 投稿作成アクティビティを捌きます */ -export default async function(resolver: Resolver, actor: IRemoteUser, note: IObject, silent = false, activity?: ICreate): Promise { +export default async function(resolver: Resolver, actor: CacheableRemoteUser, note: IObject, silent = false, activity?: ICreate): Promise { const uri = getApId(note); if (typeof note === 'object') { diff --git a/packages/backend/src/remote/activitypub/kernel/delete/actor.ts b/packages/backend/src/remote/activitypub/kernel/delete/actor.ts index 2f75841e52..1f94df033d 100644 --- a/packages/backend/src/remote/activitypub/kernel/delete/actor.ts +++ b/packages/backend/src/remote/activitypub/kernel/delete/actor.ts @@ -1,18 +1,19 @@ import { apLogger } from '../../logger.js'; import { createDeleteAccountJob } from '@/queue/index.js'; -import { IRemoteUser } from '@/models/entities/user.js'; +import { CacheableRemoteUser } from '@/models/entities/user.js'; import { Users } from '@/models/index.js'; const logger = apLogger; -export async function deleteActor(actor: IRemoteUser, uri: string): Promise { +export async function deleteActor(actor: CacheableRemoteUser, uri: string): Promise { logger.info(`Deleting the Actor: ${uri}`); if (actor.uri !== uri) { return `skip: delete actor ${actor.uri} !== ${uri}`; } - if (actor.isDeleted) { + const user = await Users.findOneByOrFail({ id: actor.id }); + if (user.isDeleted) { logger.info(`skip: already deleted`); } diff --git a/packages/backend/src/remote/activitypub/kernel/delete/index.ts b/packages/backend/src/remote/activitypub/kernel/delete/index.ts index b6d5e96d03..4c06a9de0b 100644 --- a/packages/backend/src/remote/activitypub/kernel/delete/index.ts +++ b/packages/backend/src/remote/activitypub/kernel/delete/index.ts @@ -1,5 +1,5 @@ import deleteNote from './note.js'; -import { IRemoteUser } from '@/models/entities/user.js'; +import { CacheableRemoteUser } from '@/models/entities/user.js'; import { IDelete, getApId, isTombstone, IObject, validPost, validActor } from '../../type.js'; import { toSingle } from '@/prelude/array.js'; import { deleteActor } from './actor.js'; @@ -7,7 +7,7 @@ import { deleteActor } from './actor.js'; /** * 削除アクティビティを捌きます */ -export default async (actor: IRemoteUser, activity: IDelete): Promise => { +export default async (actor: CacheableRemoteUser, activity: IDelete): Promise => { if ('actor' in activity && actor.uri !== activity.actor) { throw new Error('invalid actor'); } diff --git a/packages/backend/src/remote/activitypub/kernel/delete/note.ts b/packages/backend/src/remote/activitypub/kernel/delete/note.ts index ad5e1a2edc..1f44c35562 100644 --- a/packages/backend/src/remote/activitypub/kernel/delete/note.ts +++ b/packages/backend/src/remote/activitypub/kernel/delete/note.ts @@ -1,4 +1,4 @@ -import { IRemoteUser } from '@/models/entities/user.js'; +import { CacheableRemoteUser } from '@/models/entities/user.js'; import deleteNode from '@/services/note/delete.js'; import { apLogger } from '../../logger.js'; import DbResolver from '../../db-resolver.js'; @@ -7,7 +7,7 @@ import { deleteMessage } from '@/services/messages/delete.js'; const logger = apLogger; -export default async function(actor: IRemoteUser, uri: string): Promise { +export default async function(actor: CacheableRemoteUser, uri: string): Promise { logger.info(`Deleting the Note: ${uri}`); const unlock = await getApLock(uri); diff --git a/packages/backend/src/remote/activitypub/kernel/flag/index.ts b/packages/backend/src/remote/activitypub/kernel/flag/index.ts index e80e632786..aa2f1f5362 100644 --- a/packages/backend/src/remote/activitypub/kernel/flag/index.ts +++ b/packages/backend/src/remote/activitypub/kernel/flag/index.ts @@ -1,17 +1,17 @@ -import { IRemoteUser } from '@/models/entities/user.js'; +import { CacheableRemoteUser } from '@/models/entities/user.js'; import config from '@/config/index.js'; import { IFlag, getApIds } from '../../type.js'; import { AbuseUserReports, Users } from '@/models/index.js'; import { In } from 'typeorm'; import { genId } from '@/misc/gen-id.js'; -export default async (actor: IRemoteUser, activity: IFlag): Promise => { +export default async (actor: CacheableRemoteUser, activity: IFlag): Promise => { // objectは `(User|Note) | (User|Note)[]` だけど、全パターンDBスキーマと対応させられないので // 対象ユーザーは一番最初のユーザー として あとはコメントとして格納する const uris = getApIds(activity.object); 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), }); if (users.length < 1) return `skip`; diff --git a/packages/backend/src/remote/activitypub/kernel/follow.ts b/packages/backend/src/remote/activitypub/kernel/follow.ts index 49c1a7ee01..a9e92fa229 100644 --- a/packages/backend/src/remote/activitypub/kernel/follow.ts +++ b/packages/backend/src/remote/activitypub/kernel/follow.ts @@ -1,9 +1,9 @@ -import { IRemoteUser } from '@/models/entities/user.js'; +import { CacheableRemoteUser } from '@/models/entities/user.js'; import follow from '@/services/following/create.js'; import { IFollow } from '../type.js'; import DbResolver from '../db-resolver.js'; -export default async (actor: IRemoteUser, activity: IFollow): Promise => { +export default async (actor: CacheableRemoteUser, activity: IFollow): Promise => { const dbResolver = new DbResolver(); const followee = await dbResolver.getUserFromApId(activity.object); diff --git a/packages/backend/src/remote/activitypub/kernel/index.ts b/packages/backend/src/remote/activitypub/kernel/index.ts index 6aea8e57cf..254a121605 100644 --- a/packages/backend/src/remote/activitypub/kernel/index.ts +++ b/packages/backend/src/remote/activitypub/kernel/index.ts @@ -1,5 +1,5 @@ import { IObject, isCreate, isDelete, isUpdate, isRead, isFollow, isAccept, isReject, isAdd, isRemove, isAnnounce, isLike, isUndo, isBlock, isCollectionOrOrderedCollection, isCollection, isFlag } from '../type.js'; -import { IRemoteUser } from '@/models/entities/user.js'; +import { CacheableRemoteUser } from '@/models/entities/user.js'; import create from './create/index.js'; import performDeleteActivity from './delete/index.js'; import performUpdateActivity from './update/index.js'; @@ -17,8 +17,9 @@ import flag from './flag/index.js'; import { apLogger } from '../logger.js'; import Resolver from '../resolver.js'; import { toArray } from '@/prelude/array.js'; +import { Users } from '@/models/index.js'; -export async function performActivity(actor: IRemoteUser, activity: IObject) { +export async function performActivity(actor: CacheableRemoteUser, activity: IObject) { if (isCollectionOrOrderedCollection(activity)) { const resolver = new Resolver(); for (const item of toArray(isCollection(activity) ? activity.items : activity.orderedItems)) { @@ -36,7 +37,7 @@ export async function performActivity(actor: IRemoteUser, activity: IObject) { } } -async function performOneActivity(actor: IRemoteUser, activity: IObject): Promise { +async function performOneActivity(actor: CacheableRemoteUser, activity: IObject): Promise { if (actor.isSuspended) return; if (isCreate(activity)) { diff --git a/packages/backend/src/remote/activitypub/kernel/like.ts b/packages/backend/src/remote/activitypub/kernel/like.ts index 715cc379b9..2b65ff7383 100644 --- a/packages/backend/src/remote/activitypub/kernel/like.ts +++ b/packages/backend/src/remote/activitypub/kernel/like.ts @@ -1,9 +1,9 @@ -import { IRemoteUser } from '@/models/entities/user.js'; +import { CacheableRemoteUser } from '@/models/entities/user.js'; import { ILike, getApId } from '../type.js'; import create from '@/services/note/reaction/create.js'; import { fetchNote, extractEmojis } from '../models/note.js'; -export default async (actor: IRemoteUser, activity: ILike) => { +export default async (actor: CacheableRemoteUser, activity: ILike) => { const targetUri = getApId(activity.object); const note = await fetchNote(targetUri); diff --git a/packages/backend/src/remote/activitypub/kernel/read.ts b/packages/backend/src/remote/activitypub/kernel/read.ts index 93cc36ec46..7f1519ac2e 100644 --- a/packages/backend/src/remote/activitypub/kernel/read.ts +++ b/packages/backend/src/remote/activitypub/kernel/read.ts @@ -1,10 +1,10 @@ -import { IRemoteUser } from '@/models/entities/user.js'; +import { CacheableRemoteUser } from '@/models/entities/user.js'; import { IRead, getApId } from '../type.js'; import { isSelfHost, extractDbHost } from '@/misc/convert-host.js'; import { MessagingMessages } from '@/models/index.js'; import { readUserMessagingMessage } from '../../../server/api/common/read-messaging-message.js'; -export const performReadActivity = async (actor: IRemoteUser, activity: IRead): Promise => { +export const performReadActivity = async (actor: CacheableRemoteUser, activity: IRead): Promise => { const id = await getApId(activity.object); if (!isSelfHost(extractDbHost(id))) { @@ -13,7 +13,7 @@ export const performReadActivity = async (actor: IRemoteUser, activity: IRead): const messageId = id.split('/').pop(); - const message = await MessagingMessages.findOne(messageId); + const message = await MessagingMessages.findOneBy({ id: messageId }); if (message == null) { return `skip: message not found`; } diff --git a/packages/backend/src/remote/activitypub/kernel/reject/follow.ts b/packages/backend/src/remote/activitypub/kernel/reject/follow.ts index 72751e83c0..824ac69d70 100644 --- a/packages/backend/src/remote/activitypub/kernel/reject/follow.ts +++ b/packages/backend/src/remote/activitypub/kernel/reject/follow.ts @@ -1,11 +1,11 @@ -import { IRemoteUser } from '@/models/entities/user.js'; +import { CacheableRemoteUser } from '@/models/entities/user.js'; import { remoteReject } from '@/services/following/reject.js'; import { IFollow } from '../../type.js'; import DbResolver from '../../db-resolver.js'; import { relayRejected } from '@/services/relay.js'; import { Users } from '@/models/index.js'; -export default async (actor: IRemoteUser, activity: IFollow): Promise => { +export default async (actor: CacheableRemoteUser, activity: IFollow): Promise => { // ※ activityはこっちから投げたフォローリクエストなので、activity.actorは存在するローカルユーザーである必要がある const dbResolver = new DbResolver(); diff --git a/packages/backend/src/remote/activitypub/kernel/reject/index.ts b/packages/backend/src/remote/activitypub/kernel/reject/index.ts index ed86a4aa2f..00f08842f4 100644 --- a/packages/backend/src/remote/activitypub/kernel/reject/index.ts +++ b/packages/backend/src/remote/activitypub/kernel/reject/index.ts @@ -1,12 +1,12 @@ import Resolver from '../../resolver.js'; -import { IRemoteUser } from '@/models/entities/user.js'; +import { CacheableRemoteUser } from '@/models/entities/user.js'; import rejectFollow from './follow.js'; import { IReject, isFollow, getApType } from '../../type.js'; import { apLogger } from '../../logger.js'; const logger = apLogger; -export default async (actor: IRemoteUser, activity: IReject): Promise => { +export default async (actor: CacheableRemoteUser, activity: IReject): Promise => { const uri = activity.id || activity; logger.info(`Reject: ${uri}`); diff --git a/packages/backend/src/remote/activitypub/kernel/remove/index.ts b/packages/backend/src/remote/activitypub/kernel/remove/index.ts index 7d7b3386c0..11a994a83b 100644 --- a/packages/backend/src/remote/activitypub/kernel/remove/index.ts +++ b/packages/backend/src/remote/activitypub/kernel/remove/index.ts @@ -1,9 +1,9 @@ -import { IRemoteUser } from '@/models/entities/user.js'; +import { CacheableRemoteUser } from '@/models/entities/user.js'; import { IRemove } from '../../type.js'; import { resolveNote } from '../../models/note.js'; import { removePinned } from '@/services/i/pin.js'; -export default async (actor: IRemoteUser, activity: IRemove): Promise => { +export default async (actor: CacheableRemoteUser, activity: IRemove): Promise => { if ('actor' in activity && actor.uri !== activity.actor) { throw new Error('invalid actor'); } diff --git a/packages/backend/src/remote/activitypub/kernel/undo/accept.ts b/packages/backend/src/remote/activitypub/kernel/undo/accept.ts index 2383eea5bd..8f6eab6858 100644 --- a/packages/backend/src/remote/activitypub/kernel/undo/accept.ts +++ b/packages/backend/src/remote/activitypub/kernel/undo/accept.ts @@ -1,11 +1,11 @@ import unfollow from '@/services/following/delete.js'; import cancelRequest from '@/services/following/requests/cancel.js'; import {IAccept} from '../../type.js'; -import { IRemoteUser } from '@/models/entities/user.js'; +import { CacheableRemoteUser } from '@/models/entities/user.js'; import { Followings } from '@/models/index.js'; import DbResolver from '../../db-resolver.js'; -export default async (actor: IRemoteUser, activity: IAccept): Promise => { +export default async (actor: CacheableRemoteUser, activity: IAccept): Promise => { const dbResolver = new DbResolver(); const follower = await dbResolver.getUserFromApId(activity.object); @@ -13,7 +13,7 @@ export default async (actor: IRemoteUser, activity: IAccept): Promise => return `skip: follower not found`; } - const following = await Followings.findOne({ + const following = await Followings.findOneBy({ followerId: follower.id, followeeId: actor.id, }); diff --git a/packages/backend/src/remote/activitypub/kernel/undo/announce.ts b/packages/backend/src/remote/activitypub/kernel/undo/announce.ts index 822c1e4948..c2ac31bf8d 100644 --- a/packages/backend/src/remote/activitypub/kernel/undo/announce.ts +++ b/packages/backend/src/remote/activitypub/kernel/undo/announce.ts @@ -1,12 +1,12 @@ import { Notes } from '@/models/index.js'; -import { IRemoteUser } from '@/models/entities/user.js'; +import { CacheableRemoteUser } from '@/models/entities/user.js'; import { IAnnounce, getApId } from '../../type.js'; import deleteNote from '@/services/note/delete.js'; -export const undoAnnounce = async (actor: IRemoteUser, activity: IAnnounce): Promise => { +export const undoAnnounce = async (actor: CacheableRemoteUser, activity: IAnnounce): Promise => { const uri = getApId(activity); - const note = await Notes.findOne({ + const note = await Notes.findOneBy({ uri, }); diff --git a/packages/backend/src/remote/activitypub/kernel/undo/block.ts b/packages/backend/src/remote/activitypub/kernel/undo/block.ts index 844b067e2b..4ac6698578 100644 --- a/packages/backend/src/remote/activitypub/kernel/undo/block.ts +++ b/packages/backend/src/remote/activitypub/kernel/undo/block.ts @@ -1,9 +1,10 @@ import { IBlock } from '../../type.js'; import unblock from '@/services/blocking/delete.js'; -import { IRemoteUser } from '@/models/entities/user.js'; +import { CacheableRemoteUser } from '@/models/entities/user.js'; import DbResolver from '../../db-resolver.js'; +import { Users } from '@/models/index.js'; -export default async (actor: IRemoteUser, activity: IBlock): Promise => { +export default async (actor: CacheableRemoteUser, activity: IBlock): Promise => { const dbResolver = new DbResolver(); const blockee = await dbResolver.getUserFromApId(activity.object); @@ -15,6 +16,6 @@ export default async (actor: IRemoteUser, activity: IBlock): Promise => return `skip: ブロック解除しようとしているユーザーはローカルユーザーではありません`; } - await unblock(actor, blockee); + await unblock(await Users.findOneByOrFail({ id: actor.id }), blockee); return `ok`; }; diff --git a/packages/backend/src/remote/activitypub/kernel/undo/follow.ts b/packages/backend/src/remote/activitypub/kernel/undo/follow.ts index 6715adcf76..6a43c1444a 100644 --- a/packages/backend/src/remote/activitypub/kernel/undo/follow.ts +++ b/packages/backend/src/remote/activitypub/kernel/undo/follow.ts @@ -1,11 +1,11 @@ import unfollow from '@/services/following/delete.js'; import cancelRequest from '@/services/following/requests/cancel.js'; import { IFollow } from '../../type.js'; -import { IRemoteUser } from '@/models/entities/user.js'; +import { CacheableRemoteUser } from '@/models/entities/user.js'; import { FollowRequests, Followings } from '@/models/index.js'; import DbResolver from '../../db-resolver.js'; -export default async (actor: IRemoteUser, activity: IFollow): Promise => { +export default async (actor: CacheableRemoteUser, activity: IFollow): Promise => { const dbResolver = new DbResolver(); const followee = await dbResolver.getUserFromApId(activity.object); @@ -17,12 +17,12 @@ export default async (actor: IRemoteUser, activity: IFollow): Promise => return `skip: フォロー解除しようとしているユーザーはローカルユーザーではありません`; } - const req = await FollowRequests.findOne({ + const req = await FollowRequests.findOneBy({ followerId: actor.id, followeeId: followee.id, }); - const following = await Followings.findOne({ + const following = await Followings.findOneBy({ followerId: actor.id, followeeId: followee.id, }); diff --git a/packages/backend/src/remote/activitypub/kernel/undo/index.ts b/packages/backend/src/remote/activitypub/kernel/undo/index.ts index 05937c6855..27d433eb33 100644 --- a/packages/backend/src/remote/activitypub/kernel/undo/index.ts +++ b/packages/backend/src/remote/activitypub/kernel/undo/index.ts @@ -1,5 +1,5 @@ -import { IRemoteUser } from '@/models/entities/user.js'; -import {IUndo, isFollow, isBlock, isLike, isAnnounce, getApType, isAccept} from '../../type.js'; +import { CacheableRemoteUser } from '@/models/entities/user.js'; +import { IUndo, isFollow, isBlock, isLike, isAnnounce, getApType, isAccept } from '../../type.js'; import unfollow from './follow.js'; import unblock from './block.js'; import undoLike from './like.js'; @@ -10,7 +10,7 @@ import { apLogger } from '../../logger.js'; const logger = apLogger; -export default async (actor: IRemoteUser, activity: IUndo): Promise => { +export default async (actor: CacheableRemoteUser, activity: IUndo): Promise => { if ('actor' in activity && actor.uri !== activity.actor) { throw new Error('invalid actor'); } diff --git a/packages/backend/src/remote/activitypub/kernel/undo/like.ts b/packages/backend/src/remote/activitypub/kernel/undo/like.ts index 08ac630351..01aeba1fb7 100644 --- a/packages/backend/src/remote/activitypub/kernel/undo/like.ts +++ b/packages/backend/src/remote/activitypub/kernel/undo/like.ts @@ -1,4 +1,4 @@ -import { IRemoteUser } from '@/models/entities/user.js'; +import { CacheableRemoteUser } from '@/models/entities/user.js'; import { ILike, getApId } from '../../type.js'; import deleteReaction from '@/services/note/reaction/delete.js'; import { fetchNote } from '../../models/note.js'; @@ -6,7 +6,7 @@ import { fetchNote } from '../../models/note.js'; /** * Process Undo.Like activity */ -export default async (actor: IRemoteUser, activity: ILike) => { +export default async (actor: CacheableRemoteUser, activity: ILike) => { const targetUri = getApId(activity.object); const note = await fetchNote(targetUri); diff --git a/packages/backend/src/remote/activitypub/kernel/update/index.ts b/packages/backend/src/remote/activitypub/kernel/update/index.ts index 7888c698e3..9e8a81bb39 100644 --- a/packages/backend/src/remote/activitypub/kernel/update/index.ts +++ b/packages/backend/src/remote/activitypub/kernel/update/index.ts @@ -1,4 +1,4 @@ -import { IRemoteUser } from '@/models/entities/user.js'; +import { CacheableRemoteUser } from '@/models/entities/user.js'; import { getApType, IUpdate, isActor } from '../../type.js'; import { apLogger } from '../../logger.js'; import { updateQuestion } from '../../models/question.js'; @@ -8,7 +8,7 @@ import { updatePerson } from '../../models/person.js'; /** * Updateアクティビティを捌きます */ -export default async (actor: IRemoteUser, activity: IUpdate): Promise => { +export default async (actor: CacheableRemoteUser, activity: IUpdate): Promise => { if ('actor' in activity && actor.uri !== activity.actor) { return `skip: invalid actor`; } diff --git a/packages/backend/src/remote/activitypub/models/image.ts b/packages/backend/src/remote/activitypub/models/image.ts index b5e9181d30..102b7b1346 100644 --- a/packages/backend/src/remote/activitypub/models/image.ts +++ b/packages/backend/src/remote/activitypub/models/image.ts @@ -1,10 +1,10 @@ import { uploadFromUrl } from '@/services/drive/upload-from-url.js'; -import { IRemoteUser } from '@/models/entities/user.js'; +import { CacheableRemoteUser, IRemoteUser } from '@/models/entities/user.js'; import Resolver from '../resolver.js'; import { fetchMeta } from '@/misc/fetch-meta.js'; import { apLogger } from '../logger.js'; import { DriveFile } from '@/models/entities/drive-file.js'; -import { DriveFiles } from '@/models/index.js'; +import { DriveFiles, Users } from '@/models/index.js'; import { truncate } from '@/misc/truncate.js'; import { DB_MAX_IMAGE_COMMENT_LENGTH } from '@/misc/hard-limits.js'; @@ -13,7 +13,7 @@ const logger = apLogger; /** * Imageを作成します。 */ -export async function createImage(actor: IRemoteUser, value: any): Promise { +export async function createImage(actor: CacheableRemoteUser, value: any): Promise { // 投稿者が凍結されていたらスキップ if (actor.isSuspended) { throw new Error('actor has been suspended'); @@ -47,7 +47,7 @@ export async function createImage(actor: IRemoteUser, value: any): Promise { +export async function resolveImage(actor: CacheableRemoteUser, value: any): Promise { // TODO // リモートサーバーからフェッチしてきて登録 diff --git a/packages/backend/src/remote/activitypub/models/mention.ts b/packages/backend/src/remote/activitypub/models/mention.ts index c5b0ea53ce..a160092969 100644 --- a/packages/backend/src/remote/activitypub/models/mention.ts +++ b/packages/backend/src/remote/activitypub/models/mention.ts @@ -3,17 +3,17 @@ import { IObject, isMention, IApMention } from '../type.js'; import { resolvePerson } from './person.js'; import promiseLimit from 'promise-limit'; import Resolver from '../resolver.js'; -import { User } from '@/models/entities/user.js'; +import { CacheableUser, User } from '@/models/entities/user.js'; export async function extractApMentions(tags: IObject | IObject[] | null | undefined) { const hrefs = unique(extractApMentionObjects(tags).map(x => x.href as string)); const resolver = new Resolver(); - const limit = promiseLimit(2); + const limit = promiseLimit(2); const mentionedUsers = (await Promise.all( hrefs.map(x => limit(() => resolvePerson(x, resolver).catch(() => null))) - )).filter((x): x is User => x != null); + )).filter((x): x is CacheableUser => x != null); return mentionedUsers; } diff --git a/packages/backend/src/remote/activitypub/models/note.ts b/packages/backend/src/remote/activitypub/models/note.ts index 0bcc89fbbb..097a716614 100644 --- a/packages/backend/src/remote/activitypub/models/note.ts +++ b/packages/backend/src/remote/activitypub/models/note.ts @@ -5,7 +5,7 @@ import Resolver from '../resolver.js'; import post from '@/services/note/create.js'; import { resolvePerson, updatePerson } from './person.js'; import { resolveImage } from './image.js'; -import { IRemoteUser } from '@/models/entities/user.js'; +import { CacheableRemoteUser, IRemoteUser } from '@/models/entities/user.js'; import { htmlToMfm } from '../misc/html-to-mfm.js'; import { extractApHashtags } from './tag.js'; import { unique, toArray, toSingle } from '@/prelude/array.js'; @@ -15,7 +15,7 @@ import { apLogger } from '../logger.js'; import { DriveFile } from '@/models/entities/drive-file.js'; import { deliverQuestionUpdate } from '@/services/note/polls/update.js'; import { extractDbHost, toPuny } from '@/misc/convert-host.js'; -import { Emojis, Polls, MessagingMessages } from '@/models/index.js'; +import { Emojis, Polls, MessagingMessages, Users } from '@/models/index.js'; import { Note } from '@/models/entities/note.js'; import { IObject, getOneApId, getApId, getOneApHrefNullable, validPost, IPost, isEmoji, getApType } from '../type.js'; import { Emoji } from '@/models/entities/emoji.js'; @@ -90,7 +90,7 @@ export async function createNote(value: string | IObject, resolver?: Resolver, s logger.info(`Creating the Note: ${note.id}`); // 投稿者をフェッチ - const actor = await resolvePerson(getOneApId(note.attributedTo), resolver) as IRemoteUser; + const actor = await resolvePerson(getOneApId(note.attributedTo), resolver) as CacheableRemoteUser; // 投稿者が凍結されていたらスキップ if (actor.isSuspended) { @@ -141,7 +141,7 @@ export async function createNote(value: string | IObject, resolver?: Resolver, s const uri = getApId(note.inReplyTo); if (uri.startsWith(config.url + '/')) { const id = uri.split('/').pop(); - const talk = await MessagingMessages.findOne(id); + const talk = await MessagingMessages.findOneBy({ id }); if (talk) { isTalk = true; return null; @@ -201,7 +201,7 @@ export async function createNote(value: string | IObject, resolver?: Resolver, s // vote 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 => { if (poll.expiresAt && Date.now() > new Date(poll.expiresAt).getTime()) { @@ -230,11 +230,6 @@ export async function createNote(value: string | IObject, resolver?: Resolver, s const poll = await extractPollFromQuestion(note, resolver).catch(() => undefined); - // ユーザーの情報が古かったらついでに更新しておく - if (actor.lastFetchedAt == null || Date.now() - actor.lastFetchedAt.getTime() > 1000 * 60 * 60 * 24) { - if (actor.uri) updatePerson(actor.uri); - } - if (isTalk) { for (const recipient of visibleUsers) { await createMessage(actor, recipient, undefined, text || undefined, (files && files.length > 0) ? files[0] : null, object.id); @@ -311,7 +306,7 @@ export async function extractEmojis(tags: IObject | IObject[], host: string): Pr const name = tag.name!.replace(/^:/, '').replace(/:$/, ''); tag.icon = toSingle(tag.icon); - const exists = await Emojis.findOne({ + const exists = await Emojis.findOneBy({ host, name, }); @@ -332,7 +327,7 @@ export async function extractEmojis(tags: IObject | IObject[], host: string): Pr updatedAt: new Date(), }); - return await Emojis.findOne({ + return await Emojis.findOneBy({ host, name, }) as Emoji; @@ -352,6 +347,6 @@ export async function extractEmojis(tags: IObject | IObject[], host: string): Pr publicUrl: tag.icon!.url, updatedAt: new Date(), aliases: [], - } as Partial).then(x => Emojis.findOneOrFail(x.identifiers[0])); + } as Partial).then(x => Emojis.findOneByOrFail(x.identifiers[0])); })); } diff --git a/packages/backend/src/remote/activitypub/models/person.ts b/packages/backend/src/remote/activitypub/models/person.ts index 659d3ac9a2..88661865da 100644 --- a/packages/backend/src/remote/activitypub/models/person.ts +++ b/packages/backend/src/remote/activitypub/models/person.ts @@ -15,7 +15,7 @@ import { apLogger } from '../logger.js'; import { Note } from '@/models/entities/note.js'; import { updateUsertags } from '@/services/update-hashtag.js'; import { Users, Instances, DriveFiles, Followings, UserProfiles, UserPublickeys } from '@/models/index.js'; -import { User, IRemoteUser } from '@/models/entities/user.js'; +import { User, IRemoteUser, CacheableUser } from '@/models/entities/user.js'; import { Emoji } from '@/models/entities/emoji.js'; import { UserNotePining } from '@/models/entities/user-note-pining.js'; import { genId } from '@/misc/gen-id.js'; @@ -24,12 +24,14 @@ import { UserPublickey } from '@/models/entities/user-publickey.js'; import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js'; import { toPuny } from '@/misc/convert-host.js'; import { UserProfile } from '@/models/entities/user-profile.js'; -import { getConnection } from 'typeorm'; import { toArray } from '@/prelude/array.js'; import { fetchInstanceMetadata } from '@/services/fetch-instance-metadata.js'; import { normalizeForSearch } from '@/misc/normalize-for-search.js'; import { truncate } from '@/misc/truncate.js'; import { StatusError } from '@/misc/fetch.js'; +import { uriPersonCache } from '@/services/user-cache.js'; +import { publishInternalEvent } from '@/services/stream.js'; +import { db } from '@/db/postgre.js'; const logger = apLogger; @@ -91,19 +93,25 @@ function validateActor(x: IObject, uri: string): IActor { * * Misskeyに対象のPersonが登録されていればそれを返します。 */ -export async function fetchPerson(uri: string, resolver?: Resolver): Promise { +export async function fetchPerson(uri: string, resolver?: Resolver): Promise { if (typeof uri !== 'string') throw new Error('uri is not string'); + const cached = uriPersonCache.get(uri); + if (cached) return cached; + // URIがこのサーバーを指しているならデータベースからフェッチ if (uri.startsWith(config.url + '/')) { const id = uri.split('/').pop(); - return await Users.findOne(id).then(x => x || null); + const u = await Users.findOneBy({ id }); + if (u) uriPersonCache.set(uri, u); + return u; } //#region このサーバーに既に登録されていたらそれを返す - const exist = await Users.findOne({ uri }); + const exist = await Users.findOneBy({ uri }); if (exist) { + uriPersonCache.set(uri, exist); return exist; } //#endregion @@ -143,7 +151,7 @@ export async function createPerson(uri: string, resolver?: Resolver): Promise { + await db.transaction(async transactionalEntityManager => { user = await transactionalEntityManager.save(new User({ id: genId(), avatarId: null, @@ -189,7 +197,7 @@ export async function createPerson(uri: string, resolver?: Resolver): Promise /users/:id のように入力がaliasなときにエラーになることがあるのを対応 - const u = await Users.findOne({ + const u = await Users.findOneBy({ uri: person.id, }); @@ -272,7 +280,7 @@ export async function updatePerson(uri: string, resolver?: Resolver | null, hint } //#region このサーバーに既に登録されているか - const exist = await Users.findOne({ uri }) as IRemoteUser; + const exist = await Users.findOneBy({ uri }) as IRemoteUser; if (exist == null) { return; @@ -352,6 +360,8 @@ export async function updatePerson(uri: string, resolver?: Resolver | null, hint location: person['vcard:Address'] || null, }); + publishInternalEvent('remoteUserUpdated', { id: exist.id }); + // ハッシュタグ更新 updateUsertags(exist, tags); @@ -371,7 +381,7 @@ export async function updatePerson(uri: string, resolver?: Resolver | null, hint * Misskeyに対象のPersonが登録されていればそれを返し、そうでなければ * リモートサーバーからフェッチしてMisskeyに登録しそれを返します。 */ -export async function resolvePerson(uri: string, resolver?: Resolver): Promise { +export async function resolvePerson(uri: string, resolver?: Resolver): Promise { if (typeof uri !== 'string') throw new Error('uri is not string'); //#region このサーバーに既に登録されていたらそれを返す @@ -441,7 +451,7 @@ export function analyzeAttachments(attachments: IObject | IObject[] | undefined) } 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 (!user.featured) return; @@ -464,7 +474,7 @@ export async function updateFeatured(userId: User['id']) { .slice(0, 5) .map(item => limit(() => resolveNote(item, resolver)))); - await getConnection().transaction(async transactionalEntityManager => { + await db.transaction(async transactionalEntityManager => { await transactionalEntityManager.delete(UserNotePining, { userId: user.id }); // とりあえずidを別の時間で生成して順番を維持 diff --git a/packages/backend/src/remote/activitypub/models/question.ts b/packages/backend/src/remote/activitypub/models/question.ts index 0a77465e31..9e75864c63 100644 --- a/packages/backend/src/remote/activitypub/models/question.ts +++ b/packages/backend/src/remote/activitypub/models/question.ts @@ -47,10 +47,10 @@ export async function updateQuestion(value: any) { if (uri.startsWith(config.url + '/')) throw new Error('uri points local'); //#region このサーバーに既に登録されているか - const note = await Notes.findOne({ uri }); + const note = await Notes.findOneBy({ uri }); 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'); //#endregion diff --git a/packages/backend/src/remote/activitypub/perform.ts b/packages/backend/src/remote/activitypub/perform.ts index 3e18815586..a3c10ba945 100644 --- a/packages/backend/src/remote/activitypub/perform.ts +++ b/packages/backend/src/remote/activitypub/perform.ts @@ -1,7 +1,17 @@ import { IObject } from './type.js'; -import { IRemoteUser } from '@/models/entities/user.js'; +import { CacheableRemoteUser } from '@/models/entities/user.js'; import { performActivity } from './kernel/index.js'; +import { updatePerson } from './models/person.js'; -export default async (actor: IRemoteUser, activity: IObject): Promise => { +export default async (actor: CacheableRemoteUser, activity: IObject): Promise => { await performActivity(actor, activity); + + // ついでにリモートユーザーの情報が古かったら更新しておく + if (actor.uri) { + if (actor.lastFetchedAt == null || Date.now() - actor.lastFetchedAt.getTime() > 1000 * 60 * 60 * 24) { + setImmediate(() => { + updatePerson(actor.uri!); + }); + } + } }; diff --git a/packages/backend/src/remote/activitypub/renderer/follow-user.ts b/packages/backend/src/remote/activitypub/renderer/follow-user.ts index ad1d63b933..9a8a16d749 100644 --- a/packages/backend/src/remote/activitypub/renderer/follow-user.ts +++ b/packages/backend/src/remote/activitypub/renderer/follow-user.ts @@ -7,6 +7,6 @@ import { User } from '@/models/entities/user.js'; * @param id Follower|Followee ID */ export default async function renderFollowUser(id: User['id']): Promise { - const user = await Users.findOneOrFail(id); + const user = await Users.findOneByOrFail({ id: id }); return Users.isLocalUser(user) ? `${config.url}/users/${user.id}` : user.uri; } diff --git a/packages/backend/src/remote/activitypub/renderer/like.ts b/packages/backend/src/remote/activitypub/renderer/like.ts index 1bf36d4708..da1bfe6e8e 100644 --- a/packages/backend/src/remote/activitypub/renderer/like.ts +++ b/packages/backend/src/remote/activitypub/renderer/like.ts @@ -2,6 +2,7 @@ import config from '@/config/index.js'; import { NoteReaction } from '@/models/entities/note-reaction.js'; import { Note } from '@/models/entities/note.js'; import { Emojis } from '@/models/index.js'; +import { IsNull } from 'typeorm'; import renderEmoji from './emoji.js'; export const renderLike = async (noteReaction: NoteReaction, note: Note) => { @@ -18,9 +19,9 @@ export const renderLike = async (noteReaction: NoteReaction, note: Note) => { if (reaction.startsWith(':')) { const name = reaction.replace(/:/g, ''); - const emoji = await Emojis.findOne({ + const emoji = await Emojis.findOneBy({ name, - host: null, + host: IsNull(), }); if (emoji) object.tag = [ renderEmoji(emoji) ]; diff --git a/packages/backend/src/remote/activitypub/renderer/note.ts b/packages/backend/src/remote/activitypub/renderer/note.ts index 78190751f6..679c8bbfe4 100644 --- a/packages/backend/src/remote/activitypub/renderer/note.ts +++ b/packages/backend/src/remote/activitypub/renderer/note.ts @@ -7,25 +7,25 @@ import toHtml from '../misc/get-note-html.js'; import { Note, IMentionedRemoteUsers } from '@/models/entities/note.js'; import { DriveFile } from '@/models/entities/drive-file.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 { Poll } from '@/models/entities/poll.js'; export default async function renderNote(note: Note, dive = true, isTalk = false): Promise> { const getPromisedFiles = async (ids: string[]) => { 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[]; }; let inReplyTo; - let inReplyToNote: Note | undefined; + let inReplyToNote: Note | null; if (note.replyId) { - inReplyToNote = await Notes.findOne(note.replyId); + inReplyToNote = await Notes.findOneBy({ id: note.replyId }); if (inReplyToNote != null) { - const inReplyToUser = await Users.findOne(inReplyToNote.userId); + const inReplyToUser = await Users.findOneBy({ id: inReplyToNote.userId }); if (inReplyToUser != null) { if (inReplyToNote.uri) { @@ -46,7 +46,7 @@ export default async function renderNote(note: Note, dive = true, isTalk = false let quote; if (note.renoteId) { - const renote = await Notes.findOne(note.renoteId); + const renote = await Notes.findOneBy({ id: note.renoteId }); if (renote) { 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; } - const mentionedUsers = note.mentions.length > 0 ? await Users.find({ + const mentionedUsers = note.mentions.length > 0 ? await Users.findBy({ 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 text = note.text; - let poll: Poll | undefined; + let poll: Poll | null; if (note.hasPoll) { - poll = await Polls.findOne({ noteId: note.id }); + poll = await Polls.findOneBy({ noteId: note.id }); } let apText = text; @@ -156,9 +156,9 @@ export async function getEmojis(names: string[]): Promise { if (names == null || names.length === 0) return []; const emojis = await Promise.all( - names.map(name => Emojis.findOne({ + names.map(name => Emojis.findOneBy({ name, - host: null, + host: IsNull(), })) ); diff --git a/packages/backend/src/remote/activitypub/renderer/person.ts b/packages/backend/src/remote/activitypub/renderer/person.ts index 3d86e37cca..cd2fd74d47 100644 --- a/packages/backend/src/remote/activitypub/renderer/person.ts +++ b/packages/backend/src/remote/activitypub/renderer/person.ts @@ -17,9 +17,9 @@ export async function renderPerson(user: ILocalUser) { const isSystem = !!user.username.match(/\./); const [avatar, banner, profile] = await Promise.all([ - user.avatarId ? DriveFiles.findOne(user.avatarId) : Promise.resolve(undefined), - user.bannerId ? DriveFiles.findOne(user.bannerId) : Promise.resolve(undefined), - UserProfiles.findOneOrFail(user.id), + user.avatarId ? DriveFiles.findOneBy({ id: user.avatarId }) : Promise.resolve(undefined), + user.bannerId ? DriveFiles.findOneBy({ id: user.bannerId }) : Promise.resolve(undefined), + UserProfiles.findOneByOrFail({ userId: user.id }), ]); const attachment: { diff --git a/packages/backend/src/remote/resolve-user.ts b/packages/backend/src/remote/resolve-user.ts index aa37013c4a..6fc6f2c4d3 100644 --- a/packages/backend/src/remote/resolve-user.ts +++ b/packages/backend/src/remote/resolve-user.ts @@ -7,15 +7,16 @@ import chalk from 'chalk'; import { User, IRemoteUser } from '@/models/entities/user.js'; import { Users } from '@/models/index.js'; import { toPuny } from '@/misc/convert-host.js'; +import { IsNull } from 'typeorm'; const logger = remoteLogger.createSubLogger('resolve-user'); -export async function resolveUser(username: string, host: string | null, option?: any, resync = false): Promise { +export async function resolveUser(username: string, host: string | null): Promise { const usernameLower = username.toLowerCase(); if (host == null) { 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) { throw new Error('user not found'); } else { @@ -28,7 +29,7 @@ export async function resolveUser(username: string, host: string | null, option? if (config.host === host) { 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) { throw new Error('user not found'); } 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}`; @@ -48,8 +49,8 @@ export async function resolveUser(username: string, host: string | null, option? return await createPerson(self.href); } - // resyncオプション OR ユーザー情報が古い場合は、WebFilgerからやりなおして返す - if (resync || user.lastFetchedAt == null || Date.now() - user.lastFetchedAt.getTime() > 1000 * 60 * 60 * 24) { + // ユーザー情報が古い場合は、WebFilgerからやりなおして返す + if (user.lastFetchedAt == null || Date.now() - user.lastFetchedAt.getTime() > 1000 * 60 * 60 * 24) { // 繋がらないインスタンスに何回も試行するのを防ぐ, 後続の同様処理の連続試行を防ぐ ため 試行前にも更新する await Users.update(user.id, { lastFetchedAt: new Date(), @@ -82,7 +83,7 @@ export async function resolveUser(username: string, host: string | null, option? await updatePerson(self.href); 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) { throw new Error('user not found'); } else { diff --git a/packages/backend/src/server/activitypub.ts b/packages/backend/src/server/activitypub.ts index c0a9b37726..133dd36066 100644 --- a/packages/backend/src/server/activitypub.ts +++ b/packages/backend/src/server/activitypub.ts @@ -15,10 +15,9 @@ import { inbox as processInbox } from '@/queue/index.js'; import { isSelfHost } from '@/misc/convert-host.js'; import { Notes, Users, Emojis, NoteReactions } from '@/models/index.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 { getUserKeypair } from '@/misc/keypair-store.js'; -import { noteCache, userCache } from './activitypub/cache.js'; // Init router const router = new Router(); @@ -66,13 +65,11 @@ router.post('/users/:user/inbox', json(), inbox); router.get('/notes/:note', async (ctx, next) => { if (!isActivityPubReq(ctx)) return await next(); - // TODO: typeorm 3.0にしたら .then(x => x || null) は消せる - // nginxとかでキャッシュしてくれそうだからそもそもnode側でのキャッシュ不要かも? - const note = await noteCache.fetch(ctx.params.note, () => Notes.findOne({ + const note = await Notes.findOneBy({ id: ctx.params.note, visibility: In(['public' as const, 'home' as const]), localOnly: false, - }).then(x => x || null)); + }); if (note == null) { ctx.status = 404; @@ -96,9 +93,9 @@ router.get('/notes/:note', async (ctx, next) => { // note activity router.get('/notes/:note/activity', async ctx => { - const note = await Notes.findOne({ + const note = await Notes.findOneBy({ id: ctx.params.note, - userHost: null, + userHost: IsNull(), visibility: In(['public' as const, 'home' as const]), localOnly: false, }); @@ -129,9 +126,9 @@ router.get('/users/:user/collections/featured', Featured); router.get('/users/:user/publickey', async ctx => { const userId = ctx.params.user; - const user = await Users.findOne({ + const user = await Users.findOneBy({ id: userId, - host: null, + host: IsNull(), }); if (user == null) { @@ -151,7 +148,7 @@ router.get('/users/:user/publickey', async ctx => { }); // user -async function userInfo(ctx: Router.RouterContext, user: User | undefined | null) { +async function userInfo(ctx: Router.RouterContext, user: User | null) { if (user == null) { ctx.status = 404; return; @@ -167,13 +164,11 @@ router.get('/users/:user', async (ctx, next) => { const userId = ctx.params.user; - // TODO: typeorm 3.0にしたら .then(x => x || null) は消せる - // nginxとかでキャッシュしてくれそうだからそもそもnode側でのキャッシュ不要かも? - const user = await userCache.fetch(userId, () => Users.findOne({ + const user = await Users.findOneBy({ id: userId, - host: null, + host: IsNull(), isSuspended: false, - }).then(x => x || null)); + }); await userInfo(ctx, user); }); @@ -181,9 +176,9 @@ router.get('/users/:user', async (ctx, next) => { router.get('/@:user', async (ctx, next) => { if (!isActivityPubReq(ctx)) return await next(); - const user = await Users.findOne({ + const user = await Users.findOneBy({ usernameLower: ctx.params.user.toLowerCase(), - host: null, + host: IsNull(), isSuspended: false, }); @@ -193,8 +188,8 @@ router.get('/@:user', async (ctx, next) => { // emoji router.get('/emojis/:emoji', async ctx => { - const emoji = await Emojis.findOne({ - host: null, + const emoji = await Emojis.findOneBy({ + host: IsNull(), name: ctx.params.emoji, }); @@ -210,14 +205,14 @@ router.get('/emojis/:emoji', async ctx => { // like 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) { ctx.status = 404; return; } - const note = await Notes.findOne(reaction.noteId); + const note = await Notes.findOneBy({ id: reaction.noteId }); if (note == null) { ctx.status = 404; diff --git a/packages/backend/src/server/activitypub/cache.ts b/packages/backend/src/server/activitypub/cache.ts deleted file mode 100644 index 00199ee253..0000000000 --- a/packages/backend/src/server/activitypub/cache.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { Cache } from "@/misc/cache.js"; -import { Note } from "@/models/entities/note.js"; -import { User } from "@/models/entities/user.js"; - -export const userCache = new Cache(1000 * 60 * 30); -export const noteCache = new Cache(1000 * 60 * 30); diff --git a/packages/backend/src/server/activitypub/featured.ts b/packages/backend/src/server/activitypub/featured.ts index d06a28a9ca..c03fd1049f 100644 --- a/packages/backend/src/server/activitypub/featured.ts +++ b/packages/backend/src/server/activitypub/featured.ts @@ -5,16 +5,15 @@ import renderOrderedCollection from '@/remote/activitypub/renderer/ordered-colle import { setResponseType } from '../activitypub.js'; import renderNote from '@/remote/activitypub/renderer/note.js'; import { Users, Notes, UserNotePinings } from '@/models/index.js'; -import { userCache } from './cache.js'; +import { IsNull } from 'typeorm'; export default async (ctx: Router.RouterContext) => { const userId = ctx.params.user; - // TODO: typeorm 3.0にしたら .then(x => x || null) は消せる - const user = await userCache.fetch(userId, () => Users.findOne({ + const user = await Users.findOneBy({ id: userId, - host: null, - }).then(x => x || null)); + host: IsNull(), + }); if (user == null) { ctx.status = 404; @@ -27,7 +26,7 @@ export default async (ctx: Router.RouterContext) => { }); 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))); diff --git a/packages/backend/src/server/activitypub/followers.ts b/packages/backend/src/server/activitypub/followers.ts index fdae9dd928..4d4f733162 100644 --- a/packages/backend/src/server/activitypub/followers.ts +++ b/packages/backend/src/server/activitypub/followers.ts @@ -9,8 +9,7 @@ import renderOrderedCollectionPage from '@/remote/activitypub/renderer/ordered-c import renderFollowUser from '@/remote/activitypub/renderer/follow-user.js'; import { setResponseType } from '../activitypub.js'; import { Users, Followings, UserProfiles } from '@/models/index.js'; -import { LessThan } from 'typeorm'; -import { userCache } from './cache.js'; +import { IsNull, LessThan } from 'typeorm'; export default async (ctx: Router.RouterContext) => { const userId = ctx.params.user; @@ -28,11 +27,10 @@ export default async (ctx: Router.RouterContext) => { return; } - // TODO: typeorm 3.0にしたら .then(x => x || null) は消せる - const user = await userCache.fetch(userId, () => Users.findOne({ + const user = await Users.findOneBy({ id: userId, - host: null, - }).then(x => x || null)); + host: IsNull(), + }); if (user == null) { ctx.status = 404; @@ -40,7 +38,7 @@ export default async (ctx: Router.RouterContext) => { } //#region Check ff visibility - const profile = await UserProfiles.findOneOrFail(user.id); + const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); if (profile.ffVisibility === 'private') { ctx.status = 403; diff --git a/packages/backend/src/server/activitypub/following.ts b/packages/backend/src/server/activitypub/following.ts index eb1b7a9d8c..0af1f424f9 100644 --- a/packages/backend/src/server/activitypub/following.ts +++ b/packages/backend/src/server/activitypub/following.ts @@ -9,9 +9,8 @@ import renderOrderedCollectionPage from '@/remote/activitypub/renderer/ordered-c import renderFollowUser from '@/remote/activitypub/renderer/follow-user.js'; import { setResponseType } from '../activitypub.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 { userCache } from './cache.js'; export default async (ctx: Router.RouterContext) => { const userId = ctx.params.user; @@ -29,11 +28,10 @@ export default async (ctx: Router.RouterContext) => { return; } - // TODO: typeorm 3.0にしたら .then(x => x || null) は消せる - const user = await userCache.fetch(userId, () => Users.findOne({ + const user = await Users.findOneBy({ id: userId, - host: null, - }).then(x => x || null)); + host: IsNull(), + }); if (user == null) { ctx.status = 404; @@ -41,7 +39,7 @@ export default async (ctx: Router.RouterContext) => { } //#region Check ff visibility - const profile = await UserProfiles.findOneOrFail(user.id); + const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); if (profile.ffVisibility === 'private') { ctx.status = 403; @@ -60,7 +58,7 @@ export default async (ctx: Router.RouterContext) => { if (page) { const query = { followerId: user.id, - } as FindConditions; + } as FindOptionsWhere; // カーソルが指定されている場合 if (cursor) { diff --git a/packages/backend/src/server/activitypub/outbox.ts b/packages/backend/src/server/activitypub/outbox.ts index db2a18efcd..6b9592bcf3 100644 --- a/packages/backend/src/server/activitypub/outbox.ts +++ b/packages/backend/src/server/activitypub/outbox.ts @@ -13,9 +13,8 @@ import { countIf } from '@/prelude/array.js'; import * as url from '@/prelude/url.js'; import { Users, Notes } from '@/models/index.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 { userCache } from './cache.js'; export default async (ctx: Router.RouterContext) => { const userId = ctx.params.user; @@ -36,11 +35,10 @@ export default async (ctx: Router.RouterContext) => { return; } - // TODO: typeorm 3.0にしたら .then(x => x || null) は消せる - const user = await userCache.fetch(userId, () => Users.findOne({ + const user = await Users.findOneBy({ id: userId, - host: null, - }).then(x => x || null)); + host: IsNull(), + }); if (user == null) { ctx.status = 404; @@ -101,7 +99,7 @@ export default async (ctx: Router.RouterContext) => { */ export async function packActivity(note: Note): Promise { 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); } diff --git a/packages/backend/src/server/api/authenticate.ts b/packages/backend/src/server/api/authenticate.ts index 7fdf14666e..65ccfcf551 100644 --- a/packages/backend/src/server/api/authenticate.ts +++ b/packages/backend/src/server/api/authenticate.ts @@ -1,7 +1,12 @@ import isNativeToken from './common/is-native-token.js'; -import { User } from '@/models/entities/user.js'; +import { CacheableLocalUser, ILocalUser } from '@/models/entities/user.js'; import { Users, AccessTokens, Apps } from '@/models/index.js'; import { AccessToken } from '@/models/entities/access-token.js'; +import { Cache } from '@/misc/cache.js'; +import { App } from '@/models/entities/app.js'; +import { localUserByIdCache, localUserByNativeTokenCache } from '@/services/user-cache.js'; + +const appCache = new Cache(Infinity); export class AuthenticationError extends Error { constructor(message: string) { @@ -10,15 +15,14 @@ export class AuthenticationError extends Error { } } -export default async (token: string | null): Promise<[User | null | undefined, AccessToken | null | undefined]> => { +export default async (token: string | null): Promise<[CacheableLocalUser | null | undefined, AccessToken | null | undefined]> => { if (token == null) { return [null, null]; } if (isNativeToken(token)) { - // Fetch user - const user = await Users - .findOne({ token }); + const user = await localUserByNativeTokenCache.fetch(token, + () => Users.findOneBy({ token }) as Promise); if (user == null) { throw new AuthenticationError('user not found'); @@ -42,14 +46,14 @@ export default async (token: string | null): Promise<[User | null | undefined, A lastUsedAt: new Date(), }); - const user = await Users - .findOne({ - id: accessToken.userId, // findOne(accessToken.userId) のように書かないのは後方互換性のため - }); + const user = await localUserByIdCache.fetch(accessToken.userId, + () => Users.findOneBy({ + id: accessToken.userId, + }) as Promise); if (accessToken.appId) { - const app = await Apps - .findOneOrFail(accessToken.appId); + const app = await appCache.fetch(accessToken.appId, + () => Apps.findOneByOrFail({ id: accessToken.appId! })); return [user, { id: accessToken.id, diff --git a/packages/backend/src/server/api/call.ts b/packages/backend/src/server/api/call.ts index 5c5ef66019..9a85e4565b 100644 --- a/packages/backend/src/server/api/call.ts +++ b/packages/backend/src/server/api/call.ts @@ -1,7 +1,7 @@ import Koa from 'koa'; import { performance } from 'perf_hooks'; import { limiter } from './limiter.js'; -import { User } from '@/models/entities/user.js'; +import { CacheableLocalUser, User } from '@/models/entities/user.js'; import endpoints, { IEndpoint } from './endpoints.js'; import { ApiError } from './error.js'; import { apiLogger } from './logger.js'; @@ -13,7 +13,7 @@ const accessDenied = { id: '56f35758-7dd5-468b-8439-5d6fb8ec9b8e', }; -export default async (endpoint: string, user: User | null | undefined, token: AccessToken | null | undefined, data: any, ctx?: Koa.Context) => { +export default async (endpoint: string, user: CacheableLocalUser | null | undefined, token: AccessToken | null | undefined, data: any, ctx?: Koa.Context) => { const isSecure = user != null && token == null; const ep = endpoints.find(e => e.name === endpoint); diff --git a/packages/backend/src/server/api/common/getters.ts b/packages/backend/src/server/api/common/getters.ts index c5a47876d0..783ea9ef75 100644 --- a/packages/backend/src/server/api/common/getters.ts +++ b/packages/backend/src/server/api/common/getters.ts @@ -7,7 +7,7 @@ import { Notes, Users } from '@/models/index.js'; * Get note for API processing */ export async function getNote(noteId: Note['id']) { - const note = await Notes.findOne(noteId); + const note = await Notes.findOneBy({ id: noteId }); if (note == null) { 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 */ export async function getUser(userId: User['id']) { - const user = await Users.findOne(userId); + const user = await Users.findOneBy({ id: userId }); if (user == null) { throw new IdentifiableError('15348ddd-432d-49c2-8a5a-8069753becff', 'No such user.'); diff --git a/packages/backend/src/server/api/common/inject-featured.ts b/packages/backend/src/server/api/common/inject-featured.ts index b7dd8028b5..f7cdd365ed 100644 --- a/packages/backend/src/server/api/common/inject-featured.ts +++ b/packages/backend/src/server/api/common/inject-featured.ts @@ -11,7 +11,7 @@ export async function injectFeatured(timeline: Note[], user?: User | null) { if (timeline.length < 5) return; if (user) { - const profile = await UserProfiles.findOneOrFail(user.id); + const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); if (!profile.injectFeaturedNote) return; } diff --git a/packages/backend/src/server/api/common/inject-promo.ts b/packages/backend/src/server/api/common/inject-promo.ts index b467b7b70b..b0da8118b4 100644 --- a/packages/backend/src/server/api/common/inject-promo.ts +++ b/packages/backend/src/server/api/common/inject-promo.ts @@ -8,7 +8,7 @@ export async function injectPromo(timeline: Note[], user?: User | null) { // TODO: readやexpireフィルタはクエリ側でやる - const reads = user ? await PromoReads.find({ + const reads = user ? await PromoReads.findBy({ userId: user.id, }) : []; @@ -22,10 +22,10 @@ export async function injectPromo(timeline: Note[], user?: User | null) { // Pick random promo 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 - note.user = await Users.findOneOrFail(note.userId); + note.user = await Users.findOneByOrFail({ id: note.userId }); (note as any)._prId_ = rndstr('a-z0-9', 8); diff --git a/packages/backend/src/server/api/common/read-messaging-message.ts b/packages/backend/src/server/api/common/read-messaging-message.ts index 5441b3c68e..c4c18ffa06 100644 --- a/packages/backend/src/server/api/common/read-messaging-message.ts +++ b/packages/backend/src/server/api/common/read-messaging-message.ts @@ -24,7 +24,7 @@ export async function readUserMessagingMessage( ) { if (messageIds.length === 0) return; - const messages = await MessagingMessages.find({ + const messages = await MessagingMessages.findBy({ id: In(messageIds), }); @@ -80,7 +80,7 @@ export async function readGroupMessagingMessage( if (messageIds.length === 0) return; // check joined - const joining = await UserGroupJoinings.findOne({ + const joining = await UserGroupJoinings.findOneBy({ userId: userId, userGroupId: groupId, }); @@ -89,7 +89,7 @@ export async function readGroupMessagingMessage( throw new IdentifiableError('930a270c-714a-46b2-b776-ad27276dc569', 'Access denied (group).'); } - const messages = await MessagingMessages.find({ + const messages = await MessagingMessages.findBy({ id: In(messageIds), }); diff --git a/packages/backend/src/server/api/common/signin.ts b/packages/backend/src/server/api/common/signin.ts index 163f132a44..f1dccee2ce 100644 --- a/packages/backend/src/server/api/common/signin.ts +++ b/packages/backend/src/server/api/common/signin.ts @@ -36,7 +36,7 @@ export default function(ctx: Koa.Context, user: ILocalUser, redirect = false) { ip: ctx.ip, headers: ctx.headers, success: true, - }).then(x => Signins.findOneOrFail(x.identifiers[0])); + }).then(x => Signins.findOneByOrFail(x.identifiers[0])); // Publish signin event publishMainStream(user.id, 'signin', await Signins.pack(record)); diff --git a/packages/backend/src/server/api/common/signup.ts b/packages/backend/src/server/api/common/signup.ts index 7689e8233f..abc142472a 100644 --- a/packages/backend/src/server/api/common/signup.ts +++ b/packages/backend/src/server/api/common/signup.ts @@ -4,12 +4,13 @@ import generateUserToken from './generate-native-user-token.js'; import { User } from '@/models/entities/user.js'; import { Users, UsedUsernames } from '@/models/index.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 { toPunyNullable } from '@/misc/convert-host.js'; import { UserKeypair } from '@/models/entities/user-keypair.js'; import { usersChart } from '@/services/chart/index.js'; import { UsedUsername } from '@/models/entities/used-username.js'; +import { db } from '@/db/postgre.js'; export async function signup(opts: { username: User['username']; @@ -40,12 +41,12 @@ export async function signup(opts: { const secret = generateUserToken(); // 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'); } // Check deleted username duplication - if (await UsedUsernames.findOne({ username: username.toLowerCase() })) { + if (await UsedUsernames.findOneBy({ username: username.toLowerCase() })) { throw new Error('USED_USERNAME'); } @@ -69,10 +70,10 @@ export async function signup(opts: { let account!: User; // Start transaction - await getConnection().transaction(async transactionalEntityManager => { - const exist = await transactionalEntityManager.findOne(User, { + await db.transaction(async transactionalEntityManager => { + const exist = await transactionalEntityManager.findOneBy(User, { usernameLower: username.toLowerCase(), - host: null, + host: IsNull(), }); if (exist) throw new Error(' the username is already used'); @@ -84,8 +85,8 @@ export async function signup(opts: { usernameLower: username.toLowerCase(), host: toPunyNullable(host), token: secret, - isAdmin: (await Users.count({ - host: null, + isAdmin: (await Users.countBy({ + host: IsNull(), })) === 0, })); diff --git a/packages/backend/src/server/api/define.ts b/packages/backend/src/server/api/define.ts index 4e6d041a29..1529894341 100644 --- a/packages/backend/src/server/api/define.ts +++ b/packages/backend/src/server/api/define.ts @@ -1,30 +1,16 @@ import * as fs from 'node:fs'; import Ajv from 'ajv'; -import { ILocalUser } from '@/models/entities/user.js'; +import { CacheableLocalUser, ILocalUser } from '@/models/entities/user.js'; import { IEndpointMeta } from './endpoints.js'; import { ApiError } from './error.js'; import { Schema, SchemaType } from '@/misc/schema.js'; import { AccessToken } from '@/models/entities/access-token.js'; -type SimpleUserInfo = { - id: ILocalUser['id']; - createdAt: ILocalUser['createdAt']; - host: ILocalUser['host']; - username: ILocalUser['username']; - uri: ILocalUser['uri']; - inbox: ILocalUser['inbox']; - sharedInbox: ILocalUser['sharedInbox']; - isAdmin: ILocalUser['isAdmin']; - isModerator: ILocalUser['isModerator']; - isSilenced: ILocalUser['isSilenced']; - showTimelineReplies: ILocalUser['showTimelineReplies']; -}; - export type Response = Record | void; // TODO: paramsの型をT['params']のスキーマ定義から推論する type executor = - (params: SchemaType, user: T['requireCredential'] extends true ? SimpleUserInfo : SimpleUserInfo | null, token: AccessToken | null, file?: any, cleanup?: () => any) => + (params: SchemaType, user: T['requireCredential'] extends true ? CacheableLocalUser : CacheableLocalUser | null, token: AccessToken | null, file?: any, cleanup?: () => any) => Promise>>; const ajv = new Ajv({ @@ -34,11 +20,11 @@ const ajv = new Ajv({ ajv.addFormat('misskey:id', /^[a-zA-Z0-9]+$/); export default function (meta: T, paramDef: Ps, cb: executor) - : (params: any, user: T['requireCredential'] extends true ? SimpleUserInfo : SimpleUserInfo | null, token: AccessToken | null, file?: any) => Promise { + : (params: any, user: T['requireCredential'] extends true ? CacheableLocalUser : CacheableLocalUser | null, token: AccessToken | null, file?: any) => Promise { const validate = ajv.compile(paramDef); - return (params: any, user: T['requireCredential'] extends true ? SimpleUserInfo : SimpleUserInfo | null, token: AccessToken | null, file?: any) => { + return (params: any, user: T['requireCredential'] extends true ? CacheableLocalUser : CacheableLocalUser | null, token: AccessToken | null, file?: any) => { function cleanup() { fs.unlink(file.path, () => {}); } diff --git a/packages/backend/src/server/api/endpoints/admin/accounts/create.ts b/packages/backend/src/server/api/endpoints/admin/accounts/create.ts index 2820c7993d..5f89219991 100644 --- a/packages/backend/src/server/api/endpoints/admin/accounts/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/accounts/create.ts @@ -1,6 +1,7 @@ import define from '../../../define.js'; import { Users } from '@/models/index.js'; import { signup } from '../../../common/signup.js'; +import { IsNull } from 'typeorm'; export const meta = { tags: ['admin'], @@ -29,9 +30,9 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, _me) => { - const me = _me ? await Users.findOneOrFail(_me.id) : null; - const noUsers = (await Users.count({ - host: null, + const me = _me ? await Users.findOneByOrFail({ id: _me.id }) : null; + const noUsers = (await Users.countBy({ + host: IsNull(), })) === 0; if (!noUsers && !me?.isAdmin) throw new Error('access denied'); diff --git a/packages/backend/src/server/api/endpoints/admin/accounts/delete.ts b/packages/backend/src/server/api/endpoints/admin/accounts/delete.ts index 01754ec8f3..629d700582 100644 --- a/packages/backend/src/server/api/endpoints/admin/accounts/delete.ts +++ b/packages/backend/src/server/api/endpoints/admin/accounts/delete.ts @@ -21,7 +21,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export 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) { throw new Error('user not found'); diff --git a/packages/backend/src/server/api/endpoints/admin/ad/delete.ts b/packages/backend/src/server/api/endpoints/admin/ad/delete.ts index 3663d974c5..0ead2be005 100644 --- a/packages/backend/src/server/api/endpoints/admin/ad/delete.ts +++ b/packages/backend/src/server/api/endpoints/admin/ad/delete.ts @@ -27,7 +27,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export 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); diff --git a/packages/backend/src/server/api/endpoints/admin/ad/update.ts b/packages/backend/src/server/api/endpoints/admin/ad/update.ts index 89c421db66..650f8670e3 100644 --- a/packages/backend/src/server/api/endpoints/admin/ad/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/ad/update.ts @@ -34,7 +34,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export 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); diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/create.ts b/packages/backend/src/server/api/endpoints/admin/announcements/create.ts index 41570078d4..33076b6d30 100644 --- a/packages/backend/src/server/api/endpoints/admin/announcements/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/announcements/create.ts @@ -63,7 +63,7 @@ export default define(meta, paramDef, async (ps) => { title: ps.title, text: ps.text, 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 }); }); diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/delete.ts b/packages/backend/src/server/api/endpoints/admin/announcements/delete.ts index 4871dc4e12..c17765f4fc 100644 --- a/packages/backend/src/server/api/endpoints/admin/announcements/delete.ts +++ b/packages/backend/src/server/api/endpoints/admin/announcements/delete.ts @@ -27,7 +27,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export 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); diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/list.ts b/packages/backend/src/server/api/endpoints/admin/announcements/list.ts index 0ba0a8ee08..1d8eb1d618 100644 --- a/packages/backend/src/server/api/endpoints/admin/announcements/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/announcements/list.ts @@ -69,7 +69,7 @@ export default define(meta, paramDef, async (ps) => { const announcements = await query.take(ps.limit).getMany(); for (const announcement of announcements) { - (announcement as any).reads = await AnnouncementReads.count({ + (announcement as any).reads = await AnnouncementReads.countBy({ announcementId: announcement.id, }); } diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/update.ts b/packages/backend/src/server/api/endpoints/admin/announcements/update.ts index 138337ef5b..61ce106d88 100644 --- a/packages/backend/src/server/api/endpoints/admin/announcements/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/announcements/update.ts @@ -30,7 +30,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export 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); diff --git a/packages/backend/src/server/api/endpoints/admin/delete-all-files-of-a-user.ts b/packages/backend/src/server/api/endpoints/admin/delete-all-files-of-a-user.ts index 90e65ec4cd..dc1976624d 100644 --- a/packages/backend/src/server/api/endpoints/admin/delete-all-files-of-a-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/delete-all-files-of-a-user.ts @@ -19,7 +19,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const files = await DriveFiles.find({ + const files = await DriveFiles.findBy({ userId: ps.userId, }); diff --git a/packages/backend/src/server/api/endpoints/admin/drive/cleanup.ts b/packages/backend/src/server/api/endpoints/admin/drive/cleanup.ts index 3e7d43fb0b..3db942e6cd 100644 --- a/packages/backend/src/server/api/endpoints/admin/drive/cleanup.ts +++ b/packages/backend/src/server/api/endpoints/admin/drive/cleanup.ts @@ -18,7 +18,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const files = await DriveFiles.find({ + const files = await DriveFiles.findBy({ userId: IsNull(), }); diff --git a/packages/backend/src/server/api/endpoints/admin/drive/show-file.ts b/packages/backend/src/server/api/endpoints/admin/drive/show-file.ts index e821160095..4b27fc0188 100644 --- a/packages/backend/src/server/api/endpoints/admin/drive/show-file.ts +++ b/packages/backend/src/server/api/endpoints/admin/drive/show-file.ts @@ -160,7 +160,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const file = ps.fileId ? await DriveFiles.findOne(ps.fileId) : await DriveFiles.findOne({ + const file = ps.fileId ? await DriveFiles.findOneBy({ id: ps.fileId }) : await DriveFiles.findOne({ where: [{ url: ps.url, }, { diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/add-aliases-bulk.ts b/packages/backend/src/server/api/endpoints/admin/emoji/add-aliases-bulk.ts index 77a4adea61..232fbbd573 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/add-aliases-bulk.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/add-aliases-bulk.ts @@ -1,7 +1,8 @@ import define from '../../../define.js'; import { Emojis } from '@/models/index.js'; -import { getConnection, In } from 'typeorm'; +import { In } from 'typeorm'; import { ApiError } from '../../../error.js'; +import { db } from '@/db/postgre.js'; export const meta = { tags: ['admin'], @@ -25,7 +26,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { - const emojis = await Emojis.find({ + const emojis = await Emojis.findBy({ id: In(ps.ids), }); @@ -36,5 +37,5 @@ export default define(meta, paramDef, async (ps) => { }); } - await getConnection().queryResultCache!.remove(['meta_emojis']); + await db.queryResultCache!.remove(['meta_emojis']); }); diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/add.ts b/packages/backend/src/server/api/endpoints/admin/emoji/add.ts index c5787d59dc..67349c24e0 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/add.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/add.ts @@ -1,11 +1,11 @@ import define from '../../../define.js'; import { Emojis, DriveFiles } from '@/models/index.js'; import { genId } from '@/misc/gen-id.js'; -import { getConnection } from 'typeorm'; import { insertModerationLog } from '@/services/insert-moderation-log.js'; import { ApiError } from '../../../error.js'; import rndstr from 'rndstr'; import { publishBroadcastStream } from '@/services/stream.js'; +import { db } from '@/db/postgre.js'; export const meta = { tags: ['admin'], @@ -32,7 +32,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const file = await DriveFiles.findOne(ps.fileId); + const file = await DriveFiles.findOneBy({ id: ps.fileId }); if (file == null) throw new ApiError(meta.errors.noSuchFile); @@ -48,9 +48,9 @@ export default define(meta, paramDef, async (ps, me) => { originalUrl: file.url, publicUrl: file.webpublicUrl ?? file.url, type: file.webpublicType ?? file.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']); publishBroadcastStream('emojiAdded', { emoji: await Emojis.pack(emoji.id), diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/copy.ts b/packages/backend/src/server/api/endpoints/admin/emoji/copy.ts index a0eaa61258..7010ade0d8 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/copy.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/copy.ts @@ -1,11 +1,11 @@ import define from '../../../define.js'; import { Emojis } from '@/models/index.js'; import { genId } from '@/misc/gen-id.js'; -import { getConnection } from 'typeorm'; import { ApiError } from '../../../error.js'; import { DriveFile } from '@/models/entities/drive-file.js'; import { uploadFromUrl } from '@/services/drive/upload-from-url.js'; import { publishBroadcastStream } from '@/services/stream.js'; +import { db } from '@/db/postgre.js'; export const meta = { tags: ['admin'], @@ -44,7 +44,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const emoji = await Emojis.findOne(ps.emojiId); + const emoji = await Emojis.findOneBy({ id: ps.emojiId }); if (emoji == null) { throw new ApiError(meta.errors.noSuchEmoji); @@ -68,9 +68,9 @@ export default define(meta, paramDef, async (ps, me) => { originalUrl: driveFile.url, publicUrl: driveFile.webpublicUrl ?? driveFile.url, 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']); publishBroadcastStream('emojiAdded', { emoji: await Emojis.pack(copied.id), diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/delete-bulk.ts b/packages/backend/src/server/api/endpoints/admin/emoji/delete-bulk.ts index 38a2d65cf6..93a6c4e4e2 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/delete-bulk.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/delete-bulk.ts @@ -1,8 +1,9 @@ import define from '../../../define.js'; import { Emojis } from '@/models/index.js'; -import { getConnection, In } from 'typeorm'; +import { In } from 'typeorm'; import { insertModerationLog } from '@/services/insert-moderation-log.js'; import { ApiError } from '../../../error.js'; +import { db } from '@/db/postgre.js'; export const meta = { tags: ['admin'], @@ -23,14 +24,14 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const emojis = await Emojis.find({ + const emojis = await Emojis.findBy({ id: In(ps.ids), }); for (const emoji of emojis) { await Emojis.delete(emoji.id); - await getConnection().queryResultCache!.remove(['meta_emojis']); + await db.queryResultCache!.remove(['meta_emojis']); insertModerationLog(me, 'deleteEmoji', { emoji: emoji, diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/delete.ts b/packages/backend/src/server/api/endpoints/admin/emoji/delete.ts index a0cffb47f8..67dbf28d85 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/delete.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/delete.ts @@ -1,8 +1,8 @@ import define from '../../../define.js'; import { Emojis } from '@/models/index.js'; -import { getConnection } from 'typeorm'; import { insertModerationLog } from '@/services/insert-moderation-log.js'; import { ApiError } from '../../../error.js'; +import { db } from '@/db/postgre.js'; export const meta = { tags: ['admin'], @@ -29,13 +29,13 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const emoji = await Emojis.findOne(ps.id); + const emoji = await Emojis.findOneBy({ id: ps.id }); if (emoji == null) throw new ApiError(meta.errors.noSuchEmoji); await Emojis.delete(emoji.id); - await getConnection().queryResultCache!.remove(['meta_emojis']); + await db.queryResultCache!.remove(['meta_emojis']); insertModerationLog(me, 'deleteEmoji', { emoji: emoji, diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/remove-aliases-bulk.ts b/packages/backend/src/server/api/endpoints/admin/emoji/remove-aliases-bulk.ts index dbad93d336..a4da40fffd 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/remove-aliases-bulk.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/remove-aliases-bulk.ts @@ -1,7 +1,8 @@ import define from '../../../define.js'; import { Emojis } from '@/models/index.js'; -import { getConnection, In } from 'typeorm'; +import { In } from 'typeorm'; import { ApiError } from '../../../error.js'; +import { db } from '@/db/postgre.js'; export const meta = { tags: ['admin'], @@ -25,7 +26,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { - const emojis = await Emojis.find({ + const emojis = await Emojis.findBy({ id: In(ps.ids), }); @@ -36,5 +37,5 @@ export default define(meta, paramDef, async (ps) => { }); } - await getConnection().queryResultCache!.remove(['meta_emojis']); + await db.queryResultCache!.remove(['meta_emojis']); }); diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/set-aliases-bulk.ts b/packages/backend/src/server/api/endpoints/admin/emoji/set-aliases-bulk.ts index 470b9bef08..ae3b190f40 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/set-aliases-bulk.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/set-aliases-bulk.ts @@ -1,7 +1,8 @@ import define from '../../../define.js'; import { Emojis } from '@/models/index.js'; -import { getConnection, In } from 'typeorm'; +import { In } from 'typeorm'; import { ApiError } from '../../../error.js'; +import { db } from '@/db/postgre.js'; export const meta = { tags: ['admin'], @@ -32,5 +33,5 @@ export default define(meta, paramDef, async (ps) => { aliases: ps.aliases, }); - await getConnection().queryResultCache!.remove(['meta_emojis']); + await db.queryResultCache!.remove(['meta_emojis']); }); diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/set-category-bulk.ts b/packages/backend/src/server/api/endpoints/admin/emoji/set-category-bulk.ts index 40e4c0199e..6063f3e3be 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/set-category-bulk.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/set-category-bulk.ts @@ -1,7 +1,8 @@ import define from '../../../define.js'; import { Emojis } from '@/models/index.js'; -import { getConnection, In } from 'typeorm'; +import { In } from 'typeorm'; import { ApiError } from '../../../error.js'; +import { db } from '@/db/postgre.js'; export const meta = { tags: ['admin'], @@ -30,5 +31,5 @@ export default define(meta, paramDef, async (ps) => { category: ps.category, }); - await getConnection().queryResultCache!.remove(['meta_emojis']); + await db.queryResultCache!.remove(['meta_emojis']); }); diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/update.ts b/packages/backend/src/server/api/endpoints/admin/emoji/update.ts index c6d07e16fa..e26514e0ca 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/update.ts @@ -1,7 +1,7 @@ import define from '../../../define.js'; import { Emojis } from '@/models/index.js'; -import { getConnection } from 'typeorm'; import { ApiError } from '../../../error.js'; +import { db } from '@/db/postgre.js'; export const meta = { tags: ['admin'], @@ -33,7 +33,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { - const emoji = await Emojis.findOne(ps.id); + const emoji = await Emojis.findOneBy({ id: ps.id }); if (emoji == null) throw new ApiError(meta.errors.noSuchEmoji); @@ -44,5 +44,5 @@ export default define(meta, paramDef, async (ps) => { aliases: ps.aliases, }); - await getConnection().queryResultCache!.remove(['meta_emojis']); + await db.queryResultCache!.remove(['meta_emojis']); }); diff --git a/packages/backend/src/server/api/endpoints/admin/federation/delete-all-files.ts b/packages/backend/src/server/api/endpoints/admin/federation/delete-all-files.ts index d4251f2feb..da54201473 100644 --- a/packages/backend/src/server/api/endpoints/admin/federation/delete-all-files.ts +++ b/packages/backend/src/server/api/endpoints/admin/federation/delete-all-files.ts @@ -19,7 +19,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const files = await DriveFiles.find({ + const files = await DriveFiles.findBy({ userHost: ps.host, }); diff --git a/packages/backend/src/server/api/endpoints/admin/federation/refresh-remote-instance-metadata.ts b/packages/backend/src/server/api/endpoints/admin/federation/refresh-remote-instance-metadata.ts index 86978cc309..cb2be5ab37 100644 --- a/packages/backend/src/server/api/endpoints/admin/federation/refresh-remote-instance-metadata.ts +++ b/packages/backend/src/server/api/endpoints/admin/federation/refresh-remote-instance-metadata.ts @@ -20,7 +20,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const instance = await Instances.findOne({ host: toPuny(ps.host) }); + const instance = await Instances.findOneBy({ host: toPuny(ps.host) }); if (instance == null) { throw new Error('instance not found'); diff --git a/packages/backend/src/server/api/endpoints/admin/federation/remove-all-following.ts b/packages/backend/src/server/api/endpoints/admin/federation/remove-all-following.ts index ccd07489cb..b7ee27db64 100644 --- a/packages/backend/src/server/api/endpoints/admin/federation/remove-all-following.ts +++ b/packages/backend/src/server/api/endpoints/admin/federation/remove-all-following.ts @@ -19,13 +19,13 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const followings = await Followings.find({ + const followings = await Followings.findBy({ followerHost: ps.host, }); const pairs = await Promise.all(followings.map(f => Promise.all([ - Users.findOneOrFail(f.followerId), - Users.findOneOrFail(f.followeeId), + Users.findOneByOrFail({ id: f.followerId }), + Users.findOneByOrFail({ id: f.followeeId }), ]))); for (const pair of pairs) { diff --git a/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts b/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts index 1981082428..278131fb37 100644 --- a/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts +++ b/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts @@ -20,7 +20,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const instance = await Instances.findOne({ host: toPuny(ps.host) }); + const instance = await Instances.findOneBy({ host: toPuny(ps.host) }); if (instance == null) { throw new Error('instance not found'); diff --git a/packages/backend/src/server/api/endpoints/admin/get-index-stats.ts b/packages/backend/src/server/api/endpoints/admin/get-index-stats.ts index 37878c4143..dd16473f30 100644 --- a/packages/backend/src/server/api/endpoints/admin/get-index-stats.ts +++ b/packages/backend/src/server/api/endpoints/admin/get-index-stats.ts @@ -1,5 +1,5 @@ import define from '../../define.js'; -import { getConnection } from 'typeorm'; +import { db } from '@/db/postgre.js'; export const meta = { requireCredential: true, @@ -16,15 +16,13 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async () => { - const stats = await - getConnection().query(`SELECT * FROM pg_indexes;`) - .then(recs => { - const res = [] as { tablename: string; indexname: string; }[]; - for (const rec of recs) { - res.push(rec); - } - return res; - }); + const stats = await db.query(`SELECT * FROM pg_indexes;`).then(recs => { + const res = [] as { tablename: string; indexname: string; }[]; + for (const rec of recs) { + res.push(rec); + } + return res; + }); return stats; }); diff --git a/packages/backend/src/server/api/endpoints/admin/get-table-stats.ts b/packages/backend/src/server/api/endpoints/admin/get-table-stats.ts index 7cf2d5ffd4..aca2540fd5 100644 --- a/packages/backend/src/server/api/endpoints/admin/get-table-stats.ts +++ b/packages/backend/src/server/api/endpoints/admin/get-table-stats.ts @@ -1,5 +1,5 @@ +import { db } from '@/db/postgre.js'; import define from '../../define.js'; -import { getConnection } from 'typeorm'; export const meta = { requireCredential: true, @@ -28,7 +28,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async () => { const sizes = await - getConnection().query(` + db.query(` SELECT relname AS "table", reltuples as "count", pg_total_relation_size(C.oid) AS "size" FROM pg_class C LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) WHERE nspname NOT IN ('pg_catalog', 'information_schema') diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts new file mode 100644 index 0000000000..8d50486ef6 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/admin/meta.ts @@ -0,0 +1,401 @@ +import config from '@/config/index.js'; +import define from '../../define.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; +import { MAX_NOTE_TEXT_LENGTH } from '@/const.js'; + +export const meta = { + tags: ['meta'], + + requireCredential: true, + requireAdmin: true, + + res: { + type: 'object', + optional: false, nullable: false, + properties: { + driveCapacityPerLocalUserMb: { + type: 'number', + optional: false, nullable: false, + }, + driveCapacityPerRemoteUserMb: { + type: 'number', + optional: false, nullable: false, + }, + cacheRemoteFiles: { + type: 'boolean', + optional: false, nullable: false, + }, + emailRequiredForSignup: { + type: 'boolean', + optional: false, nullable: false, + }, + enableHcaptcha: { + type: 'boolean', + optional: false, nullable: false, + }, + hcaptchaSiteKey: { + type: 'string', + optional: false, nullable: true, + }, + enableRecaptcha: { + type: 'boolean', + optional: false, nullable: false, + }, + recaptchaSiteKey: { + type: 'string', + optional: false, nullable: true, + }, + swPublickey: { + type: 'string', + optional: false, nullable: true, + }, + mascotImageUrl: { + type: 'string', + optional: false, nullable: false, + default: '/assets/ai.png', + }, + bannerUrl: { + type: 'string', + optional: false, nullable: false, + }, + errorImageUrl: { + type: 'string', + optional: false, nullable: false, + default: 'https://xn--931a.moe/aiart/yubitun.png', + }, + iconUrl: { + type: 'string', + optional: false, nullable: true, + }, + maxNoteTextLength: { + type: 'number', + optional: false, nullable: false, + }, + emojis: { + type: 'array', + optional: false, nullable: false, + items: { + type: 'object', + optional: false, nullable: false, + properties: { + id: { + type: 'string', + optional: false, nullable: false, + format: 'id', + }, + aliases: { + type: 'array', + optional: false, nullable: false, + items: { + type: 'string', + optional: false, nullable: false, + }, + }, + category: { + type: 'string', + optional: false, nullable: true, + }, + host: { + type: 'string', + optional: false, nullable: true, + }, + url: { + type: 'string', + optional: false, nullable: false, + format: 'url', + }, + }, + }, + }, + ads: { + type: 'array', + optional: false, nullable: false, + items: { + type: 'object', + optional: false, nullable: false, + properties: { + place: { + type: 'string', + optional: false, nullable: false, + }, + url: { + type: 'string', + optional: false, nullable: false, + format: 'url', + }, + imageUrl: { + type: 'string', + optional: false, nullable: false, + format: 'url', + }, + }, + }, + }, + enableEmail: { + type: 'boolean', + optional: false, nullable: false, + }, + enableTwitterIntegration: { + type: 'boolean', + optional: false, nullable: false, + }, + enableGithubIntegration: { + type: 'boolean', + optional: false, nullable: false, + }, + enableDiscordIntegration: { + type: 'boolean', + optional: false, nullable: false, + }, + enableServiceWorker: { + type: 'boolean', + optional: false, nullable: false, + }, + translatorAvailable: { + type: 'boolean', + optional: false, nullable: false, + }, + proxyAccountName: { + type: 'string', + optional: false, nullable: true, + }, + userStarForReactionFallback: { + type: 'boolean', + optional: true, nullable: false, + }, + pinnedUsers: { + type: 'array', + optional: true, nullable: false, + items: { + type: 'string', + optional: false, nullable: false, + }, + }, + hiddenTags: { + type: 'array', + optional: true, nullable: false, + items: { + type: 'string', + optional: false, nullable: false, + }, + }, + blockedHosts: { + type: 'array', + optional: true, nullable: false, + items: { + type: 'string', + optional: false, nullable: false, + }, + }, + hcaptchaSecretKey: { + type: 'string', + optional: true, nullable: true, + }, + recaptchaSecretKey: { + type: 'string', + optional: true, nullable: true, + }, + proxyAccountId: { + type: 'string', + optional: true, nullable: true, + format: 'id', + }, + twitterConsumerKey: { + type: 'string', + optional: true, nullable: true, + }, + twitterConsumerSecret: { + type: 'string', + optional: true, nullable: true, + }, + githubClientId: { + type: 'string', + optional: true, nullable: true, + }, + githubClientSecret: { + type: 'string', + optional: true, nullable: true, + }, + discordClientId: { + type: 'string', + optional: true, nullable: true, + }, + discordClientSecret: { + type: 'string', + optional: true, nullable: true, + }, + summaryProxy: { + type: 'string', + optional: true, nullable: true, + }, + email: { + type: 'string', + optional: true, nullable: true, + }, + smtpSecure: { + type: 'boolean', + optional: true, nullable: false, + }, + smtpHost: { + type: 'string', + optional: true, nullable: true, + }, + smtpPort: { + type: 'string', + optional: true, nullable: true, + }, + smtpUser: { + type: 'string', + optional: true, nullable: true, + }, + smtpPass: { + type: 'string', + optional: true, nullable: true, + }, + swPrivateKey: { + type: 'string', + optional: true, nullable: true, + }, + useObjectStorage: { + type: 'boolean', + optional: true, nullable: false, + }, + objectStorageBaseUrl: { + type: 'string', + optional: true, nullable: true, + }, + objectStorageBucket: { + type: 'string', + optional: true, nullable: true, + }, + objectStoragePrefix: { + type: 'string', + optional: true, nullable: true, + }, + objectStorageEndpoint: { + type: 'string', + optional: true, nullable: true, + }, + objectStorageRegion: { + type: 'string', + optional: true, nullable: true, + }, + objectStoragePort: { + type: 'number', + optional: true, nullable: true, + }, + objectStorageAccessKey: { + type: 'string', + optional: true, nullable: true, + }, + objectStorageSecretKey: { + type: 'string', + optional: true, nullable: true, + }, + objectStorageUseSSL: { + type: 'boolean', + optional: true, nullable: false, + }, + objectStorageUseProxy: { + type: 'boolean', + optional: true, nullable: false, + }, + objectStorageSetPublicRead: { + type: 'boolean', + optional: true, nullable: false, + }, + }, + }, +} as const; + +export const paramDef = { + type: 'object', + properties: { + }, + required: [], +} as const; + +// eslint-disable-next-line import/no-default-export +export default define(meta, paramDef, async (ps, me) => { + const instance = await fetchMeta(true); + + return { + maintainerName: instance.maintainerName, + maintainerEmail: instance.maintainerEmail, + version: config.version, + name: instance.name, + uri: config.url, + description: instance.description, + langs: instance.langs, + tosUrl: instance.ToSUrl, + repositoryUrl: instance.repositoryUrl, + feedbackUrl: instance.feedbackUrl, + disableRegistration: instance.disableRegistration, + disableLocalTimeline: instance.disableLocalTimeline, + disableGlobalTimeline: instance.disableGlobalTimeline, + driveCapacityPerLocalUserMb: instance.localDriveCapacityMb, + driveCapacityPerRemoteUserMb: instance.remoteDriveCapacityMb, + emailRequiredForSignup: instance.emailRequiredForSignup, + enableHcaptcha: instance.enableHcaptcha, + hcaptchaSiteKey: instance.hcaptchaSiteKey, + enableRecaptcha: instance.enableRecaptcha, + recaptchaSiteKey: instance.recaptchaSiteKey, + swPublickey: instance.swPublicKey, + themeColor: instance.themeColor, + mascotImageUrl: instance.mascotImageUrl, + bannerUrl: instance.bannerUrl, + errorImageUrl: instance.errorImageUrl, + iconUrl: instance.iconUrl, + backgroundImageUrl: instance.backgroundImageUrl, + logoImageUrl: instance.logoImageUrl, + maxNoteTextLength: MAX_NOTE_TEXT_LENGTH, // 後方互換性のため + defaultLightTheme: instance.defaultLightTheme, + defaultDarkTheme: instance.defaultDarkTheme, + enableEmail: instance.enableEmail, + enableTwitterIntegration: instance.enableTwitterIntegration, + enableGithubIntegration: instance.enableGithubIntegration, + enableDiscordIntegration: instance.enableDiscordIntegration, + enableServiceWorker: instance.enableServiceWorker, + translatorAvailable: instance.deeplAuthKey != null, + pinnedPages: instance.pinnedPages, + pinnedClipId: instance.pinnedClipId, + cacheRemoteFiles: instance.cacheRemoteFiles, + + useStarForReactionFallback: instance.useStarForReactionFallback, + pinnedUsers: instance.pinnedUsers, + hiddenTags: instance.hiddenTags, + blockedHosts: instance.blockedHosts, + hcaptchaSecretKey: instance.hcaptchaSecretKey, + recaptchaSecretKey: instance.recaptchaSecretKey, + proxyAccountId: instance.proxyAccountId, + twitterConsumerKey: instance.twitterConsumerKey, + twitterConsumerSecret: instance.twitterConsumerSecret, + githubClientId: instance.githubClientId, + githubClientSecret: instance.githubClientSecret, + discordClientId: instance.discordClientId, + discordClientSecret: instance.discordClientSecret, + summalyProxy: instance.summalyProxy, + email: instance.email, + smtpSecure: instance.smtpSecure, + smtpHost: instance.smtpHost, + smtpPort: instance.smtpPort, + smtpUser: instance.smtpUser, + smtpPass: instance.smtpPass, + swPrivateKey: instance.swPrivateKey, + useObjectStorage: instance.useObjectStorage, + objectStorageBaseUrl: instance.objectStorageBaseUrl, + objectStorageBucket: instance.objectStorageBucket, + objectStoragePrefix: instance.objectStoragePrefix, + objectStorageEndpoint: instance.objectStorageEndpoint, + objectStorageRegion: instance.objectStorageRegion, + objectStoragePort: instance.objectStoragePort, + objectStorageAccessKey: instance.objectStorageAccessKey, + objectStorageSecretKey: instance.objectStorageSecretKey, + objectStorageUseSSL: instance.objectStorageUseSSL, + objectStorageUseProxy: instance.objectStorageUseProxy, + objectStorageSetPublicRead: instance.objectStorageSetPublicRead, + objectStorageS3ForcePathStyle: instance.objectStorageS3ForcePathStyle, + deeplAuthKey: instance.deeplAuthKey, + deeplIsPro: instance.deeplIsPro, + }; +}); diff --git a/packages/backend/src/server/api/endpoints/admin/moderators/add.ts b/packages/backend/src/server/api/endpoints/admin/moderators/add.ts index 4206e3a3c2..7b209c2d99 100644 --- a/packages/backend/src/server/api/endpoints/admin/moderators/add.ts +++ b/packages/backend/src/server/api/endpoints/admin/moderators/add.ts @@ -1,5 +1,6 @@ import define from '../../../define.js'; import { Users } from '@/models/index.js'; +import { publishInternalEvent } from '@/services/stream.js'; export const meta = { tags: ['admin'], @@ -18,7 +19,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { - const user = await Users.findOne(ps.userId as string); + const user = await Users.findOneBy({ id: ps.userId }); if (user == null) { throw new Error('user not found'); @@ -31,4 +32,6 @@ export default define(meta, paramDef, async (ps) => { await Users.update(user.id, { isModerator: true, }); + + publishInternalEvent('userChangeModeratorState', { id: user.id, isModerator: true }); }); diff --git a/packages/backend/src/server/api/endpoints/admin/moderators/remove.ts b/packages/backend/src/server/api/endpoints/admin/moderators/remove.ts index 143119bfe4..b85a677e81 100644 --- a/packages/backend/src/server/api/endpoints/admin/moderators/remove.ts +++ b/packages/backend/src/server/api/endpoints/admin/moderators/remove.ts @@ -18,7 +18,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { - const user = await Users.findOne(ps.userId as string); + const user = await Users.findOneBy({ id: ps.userId }); if (user == null) { throw new Error('user not found'); @@ -27,4 +27,6 @@ export default define(meta, paramDef, async (ps) => { await Users.update(user.id, { isModerator: false, }); + + publishInternalEvent('userChangeModeratorState', { id: user.id, isModerator: false }); }); diff --git a/packages/backend/src/server/api/endpoints/admin/promo/create.ts b/packages/backend/src/server/api/endpoints/admin/promo/create.ts index 2eec5bf0db..68a17867b2 100644 --- a/packages/backend/src/server/api/endpoints/admin/promo/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/promo/create.ts @@ -40,7 +40,7 @@ export default define(meta, paramDef, async (ps, user) => { throw e; }); - const exist = await PromoNotes.findOne(note.id); + const exist = await PromoNotes.findOneBy({ noteId: note.id }); if (exist != null) { throw new ApiError(meta.errors.alreadyPromoted); diff --git a/packages/backend/src/server/api/endpoints/admin/reset-password.ts b/packages/backend/src/server/api/endpoints/admin/reset-password.ts index 1fd5c8d5a5..be4c2dceed 100644 --- a/packages/backend/src/server/api/endpoints/admin/reset-password.ts +++ b/packages/backend/src/server/api/endpoints/admin/reset-password.ts @@ -33,7 +33,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { - const user = await Users.findOne(ps.userId as string); + const user = await Users.findOneBy({ id: ps.userId }); if (user == null) { throw new Error('user not found'); diff --git a/packages/backend/src/server/api/endpoints/admin/resolve-abuse-user-report.ts b/packages/backend/src/server/api/endpoints/admin/resolve-abuse-user-report.ts index a9e5658413..3edae4a85f 100644 --- a/packages/backend/src/server/api/endpoints/admin/resolve-abuse-user-report.ts +++ b/packages/backend/src/server/api/endpoints/admin/resolve-abuse-user-report.ts @@ -23,7 +23,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const report = await AbuseUserReports.findOne(ps.reportId); + const report = await AbuseUserReports.findOneByOrFail({ id: ps.reportId }); if (report == null) { throw new Error('report not found'); @@ -31,7 +31,7 @@ export default define(meta, paramDef, async (ps, me) => { if (ps.forward && report.targetUserHost != null) { const actor = await getInstanceActor(); - const targetUser = await Users.findOneOrFail(report.targetUserId); + const targetUser = await Users.findOneByOrFail({ id: report.targetUserId }); deliver(actor, renderActivity(renderFlag(actor, [targetUser.uri!], report.comment)), targetUser.inbox); } diff --git a/packages/backend/src/server/api/endpoints/admin/server-info.ts b/packages/backend/src/server/api/endpoints/admin/server-info.ts index 8bf1c4341c..9c150420b1 100644 --- a/packages/backend/src/server/api/endpoints/admin/server-info.ts +++ b/packages/backend/src/server/api/endpoints/admin/server-info.ts @@ -1,8 +1,8 @@ import * as os from 'node:os'; import si from 'systeminformation'; -import { getConnection } from 'typeorm'; import define from '../../define.js'; import { redisClient } from '../../../../db/redis.js'; +import { db } from '@/db/postgre.js'; export const meta = { requireCredential: true, @@ -103,7 +103,7 @@ export default define(meta, paramDef, async () => { machine: os.hostname(), os: os.platform(), node: process.version, - psql: await getConnection().query('SHOW server_version').then(x => x[0].server_version), + psql: await db.query('SHOW server_version').then(x => x[0].server_version), redis: redisClient.server_info.redis_version, cpu: { model: os.cpus()[0].model, diff --git a/packages/backend/src/server/api/endpoints/admin/show-user.ts b/packages/backend/src/server/api/endpoints/admin/show-user.ts index a435dcc288..bf6cc16532 100644 --- a/packages/backend/src/server/api/endpoints/admin/show-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/show-user.ts @@ -23,13 +23,14 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const user = await Users.findOne(ps.userId as string); + const user = await Users.findOneBy({ id: ps.userId }); if (user == null) { throw new Error('user not found'); } - if ((me.isModerator && !me.isAdmin) && user.isAdmin) { + const _me = await Users.findOneByOrFail({ id: me.id }); + if ((_me.isModerator && !_me.isAdmin) && user.isAdmin) { throw new Error('cannot show info of admin'); } diff --git a/packages/backend/src/server/api/endpoints/admin/silence-user.ts b/packages/backend/src/server/api/endpoints/admin/silence-user.ts index 4a74c3fb00..17b9f3b5a0 100644 --- a/packages/backend/src/server/api/endpoints/admin/silence-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/silence-user.ts @@ -1,6 +1,7 @@ import define from '../../define.js'; import { Users } from '@/models/index.js'; import { insertModerationLog } from '@/services/insert-moderation-log.js'; +import { publishInternalEvent } from '@/services/stream.js'; export const meta = { tags: ['admin'], @@ -19,7 +20,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const user = await Users.findOne(ps.userId as string); + const user = await Users.findOneBy({ id: ps.userId }); if (user == null) { throw new Error('user not found'); @@ -33,6 +34,8 @@ export default define(meta, paramDef, async (ps, me) => { isSilenced: true, }); + publishInternalEvent('userChangeSilencedState', { id: user.id, isSilenced: true }); + insertModerationLog(me, 'silence', { targetId: user.id, }); diff --git a/packages/backend/src/server/api/endpoints/admin/suspend-user.ts b/packages/backend/src/server/api/endpoints/admin/suspend-user.ts index adaa7b86ce..ed513eda08 100644 --- a/packages/backend/src/server/api/endpoints/admin/suspend-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/suspend-user.ts @@ -23,7 +23,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const user = await Users.findOne(ps.userId as string); + const user = await Users.findOneBy({ id: ps.userId }); if (user == null) { throw new Error('user not found'); @@ -58,12 +58,12 @@ export default define(meta, paramDef, async (ps, me) => { }); async function unFollowAll(follower: User) { - const followings = await Followings.find({ + const followings = await Followings.findBy({ followerId: follower.id, }); for (const following of followings) { - const followee = await Users.findOne({ + const followee = await Users.findOneBy({ id: following.followeeId, }); diff --git a/packages/backend/src/server/api/endpoints/admin/unsilence-user.ts b/packages/backend/src/server/api/endpoints/admin/unsilence-user.ts index 4e6366aa18..a4b373f5c7 100644 --- a/packages/backend/src/server/api/endpoints/admin/unsilence-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/unsilence-user.ts @@ -1,6 +1,7 @@ import define from '../../define.js'; import { Users } from '@/models/index.js'; import { insertModerationLog } from '@/services/insert-moderation-log.js'; +import { publishInternalEvent } from '@/services/stream.js'; export const meta = { tags: ['admin'], @@ -19,7 +20,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const user = await Users.findOne(ps.userId as string); + const user = await Users.findOneBy({ id: ps.userId }); if (user == null) { throw new Error('user not found'); @@ -29,6 +30,8 @@ export default define(meta, paramDef, async (ps, me) => { isSilenced: false, }); + publishInternalEvent('userChangeSilencedState', { id: user.id, isSilenced: false }); + insertModerationLog(me, 'unsilence', { targetId: user.id, }); diff --git a/packages/backend/src/server/api/endpoints/admin/unsuspend-user.ts b/packages/backend/src/server/api/endpoints/admin/unsuspend-user.ts index 3b9e0a94e0..5cf26251be 100644 --- a/packages/backend/src/server/api/endpoints/admin/unsuspend-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/unsuspend-user.ts @@ -20,7 +20,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const user = await Users.findOne(ps.userId as string); + const user = await Users.findOneBy({ id: ps.userId }); if (user == null) { throw new Error('user not found'); diff --git a/packages/backend/src/server/api/endpoints/admin/update-meta.ts b/packages/backend/src/server/api/endpoints/admin/update-meta.ts index 66b634c877..3c39bf0f30 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts @@ -1,8 +1,8 @@ import define from '../../define.js'; -import { getConnection } from 'typeorm'; import { Meta } from '@/models/entities/meta.js'; import { insertModerationLog } from '@/services/insert-moderation-log.js'; import { DB_MAX_NOTE_TEXT_LENGTH } from '@/misc/hard-limits.js'; +import { db } from '@/db/postgre.js'; export const meta = { tags: ['admin'], @@ -396,7 +396,7 @@ export default define(meta, paramDef, async (ps, me) => { set.deeplIsPro = ps.deeplIsPro; } - await getConnection().transaction(async transactionalEntityManager => { + await db.transaction(async transactionalEntityManager => { const meta = await transactionalEntityManager.findOne(Meta, { order: { id: 'DESC', diff --git a/packages/backend/src/server/api/endpoints/admin/vacuum.ts b/packages/backend/src/server/api/endpoints/admin/vacuum.ts index 4c04e019da..0546acfacb 100644 --- a/packages/backend/src/server/api/endpoints/admin/vacuum.ts +++ b/packages/backend/src/server/api/endpoints/admin/vacuum.ts @@ -1,6 +1,6 @@ import define from '../../define.js'; -import { getConnection } from 'typeorm'; import { insertModerationLog } from '@/services/insert-moderation-log.js'; +import { db } from '@/db/postgre.js'; export const meta = { tags: ['admin'], @@ -30,7 +30,7 @@ export default define(meta, paramDef, async (ps, me) => { params.push('ANALYZE'); } - getConnection().query('VACUUM ' + params.join(' ')); + db.query('VACUUM ' + params.join(' ')); insertModerationLog(me, 'vacuum', ps); }); diff --git a/packages/backend/src/server/api/endpoints/announcements.ts b/packages/backend/src/server/api/endpoints/announcements.ts index bba66e98cf..222efdcef0 100644 --- a/packages/backend/src/server/api/endpoints/announcements.ts +++ b/packages/backend/src/server/api/endpoints/announcements.ts @@ -69,7 +69,7 @@ export default define(meta, paramDef, async (ps, user) => { const announcements = await query.take(ps.limit).getMany(); if (user) { - const reads = (await AnnouncementReads.find({ + const reads = (await AnnouncementReads.findBy({ userId: user.id, })).map(x => x.announcementId); diff --git a/packages/backend/src/server/api/endpoints/antennas/create.ts b/packages/backend/src/server/api/endpoints/antennas/create.ts index 92cbba817e..7a4923b944 100644 --- a/packages/backend/src/server/api/endpoints/antennas/create.ts +++ b/packages/backend/src/server/api/endpoints/antennas/create.ts @@ -66,7 +66,7 @@ export default define(meta, paramDef, async (ps, user) => { let userGroupJoining; if (ps.src === 'list' && ps.userListId) { - userList = await UserLists.findOne({ + userList = await UserLists.findOneBy({ id: ps.userListId, userId: user.id, }); @@ -75,7 +75,7 @@ export default define(meta, paramDef, async (ps, user) => { throw new ApiError(meta.errors.noSuchUserList); } } else if (ps.src === 'group' && ps.userGroupId) { - userGroupJoining = await UserGroupJoinings.findOne({ + userGroupJoining = await UserGroupJoinings.findOneBy({ userGroupId: ps.userGroupId, userId: user.id, }); @@ -100,7 +100,7 @@ export default define(meta, paramDef, async (ps, user) => { withReplies: ps.withReplies, withFile: ps.withFile, notify: ps.notify, - }).then(x => Antennas.findOneOrFail(x.identifiers[0])); + }).then(x => Antennas.findOneByOrFail(x.identifiers[0])); publishInternalEvent('antennaCreated', antenna); diff --git a/packages/backend/src/server/api/endpoints/antennas/delete.ts b/packages/backend/src/server/api/endpoints/antennas/delete.ts index 4e6b8b3d2e..ced34ba313 100644 --- a/packages/backend/src/server/api/endpoints/antennas/delete.ts +++ b/packages/backend/src/server/api/endpoints/antennas/delete.ts @@ -29,7 +29,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const antenna = await Antennas.findOne({ + const antenna = await Antennas.findOneBy({ id: ps.antennaId, userId: user.id, }); diff --git a/packages/backend/src/server/api/endpoints/antennas/list.ts b/packages/backend/src/server/api/endpoints/antennas/list.ts index accca5de76..c519b452ef 100644 --- a/packages/backend/src/server/api/endpoints/antennas/list.ts +++ b/packages/backend/src/server/api/endpoints/antennas/list.ts @@ -27,7 +27,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const antennas = await Antennas.find({ + const antennas = await Antennas.findBy({ userId: me.id, }); diff --git a/packages/backend/src/server/api/endpoints/antennas/notes.ts b/packages/backend/src/server/api/endpoints/antennas/notes.ts index f0cb2ba3c0..004e4c131d 100644 --- a/packages/backend/src/server/api/endpoints/antennas/notes.ts +++ b/packages/backend/src/server/api/endpoints/antennas/notes.ts @@ -48,7 +48,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const antenna = await Antennas.findOne({ + const antenna = await Antennas.findOneBy({ id: ps.antennaId, userId: user.id, }); diff --git a/packages/backend/src/server/api/endpoints/antennas/show.ts b/packages/backend/src/server/api/endpoints/antennas/show.ts index 36c4da81b7..dd693789cb 100644 --- a/packages/backend/src/server/api/endpoints/antennas/show.ts +++ b/packages/backend/src/server/api/endpoints/antennas/show.ts @@ -35,7 +35,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { // Fetch the antenna - const antenna = await Antennas.findOne({ + const antenna = await Antennas.findOneBy({ id: ps.antennaId, userId: me.id, }); diff --git a/packages/backend/src/server/api/endpoints/antennas/update.ts b/packages/backend/src/server/api/endpoints/antennas/update.ts index a99964555b..edfedc1752 100644 --- a/packages/backend/src/server/api/endpoints/antennas/update.ts +++ b/packages/backend/src/server/api/endpoints/antennas/update.ts @@ -69,7 +69,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // Fetch the antenna - const antenna = await Antennas.findOne({ + const antenna = await Antennas.findOneBy({ id: ps.antennaId, userId: user.id, }); @@ -82,7 +82,7 @@ export default define(meta, paramDef, async (ps, user) => { let userGroupJoining; if (ps.src === 'list' && ps.userListId) { - userList = await UserLists.findOne({ + userList = await UserLists.findOneBy({ id: ps.userListId, userId: user.id, }); @@ -91,7 +91,7 @@ export default define(meta, paramDef, async (ps, user) => { throw new ApiError(meta.errors.noSuchUserList); } } else if (ps.src === 'group' && ps.userGroupId) { - userGroupJoining = await UserGroupJoinings.findOne({ + userGroupJoining = await UserGroupJoinings.findOneBy({ userGroupId: ps.userGroupId, userId: user.id, }); @@ -115,7 +115,7 @@ export default define(meta, paramDef, async (ps, user) => { notify: ps.notify, }); - publishInternalEvent('antennaUpdated', await Antennas.findOneOrFail(antenna.id)); + publishInternalEvent('antennaUpdated', await Antennas.findOneByOrFail({ id: antenna.id })); return await Antennas.pack(antenna.id); }); diff --git a/packages/backend/src/server/api/endpoints/ap/show.ts b/packages/backend/src/server/api/endpoints/ap/show.ts index 7595c38e8a..3c0c0642e3 100644 --- a/packages/backend/src/server/api/endpoints/ap/show.ts +++ b/packages/backend/src/server/api/endpoints/ap/show.ts @@ -97,7 +97,7 @@ async function fetchAny(uri: string): Promise | n const type = parts.pop(); if (type === 'notes') { - const note = await Notes.findOne(id); + const note = await Notes.findOneBy({ id }); if (note) { return { @@ -106,7 +106,7 @@ async function fetchAny(uri: string): Promise | n }; } } else if (type === 'users') { - const user = await Users.findOne(id); + const user = await Users.findOneBy({ id }); if (user) { return { @@ -124,8 +124,8 @@ async function fetchAny(uri: string): Promise | n // URI(AP Object id)としてDB検索 { const [user, note] = await Promise.all([ - Users.findOne({ uri: uri }), - Notes.findOne({ uri: uri }), + Users.findOneBy({ uri: uri }), + Notes.findOneBy({ uri: uri }), ]); const packed = await mergePack(user, note); @@ -145,7 +145,7 @@ async function fetchAny(uri: string): Promise | n const type = parts.pop(); if (type === 'notes') { - const note = await Notes.findOne(id); + const note = await Notes.findOneBy({ id }); if (note) { return { @@ -154,7 +154,7 @@ async function fetchAny(uri: string): Promise | n }; } } else if (type === 'users') { - const user = await Users.findOne(id); + const user = await Users.findOneBy({ id }); if (user) { return { @@ -166,8 +166,8 @@ async function fetchAny(uri: string): Promise | n } const [user, note] = await Promise.all([ - Users.findOne({ uri: object.id }), - Notes.findOne({ uri: object.id }), + Users.findOneBy({ uri: object.id }), + Notes.findOneBy({ uri: object.id }), ]); const packed = await mergePack(user, note); diff --git a/packages/backend/src/server/api/endpoints/app/create.ts b/packages/backend/src/server/api/endpoints/app/create.ts index e0cf8632fb..a0a7350822 100644 --- a/packages/backend/src/server/api/endpoints/app/create.ts +++ b/packages/backend/src/server/api/endpoints/app/create.ts @@ -47,7 +47,7 @@ export default define(meta, paramDef, async (ps, user) => { permission, callbackUrl: ps.callbackUrl, secret: secret, - }).then(x => Apps.findOneOrFail(x.identifiers[0])); + }).then(x => Apps.findOneByOrFail(x.identifiers[0])); return await Apps.pack(app, null, { detail: true, diff --git a/packages/backend/src/server/api/endpoints/app/show.ts b/packages/backend/src/server/api/endpoints/app/show.ts index 54e714e193..451969d971 100644 --- a/packages/backend/src/server/api/endpoints/app/show.ts +++ b/packages/backend/src/server/api/endpoints/app/show.ts @@ -33,7 +33,7 @@ export default define(meta, paramDef, async (ps, user, token) => { const isSecure = user != null && token == null; // Lookup app - const ap = await Apps.findOne(ps.appId); + const ap = await Apps.findOneBy({ id: ps.appId }); if (ap == null) { throw new ApiError(meta.errors.noSuchApp); diff --git a/packages/backend/src/server/api/endpoints/auth/accept.ts b/packages/backend/src/server/api/endpoints/auth/accept.ts index 0760eef52b..b5c06792bb 100644 --- a/packages/backend/src/server/api/endpoints/auth/accept.ts +++ b/packages/backend/src/server/api/endpoints/auth/accept.ts @@ -33,7 +33,7 @@ export const paramDef = { export default define(meta, paramDef, async (ps, user) => { // Fetch token const session = await AuthSessions - .findOne({ token: ps.token }); + .findOneBy({ token: ps.token }); if (session == null) { throw new ApiError(meta.errors.noSuchSession); @@ -43,14 +43,14 @@ export default define(meta, paramDef, async (ps, user) => { const accessToken = secureRndstr(32, true); // Fetch exist access token - const exist = await AccessTokens.findOne({ + const exist = await AccessTokens.findOneBy({ appId: session.appId, userId: user.id, }); if (exist == null) { // Lookup app - const app = await Apps.findOneOrFail(session.appId); + const app = await Apps.findOneByOrFail({ id: session.appId }); // Generate Hash const sha256 = crypto.createHash('sha256'); diff --git a/packages/backend/src/server/api/endpoints/auth/session/generate.ts b/packages/backend/src/server/api/endpoints/auth/session/generate.ts index bd571327d2..717c3e5086 100644 --- a/packages/backend/src/server/api/endpoints/auth/session/generate.ts +++ b/packages/backend/src/server/api/endpoints/auth/session/generate.ts @@ -46,7 +46,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { // Lookup app - const app = await Apps.findOne({ + const app = await Apps.findOneBy({ secret: ps.appSecret, }); @@ -63,7 +63,7 @@ export default define(meta, paramDef, async (ps) => { createdAt: new Date(), appId: app.id, token: token, - }).then(x => AuthSessions.findOneOrFail(x.identifiers[0])); + }).then(x => AuthSessions.findOneByOrFail(x.identifiers[0])); return { token: doc.token, diff --git a/packages/backend/src/server/api/endpoints/auth/session/show.ts b/packages/backend/src/server/api/endpoints/auth/session/show.ts index d40c9363c6..3f3a4d1427 100644 --- a/packages/backend/src/server/api/endpoints/auth/session/show.ts +++ b/packages/backend/src/server/api/endpoints/auth/session/show.ts @@ -48,7 +48,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // Lookup session - const session = await AuthSessions.findOne({ + const session = await AuthSessions.findOneBy({ token: ps.token, }); diff --git a/packages/backend/src/server/api/endpoints/auth/session/userkey.ts b/packages/backend/src/server/api/endpoints/auth/session/userkey.ts index b699c6fa25..89884ed38a 100644 --- a/packages/backend/src/server/api/endpoints/auth/session/userkey.ts +++ b/packages/backend/src/server/api/endpoints/auth/session/userkey.ts @@ -57,7 +57,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { // Lookup app - const app = await Apps.findOne({ + const app = await Apps.findOneBy({ secret: ps.appSecret, }); @@ -66,7 +66,7 @@ export default define(meta, paramDef, async (ps) => { } // Fetch token - const session = await AuthSessions.findOne({ + const session = await AuthSessions.findOneBy({ token: ps.token, appId: app.id, }); @@ -80,7 +80,7 @@ export default define(meta, paramDef, async (ps) => { } // Lookup access token - const accessToken = await AccessTokens.findOneOrFail({ + const accessToken = await AccessTokens.findOneByOrFail({ appId: app.id, userId: session.userId, }); diff --git a/packages/backend/src/server/api/endpoints/blocking/create.ts b/packages/backend/src/server/api/endpoints/blocking/create.ts index c5e73c0131..0540e6ab0f 100644 --- a/packages/backend/src/server/api/endpoints/blocking/create.ts +++ b/packages/backend/src/server/api/endpoints/blocking/create.ts @@ -54,7 +54,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const blocker = await Users.findOneOrFail(user.id); + const blocker = await Users.findOneByOrFail({ id: user.id }); // 自分自身 if (user.id === ps.userId) { @@ -68,7 +68,7 @@ export default define(meta, paramDef, async (ps, user) => { }); // Check if already blocking - const exist = await Blockings.findOne({ + const exist = await Blockings.findOneBy({ blockerId: blocker.id, blockeeId: blockee.id, }); diff --git a/packages/backend/src/server/api/endpoints/blocking/delete.ts b/packages/backend/src/server/api/endpoints/blocking/delete.ts index a45547290c..77e17b3ba9 100644 --- a/packages/backend/src/server/api/endpoints/blocking/delete.ts +++ b/packages/backend/src/server/api/endpoints/blocking/delete.ts @@ -54,7 +54,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const blocker = await Users.findOneOrFail(user.id); + const blocker = await Users.findOneByOrFail({ id: user.id }); // Check if the blockee is yourself if (user.id === ps.userId) { @@ -68,7 +68,7 @@ export default define(meta, paramDef, async (ps, user) => { }); // Check not blocking - const exist = await Blockings.findOne({ + const exist = await Blockings.findOneBy({ blockerId: blocker.id, blockeeId: blockee.id, }); diff --git a/packages/backend/src/server/api/endpoints/channels/create.ts b/packages/backend/src/server/api/endpoints/channels/create.ts index 16456b9c01..94dcfe5023 100644 --- a/packages/backend/src/server/api/endpoints/channels/create.ts +++ b/packages/backend/src/server/api/endpoints/channels/create.ts @@ -40,7 +40,7 @@ export const paramDef = { export default define(meta, paramDef, async (ps, user) => { let banner = null; if (ps.bannerId != null) { - banner = await DriveFiles.findOne({ + banner = await DriveFiles.findOneBy({ id: ps.bannerId, userId: user.id, }); @@ -57,7 +57,7 @@ export default define(meta, paramDef, async (ps, user) => { name: ps.name, description: ps.description || null, bannerId: banner ? banner.id : null, - } as Channel).then(x => Channels.findOneOrFail(x.identifiers[0])); + } as Channel).then(x => Channels.findOneByOrFail(x.identifiers[0])); return await Channels.pack(channel, user); }); diff --git a/packages/backend/src/server/api/endpoints/channels/follow.ts b/packages/backend/src/server/api/endpoints/channels/follow.ts index 4372c283cb..895ffed0bd 100644 --- a/packages/backend/src/server/api/endpoints/channels/follow.ts +++ b/packages/backend/src/server/api/endpoints/channels/follow.ts @@ -30,7 +30,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const channel = await Channels.findOne({ + const channel = await Channels.findOneBy({ id: ps.channelId, }); diff --git a/packages/backend/src/server/api/endpoints/channels/show.ts b/packages/backend/src/server/api/endpoints/channels/show.ts index ea4e013073..87665a9865 100644 --- a/packages/backend/src/server/api/endpoints/channels/show.ts +++ b/packages/backend/src/server/api/endpoints/channels/show.ts @@ -32,7 +32,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const channel = await Channels.findOne({ + const channel = await Channels.findOneBy({ id: ps.channelId, }); diff --git a/packages/backend/src/server/api/endpoints/channels/timeline.ts b/packages/backend/src/server/api/endpoints/channels/timeline.ts index 57a9fa44b8..deaa299013 100644 --- a/packages/backend/src/server/api/endpoints/channels/timeline.ts +++ b/packages/backend/src/server/api/endpoints/channels/timeline.ts @@ -43,7 +43,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const channel = await Channels.findOne({ + const channel = await Channels.findOneBy({ id: ps.channelId, }); diff --git a/packages/backend/src/server/api/endpoints/channels/unfollow.ts b/packages/backend/src/server/api/endpoints/channels/unfollow.ts index 32beb24d6f..e065d897a5 100644 --- a/packages/backend/src/server/api/endpoints/channels/unfollow.ts +++ b/packages/backend/src/server/api/endpoints/channels/unfollow.ts @@ -29,7 +29,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const channel = await Channels.findOne({ + const channel = await Channels.findOneBy({ id: ps.channelId, }); diff --git a/packages/backend/src/server/api/endpoints/channels/update.ts b/packages/backend/src/server/api/endpoints/channels/update.ts index 2f2b4aeeb2..13104f324f 100644 --- a/packages/backend/src/server/api/endpoints/channels/update.ts +++ b/packages/backend/src/server/api/endpoints/channels/update.ts @@ -49,7 +49,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const channel = await Channels.findOne({ + const channel = await Channels.findOneBy({ id: ps.channelId, }); @@ -64,7 +64,7 @@ export default define(meta, paramDef, async (ps, me) => { // eslint:disable-next-line:no-unnecessary-initializer let banner = undefined; if (ps.bannerId != null) { - banner = await DriveFiles.findOne({ + banner = await DriveFiles.findOneBy({ id: ps.bannerId, userId: me.id, }); diff --git a/packages/backend/src/server/api/endpoints/clips/add-note.ts b/packages/backend/src/server/api/endpoints/clips/add-note.ts index c630302b98..5d72f5c1bf 100644 --- a/packages/backend/src/server/api/endpoints/clips/add-note.ts +++ b/packages/backend/src/server/api/endpoints/clips/add-note.ts @@ -43,7 +43,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const clip = await Clips.findOne({ + const clip = await Clips.findOneBy({ id: ps.clipId, userId: user.id, }); @@ -57,7 +57,7 @@ export default define(meta, paramDef, async (ps, user) => { throw e; }); - const exist = await ClipNotes.findOne({ + const exist = await ClipNotes.findOneBy({ noteId: note.id, clipId: clip.id, }); diff --git a/packages/backend/src/server/api/endpoints/clips/create.ts b/packages/backend/src/server/api/endpoints/clips/create.ts index 531847d15c..a2dbef12e0 100644 --- a/packages/backend/src/server/api/endpoints/clips/create.ts +++ b/packages/backend/src/server/api/endpoints/clips/create.ts @@ -35,7 +35,7 @@ export default define(meta, paramDef, async (ps, user) => { name: ps.name, isPublic: ps.isPublic, description: ps.description, - }).then(x => Clips.findOneOrFail(x.identifiers[0])); + }).then(x => Clips.findOneByOrFail(x.identifiers[0])); return await Clips.pack(clip); }); diff --git a/packages/backend/src/server/api/endpoints/clips/delete.ts b/packages/backend/src/server/api/endpoints/clips/delete.ts index 675db1d57f..b6c0eb702a 100644 --- a/packages/backend/src/server/api/endpoints/clips/delete.ts +++ b/packages/backend/src/server/api/endpoints/clips/delete.ts @@ -28,7 +28,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const clip = await Clips.findOne({ + const clip = await Clips.findOneBy({ id: ps.clipId, userId: user.id, }); diff --git a/packages/backend/src/server/api/endpoints/clips/list.ts b/packages/backend/src/server/api/endpoints/clips/list.ts index 1c955d64fc..378811eba0 100644 --- a/packages/backend/src/server/api/endpoints/clips/list.ts +++ b/packages/backend/src/server/api/endpoints/clips/list.ts @@ -27,7 +27,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const clips = await Clips.find({ + const clips = await Clips.findBy({ userId: me.id, }); diff --git a/packages/backend/src/server/api/endpoints/clips/notes.ts b/packages/backend/src/server/api/endpoints/clips/notes.ts index 2627884ee1..4b6782fca0 100644 --- a/packages/backend/src/server/api/endpoints/clips/notes.ts +++ b/packages/backend/src/server/api/endpoints/clips/notes.ts @@ -45,7 +45,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const clip = await Clips.findOne({ + const clip = await Clips.findOneBy({ id: ps.clipId, }); diff --git a/packages/backend/src/server/api/endpoints/clips/show.ts b/packages/backend/src/server/api/endpoints/clips/show.ts index 0a3b25c94e..c3d73c168d 100644 --- a/packages/backend/src/server/api/endpoints/clips/show.ts +++ b/packages/backend/src/server/api/endpoints/clips/show.ts @@ -35,7 +35,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { // Fetch the clip - const clip = await Clips.findOne({ + const clip = await Clips.findOneBy({ id: ps.clipId, }); diff --git a/packages/backend/src/server/api/endpoints/clips/update.ts b/packages/backend/src/server/api/endpoints/clips/update.ts index 0ac5ccd047..b67d844f6e 100644 --- a/packages/backend/src/server/api/endpoints/clips/update.ts +++ b/packages/backend/src/server/api/endpoints/clips/update.ts @@ -38,7 +38,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // Fetch the clip - const clip = await Clips.findOne({ + const clip = await Clips.findOneBy({ id: ps.clipId, userId: user.id, }); diff --git a/packages/backend/src/server/api/endpoints/drive/files/attached-notes.ts b/packages/backend/src/server/api/endpoints/drive/files/attached-notes.ts index 3c68beee17..7ffe89a1e5 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/attached-notes.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/attached-notes.ts @@ -39,7 +39,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // Fetch file - const file = await DriveFiles.findOne({ + const file = await DriveFiles.findOneBy({ id: ps.fileId, userId: user.id, }); diff --git a/packages/backend/src/server/api/endpoints/drive/files/check-existence.ts b/packages/backend/src/server/api/endpoints/drive/files/check-existence.ts index 7e5cb2498e..80293df5d9 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/check-existence.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/check-existence.ts @@ -24,7 +24,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const file = await DriveFiles.findOne({ + const file = await DriveFiles.findOneBy({ md5: ps.md5, userId: user.id, }); diff --git a/packages/backend/src/server/api/endpoints/drive/files/delete.ts b/packages/backend/src/server/api/endpoints/drive/files/delete.ts index 5f565a63fb..61c56e6314 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/delete.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/delete.ts @@ -2,7 +2,7 @@ import { deleteFile } from '@/services/drive/delete-file.js'; import { publishDriveStream } from '@/services/stream.js'; import define from '../../../define.js'; import { ApiError } from '../../../error.js'; -import { DriveFiles } from '@/models/index.js'; +import { DriveFiles, Users } from '@/models/index.js'; export const meta = { tags: ['drive'], @@ -36,13 +36,13 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const file = await DriveFiles.findOne(ps.fileId); + const file = await DriveFiles.findOneBy({ id: ps.fileId }); if (file == null) { throw new ApiError(meta.errors.noSuchFile); } - if (!user.isAdmin && !user.isModerator && (file.userId !== user.id)) { + if ((!user.isAdmin && !user.isModerator) && (file.userId !== user.id)) { throw new ApiError(meta.errors.accessDenied); } diff --git a/packages/backend/src/server/api/endpoints/drive/files/find-by-hash.ts b/packages/backend/src/server/api/endpoints/drive/files/find-by-hash.ts index e45ec633d3..f9b4ea89ea 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/find-by-hash.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/find-by-hash.ts @@ -29,7 +29,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const files = await DriveFiles.find({ + const files = await DriveFiles.findBy({ md5: ps.md5, userId: user.id, }); diff --git a/packages/backend/src/server/api/endpoints/drive/files/find.ts b/packages/backend/src/server/api/endpoints/drive/files/find.ts index 974fc9fbad..4938a69d11 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/find.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/find.ts @@ -1,5 +1,6 @@ import define from '../../../define.js'; import { DriveFiles } from '@/models/index.js'; +import { IsNull } from 'typeorm'; export const meta = { requireCredential: true, @@ -30,10 +31,10 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const files = await DriveFiles.find({ + const files = await DriveFiles.findBy({ name: ps.name, userId: user.id, - folderId: ps.folderId, + folderId: ps.folderId ?? IsNull(), }); return await Promise.all(files.map(file => DriveFiles.pack(file, { self: true }))); diff --git a/packages/backend/src/server/api/endpoints/drive/files/show.ts b/packages/backend/src/server/api/endpoints/drive/files/show.ts index 181365c7e6..c8e9d3dd93 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/show.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/show.ts @@ -1,7 +1,7 @@ import define from '../../../define.js'; import { ApiError } from '../../../error.js'; import { DriveFile } from '@/models/entities/drive-file.js'; -import { DriveFiles } from '@/models/index.js'; +import { DriveFiles, Users } from '@/models/index.js'; export const meta = { tags: ['drive'], @@ -51,7 +51,7 @@ export default define(meta, paramDef, async (ps, user) => { let file: DriveFile | undefined; if (ps.fileId) { - file = await DriveFiles.findOne(ps.fileId); + file = await DriveFiles.findOneBy({ id: ps.fileId }); } else if (ps.url) { file = await DriveFiles.findOne({ where: [{ @@ -70,7 +70,7 @@ export default define(meta, paramDef, async (ps, user) => { throw new ApiError(meta.errors.noSuchFile); } - if (!user.isAdmin && !user.isModerator && (file.userId !== user.id)) { + if ((!user.isAdmin && !user.isModerator) && (file.userId !== user.id)) { throw new ApiError(meta.errors.accessDenied); } diff --git a/packages/backend/src/server/api/endpoints/drive/files/update.ts b/packages/backend/src/server/api/endpoints/drive/files/update.ts index ab8e4aeeb2..4b3f5f2dc9 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/update.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/update.ts @@ -1,7 +1,7 @@ import { publishDriveStream } from '@/services/stream.js'; import define from '../../../define.js'; import { ApiError } from '../../../error.js'; -import { DriveFiles, DriveFolders } from '@/models/index.js'; +import { DriveFiles, DriveFolders, Users } from '@/models/index.js'; import { DB_MAX_IMAGE_COMMENT_LENGTH } from '@/misc/hard-limits.js'; export const meta = { @@ -58,13 +58,13 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const file = await DriveFiles.findOne(ps.fileId); + const file = await DriveFiles.findOneBy({ id: ps.fileId }); if (file == null) { throw new ApiError(meta.errors.noSuchFile); } - if (!user.isAdmin && !user.isModerator && (file.userId !== user.id)) { + if ((!user.isAdmin && !user.isModerator) && (file.userId !== user.id)) { throw new ApiError(meta.errors.accessDenied); } @@ -81,7 +81,7 @@ export default define(meta, paramDef, async (ps, user) => { if (ps.folderId === null) { file.folderId = null; } else { - const folder = await DriveFolders.findOne({ + const folder = await DriveFolders.findOneBy({ id: ps.folderId, userId: user.id, }); diff --git a/packages/backend/src/server/api/endpoints/drive/folders/create.ts b/packages/backend/src/server/api/endpoints/drive/folders/create.ts index 4ae10f0621..3d7f514c85 100644 --- a/packages/backend/src/server/api/endpoints/drive/folders/create.ts +++ b/packages/backend/src/server/api/endpoints/drive/folders/create.ts @@ -41,7 +41,7 @@ export default define(meta, paramDef, async (ps, user) => { let parent = null; if (ps.parentId) { // Fetch parent folder - parent = await DriveFolders.findOne({ + parent = await DriveFolders.findOneBy({ id: ps.parentId, userId: user.id, }); @@ -58,7 +58,7 @@ export default define(meta, paramDef, async (ps, user) => { name: ps.name, parentId: parent !== null ? parent.id : null, userId: user.id, - }).then(x => DriveFolders.findOneOrFail(x.identifiers[0])); + }).then(x => DriveFolders.findOneByOrFail(x.identifiers[0])); const folderObj = await DriveFolders.pack(folder); diff --git a/packages/backend/src/server/api/endpoints/drive/folders/delete.ts b/packages/backend/src/server/api/endpoints/drive/folders/delete.ts index 4994615cc6..ab9d411ec0 100644 --- a/packages/backend/src/server/api/endpoints/drive/folders/delete.ts +++ b/packages/backend/src/server/api/endpoints/drive/folders/delete.ts @@ -36,7 +36,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // Get folder - const folder = await DriveFolders.findOne({ + const folder = await DriveFolders.findOneBy({ id: ps.folderId, userId: user.id, }); @@ -46,8 +46,8 @@ export default define(meta, paramDef, async (ps, user) => { } const [childFoldersCount, childFilesCount] = await Promise.all([ - DriveFolders.count({ parentId: folder.id }), - DriveFiles.count({ folderId: folder.id }), + DriveFolders.countBy({ parentId: folder.id }), + DriveFiles.countBy({ folderId: folder.id }), ]); if (childFoldersCount !== 0 || childFilesCount !== 0) { diff --git a/packages/backend/src/server/api/endpoints/drive/folders/find.ts b/packages/backend/src/server/api/endpoints/drive/folders/find.ts index 9bf0e3d61b..1feab273a1 100644 --- a/packages/backend/src/server/api/endpoints/drive/folders/find.ts +++ b/packages/backend/src/server/api/endpoints/drive/folders/find.ts @@ -1,5 +1,6 @@ import define from '../../../define.js'; import { DriveFolders } from '@/models/index.js'; +import { IsNull } from 'typeorm'; export const meta = { tags: ['drive'], @@ -30,10 +31,10 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const folders = await DriveFolders.find({ + const folders = await DriveFolders.findBy({ name: ps.name, userId: user.id, - parentId: ps.parentId, + parentId: ps.parentId ?? IsNull(), }); return await Promise.all(folders.map(folder => DriveFolders.pack(folder))); diff --git a/packages/backend/src/server/api/endpoints/drive/folders/show.ts b/packages/backend/src/server/api/endpoints/drive/folders/show.ts index f09816d57a..1e7aa2b16c 100644 --- a/packages/backend/src/server/api/endpoints/drive/folders/show.ts +++ b/packages/backend/src/server/api/endpoints/drive/folders/show.ts @@ -35,7 +35,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // Get folder - const folder = await DriveFolders.findOne({ + const folder = await DriveFolders.findOneBy({ id: ps.folderId, userId: user.id, }); diff --git a/packages/backend/src/server/api/endpoints/drive/folders/update.ts b/packages/backend/src/server/api/endpoints/drive/folders/update.ts index c020b243ef..1aa2e84292 100644 --- a/packages/backend/src/server/api/endpoints/drive/folders/update.ts +++ b/packages/backend/src/server/api/endpoints/drive/folders/update.ts @@ -50,7 +50,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // Fetch folder - const folder = await DriveFolders.findOne({ + const folder = await DriveFolders.findOneBy({ id: ps.folderId, userId: user.id, }); @@ -68,7 +68,7 @@ export default define(meta, paramDef, async (ps, user) => { folder.parentId = null; } else { // Get parent folder - const parent = await DriveFolders.findOne({ + const parent = await DriveFolders.findOneBy({ id: ps.parentId, userId: user.id, }); @@ -78,9 +78,9 @@ export default define(meta, paramDef, async (ps, user) => { } // Check if the circular reference will occur - async function checkCircle(folderId: any): Promise { + async function checkCircle(folderId: string): Promise { // Fetch folder - const folder2 = await DriveFolders.findOne({ + const folder2 = await DriveFolders.findOneBy({ id: folderId, }); diff --git a/packages/backend/src/server/api/endpoints/federation/show-instance.ts b/packages/backend/src/server/api/endpoints/federation/show-instance.ts index 5bfe43fc9c..2fbb8a15cb 100644 --- a/packages/backend/src/server/api/endpoints/federation/show-instance.ts +++ b/packages/backend/src/server/api/endpoints/federation/show-instance.ts @@ -28,7 +28,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { const instance = await Instances - .findOne({ host: toPuny(ps.host) }); + .findOneBy({ host: toPuny(ps.host) }); return instance ? await Instances.pack(instance) : null; }); diff --git a/packages/backend/src/server/api/endpoints/following/create.ts b/packages/backend/src/server/api/endpoints/following/create.ts index 8758a64a39..02a030cd5e 100644 --- a/packages/backend/src/server/api/endpoints/following/create.ts +++ b/packages/backend/src/server/api/endpoints/following/create.ts @@ -81,7 +81,7 @@ export default define(meta, paramDef, async (ps, user) => { }); // Check if already following - const exist = await Followings.findOne({ + const exist = await Followings.findOneBy({ followerId: follower.id, followeeId: followee.id, }); diff --git a/packages/backend/src/server/api/endpoints/following/delete.ts b/packages/backend/src/server/api/endpoints/following/delete.ts index 47efc59b81..2f41b16e9a 100644 --- a/packages/backend/src/server/api/endpoints/following/delete.ts +++ b/packages/backend/src/server/api/endpoints/following/delete.ts @@ -68,7 +68,7 @@ export default define(meta, paramDef, async (ps, user) => { }); // Check not following - const exist = await Followings.findOne({ + const exist = await Followings.findOneBy({ followerId: follower.id, followeeId: followee.id, }); diff --git a/packages/backend/src/server/api/endpoints/following/invalidate.ts b/packages/backend/src/server/api/endpoints/following/invalidate.ts index 24d8256ca6..18ec5affe8 100644 --- a/packages/backend/src/server/api/endpoints/following/invalidate.ts +++ b/packages/backend/src/server/api/endpoints/following/invalidate.ts @@ -68,7 +68,7 @@ export default define(meta, paramDef, async (ps, user) => { }); // Check not following - const exist = await Followings.findOne({ + const exist = await Followings.findOneBy({ followerId: follower.id, followeeId: followee.id, }); diff --git a/packages/backend/src/server/api/endpoints/following/requests/list.ts b/packages/backend/src/server/api/endpoints/following/requests/list.ts index 3b60b89b3c..a8f42c481d 100644 --- a/packages/backend/src/server/api/endpoints/following/requests/list.ts +++ b/packages/backend/src/server/api/endpoints/following/requests/list.ts @@ -43,7 +43,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const reqs = await FollowRequests.find({ + const reqs = await FollowRequests.findBy({ followeeId: user.id, }); diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/create.ts b/packages/backend/src/server/api/endpoints/gallery/posts/create.ts index eb6c0f3eb1..8074a3b34f 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts/create.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts/create.ts @@ -45,7 +45,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const files = (await Promise.all(ps.fileIds.map(fileId => - DriveFiles.findOne({ + DriveFiles.findOneBy({ id: fileId, userId: user.id, }) @@ -64,7 +64,7 @@ export default define(meta, paramDef, async (ps, user) => { userId: user.id, isSensitive: ps.isSensitive, fileIds: files.map(file => file.id), - })).then(x => GalleryPosts.findOneOrFail(x.identifiers[0])); + })).then(x => GalleryPosts.findOneByOrFail(x.identifiers[0])); return await GalleryPosts.pack(post, user); }); diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/delete.ts b/packages/backend/src/server/api/endpoints/gallery/posts/delete.ts index f8bf785ee6..b00ee0e2ae 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts/delete.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts/delete.ts @@ -28,7 +28,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const post = await GalleryPosts.findOne({ + const post = await GalleryPosts.findOneBy({ id: ps.postId, userId: user.id, }); diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/like.ts b/packages/backend/src/server/api/endpoints/gallery/posts/like.ts index d154bfc3c6..b858114aec 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts/like.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts/like.ts @@ -41,7 +41,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const post = await GalleryPosts.findOne(ps.postId); + const post = await GalleryPosts.findOneBy({ id: ps.postId }); if (post == null) { throw new ApiError(meta.errors.noSuchPost); } @@ -51,7 +51,7 @@ export default define(meta, paramDef, async (ps, user) => { } // if already liked - const exist = await GalleryLikes.findOne({ + const exist = await GalleryLikes.findOneBy({ postId: post.id, userId: user.id, }); diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/show.ts b/packages/backend/src/server/api/endpoints/gallery/posts/show.ts index 5b4594070c..4f6dafd7cb 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts/show.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts/show.ts @@ -32,7 +32,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const post = await GalleryPosts.findOne({ + const post = await GalleryPosts.findOneBy({ id: ps.postId, }); diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/unlike.ts b/packages/backend/src/server/api/endpoints/gallery/posts/unlike.ts index b00008a864..d136239e5e 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts/unlike.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts/unlike.ts @@ -34,12 +34,12 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const post = await GalleryPosts.findOne(ps.postId); + const post = await GalleryPosts.findOneBy({ id: ps.postId }); if (post == null) { throw new ApiError(meta.errors.noSuchPost); } - const exist = await GalleryLikes.findOne({ + const exist = await GalleryLikes.findOneBy({ postId: post.id, userId: user.id, }); diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/update.ts b/packages/backend/src/server/api/endpoints/gallery/posts/update.ts index 123794d08c..82fe38078e 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts/update.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts/update.ts @@ -45,7 +45,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const files = (await Promise.all(ps.fileIds.map(fileId => - DriveFiles.findOne({ + DriveFiles.findOneBy({ id: fileId, userId: user.id, }) @@ -66,7 +66,7 @@ export default define(meta, paramDef, async (ps, user) => { fileIds: files.map(file => file.id), }); - const post = await GalleryPosts.findOneOrFail(ps.postId); + const post = await GalleryPosts.findOneByOrFail({ id: ps.postId }); return await GalleryPosts.pack(post, user); }); diff --git a/packages/backend/src/server/api/endpoints/get-online-users-count.ts b/packages/backend/src/server/api/endpoints/get-online-users-count.ts index 80a2334cfa..b0c1225bee 100644 --- a/packages/backend/src/server/api/endpoints/get-online-users-count.ts +++ b/packages/backend/src/server/api/endpoints/get-online-users-count.ts @@ -17,7 +17,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async () => { - const count = await Users.count({ + const count = await Users.countBy({ lastActiveDate: MoreThan(new Date(Date.now() - USER_ONLINE_THRESHOLD)), }); diff --git a/packages/backend/src/server/api/endpoints/hashtags/show.ts b/packages/backend/src/server/api/endpoints/hashtags/show.ts index 6e6afa4f13..5b78f6ac7f 100644 --- a/packages/backend/src/server/api/endpoints/hashtags/show.ts +++ b/packages/backend/src/server/api/endpoints/hashtags/show.ts @@ -33,7 +33,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const hashtag = await Hashtags.findOne({ name: normalizeForSearch(ps.tag) }); + const hashtag = await Hashtags.findOneBy({ name: normalizeForSearch(ps.tag) }); if (hashtag == null) { throw new ApiError(meta.errors.noSuchHashtag); } diff --git a/packages/backend/src/server/api/endpoints/i/2fa/done.ts b/packages/backend/src/server/api/endpoints/i/2fa/done.ts index 70478430db..35806b2bc3 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/done.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/done.ts @@ -20,7 +20,7 @@ export const paramDef = { export default define(meta, paramDef, async (ps, user) => { const token = ps.token.replace(/\s/g, ''); - const profile = await UserProfiles.findOneOrFail(user.id); + const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); if (profile.twoFactorTempSecret == null) { throw new Error('二段階認証の設定が開始されていません'); diff --git a/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts b/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts index f33237c8bf..0116a55fb7 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts @@ -35,7 +35,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const profile = await UserProfiles.findOneOrFail(user.id); + const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); // Compare password const same = await bcrypt.compare(ps.password, profile.password!); @@ -96,7 +96,7 @@ export default define(meta, paramDef, async (ps, user) => { }); if (!verificationData.valid) throw new Error('signature invalid'); - const attestationChallenge = await AttestationChallenges.findOne({ + const attestationChallenge = await AttestationChallenges.findOneBy({ userId: user.id, id: ps.challengeId, registrationChallenge: true, diff --git a/packages/backend/src/server/api/endpoints/i/2fa/register-key.ts b/packages/backend/src/server/api/endpoints/i/2fa/register-key.ts index 0c4c99271e..e906b82043 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/register-key.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/register-key.ts @@ -24,7 +24,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const profile = await UserProfiles.findOneOrFail(user.id); + const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); // Compare password const same = await bcrypt.compare(ps.password, profile.password!); diff --git a/packages/backend/src/server/api/endpoints/i/2fa/register.ts b/packages/backend/src/server/api/endpoints/i/2fa/register.ts index 7951e393b8..d5e1b19e54 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/register.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/register.ts @@ -21,7 +21,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const profile = await UserProfiles.findOneOrFail(user.id); + const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); // Compare password const same = await bcrypt.compare(ps.password, profile.password!); diff --git a/packages/backend/src/server/api/endpoints/i/2fa/remove-key.ts b/packages/backend/src/server/api/endpoints/i/2fa/remove-key.ts index 2b69b1f8c3..eb2f75308d 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/remove-key.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/remove-key.ts @@ -20,7 +20,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const profile = await UserProfiles.findOneOrFail(user.id); + const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); // Compare password const same = await bcrypt.compare(ps.password, profile.password!); diff --git a/packages/backend/src/server/api/endpoints/i/2fa/unregister.ts b/packages/backend/src/server/api/endpoints/i/2fa/unregister.ts index c5633f68b1..45e7a98639 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/unregister.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/unregister.ts @@ -18,7 +18,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const profile = await UserProfiles.findOneOrFail(user.id); + const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); // Compare password const same = await bcrypt.compare(ps.password, profile.password!); diff --git a/packages/backend/src/server/api/endpoints/i/change-password.ts b/packages/backend/src/server/api/endpoints/i/change-password.ts index 16509d2dcf..f9f6a33a80 100644 --- a/packages/backend/src/server/api/endpoints/i/change-password.ts +++ b/packages/backend/src/server/api/endpoints/i/change-password.ts @@ -19,7 +19,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const profile = await UserProfiles.findOneOrFail(user.id); + const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); // Compare password const same = await bcrypt.compare(ps.currentPassword, profile.password!); diff --git a/packages/backend/src/server/api/endpoints/i/delete-account.ts b/packages/backend/src/server/api/endpoints/i/delete-account.ts index 8cb6b6a631..184005eb53 100644 --- a/packages/backend/src/server/api/endpoints/i/delete-account.ts +++ b/packages/backend/src/server/api/endpoints/i/delete-account.ts @@ -21,8 +21,8 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const profile = await UserProfiles.findOneOrFail(user.id); - const userDetailed = await Users.findOneOrFail(user.id); + const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); + const userDetailed = await Users.findOneByOrFail({ id: user.id }); if (userDetailed.isDeleted) { return; } diff --git a/packages/backend/src/server/api/endpoints/i/get-word-muted-notes-count.ts b/packages/backend/src/server/api/endpoints/i/get-word-muted-notes-count.ts index bc3e0aff47..e7d7518c5b 100644 --- a/packages/backend/src/server/api/endpoints/i/get-word-muted-notes-count.ts +++ b/packages/backend/src/server/api/endpoints/i/get-word-muted-notes-count.ts @@ -29,7 +29,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { return { - count: await MutedNotes.count({ + count: await MutedNotes.countBy({ userId: user.id, reason: 'word', }), diff --git a/packages/backend/src/server/api/endpoints/i/import-blocking.ts b/packages/backend/src/server/api/endpoints/i/import-blocking.ts index c70704f9a8..0bcbf37ddd 100644 --- a/packages/backend/src/server/api/endpoints/i/import-blocking.ts +++ b/packages/backend/src/server/api/endpoints/i/import-blocking.ts @@ -50,7 +50,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const file = await DriveFiles.findOne(ps.fileId); + const file = await DriveFiles.findOneBy({ id: ps.fileId }); if (file == null) throw new ApiError(meta.errors.noSuchFile); //if (!file.type.endsWith('/csv')) throw new ApiError(meta.errors.unexpectedFileType); diff --git a/packages/backend/src/server/api/endpoints/i/import-following.ts b/packages/backend/src/server/api/endpoints/i/import-following.ts index 7e9175cbf8..ee2abbea19 100644 --- a/packages/backend/src/server/api/endpoints/i/import-following.ts +++ b/packages/backend/src/server/api/endpoints/i/import-following.ts @@ -49,7 +49,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const file = await DriveFiles.findOne(ps.fileId); + const file = await DriveFiles.findOneBy({ id: ps.fileId }); if (file == null) throw new ApiError(meta.errors.noSuchFile); //if (!file.type.endsWith('/csv')) throw new ApiError(meta.errors.unexpectedFileType); diff --git a/packages/backend/src/server/api/endpoints/i/import-muting.ts b/packages/backend/src/server/api/endpoints/i/import-muting.ts index abbf07212e..b3b3b39238 100644 --- a/packages/backend/src/server/api/endpoints/i/import-muting.ts +++ b/packages/backend/src/server/api/endpoints/i/import-muting.ts @@ -50,7 +50,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const file = await DriveFiles.findOne(ps.fileId); + const file = await DriveFiles.findOneBy({ id: ps.fileId }); if (file == null) throw new ApiError(meta.errors.noSuchFile); //if (!file.type.endsWith('/csv')) throw new ApiError(meta.errors.unexpectedFileType); diff --git a/packages/backend/src/server/api/endpoints/i/import-user-lists.ts b/packages/backend/src/server/api/endpoints/i/import-user-lists.ts index be162817f1..64f5ec05fd 100644 --- a/packages/backend/src/server/api/endpoints/i/import-user-lists.ts +++ b/packages/backend/src/server/api/endpoints/i/import-user-lists.ts @@ -49,7 +49,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const file = await DriveFiles.findOne(ps.fileId); + const file = await DriveFiles.findOneBy({ id: ps.fileId }); if (file == null) throw new ApiError(meta.errors.noSuchFile); //if (!file.type.endsWith('/csv')) throw new ApiError(meta.errors.unexpectedFileType); diff --git a/packages/backend/src/server/api/endpoints/i/notifications.ts b/packages/backend/src/server/api/endpoints/i/notifications.ts index 7d9bd44d1d..6ea8cb3574 100644 --- a/packages/backend/src/server/api/endpoints/i/notifications.ts +++ b/packages/backend/src/server/api/endpoints/i/notifications.ts @@ -70,6 +70,8 @@ export default define(meta, paramDef, async (ps, user) => { .andWhere(`notification.notifieeId = :meId`, { meId: user.id }) .leftJoinAndSelect('notification.notifier', 'notifier') .leftJoinAndSelect('notification.note', 'note') + .leftJoinAndSelect('notifier.avatar', 'notifierAvatar') + .leftJoinAndSelect('notifier.banner', 'notifierBanner') .leftJoinAndSelect('note.user', 'user') .leftJoinAndSelect('user.avatar', 'avatar') .leftJoinAndSelect('user.banner', 'banner') diff --git a/packages/backend/src/server/api/endpoints/i/read-all-messaging-messages.ts b/packages/backend/src/server/api/endpoints/i/read-all-messaging-messages.ts index 2e291a34a0..7ff6409caf 100644 --- a/packages/backend/src/server/api/endpoints/i/read-all-messaging-messages.ts +++ b/packages/backend/src/server/api/endpoints/i/read-all-messaging-messages.ts @@ -26,7 +26,7 @@ export default define(meta, paramDef, async (ps, user) => { isRead: true, }); - const joinings = await UserGroupJoinings.find({ userId: user.id }); + const joinings = await UserGroupJoinings.findBy({ userId: user.id }); await Promise.all(joinings.map(j => MessagingMessages.createQueryBuilder().update() .set({ diff --git a/packages/backend/src/server/api/endpoints/i/read-announcement.ts b/packages/backend/src/server/api/endpoints/i/read-announcement.ts index 647fa77fa4..45b6e98c86 100644 --- a/packages/backend/src/server/api/endpoints/i/read-announcement.ts +++ b/packages/backend/src/server/api/endpoints/i/read-announcement.ts @@ -31,14 +31,14 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // Check if announcement exists - const announcement = await Announcements.findOne(ps.announcementId); + const announcement = await Announcements.findOneBy({ id: ps.announcementId }); if (announcement == null) { throw new ApiError(meta.errors.noSuchAnnouncement); } // Check if already read - const read = await AnnouncementReads.findOne({ + const read = await AnnouncementReads.findOneBy({ announcementId: ps.announcementId, userId: user.id, }); diff --git a/packages/backend/src/server/api/endpoints/i/regenerate-token.ts b/packages/backend/src/server/api/endpoints/i/regenerate-token.ts index 771c98b212..af929b04e8 100644 --- a/packages/backend/src/server/api/endpoints/i/regenerate-token.ts +++ b/packages/backend/src/server/api/endpoints/i/regenerate-token.ts @@ -1,5 +1,5 @@ import bcrypt from 'bcryptjs'; -import { publishMainStream, publishUserEvent } from '@/services/stream.js'; +import { publishInternalEvent, publishMainStream, publishUserEvent } from '@/services/stream.js'; import generateUserToken from '../../common/generate-native-user-token.js'; import define from '../../define.js'; import { Users, UserProfiles } from '@/models/index.js'; @@ -20,7 +20,10 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const profile = await UserProfiles.findOneOrFail(user.id); + const freshUser = await Users.findOneByOrFail({ id: user.id }); + const oldToken = freshUser.token; + + const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); // Compare password const same = await bcrypt.compare(ps.password, profile.password!); @@ -29,14 +32,14 @@ export default define(meta, paramDef, async (ps, user) => { throw new Error('incorrect password'); } - // Generate secret - const secret = generateUserToken(); + const newToken = generateUserToken(); await Users.update(user.id, { - token: secret, + token: newToken, }); // Publish event + publishInternalEvent('userTokenRegenerated', { id: user.id, oldToken, newToken }); publishMainStream(user.id, 'myTokenRegenerated'); // Terminate streaming diff --git a/packages/backend/src/server/api/endpoints/i/revoke-token.ts b/packages/backend/src/server/api/endpoints/i/revoke-token.ts index b957fd0796..c692453794 100644 --- a/packages/backend/src/server/api/endpoints/i/revoke-token.ts +++ b/packages/backend/src/server/api/endpoints/i/revoke-token.ts @@ -18,7 +18,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const token = await AccessTokens.findOne(ps.tokenId); + const token = await AccessTokens.findOneBy({ id: ps.tokenId }); if (token) { await AccessTokens.delete({ diff --git a/packages/backend/src/server/api/endpoints/i/update-email.ts b/packages/backend/src/server/api/endpoints/i/update-email.ts index 389ff1b81d..3318078523 100644 --- a/packages/backend/src/server/api/endpoints/i/update-email.ts +++ b/packages/backend/src/server/api/endpoints/i/update-email.ts @@ -45,7 +45,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const profile = await UserProfiles.findOneOrFail(user.id); + const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); // Compare password const same = await bcrypt.compare(ps.password, profile.password!); diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts index 85d0a62548..b2964e68c7 100644 --- a/packages/backend/src/server/api/endpoints/i/update.ts +++ b/packages/backend/src/server/api/endpoints/i/update.ts @@ -121,13 +121,13 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, _user, token) => { - const user = await Users.findOneOrFail(_user.id); + const user = await Users.findOneByOrFail({ id: _user.id }); const isSecure = token == null; const updates = {} as Partial; const profileUpdates = {} as Partial; - const profile = await UserProfiles.findOneOrFail(user.id); + const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); if (ps.name !== undefined) updates.name = ps.name; if (ps.description !== undefined) profileUpdates.description = ps.description; @@ -171,21 +171,21 @@ export default define(meta, paramDef, async (ps, _user, token) => { if (ps.emailNotificationTypes !== undefined) profileUpdates.emailNotificationTypes = ps.emailNotificationTypes; if (ps.avatarId) { - const avatar = await DriveFiles.findOne(ps.avatarId); + const avatar = await DriveFiles.findOneBy({ id: ps.avatarId }); if (avatar == null || avatar.userId !== user.id) throw new ApiError(meta.errors.noSuchAvatar); if (!avatar.type.startsWith('image/')) throw new ApiError(meta.errors.avatarNotAnImage); } if (ps.bannerId) { - const banner = await DriveFiles.findOne(ps.bannerId); + const banner = await DriveFiles.findOneBy({ id: ps.bannerId }); if (banner == null || banner.userId !== user.id) throw new ApiError(meta.errors.noSuchBanner); if (!banner.type.startsWith('image/')) throw new ApiError(meta.errors.bannerNotAnImage); } if (ps.pinnedPageId) { - const page = await Pages.findOne(ps.pinnedPageId); + const page = await Pages.findOneBy({ id: ps.pinnedPageId }); if (page == null || page.userId !== user.id) throw new ApiError(meta.errors.noSuchPage); @@ -238,7 +238,7 @@ export default define(meta, paramDef, async (ps, _user, token) => { // Publish meUpdated event publishMainStream(user.id, 'meUpdated', iObj); - publishUserEvent(user.id, 'updateUserProfile', await UserProfiles.findOne(user.id)); + publishUserEvent(user.id, 'updateUserProfile', await UserProfiles.findOneBy({ userId: user.id })); // 鍵垢を解除したとき、溜まっていたフォローリクエストがあるならすべて承認 if (user.isLocked && ps.isLocked === false) { diff --git a/packages/backend/src/server/api/endpoints/messaging/history.ts b/packages/backend/src/server/api/endpoints/messaging/history.ts index 14de4e1028..ea0600d0e4 100644 --- a/packages/backend/src/server/api/endpoints/messaging/history.ts +++ b/packages/backend/src/server/api/endpoints/messaging/history.ts @@ -32,11 +32,11 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const mute = await Mutings.find({ + const mute = await Mutings.findBy({ muterId: user.id, }); - const groups = ps.group ? await UserGroupJoinings.find({ + const groups = ps.group ? await UserGroupJoinings.findBy({ userId: user.id, }).then(xs => xs.map(x => x.userGroupId)) : []; diff --git a/packages/backend/src/server/api/endpoints/messaging/messages.ts b/packages/backend/src/server/api/endpoints/messaging/messages.ts index 49ace21600..9760709c29 100644 --- a/packages/backend/src/server/api/endpoints/messaging/messages.ts +++ b/packages/backend/src/server/api/endpoints/messaging/messages.ts @@ -97,14 +97,14 @@ export default define(meta, paramDef, async (ps, user) => { }))); } else if (ps.groupId != null) { // Fetch recipient (group) - const recipientGroup = await UserGroups.findOne(ps.groupId); + const recipientGroup = await UserGroups.findOneBy({ id: ps.groupId }); if (recipientGroup == null) { throw new ApiError(meta.errors.noSuchGroup); } // check joined - const joining = await UserGroupJoinings.findOne({ + const joining = await UserGroupJoinings.findOneBy({ userId: user.id, userGroupId: recipientGroup.id, }); diff --git a/packages/backend/src/server/api/endpoints/messaging/messages/create.ts b/packages/backend/src/server/api/endpoints/messaging/messages/create.ts index a9b926c4fb..8c1226b0f4 100644 --- a/packages/backend/src/server/api/endpoints/messaging/messages/create.ts +++ b/packages/backend/src/server/api/endpoints/messaging/messages/create.ts @@ -77,8 +77,8 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - let recipientUser: User | undefined; - let recipientGroup: UserGroup | undefined; + let recipientUser: User | null; + let recipientGroup: UserGroup | null; if (ps.userId != null) { // Myself @@ -93,7 +93,7 @@ export default define(meta, paramDef, async (ps, user) => { }); // Check blocking - const block = await Blockings.findOne({ + const block = await Blockings.findOneBy({ blockerId: recipientUser.id, blockeeId: user.id, }); @@ -102,14 +102,14 @@ export default define(meta, paramDef, async (ps, user) => { } } else if (ps.groupId != null) { // Fetch recipient (group) - recipientGroup = await UserGroups.findOne(ps.groupId); + recipientGroup = await UserGroups.findOneBy({ id: ps.groupId! }); if (recipientGroup == null) { throw new ApiError(meta.errors.noSuchGroup); } // check joined - const joining = await UserGroupJoinings.findOne({ + const joining = await UserGroupJoinings.findOneBy({ userId: user.id, userGroupId: recipientGroup.id, }); @@ -121,7 +121,7 @@ export default define(meta, paramDef, async (ps, user) => { let file = null; if (ps.fileId != null) { - file = await DriveFiles.findOne({ + file = await DriveFiles.findOneBy({ id: ps.fileId, userId: user.id, }); diff --git a/packages/backend/src/server/api/endpoints/messaging/messages/delete.ts b/packages/backend/src/server/api/endpoints/messaging/messages/delete.ts index a0945af510..f66d75873c 100644 --- a/packages/backend/src/server/api/endpoints/messaging/messages/delete.ts +++ b/packages/backend/src/server/api/endpoints/messaging/messages/delete.ts @@ -36,7 +36,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const message = await MessagingMessages.findOne({ + const message = await MessagingMessages.findOneBy({ id: ps.messageId, userId: user.id, }); diff --git a/packages/backend/src/server/api/endpoints/messaging/messages/read.ts b/packages/backend/src/server/api/endpoints/messaging/messages/read.ts index 8d38e509ac..db12ae922c 100644 --- a/packages/backend/src/server/api/endpoints/messaging/messages/read.ts +++ b/packages/backend/src/server/api/endpoints/messaging/messages/read.ts @@ -29,7 +29,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const message = await MessagingMessages.findOne(ps.messageId); + const message = await MessagingMessages.findOneBy({ id: ps.messageId }); if (message == null) { throw new ApiError(meta.errors.noSuchMessage); diff --git a/packages/backend/src/server/api/endpoints/meta.ts b/packages/backend/src/server/api/endpoints/meta.ts index 1aff1f63fb..057d22f33b 100644 --- a/packages/backend/src/server/api/endpoints/meta.ts +++ b/packages/backend/src/server/api/endpoints/meta.ts @@ -3,7 +3,7 @@ import define from '../define.js'; import { fetchMeta } from '@/misc/fetch-meta.js'; import { Ads, Emojis, Users } from '@/models/index.js'; import { DB_MAX_NOTE_TEXT_LENGTH } from '@/misc/hard-limits.js'; -import { MoreThan } from 'typeorm'; +import { IsNull, MoreThan } from 'typeorm'; import { MAX_NOTE_TEXT_LENGTH } from '@/const.js'; export const meta = { @@ -290,151 +290,6 @@ export const meta = { }, }, }, - userStarForReactionFallback: { - type: 'boolean', - optional: true, nullable: false, - }, - pinnedUsers: { - type: 'array', - optional: true, nullable: false, - items: { - type: 'string', - optional: false, nullable: false, - }, - }, - hiddenTags: { - type: 'array', - optional: true, nullable: false, - items: { - type: 'string', - optional: false, nullable: false, - }, - }, - blockedHosts: { - type: 'array', - optional: true, nullable: false, - items: { - type: 'string', - optional: false, nullable: false, - }, - }, - hcaptchaSecretKey: { - type: 'string', - optional: true, nullable: true, - }, - recaptchaSecretKey: { - type: 'string', - optional: true, nullable: true, - }, - proxyAccountId: { - type: 'string', - optional: true, nullable: true, - format: 'id', - }, - twitterConsumerKey: { - type: 'string', - optional: true, nullable: true, - }, - twitterConsumerSecret: { - type: 'string', - optional: true, nullable: true, - }, - githubClientId: { - type: 'string', - optional: true, nullable: true, - }, - githubClientSecret: { - type: 'string', - optional: true, nullable: true, - }, - discordClientId: { - type: 'string', - optional: true, nullable: true, - }, - discordClientSecret: { - type: 'string', - optional: true, nullable: true, - }, - summaryProxy: { - type: 'string', - optional: true, nullable: true, - }, - email: { - type: 'string', - optional: true, nullable: true, - }, - smtpSecure: { - type: 'boolean', - optional: true, nullable: false, - }, - smtpHost: { - type: 'string', - optional: true, nullable: true, - }, - smtpPort: { - type: 'string', - optional: true, nullable: true, - }, - smtpUser: { - type: 'string', - optional: true, nullable: true, - }, - smtpPass: { - type: 'string', - optional: true, nullable: true, - }, - swPrivateKey: { - type: 'string', - optional: true, nullable: true, - }, - useObjectStorage: { - type: 'boolean', - optional: true, nullable: false, - }, - objectStorageBaseUrl: { - type: 'string', - optional: true, nullable: true, - }, - objectStorageBucket: { - type: 'string', - optional: true, nullable: true, - }, - objectStoragePrefix: { - type: 'string', - optional: true, nullable: true, - }, - objectStorageEndpoint: { - type: 'string', - optional: true, nullable: true, - }, - objectStorageRegion: { - type: 'string', - optional: true, nullable: true, - }, - objectStoragePort: { - type: 'number', - optional: true, nullable: true, - }, - objectStorageAccessKey: { - type: 'string', - optional: true, nullable: true, - }, - objectStorageSecretKey: { - type: 'string', - optional: true, nullable: true, - }, - objectStorageUseSSL: { - type: 'boolean', - optional: true, nullable: false, - }, - objectStorageUseProxy: { - type: 'boolean', - optional: true, nullable: false, - }, - objectStorageSetPublicRead: { - type: 'boolean', - optional: true, nullable: false, - }, }, }, } as const; @@ -453,7 +308,7 @@ export default define(meta, paramDef, async (ps, me) => { const emojis = await Emojis.find({ where: { - host: null, + host: IsNull(), }, order: { category: 'ASC', @@ -527,8 +382,8 @@ export default define(meta, paramDef, async (ps, me) => { pinnedPages: instance.pinnedPages, pinnedClipId: instance.pinnedClipId, cacheRemoteFiles: instance.cacheRemoteFiles, - requireSetup: (await Users.count({ - host: null, + requireSetup: (await Users.countBy({ + host: IsNull(), })) === 0, } : {}), }; @@ -552,45 +407,6 @@ export default define(meta, paramDef, async (ps, me) => { serviceWorker: instance.enableServiceWorker, miauth: true, }; - - if (me && me.isAdmin) { - response.useStarForReactionFallback = instance.useStarForReactionFallback; - response.pinnedUsers = instance.pinnedUsers; - response.hiddenTags = instance.hiddenTags; - response.blockedHosts = instance.blockedHosts; - response.hcaptchaSecretKey = instance.hcaptchaSecretKey; - response.recaptchaSecretKey = instance.recaptchaSecretKey; - response.proxyAccountId = instance.proxyAccountId; - response.twitterConsumerKey = instance.twitterConsumerKey; - response.twitterConsumerSecret = instance.twitterConsumerSecret; - response.githubClientId = instance.githubClientId; - response.githubClientSecret = instance.githubClientSecret; - response.discordClientId = instance.discordClientId; - response.discordClientSecret = instance.discordClientSecret; - response.summalyProxy = instance.summalyProxy; - response.email = instance.email; - response.smtpSecure = instance.smtpSecure; - response.smtpHost = instance.smtpHost; - response.smtpPort = instance.smtpPort; - response.smtpUser = instance.smtpUser; - response.smtpPass = instance.smtpPass; - response.swPrivateKey = instance.swPrivateKey; - response.useObjectStorage = instance.useObjectStorage; - response.objectStorageBaseUrl = instance.objectStorageBaseUrl; - response.objectStorageBucket = instance.objectStorageBucket; - response.objectStoragePrefix = instance.objectStoragePrefix; - response.objectStorageEndpoint = instance.objectStorageEndpoint; - response.objectStorageRegion = instance.objectStorageRegion; - response.objectStoragePort = instance.objectStoragePort; - response.objectStorageAccessKey = instance.objectStorageAccessKey; - response.objectStorageSecretKey = instance.objectStorageSecretKey; - response.objectStorageUseSSL = instance.objectStorageUseSSL; - response.objectStorageUseProxy = instance.objectStorageUseProxy; - response.objectStorageSetPublicRead = instance.objectStorageSetPublicRead; - response.objectStorageS3ForcePathStyle = instance.objectStorageS3ForcePathStyle; - response.deeplAuthKey = instance.deeplAuthKey; - response.deeplIsPro = instance.deeplIsPro; - } } return response; diff --git a/packages/backend/src/server/api/endpoints/mute/create.ts b/packages/backend/src/server/api/endpoints/mute/create.ts index dacee40d01..0c3a3453f1 100644 --- a/packages/backend/src/server/api/endpoints/mute/create.ts +++ b/packages/backend/src/server/api/endpoints/mute/create.ts @@ -59,7 +59,7 @@ export default define(meta, paramDef, async (ps, user) => { }); // Check if already muting - const exist = await Mutings.findOne({ + const exist = await Mutings.findOneBy({ muterId: muter.id, muteeId: mutee.id, }); diff --git a/packages/backend/src/server/api/endpoints/mute/delete.ts b/packages/backend/src/server/api/endpoints/mute/delete.ts index a8cf2a6667..0b173dbe24 100644 --- a/packages/backend/src/server/api/endpoints/mute/delete.ts +++ b/packages/backend/src/server/api/endpoints/mute/delete.ts @@ -56,7 +56,7 @@ export default define(meta, paramDef, async (ps, user) => { }); // Check not muting - const exist = await Mutings.findOne({ + const exist = await Mutings.findOneBy({ muterId: muter.id, muteeId: mutee.id, }); diff --git a/packages/backend/src/server/api/endpoints/notes/clips.ts b/packages/backend/src/server/api/endpoints/notes/clips.ts index 9a863b7148..8683a7f75a 100644 --- a/packages/backend/src/server/api/endpoints/notes/clips.ts +++ b/packages/backend/src/server/api/endpoints/notes/clips.ts @@ -43,11 +43,11 @@ export default define(meta, paramDef, async (ps, me) => { throw e; }); - const clipNotes = await ClipNotes.find({ + const clipNotes = await ClipNotes.findBy({ noteId: note.id, }); - const clips = await Clips.find({ + const clips = await Clips.findBy({ id: In(clipNotes.map(x => x.clipId)), isPublic: true, }); diff --git a/packages/backend/src/server/api/endpoints/notes/conversation.ts b/packages/backend/src/server/api/endpoints/notes/conversation.ts index 2552c0f99d..8f5d21db60 100644 --- a/packages/backend/src/server/api/endpoints/notes/conversation.ts +++ b/packages/backend/src/server/api/endpoints/notes/conversation.ts @@ -50,7 +50,7 @@ export default define(meta, paramDef, async (ps, user) => { async function get(id: any) { i++; - const p = await Notes.findOne(id); + const p = await Notes.findOneBy({ id }); if (p == null) return; if (i > ps.offset!) { diff --git a/packages/backend/src/server/api/endpoints/notes/create.ts b/packages/backend/src/server/api/endpoints/notes/create.ts index e4a9b28891..961983f5f4 100644 --- a/packages/backend/src/server/api/endpoints/notes/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/create.ts @@ -130,7 +130,7 @@ export const paramDef = { export default define(meta, paramDef, async (ps, user) => { let visibleUsers: User[] = []; if (ps.visibleUserIds) { - visibleUsers = (await Promise.all(ps.visibleUserIds.map(id => Users.findOne(id)))) + visibleUsers = (await Promise.all(ps.visibleUserIds.map(id => Users.findOneBy({ id })))) .filter(x => x != null) as User[]; } @@ -138,17 +138,17 @@ export default define(meta, paramDef, async (ps, user) => { const fileIds = ps.fileIds != null ? ps.fileIds : ps.mediaIds != null ? ps.mediaIds : null; if (fileIds != null) { files = (await Promise.all(fileIds.map(fileId => - DriveFiles.findOne({ + DriveFiles.findOneBy({ id: fileId, userId: user.id, }) ))).filter(file => file != null) as DriveFile[]; } - let renote: Note | undefined; + let renote: Note | null; if (ps.renoteId != null) { // Fetch renote to note - renote = await Notes.findOne(ps.renoteId); + renote = await Notes.findOneBy({ id: ps.renoteId }); if (renote == null) { throw new ApiError(meta.errors.noSuchRenoteTarget); @@ -158,7 +158,7 @@ export default define(meta, paramDef, async (ps, user) => { // Check blocking if (renote.userId !== user.id) { - const block = await Blockings.findOne({ + const block = await Blockings.findOneBy({ blockerId: renote.userId, blockeeId: user.id, }); @@ -168,10 +168,10 @@ export default define(meta, paramDef, async (ps, user) => { } } - let reply: Note | undefined; + let reply: Note | null; if (ps.replyId != null) { // Fetch reply - reply = await Notes.findOne(ps.replyId); + reply = await Notes.findOneBy({ id: ps.replyId }); if (reply == null) { throw new ApiError(meta.errors.noSuchReplyTarget); @@ -184,7 +184,7 @@ export default define(meta, paramDef, async (ps, user) => { // Check blocking if (reply.userId !== user.id) { - const block = await Blockings.findOne({ + const block = await Blockings.findOneBy({ blockerId: reply.userId, blockeeId: user.id, }); @@ -211,7 +211,7 @@ export default define(meta, paramDef, async (ps, user) => { let channel: Channel | undefined; if (ps.channelId != null) { - channel = await Channels.findOne(ps.channelId); + channel = await Channels.findOneBy({ id: ps.channelId }); if (channel == null) { throw new ApiError(meta.errors.noSuchChannel); diff --git a/packages/backend/src/server/api/endpoints/notes/delete.ts b/packages/backend/src/server/api/endpoints/notes/delete.ts index 22ff2275ca..804e146fa4 100644 --- a/packages/backend/src/server/api/endpoints/notes/delete.ts +++ b/packages/backend/src/server/api/endpoints/notes/delete.ts @@ -48,10 +48,10 @@ export default define(meta, paramDef, async (ps, user) => { throw e; }); - if (!user.isAdmin && !user.isModerator && (note.userId !== user.id)) { + if ((!user.isAdmin && !user.isModerator) && (note.userId !== user.id)) { throw new ApiError(meta.errors.accessDenied); } // この操作を行うのが投稿者とは限らない(例えばモデレーター)ため - await deleteNote(await Users.findOneOrFail(note.userId), note); + await deleteNote(await Users.findOneByOrFail({ id: note.userId }), note); }); diff --git a/packages/backend/src/server/api/endpoints/notes/favorites/create.ts b/packages/backend/src/server/api/endpoints/notes/favorites/create.ts index bcc2c44c02..41dc5ac8e1 100644 --- a/packages/backend/src/server/api/endpoints/notes/favorites/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/favorites/create.ts @@ -43,7 +43,7 @@ export default define(meta, paramDef, async (ps, user) => { }); // if already favorited - const exist = await NoteFavorites.findOne({ + const exist = await NoteFavorites.findOneBy({ noteId: note.id, userId: user.id, }); diff --git a/packages/backend/src/server/api/endpoints/notes/favorites/delete.ts b/packages/backend/src/server/api/endpoints/notes/favorites/delete.ts index d41fab22d3..a48f7a0aa8 100644 --- a/packages/backend/src/server/api/endpoints/notes/favorites/delete.ts +++ b/packages/backend/src/server/api/endpoints/notes/favorites/delete.ts @@ -42,7 +42,7 @@ export default define(meta, paramDef, async (ps, user) => { }); // if already favorited - const exist = await NoteFavorites.findOne({ + const exist = await NoteFavorites.findOneBy({ noteId: note.id, userId: user.id, }); diff --git a/packages/backend/src/server/api/endpoints/notes/global-timeline.ts b/packages/backend/src/server/api/endpoints/notes/global-timeline.ts index 26aaa0919c..09a8194665 100644 --- a/packages/backend/src/server/api/endpoints/notes/global-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/global-timeline.ts @@ -2,7 +2,7 @@ import define from '../../define.js'; import { fetchMeta } from '@/misc/fetch-meta.js'; import { ApiError } from '../../error.js'; import { makePaginationQuery } from '../../common/make-pagination-query.js'; -import { Notes } from '@/models/index.js'; +import { Notes, Users } from '@/models/index.js'; import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; import { generateMutedInstanceQuery } from '../../common/generate-muted-instance-query.js'; import { activeUsersChart } from '@/services/chart/index.js'; diff --git a/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts b/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts index 9bcb64b656..7c9c122963 100644 --- a/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts @@ -2,7 +2,7 @@ import define from '../../define.js'; import { fetchMeta } from '@/misc/fetch-meta.js'; import { ApiError } from '../../error.js'; import { makePaginationQuery } from '../../common/make-pagination-query.js'; -import { Followings, Notes } from '@/models/index.js'; +import { Followings, Notes, Users } from '@/models/index.js'; import { Brackets } from 'typeorm'; import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; @@ -56,7 +56,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { const m = await fetchMeta(); - if (m.disableLocalTimeline && !user.isAdmin && !user.isModerator) { + if (m.disableLocalTimeline && (!user.isAdmin && !user.isModerator)) { throw new ApiError(meta.errors.stlDisabled); } diff --git a/packages/backend/src/server/api/endpoints/notes/local-timeline.ts b/packages/backend/src/server/api/endpoints/notes/local-timeline.ts index 12fc88b1fd..bb0bbe2a20 100644 --- a/packages/backend/src/server/api/endpoints/notes/local-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/local-timeline.ts @@ -1,7 +1,7 @@ import define from '../../define.js'; import { fetchMeta } from '@/misc/fetch-meta.js'; import { ApiError } from '../../error.js'; -import { Notes } from '@/models/index.js'; +import { Notes, Users } from '@/models/index.js'; import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; import { makePaginationQuery } from '../../common/make-pagination-query.js'; import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; diff --git a/packages/backend/src/server/api/endpoints/notes/polls/recommendation.ts b/packages/backend/src/server/api/endpoints/notes/polls/recommendation.ts index bdd1aeecd4..28bfade2f0 100644 --- a/packages/backend/src/server/api/endpoints/notes/polls/recommendation.ts +++ b/packages/backend/src/server/api/endpoints/notes/polls/recommendation.ts @@ -64,7 +64,7 @@ export default define(meta, paramDef, async (ps, user) => { if (polls.length === 0) return []; - const notes = await Notes.find({ + const notes = await Notes.findBy({ id: In(polls.map(poll => poll.noteId)), }); diff --git a/packages/backend/src/server/api/endpoints/notes/polls/vote.ts b/packages/backend/src/server/api/endpoints/notes/polls/vote.ts index ef52d03664..6380b331f2 100644 --- a/packages/backend/src/server/api/endpoints/notes/polls/vote.ts +++ b/packages/backend/src/server/api/endpoints/notes/polls/vote.ts @@ -83,7 +83,7 @@ export default define(meta, paramDef, async (ps, user) => { // Check blocking if (note.userId !== user.id) { - const block = await Blockings.findOne({ + const block = await Blockings.findOneBy({ blockerId: note.userId, blockeeId: user.id, }); @@ -92,7 +92,7 @@ export default define(meta, paramDef, async (ps, user) => { } } - const poll = await Polls.findOneOrFail({ noteId: note.id }); + const poll = await Polls.findOneByOrFail({ noteId: note.id }); if (poll.expiresAt && poll.expiresAt < createdAt) { throw new ApiError(meta.errors.alreadyExpired); @@ -103,7 +103,7 @@ export default define(meta, paramDef, async (ps, user) => { } // if already voted - const exist = await PollVotes.find({ + const exist = await PollVotes.findBy({ noteId: note.id, userId: user.id, }); @@ -125,7 +125,7 @@ export default define(meta, paramDef, async (ps, user) => { noteId: note.id, userId: user.id, choice: ps.choice, - }).then(x => PollVotes.findOneOrFail(x.identifiers[0])); + }).then(x => PollVotes.findOneByOrFail(x.identifiers[0])); // Increment votes count const index = ps.choice + 1; // In SQL, array index is 1 based @@ -144,7 +144,7 @@ export default define(meta, paramDef, async (ps, user) => { }); // Fetch watchers - NoteWatchings.find({ + NoteWatchings.findBy({ noteId: note.id, userId: Not(user.id), }).then(watchers => { @@ -159,7 +159,7 @@ export default define(meta, paramDef, async (ps, user) => { // リモート投票の場合リプライ送信 if (note.userHost != null) { - const pollOwner = await Users.findOneOrFail(note.userId) as IRemoteUser; + const pollOwner = await Users.findOneByOrFail({ id: note.userId }) as IRemoteUser; deliver(user, renderActivity(await renderVote(user, vote, note, poll, pollOwner)), pollOwner.inbox); } diff --git a/packages/backend/src/server/api/endpoints/notes/reactions.ts b/packages/backend/src/server/api/endpoints/notes/reactions.ts index 43e5d1ef6f..3555424fa6 100644 --- a/packages/backend/src/server/api/endpoints/notes/reactions.ts +++ b/packages/backend/src/server/api/endpoints/notes/reactions.ts @@ -1,5 +1,4 @@ import define from '../../define.js'; -import { getNote } from '../../common/getters.js'; import { ApiError } from '../../error.js'; import { NoteReactions } from '@/models/index.js'; import { DeepPartial } from 'typeorm'; @@ -44,13 +43,8 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const note = await getNote(ps.noteId).catch(e => { - if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); - throw e; - }); - const query = { - noteId: note.id, + noteId: ps.noteId, } as DeepPartial; if (ps.type) { diff --git a/packages/backend/src/server/api/endpoints/notes/state.ts b/packages/backend/src/server/api/endpoints/notes/state.ts index 6fdb8e88fb..069f11fa4a 100644 --- a/packages/backend/src/server/api/endpoints/notes/state.ts +++ b/packages/backend/src/server/api/endpoints/notes/state.ts @@ -36,7 +36,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const note = await Notes.findOneOrFail(ps.noteId); + const note = await Notes.findOneByOrFail({ id: ps.noteId }); const [favorite, watching, threadMuting] = await Promise.all([ NoteFavorites.count({ diff --git a/packages/backend/src/server/api/endpoints/notes/unrenote.ts b/packages/backend/src/server/api/endpoints/notes/unrenote.ts index a9aadba338..5e8c31eaf8 100644 --- a/packages/backend/src/server/api/endpoints/notes/unrenote.ts +++ b/packages/backend/src/server/api/endpoints/notes/unrenote.ts @@ -42,12 +42,12 @@ export default define(meta, paramDef, async (ps, user) => { throw e; }); - const renotes = await Notes.find({ + const renotes = await Notes.findBy({ userId: user.id, renoteId: note.id, }); for (const note of renotes) { - deleteNote(await Users.findOneOrFail(user.id), note); + deleteNote(await Users.findOneByOrFail({ id: user.id }), note); } }); diff --git a/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts b/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts index 0829d0e4c1..866e306d8d 100644 --- a/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts @@ -49,7 +49,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const list = await UserLists.findOne({ + const list = await UserLists.findOneBy({ id: ps.listId, userId: user.id, }); diff --git a/packages/backend/src/server/api/endpoints/page-push.ts b/packages/backend/src/server/api/endpoints/page-push.ts index acaa118470..7096aaa3d3 100644 --- a/packages/backend/src/server/api/endpoints/page-push.ts +++ b/packages/backend/src/server/api/endpoints/page-push.ts @@ -28,7 +28,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const page = await Pages.findOne(ps.pageId); + const page = await Pages.findOneBy({ id: ps.pageId }); if (page == null) { throw new ApiError(meta.errors.noSuchPage); } diff --git a/packages/backend/src/server/api/endpoints/pages/create.ts b/packages/backend/src/server/api/endpoints/pages/create.ts index 7cac530606..c171cd39f5 100644 --- a/packages/backend/src/server/api/endpoints/pages/create.ts +++ b/packages/backend/src/server/api/endpoints/pages/create.ts @@ -62,7 +62,7 @@ export const paramDef = { export default define(meta, paramDef, async (ps, user) => { let eyeCatchingImage = null; if (ps.eyeCatchingImageId != null) { - eyeCatchingImage = await DriveFiles.findOne({ + eyeCatchingImage = await DriveFiles.findOneBy({ id: ps.eyeCatchingImageId, userId: user.id, }); @@ -72,7 +72,7 @@ export default define(meta, paramDef, async (ps, user) => { } } - await Pages.find({ + await Pages.findBy({ userId: user.id, name: ps.name, }).then(result => { @@ -97,7 +97,7 @@ export default define(meta, paramDef, async (ps, user) => { alignCenter: ps.alignCenter, hideTitleWhenPinned: ps.hideTitleWhenPinned, font: ps.font, - })).then(x => Pages.findOneOrFail(x.identifiers[0])); + })).then(x => Pages.findOneByOrFail(x.identifiers[0])); return await Pages.pack(page); }); diff --git a/packages/backend/src/server/api/endpoints/pages/delete.ts b/packages/backend/src/server/api/endpoints/pages/delete.ts index ddf691f53c..e35ad9ebf2 100644 --- a/packages/backend/src/server/api/endpoints/pages/delete.ts +++ b/packages/backend/src/server/api/endpoints/pages/delete.ts @@ -34,7 +34,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const page = await Pages.findOne(ps.pageId); + const page = await Pages.findOneBy({ id: ps.pageId }); if (page == null) { throw new ApiError(meta.errors.noSuchPage); } diff --git a/packages/backend/src/server/api/endpoints/pages/like.ts b/packages/backend/src/server/api/endpoints/pages/like.ts index cab78e576c..20793db988 100644 --- a/packages/backend/src/server/api/endpoints/pages/like.ts +++ b/packages/backend/src/server/api/endpoints/pages/like.ts @@ -41,7 +41,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const page = await Pages.findOne(ps.pageId); + const page = await Pages.findOneBy({ id: ps.pageId }); if (page == null) { throw new ApiError(meta.errors.noSuchPage); } @@ -51,7 +51,7 @@ export default define(meta, paramDef, async (ps, user) => { } // if already liked - const exist = await PageLikes.findOne({ + const exist = await PageLikes.findOneBy({ pageId: page.id, userId: user.id, }); diff --git a/packages/backend/src/server/api/endpoints/pages/show.ts b/packages/backend/src/server/api/endpoints/pages/show.ts index 4e3facae5b..1c218acfd4 100644 --- a/packages/backend/src/server/api/endpoints/pages/show.ts +++ b/packages/backend/src/server/api/endpoints/pages/show.ts @@ -2,6 +2,7 @@ import define from '../../define.js'; import { ApiError } from '../../error.js'; import { Pages, Users } from '@/models/index.js'; import { Page } from '@/models/entities/page.js'; +import { IsNull } from 'typeorm'; export const meta = { tags: ['pages'], @@ -38,14 +39,14 @@ export default define(meta, paramDef, async (ps, user) => { let page: Page | undefined; if (ps.pageId) { - page = await Pages.findOne(ps.pageId); + page = await Pages.findOneBy({ id: ps.pageId }); } else if (ps.name && ps.username) { - const author = await Users.findOne({ - host: null, + const author = await Users.findOneBy({ + host: IsNull(), usernameLower: ps.username.toLowerCase(), }); if (author) { - page = await Pages.findOne({ + page = await Pages.findOneBy({ name: ps.name, userId: author.id, }); diff --git a/packages/backend/src/server/api/endpoints/pages/unlike.ts b/packages/backend/src/server/api/endpoints/pages/unlike.ts index 31cd1a3359..636f3c7149 100644 --- a/packages/backend/src/server/api/endpoints/pages/unlike.ts +++ b/packages/backend/src/server/api/endpoints/pages/unlike.ts @@ -34,12 +34,12 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const page = await Pages.findOne(ps.pageId); + const page = await Pages.findOneBy({ id: ps.pageId }); if (page == null) { throw new ApiError(meta.errors.noSuchPage); } - const exist = await PageLikes.findOne({ + const exist = await PageLikes.findOneBy({ pageId: page.id, userId: user.id, }); diff --git a/packages/backend/src/server/api/endpoints/pages/update.ts b/packages/backend/src/server/api/endpoints/pages/update.ts index 24c8f467e6..bf95ab36f2 100644 --- a/packages/backend/src/server/api/endpoints/pages/update.ts +++ b/packages/backend/src/server/api/endpoints/pages/update.ts @@ -66,7 +66,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const page = await Pages.findOne(ps.pageId); + const page = await Pages.findOneBy({ id: ps.pageId }); if (page == null) { throw new ApiError(meta.errors.noSuchPage); } @@ -76,7 +76,7 @@ export default define(meta, paramDef, async (ps, user) => { let eyeCatchingImage = null; if (ps.eyeCatchingImageId != null) { - eyeCatchingImage = await DriveFiles.findOne({ + eyeCatchingImage = await DriveFiles.findOneBy({ id: ps.eyeCatchingImageId, userId: user.id, }); @@ -86,7 +86,7 @@ export default define(meta, paramDef, async (ps, user) => { } } - await Pages.find({ + await Pages.findBy({ id: Not(ps.pageId), userId: user.id, name: ps.name, diff --git a/packages/backend/src/server/api/endpoints/pinned-users.ts b/packages/backend/src/server/api/endpoints/pinned-users.ts index 1d26ab266e..8d253c1f33 100644 --- a/packages/backend/src/server/api/endpoints/pinned-users.ts +++ b/packages/backend/src/server/api/endpoints/pinned-users.ts @@ -3,6 +3,7 @@ import { Users } from '@/models/index.js'; import { fetchMeta } from '@/misc/fetch-meta.js'; import * as Acct from '@/misc/acct.js'; import { User } from '@/models/entities/user.js'; +import { IsNull } from 'typeorm'; export const meta = { tags: ['users'], @@ -30,7 +31,10 @@ export const paramDef = { export default define(meta, paramDef, async (ps, me) => { const meta = await fetchMeta(); - const users = await Promise.all(meta.pinnedUsers.map(acct => Users.findOne(Acct.parse(acct)))); + const users = await Promise.all(meta.pinnedUsers.map(acct => Acct.parse(acct)).map(acct => Users.findOneBy({ + usernameLower: acct.username.toLowerCase(), + host: acct.host ?? IsNull(), + }))); return await Users.packMany(users.filter(x => x !== undefined) as User[], me, { detail: true }); }); diff --git a/packages/backend/src/server/api/endpoints/promo/read.ts b/packages/backend/src/server/api/endpoints/promo/read.ts index ea34ca3aad..cc602857de 100644 --- a/packages/backend/src/server/api/endpoints/promo/read.ts +++ b/packages/backend/src/server/api/endpoints/promo/read.ts @@ -33,7 +33,7 @@ export default define(meta, paramDef, async (ps, user) => { throw e; }); - const exist = await PromoReads.findOne({ + const exist = await PromoReads.findOneBy({ noteId: note.id, userId: user.id, }); diff --git a/packages/backend/src/server/api/endpoints/request-reset-password.ts b/packages/backend/src/server/api/endpoints/request-reset-password.ts index 18cd98b164..046337f040 100644 --- a/packages/backend/src/server/api/endpoints/request-reset-password.ts +++ b/packages/backend/src/server/api/endpoints/request-reset-password.ts @@ -33,7 +33,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { - const user = await Users.findOne({ + const user = await Users.findOneBy({ usernameLower: ps.username.toLowerCase(), host: IsNull(), }); @@ -43,7 +43,7 @@ export default define(meta, paramDef, async (ps) => { return; } - const profile = await UserProfiles.findOneOrFail(user.id); + const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); // 合致するメアドが登録されていなかったら無視 if (profile.email !== ps.email) { diff --git a/packages/backend/src/server/api/endpoints/reset-password.ts b/packages/backend/src/server/api/endpoints/reset-password.ts index 3abf232af0..7acc545c40 100644 --- a/packages/backend/src/server/api/endpoints/reset-password.ts +++ b/packages/backend/src/server/api/endpoints/reset-password.ts @@ -23,7 +23,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const req = await PasswordResetRequests.findOneOrFail({ + const req = await PasswordResetRequests.findOneByOrFail({ token: ps.token, }); diff --git a/packages/backend/src/server/api/endpoints/stats.ts b/packages/backend/src/server/api/endpoints/stats.ts index 92fea4de6a..f8a1ee29de 100644 --- a/packages/backend/src/server/api/endpoints/stats.ts +++ b/packages/backend/src/server/api/endpoints/stats.ts @@ -1,6 +1,7 @@ import define from '../define.js'; import { Instances, NoteReactions, Notes, Users } from '@/models/index.js'; import { } from '@/services/chart/index.js'; +import { IsNull } from 'typeorm'; export const meta = { requireCredential: false, @@ -61,11 +62,11 @@ export default define(meta, paramDef, async () => { instances, ] = await Promise.all([ Notes.count({ cache: 3600000 }), // 1 hour - Notes.count({ where: { userHost: null }, cache: 3600000 }), + Notes.count({ where: { userHost: IsNull() }, cache: 3600000 }), Users.count({ cache: 3600000 }), - Users.count({ where: { host: null }, cache: 3600000 }), + Users.count({ where: { host: IsNull() }, cache: 3600000 }), NoteReactions.count({ cache: 3600000 }), // 1 hour - //NoteReactions.count({ where: { userHost: null }, cache: 3600000 }), + //NoteReactions.count({ where: { userHost: IsNull() }, cache: 3600000 }), Instances.count({ cache: 3600000 }), ]); diff --git a/packages/backend/src/server/api/endpoints/sw/register.ts b/packages/backend/src/server/api/endpoints/sw/register.ts index 6c7714e19b..a48973a0df 100644 --- a/packages/backend/src/server/api/endpoints/sw/register.ts +++ b/packages/backend/src/server/api/endpoints/sw/register.ts @@ -38,7 +38,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // if already subscribed - const exist = await SwSubscriptions.findOne({ + const exist = await SwSubscriptions.findOneBy({ userId: user.id, endpoint: ps.endpoint, auth: ps.auth, diff --git a/packages/backend/src/server/api/endpoints/username/available.ts b/packages/backend/src/server/api/endpoints/username/available.ts index 5a1c4128ab..04b754f4ad 100644 --- a/packages/backend/src/server/api/endpoints/username/available.ts +++ b/packages/backend/src/server/api/endpoints/username/available.ts @@ -1,5 +1,6 @@ import define from '../../define.js'; import { Users, UsedUsernames } from '@/models/index.js'; +import { IsNull } from 'typeorm'; export const meta = { tags: ['users'], @@ -29,12 +30,12 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { // Get exist - const exist = await Users.count({ - host: null, + const exist = await Users.countBy({ + host: IsNull(), usernameLower: ps.username.toLowerCase(), }); - const exist2 = await UsedUsernames.count({ username: ps.username.toLowerCase() }); + const exist2 = await UsedUsernames.countBy({ username: ps.username.toLowerCase() }); return { available: exist === 0 && exist2 === 0, diff --git a/packages/backend/src/server/api/endpoints/users/followers.ts b/packages/backend/src/server/api/endpoints/users/followers.ts index 1e104b6bcc..5de624312a 100644 --- a/packages/backend/src/server/api/endpoints/users/followers.ts +++ b/packages/backend/src/server/api/endpoints/users/followers.ts @@ -3,6 +3,7 @@ import { ApiError } from '../../error.js'; import { Users, Followings, UserProfiles } from '@/models/index.js'; import { makePaginationQuery } from '../../common/make-pagination-query.js'; import { toPunyNullable } from '@/misc/convert-host.js'; +import { IsNull } from 'typeorm'; export const meta = { tags: ['users'], @@ -49,15 +50,15 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const user = await Users.findOne(ps.userId != null + const user = await Users.findOneBy(ps.userId != null ? { id: ps.userId } - : { usernameLower: ps.username!.toLowerCase(), host: toPunyNullable(ps.host) }); + : { usernameLower: ps.username!.toLowerCase(), host: toPunyNullable(ps.host) ?? IsNull() }); if (user == null) { throw new ApiError(meta.errors.noSuchUser); } - const profile = await UserProfiles.findOneOrFail(user.id); + const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); if (profile.ffVisibility === 'private') { if (me == null || (me.id !== user.id)) { @@ -67,7 +68,7 @@ export default define(meta, paramDef, async (ps, me) => { if (me == null) { throw new ApiError(meta.errors.forbidden); } else if (me.id !== user.id) { - const following = await Followings.findOne({ + const following = await Followings.findOneBy({ followeeId: user.id, followerId: me.id, }); diff --git a/packages/backend/src/server/api/endpoints/users/following.ts b/packages/backend/src/server/api/endpoints/users/following.ts index b0a1036c76..55460f7c67 100644 --- a/packages/backend/src/server/api/endpoints/users/following.ts +++ b/packages/backend/src/server/api/endpoints/users/following.ts @@ -3,6 +3,7 @@ import { ApiError } from '../../error.js'; import { Users, Followings, UserProfiles } from '@/models/index.js'; import { makePaginationQuery } from '../../common/make-pagination-query.js'; import { toPunyNullable } from '@/misc/convert-host.js'; +import { IsNull } from 'typeorm'; export const meta = { tags: ['users'], @@ -49,15 +50,15 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const user = await Users.findOne(ps.userId != null + const user = await Users.findOneBy(ps.userId != null ? { id: ps.userId } - : { usernameLower: ps.username!.toLowerCase(), host: toPunyNullable(ps.host) }); + : { usernameLower: ps.username!.toLowerCase(), host: toPunyNullable(ps.host) ?? IsNull() }); if (user == null) { throw new ApiError(meta.errors.noSuchUser); } - const profile = await UserProfiles.findOneOrFail(user.id); + const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); if (profile.ffVisibility === 'private') { if (me == null || (me.id !== user.id)) { @@ -67,7 +68,7 @@ export default define(meta, paramDef, async (ps, me) => { if (me == null) { throw new ApiError(meta.errors.forbidden); } else if (me.id !== user.id) { - const following = await Followings.findOne({ + const following = await Followings.findOneBy({ followeeId: user.id, followerId: me.id, }); diff --git a/packages/backend/src/server/api/endpoints/users/groups/create.ts b/packages/backend/src/server/api/endpoints/users/groups/create.ts index 9f6d8464d8..fc775d7cc1 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/create.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/create.ts @@ -33,7 +33,7 @@ export default define(meta, paramDef, async (ps, user) => { createdAt: new Date(), userId: user.id, name: ps.name, - } as UserGroup).then(x => UserGroups.findOneOrFail(x.identifiers[0])); + } as UserGroup).then(x => UserGroups.findOneByOrFail(x.identifiers[0])); // Push the owner await UserGroupJoinings.insert({ diff --git a/packages/backend/src/server/api/endpoints/users/groups/delete.ts b/packages/backend/src/server/api/endpoints/users/groups/delete.ts index f4898a3c7c..f68006994c 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/delete.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/delete.ts @@ -28,7 +28,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const userGroup = await UserGroups.findOne({ + const userGroup = await UserGroups.findOneBy({ id: ps.groupId, userId: user.id, }); diff --git a/packages/backend/src/server/api/endpoints/users/groups/invitations/accept.ts b/packages/backend/src/server/api/endpoints/users/groups/invitations/accept.ts index efbdf968f6..75c1acc302 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/invitations/accept.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/invitations/accept.ts @@ -31,7 +31,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // Fetch the invitation - const invitation = await UserGroupInvitations.findOne({ + const invitation = await UserGroupInvitations.findOneBy({ id: ps.invitationId, }); diff --git a/packages/backend/src/server/api/endpoints/users/groups/invitations/reject.ts b/packages/backend/src/server/api/endpoints/users/groups/invitations/reject.ts index fe5d431eab..46bc780ab0 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/invitations/reject.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/invitations/reject.ts @@ -29,7 +29,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // Fetch the invitation - const invitation = await UserGroupInvitations.findOne({ + const invitation = await UserGroupInvitations.findOneBy({ id: ps.invitationId, }); diff --git a/packages/backend/src/server/api/endpoints/users/groups/invite.ts b/packages/backend/src/server/api/endpoints/users/groups/invite.ts index 10bfb7eca1..30a5beb1d9 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/invite.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/invite.ts @@ -52,7 +52,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { // Fetch the group - const userGroup = await UserGroups.findOne({ + const userGroup = await UserGroups.findOneBy({ id: ps.groupId, userId: me.id, }); @@ -67,7 +67,7 @@ export default define(meta, paramDef, async (ps, me) => { throw e; }); - const joining = await UserGroupJoinings.findOne({ + const joining = await UserGroupJoinings.findOneBy({ userGroupId: userGroup.id, userId: user.id, }); @@ -76,7 +76,7 @@ export default define(meta, paramDef, async (ps, me) => { throw new ApiError(meta.errors.alreadyAdded); } - const existInvitation = await UserGroupInvitations.findOne({ + const existInvitation = await UserGroupInvitations.findOneBy({ userGroupId: userGroup.id, userId: user.id, }); @@ -90,7 +90,7 @@ export default define(meta, paramDef, async (ps, me) => { createdAt: new Date(), userId: user.id, userGroupId: userGroup.id, - } as UserGroupInvitation).then(x => UserGroupInvitations.findOneOrFail(x.identifiers[0])); + } as UserGroupInvitation).then(x => UserGroupInvitations.findOneByOrFail(x.identifiers[0])); // 通知を作成 createNotification(user.id, 'groupInvited', { diff --git a/packages/backend/src/server/api/endpoints/users/groups/joined.ts b/packages/backend/src/server/api/endpoints/users/groups/joined.ts index e52de78595..77dc59d3e5 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/joined.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/joined.ts @@ -28,11 +28,11 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const ownedGroups = await UserGroups.find({ + const ownedGroups = await UserGroups.findBy({ userId: me.id, }); - const joinings = await UserGroupJoinings.find({ + const joinings = await UserGroupJoinings.findBy({ userId: me.id, ...(ownedGroups.length > 0 ? { userGroupId: Not(In(ownedGroups.map(x => x.id))), diff --git a/packages/backend/src/server/api/endpoints/users/groups/leave.ts b/packages/backend/src/server/api/endpoints/users/groups/leave.ts index c1a8c2c024..33abd5439f 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/leave.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/leave.ts @@ -35,7 +35,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { // Fetch the group - const userGroup = await UserGroups.findOne({ + const userGroup = await UserGroups.findOneBy({ id: ps.groupId, }); diff --git a/packages/backend/src/server/api/endpoints/users/groups/owned.ts b/packages/backend/src/server/api/endpoints/users/groups/owned.ts index 11aad0f73c..b1289e601f 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/owned.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/owned.ts @@ -27,7 +27,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const userGroups = await UserGroups.find({ + const userGroups = await UserGroups.findBy({ userId: me.id, }); diff --git a/packages/backend/src/server/api/endpoints/users/groups/pull.ts b/packages/backend/src/server/api/endpoints/users/groups/pull.ts index 55ec9f915b..b31990b2e3 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/pull.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/pull.ts @@ -43,7 +43,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { // Fetch the group - const userGroup = await UserGroups.findOne({ + const userGroup = await UserGroups.findOneBy({ id: ps.groupId, userId: me.id, }); diff --git a/packages/backend/src/server/api/endpoints/users/groups/show.ts b/packages/backend/src/server/api/endpoints/users/groups/show.ts index 28ca1162c8..3ffb0f5ba9 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/show.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/show.ts @@ -35,7 +35,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { // Fetch the group - const userGroup = await UserGroups.findOne({ + const userGroup = await UserGroups.findOneBy({ id: ps.groupId, }); @@ -43,7 +43,7 @@ export default define(meta, paramDef, async (ps, me) => { throw new ApiError(meta.errors.noSuchGroup); } - const joining = await UserGroupJoinings.findOne({ + const joining = await UserGroupJoinings.findOneBy({ userId: me.id, userGroupId: userGroup.id, }); diff --git a/packages/backend/src/server/api/endpoints/users/groups/transfer.ts b/packages/backend/src/server/api/endpoints/users/groups/transfer.ts index f48e1ddbf0..41ceee3b2e 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/transfer.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/transfer.ts @@ -49,7 +49,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { // Fetch the group - const userGroup = await UserGroups.findOne({ + const userGroup = await UserGroups.findOneBy({ id: ps.groupId, userId: me.id, }); @@ -64,7 +64,7 @@ export default define(meta, paramDef, async (ps, me) => { throw e; }); - const joining = await UserGroupJoinings.findOne({ + const joining = await UserGroupJoinings.findOneBy({ userGroupId: userGroup.id, userId: user.id, }); diff --git a/packages/backend/src/server/api/endpoints/users/groups/update.ts b/packages/backend/src/server/api/endpoints/users/groups/update.ts index b3e17dfd9e..1016aa8926 100644 --- a/packages/backend/src/server/api/endpoints/users/groups/update.ts +++ b/packages/backend/src/server/api/endpoints/users/groups/update.ts @@ -36,7 +36,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { // Fetch the group - const userGroup = await UserGroups.findOne({ + const userGroup = await UserGroups.findOneBy({ id: ps.groupId, userId: me.id, }); diff --git a/packages/backend/src/server/api/endpoints/users/lists/create.ts b/packages/backend/src/server/api/endpoints/users/lists/create.ts index 1a0599f9e7..d5260256d5 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/create.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/create.ts @@ -32,7 +32,7 @@ export default define(meta, paramDef, async (ps, user) => { createdAt: new Date(), userId: user.id, name: ps.name, - } as UserList).then(x => UserLists.findOneOrFail(x.identifiers[0])); + } as UserList).then(x => UserLists.findOneByOrFail(x.identifiers[0])); return await UserLists.pack(userList); }); diff --git a/packages/backend/src/server/api/endpoints/users/lists/delete.ts b/packages/backend/src/server/api/endpoints/users/lists/delete.ts index aeefb98c83..b7ad96eef0 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/delete.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/delete.ts @@ -28,7 +28,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const userList = await UserLists.findOne({ + const userList = await UserLists.findOneBy({ id: ps.listId, userId: user.id, }); diff --git a/packages/backend/src/server/api/endpoints/users/lists/list.ts b/packages/backend/src/server/api/endpoints/users/lists/list.ts index a8663ada8a..78311292cb 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/list.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/list.ts @@ -27,7 +27,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const userLists = await UserLists.find({ + const userLists = await UserLists.findBy({ userId: me.id, }); diff --git a/packages/backend/src/server/api/endpoints/users/lists/pull.ts b/packages/backend/src/server/api/endpoints/users/lists/pull.ts index 2c4c61d51e..76863f07d1 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/pull.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/pull.ts @@ -38,7 +38,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { // Fetch the list - const userList = await UserLists.findOne({ + const userList = await UserLists.findOneBy({ id: ps.listId, userId: me.id, }); diff --git a/packages/backend/src/server/api/endpoints/users/lists/push.ts b/packages/backend/src/server/api/endpoints/users/lists/push.ts index 034a9d2db6..260665c63a 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/push.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/push.ts @@ -50,7 +50,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { // Fetch the list - const userList = await UserLists.findOne({ + const userList = await UserLists.findOneBy({ id: ps.listId, userId: me.id, }); @@ -67,7 +67,7 @@ export default define(meta, paramDef, async (ps, me) => { // Check blocking if (user.id !== me.id) { - const block = await Blockings.findOne({ + const block = await Blockings.findOneBy({ blockerId: user.id, blockeeId: me.id, }); @@ -76,7 +76,7 @@ export default define(meta, paramDef, async (ps, me) => { } } - const exist = await UserListJoinings.findOne({ + const exist = await UserListJoinings.findOneBy({ userListId: userList.id, userId: user.id, }); diff --git a/packages/backend/src/server/api/endpoints/users/lists/show.ts b/packages/backend/src/server/api/endpoints/users/lists/show.ts index fadb94c90e..5f51980e95 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/show.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/show.ts @@ -35,7 +35,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { // Fetch the list - const userList = await UserLists.findOne({ + const userList = await UserLists.findOneBy({ id: ps.listId, userId: me.id, }); diff --git a/packages/backend/src/server/api/endpoints/users/lists/update.ts b/packages/backend/src/server/api/endpoints/users/lists/update.ts index 5ec99031e1..52353a14cc 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/update.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/update.ts @@ -36,7 +36,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // Fetch the list - const userList = await UserLists.findOne({ + const userList = await UserLists.findOneBy({ id: ps.listId, userId: user.id, }); diff --git a/packages/backend/src/server/api/endpoints/users/reactions.ts b/packages/backend/src/server/api/endpoints/users/reactions.ts index 7b55a16711..c2d1994343 100644 --- a/packages/backend/src/server/api/endpoints/users/reactions.ts +++ b/packages/backend/src/server/api/endpoints/users/reactions.ts @@ -43,7 +43,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const profile = await UserProfiles.findOneOrFail(ps.userId); + const profile = await UserProfiles.findOneByOrFail({ userId: ps.userId }); if (me == null || (me.id !== ps.userId && !profile.publicReactions)) { throw new ApiError(meta.errors.reactionsNotPublic); diff --git a/packages/backend/src/server/api/endpoints/users/report-abuse.ts b/packages/backend/src/server/api/endpoints/users/report-abuse.ts index e091b8e1b1..0be385dbbf 100644 --- a/packages/backend/src/server/api/endpoints/users/report-abuse.ts +++ b/packages/backend/src/server/api/endpoints/users/report-abuse.ts @@ -67,10 +67,10 @@ export default define(meta, paramDef, async (ps, me) => { reporterId: me.id, reporterHost: null, comment: ps.comment, - }).then(x => AbuseUserReports.findOneOrFail(x.identifiers[0])); + }).then(x => AbuseUserReports.findOneByOrFail(x.identifiers[0])); // Publish event to moderators - setTimeout(async () => { + setImmediate(async () => { const moderators = await Users.find({ where: [{ isAdmin: true, @@ -94,5 +94,5 @@ export default define(meta, paramDef, async (ps, me) => { sanitizeHtml(ps.comment), sanitizeHtml(ps.comment)); } - }, 1); + }); }); diff --git a/packages/backend/src/server/api/endpoints/users/show.ts b/packages/backend/src/server/api/endpoints/users/show.ts index 263c102a7a..775a4b29ff 100644 --- a/packages/backend/src/server/api/endpoints/users/show.ts +++ b/packages/backend/src/server/api/endpoints/users/show.ts @@ -3,7 +3,7 @@ import define from '../../define.js'; import { apiLogger } from '../../logger.js'; import { ApiError } from '../../error.js'; import { Users } from '@/models/index.js'; -import { In } from 'typeorm'; +import { FindOptionsWhere, In, IsNull } from 'typeorm'; import { User } from '@/models/entities/user.js'; export const meta = { @@ -68,7 +68,7 @@ export default define(meta, paramDef, async (ps, me) => { return []; } - const users = await Users.find(isAdminOrModerator ? { + const users = await Users.findBy(isAdminOrModerator ? { id: In(ps.userIds), } : { id: In(ps.userIds), @@ -92,11 +92,11 @@ export default define(meta, paramDef, async (ps, me) => { throw new ApiError(meta.errors.failedToResolveRemoteUser); }); } else { - const q: any = ps.userId != null + const q: FindOptionsWhere = ps.userId != null ? { id: ps.userId } - : { usernameLower: ps.username!.toLowerCase(), host: null }; + : { usernameLower: ps.username!.toLowerCase(), host: IsNull() }; - user = await Users.findOne(q); + user = await Users.findOneBy(q); } if (user == null || (!isAdminOrModerator && user.isSuspended)) { diff --git a/packages/backend/src/server/api/endpoints/users/stats.ts b/packages/backend/src/server/api/endpoints/users/stats.ts index 180a9386d3..d138019a72 100644 --- a/packages/backend/src/server/api/endpoints/users/stats.ts +++ b/packages/backend/src/server/api/endpoints/users/stats.ts @@ -26,7 +26,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export 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) { throw new ApiError(meta.errors.noSuchUser); } diff --git a/packages/backend/src/server/api/index.ts b/packages/backend/src/server/api/index.ts index ba2a71951c..02bec31b17 100644 --- a/packages/backend/src/server/api/index.ts +++ b/packages/backend/src/server/api/index.ts @@ -81,7 +81,7 @@ router.get('/v1/instance/peers', async ctx => { }); router.post('/miauth/:session/check', async ctx => { - const token = await AccessTokens.findOne({ + const token = await AccessTokens.findOneBy({ session: ctx.params.session, }); diff --git a/packages/backend/src/server/api/limiter.ts b/packages/backend/src/server/api/limiter.ts index 7e6b93b39f..e74db8466e 100644 --- a/packages/backend/src/server/api/limiter.ts +++ b/packages/backend/src/server/api/limiter.ts @@ -2,12 +2,12 @@ import Limiter from 'ratelimiter'; import { redisClient } from '../../db/redis.js'; import { IEndpoint } from './endpoints.js'; import * as Acct from '@/misc/acct.js'; -import { User } from '@/models/entities/user.js'; +import { CacheableLocalUser, User } from '@/models/entities/user.js'; import Logger from '@/services/logger.js'; const logger = new Logger('limiter'); -export const limiter = (endpoint: IEndpoint & { meta: { limit: NonNullable } }, user: User) => new Promise((ok, reject) => { +export const limiter = (endpoint: IEndpoint & { meta: { limit: NonNullable } }, user: CacheableLocalUser) => new Promise((ok, reject) => { const limitation = endpoint.meta.limit; const key = Object.prototype.hasOwnProperty.call(limitation, 'key') diff --git a/packages/backend/src/server/api/private/signin.ts b/packages/backend/src/server/api/private/signin.ts index b0f88948a0..3f7118ad22 100644 --- a/packages/backend/src/server/api/private/signin.ts +++ b/packages/backend/src/server/api/private/signin.ts @@ -8,6 +8,7 @@ import { ILocalUser } from '@/models/entities/user.js'; import { genId } from '@/misc/gen-id.js'; import { verifyLogin, hash } from '../2fa.js'; import { randomBytes } from 'node:crypto'; +import { IsNull } from 'typeorm'; export default async (ctx: Koa.Context) => { ctx.set('Access-Control-Allow-Origin', config.url); @@ -39,9 +40,9 @@ export default async (ctx: Koa.Context) => { } // Fetch user - const user = await Users.findOne({ + const user = await Users.findOneBy({ usernameLower: username.toLowerCase(), - host: null, + host: IsNull(), }) as ILocalUser; if (user == null) { @@ -58,7 +59,7 @@ export default async (ctx: Koa.Context) => { return; } - const profile = await UserProfiles.findOneOrFail(user.id); + const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); // Compare password const same = await bcrypt.compare(password, profile.password!); @@ -123,7 +124,7 @@ export default async (ctx: Koa.Context) => { const clientDataJSON = Buffer.from(body.clientDataJSON, 'hex'); const clientData = JSON.parse(clientDataJSON.toString('utf-8')); - const challenge = await AttestationChallenges.findOne({ + const challenge = await AttestationChallenges.findOneBy({ userId: user.id, id: body.challengeId, registrationChallenge: false, @@ -149,7 +150,7 @@ export default async (ctx: Koa.Context) => { return; } - const securityKey = await UserSecurityKeys.findOne({ + const securityKey = await UserSecurityKeys.findOneBy({ id: Buffer.from( body.credentialId .replace(/-/g, '+') @@ -191,7 +192,7 @@ export default async (ctx: Koa.Context) => { return; } - const keys = await UserSecurityKeys.find({ + const keys = await UserSecurityKeys.findBy({ userId: user.id, }); diff --git a/packages/backend/src/server/api/private/signup-pending.ts b/packages/backend/src/server/api/private/signup-pending.ts index 1a667ddb43..e5e39ba00d 100644 --- a/packages/backend/src/server/api/private/signup-pending.ts +++ b/packages/backend/src/server/api/private/signup-pending.ts @@ -9,7 +9,7 @@ export default async (ctx: Koa.Context) => { const code = body['code']; try { - const pendingUser = await UserPendings.findOneOrFail({ code }); + const pendingUser = await UserPendings.findOneByOrFail({ code }); const { account, secret } = await signup({ username: pendingUser.username, @@ -20,7 +20,7 @@ export default async (ctx: Koa.Context) => { id: pendingUser.id, }); - const profile = await UserProfiles.findOneOrFail(account.id); + const profile = await UserProfiles.findOneByOrFail({ userId: account.id }); await UserProfiles.update({ userId: profile.userId }, { email: pendingUser.email, diff --git a/packages/backend/src/server/api/private/signup.ts b/packages/backend/src/server/api/private/signup.ts index 01f284a57f..26f172637c 100644 --- a/packages/backend/src/server/api/private/signup.ts +++ b/packages/backend/src/server/api/private/signup.ts @@ -56,7 +56,7 @@ export default async (ctx: Koa.Context) => { return; } - const ticket = await RegistrationTickets.findOne({ + const ticket = await RegistrationTickets.findOneBy({ code: invitationCode, }); diff --git a/packages/backend/src/server/api/service/discord.ts b/packages/backend/src/server/api/service/discord.ts index 089f7de0cd..04197574c2 100644 --- a/packages/backend/src/server/api/service/discord.ts +++ b/packages/backend/src/server/api/service/discord.ts @@ -10,6 +10,7 @@ import signin from '../common/signin.js'; import { fetchMeta } from '@/misc/fetch-meta.js'; import { Users, UserProfiles } from '@/models/index.js'; import { ILocalUser } from '@/models/entities/user.js'; +import { IsNull } from 'typeorm'; function getUserToken(ctx: Koa.BaseContext): string | null { return ((ctx.headers['cookie'] || '').match(/igi=(\w+)/) || [null, null])[1]; @@ -40,12 +41,12 @@ router.get('/disconnect/discord', async ctx => { return; } - const user = await Users.findOneOrFail({ - host: null, + const user = await Users.findOneByOrFail({ + host: IsNull(), token: userToken, }); - const profile = await UserProfiles.findOneOrFail(user.id); + const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); delete profile.integrations.discord; @@ -206,7 +207,7 @@ router.get('/dc/cb', async ctx => { }, }); - signin(ctx, await Users.findOne(profile.userId) as ILocalUser, true); + signin(ctx, await Users.findOneBy({ id: profile.userId }) as ILocalUser, true); } else { const code = ctx.query.code; @@ -252,12 +253,12 @@ router.get('/dc/cb', async ctx => { return; } - const user = await Users.findOneOrFail({ - host: null, + const user = await Users.findOneByOrFail({ + host: IsNull(), token: userToken, }); - const profile = await UserProfiles.findOneOrFail(user.id); + const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); await UserProfiles.update(user.id, { integrations: { diff --git a/packages/backend/src/server/api/service/github.ts b/packages/backend/src/server/api/service/github.ts index ce032db181..61bb768a63 100644 --- a/packages/backend/src/server/api/service/github.ts +++ b/packages/backend/src/server/api/service/github.ts @@ -10,6 +10,7 @@ import signin from '../common/signin.js'; import { fetchMeta } from '@/misc/fetch-meta.js'; import { Users, UserProfiles } from '@/models/index.js'; import { ILocalUser } from '@/models/entities/user.js'; +import { IsNull } from 'typeorm'; function getUserToken(ctx: Koa.BaseContext): string | null { return ((ctx.headers['cookie'] || '').match(/igi=(\w+)/) || [null, null])[1]; @@ -40,12 +41,12 @@ router.get('/disconnect/github', async ctx => { return; } - const user = await Users.findOneOrFail({ - host: null, + const user = await Users.findOneByOrFail({ + host: IsNull(), token: userToken, }); - const profile = await UserProfiles.findOneOrFail(user.id); + const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); delete profile.integrations.github; @@ -184,7 +185,7 @@ router.get('/gh/cb', async ctx => { return; } - signin(ctx, await Users.findOne(link.userId) as ILocalUser, true); + signin(ctx, await Users.findOneBy({ id: link.userId }) as ILocalUser, true); } else { const code = ctx.query.code; @@ -227,12 +228,12 @@ router.get('/gh/cb', async ctx => { return; } - const user = await Users.findOneOrFail({ - host: null, + const user = await Users.findOneByOrFail({ + host: IsNull(), token: userToken, }); - const profile = await UserProfiles.findOneOrFail(user.id); + const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); await UserProfiles.update(user.id, { integrations: { diff --git a/packages/backend/src/server/api/service/twitter.ts b/packages/backend/src/server/api/service/twitter.ts index e6e4398fa2..e72b71e2f7 100644 --- a/packages/backend/src/server/api/service/twitter.ts +++ b/packages/backend/src/server/api/service/twitter.ts @@ -9,6 +9,7 @@ import signin from '../common/signin.js'; import { fetchMeta } from '@/misc/fetch-meta.js'; import { Users, UserProfiles } from '@/models/index.js'; import { ILocalUser } from '@/models/entities/user.js'; +import { IsNull } from 'typeorm'; function getUserToken(ctx: Koa.BaseContext): string | null { return ((ctx.headers['cookie'] || '').match(/igi=(\w+)/) || [null, null])[1]; @@ -39,12 +40,12 @@ router.get('/disconnect/twitter', async ctx => { return; } - const user = await Users.findOneOrFail({ - host: null, + const user = await Users.findOneByOrFail({ + host: IsNull(), token: userToken, }); - const profile = await UserProfiles.findOneOrFail(user.id); + const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); delete profile.integrations.twitter; @@ -143,7 +144,7 @@ router.get('/tw/cb', async ctx => { return; } - signin(ctx, await Users.findOne(link.userId) as ILocalUser, true); + signin(ctx, await Users.findOneBy({ id: link.userId }) as ILocalUser, true); } else { const verifier = ctx.query.oauth_verifier; @@ -162,12 +163,12 @@ router.get('/tw/cb', async ctx => { const result = await twAuth!.done(JSON.parse(twCtx), verifier); - const user = await Users.findOneOrFail({ - host: null, + const user = await Users.findOneByOrFail({ + host: IsNull(), token: userToken, }); - const profile = await UserProfiles.findOneOrFail(user.id); + const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); await UserProfiles.update(user.id, { integrations: { diff --git a/packages/backend/src/server/api/stream/channels/messaging.ts b/packages/backend/src/server/api/stream/channels/messaging.ts index 94bbdeca52..877d44c38e 100644 --- a/packages/backend/src/server/api/stream/channels/messaging.ts +++ b/packages/backend/src/server/api/stream/channels/messaging.ts @@ -26,12 +26,12 @@ export default class extends Channel { public async init(params: any) { this.otherpartyId = params.otherparty; - this.otherparty = this.otherpartyId ? await Users.findOneOrFail({ id: this.otherpartyId }) : null; + this.otherparty = this.otherpartyId ? await Users.findOneByOrFail({ id: this.otherpartyId }) : null; this.groupId = params.group; // Check joining if (this.groupId) { - const joining = await UserGroupJoinings.findOne({ + const joining = await UserGroupJoinings.findOneBy({ userId: this.user!.id, userGroupId: this.groupId, }); @@ -72,7 +72,7 @@ export default class extends Channel { // リモートユーザーからのメッセージだったら既読配信 if (Users.isLocalUser(this.user!) && Users.isRemoteUser(this.otherparty!)) { - MessagingMessages.findOne(body.id).then(message => { + MessagingMessages.findOneBy({ id: body.id }).then(message => { if (message) deliverReadActivity(this.user as ILocalUser, this.otherparty as IRemoteUser, message); }); } diff --git a/packages/backend/src/server/api/stream/channels/user-list.ts b/packages/backend/src/server/api/stream/channels/user-list.ts index 57523c8488..d8034e83fe 100644 --- a/packages/backend/src/server/api/stream/channels/user-list.ts +++ b/packages/backend/src/server/api/stream/channels/user-list.ts @@ -23,7 +23,7 @@ export default class extends Channel { this.listId = params.listId as string; // Check existence and owner - const list = await UserLists.findOne({ + const list = await UserLists.findOneBy({ id: this.listId, userId: this.user!.id, }); diff --git a/packages/backend/src/server/api/stream/index.ts b/packages/backend/src/server/api/stream/index.ts index 0cb38e2a99..b803478281 100644 --- a/packages/backend/src/server/api/stream/index.ts +++ b/packages/backend/src/server/api/stream/index.ts @@ -188,7 +188,7 @@ export default class Connection { */ private async onApiRequest(payload: any) { // 新鮮なデータを利用するためにユーザーをフェッチ - const user = this.user ? await Users.findOne(this.user.id) : null; + const user = this.user ? await Users.findOneBy({ id: this.user.id }) : null; const endpoint = payload.endpoint || payload.ep; // alias @@ -386,7 +386,7 @@ export default class Connection { } private async updateUserProfile() { - this.userProfile = await UserProfiles.findOne({ + this.userProfile = await UserProfiles.findOneBy({ userId: this.user!.id, }); } diff --git a/packages/backend/src/server/api/stream/types.ts b/packages/backend/src/server/api/stream/types.ts index 90cf59038d..bea863eb7c 100644 --- a/packages/backend/src/server/api/stream/types.ts +++ b/packages/backend/src/server/api/stream/types.ts @@ -18,6 +18,11 @@ import { Packed } from '@/misc/schema.js'; //#region Stream type-body definitions export interface InternalStreamTypes { + userChangeSuspendedState: { id: User['id']; isSuspended: User['isSuspended']; }; + userChangeSilencedState: { id: User['id']; isSilenced: User['isSilenced']; }; + userChangeModeratorState: { id: User['id']; isModerator: User['isModerator']; }; + userTokenRegenerated: { id: User['id']; oldToken: User['token']; newToken: User['token']; }; + remoteUserUpdated: { id: User['id']; }; antennaCreated: Antenna; antennaDeleted: Antenna; antennaUpdated: Antenna; diff --git a/packages/backend/src/server/index.ts b/packages/backend/src/server/index.ts index 95a9ec6a00..a68cebfeb2 100644 --- a/packages/backend/src/server/index.ts +++ b/packages/backend/src/server/index.ts @@ -26,6 +26,7 @@ import { createTemp } from '@/misc/create-temp.js'; import { publishMainStream } from '@/services/stream.js'; import * as Acct from '@/misc/acct.js'; import { initializeStreamingServer } from './api/streaming.js'; +import { IsNull } from 'typeorm'; export const serverLogger = new Logger('server', 'gray', false); @@ -71,10 +72,11 @@ router.use(wellKnown.routes()); router.get('/avatar/@:acct', async ctx => { const { username, host } = Acct.parse(ctx.params.acct); const user = await Users.findOne({ - usernameLower: username.toLowerCase(), - host: host === config.host ? null : host, - isSuspended: false, - }, { + where: { + usernameLower: username.toLowerCase(), + host: (host == null) || (host === config.host) ? IsNull() : host, + isSuspended: false, + }, relations: ['avatar'], }); @@ -93,7 +95,7 @@ router.get('/identicon/:x', async ctx => { }); router.get('/verify-email/:code', async ctx => { - const profile = await UserProfiles.findOne({ + const profile = await UserProfiles.findOneBy({ emailVerifyCode: ctx.params.code, }); diff --git a/packages/backend/src/server/nodeinfo.ts b/packages/backend/src/server/nodeinfo.ts index 2fc7b56cc2..13a362a75f 100644 --- a/packages/backend/src/server/nodeinfo.ts +++ b/packages/backend/src/server/nodeinfo.ts @@ -2,7 +2,7 @@ import Router from '@koa/router'; import config from '@/config/index.js'; import { fetchMeta } from '@/misc/fetch-meta.js'; import { Users, Notes } from '@/models/index.js'; -import { MoreThan } from 'typeorm'; +import { IsNull, MoreThan } from 'typeorm'; import { MAX_NOTE_TEXT_LENGTH } from '@/const.js'; import { Cache } from '@/misc/cache.js'; @@ -29,10 +29,10 @@ const nodeinfo2 = async () => { localPosts, ] = await Promise.all([ fetchMeta(true), - Users.count({ where: { host: null } }), - Users.count({ where: { host: null, lastActiveDate: MoreThan(new Date(now - 15552000000)) } }), - Users.count({ where: { host: null, lastActiveDate: MoreThan(new Date(now - 2592000000)) } }), - Notes.count({ where: { userHost: null } }), + Users.count({ where: { host: IsNull() } }), + Users.count({ where: { host: IsNull(), lastActiveDate: MoreThan(new Date(now - 15552000000)) } }), + Users.count({ where: { host: IsNull(), lastActiveDate: MoreThan(new Date(now - 2592000000)) } }), + Notes.count({ where: { userHost: IsNull() } }), ]); const proxyAccount = meta.proxyAccountId ? await Users.pack(meta.proxyAccountId).catch(() => null) : null; diff --git a/packages/backend/src/server/web/feed.ts b/packages/backend/src/server/web/feed.ts index b98e3f8bf6..eba8dc58d4 100644 --- a/packages/backend/src/server/web/feed.ts +++ b/packages/backend/src/server/web/feed.ts @@ -2,7 +2,7 @@ import { Feed } from 'feed'; import config from '@/config/index.js'; import { User } from '@/models/entities/user.js'; import { Notes, DriveFiles, UserProfiles } from '@/models/index.js'; -import { In } from 'typeorm'; +import { In, IsNull } from 'typeorm'; export default async function(user: User) { const author = { @@ -10,12 +10,12 @@ export default async function(user: User) { name: user.name || user.username, }; - const profile = await UserProfiles.findOneOrFail(user.id); + const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); const notes = await Notes.find({ where: { userId: user.id, - renoteId: null, + renoteId: IsNull(), visibility: In(['public', 'home']), }, order: { createdAt: -1 }, @@ -39,7 +39,7 @@ export default async function(user: User) { }); for (const note of notes) { - const files = note.fileIds.length > 0 ? await DriveFiles.find({ + const files = note.fileIds.length > 0 ? await DriveFiles.findBy({ id: In(note.fileIds), }) : []; const file = files.find(file => file.type.startsWith('image/')); diff --git a/packages/backend/src/server/web/index.ts b/packages/backend/src/server/web/index.ts index 9cd42ea793..112d7f640e 100644 --- a/packages/backend/src/server/web/index.ts +++ b/packages/backend/src/server/web/index.ts @@ -24,6 +24,7 @@ import { getNoteSummary } from '@/misc/get-note-summary.js'; import { urlPreviewHandler } from './url-preview.js'; import { manifestHandler } from './manifest.js'; import { queues } from '@/queue/queues.js'; +import { IsNull } from 'typeorm'; const _filename = fileURLToPath(import.meta.url); const _dirname = dirname(_filename); @@ -47,7 +48,7 @@ app.use(async (ctx, next) => { ctx.status = 401; return; } - const user = await Users.findOne({ token }); + const user = await Users.findOneBy({ token }); if (user == null || !(user.isAdmin || user.isModerator)) { ctx.status = 403; return; @@ -170,9 +171,9 @@ router.get('/api.json', async ctx => { const getFeed = async (acct: string) => { const { username, host } = Acct.parse(acct); - const user = await Users.findOne({ + const user = await Users.findOneBy({ usernameLower: username.toLowerCase(), - host, + host: host ?? IsNull(), isSuspended: false, }); @@ -219,14 +220,14 @@ router.get('/@:user.json', async ctx => { // User router.get(['/@:user', '/@:user/:sub'], async (ctx, next) => { const { username, host } = Acct.parse(ctx.params.user); - const user = await Users.findOne({ + const user = await Users.findOneBy({ usernameLower: username.toLowerCase(), - host, + host: host ?? IsNull(), isSuspended: false, }); if (user != null) { - const profile = await UserProfiles.findOneOrFail(user.id); + const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); const meta = await fetchMeta(); const me = profile.fields ? profile.fields @@ -250,9 +251,9 @@ router.get(['/@:user', '/@:user/:sub'], async (ctx, next) => { }); router.get('/users/:user', async ctx => { - const user = await Users.findOne({ + const user = await Users.findOneBy({ id: ctx.params.user, - host: null, + host: IsNull(), isSuspended: false, }); @@ -266,11 +267,11 @@ router.get('/users/:user', async ctx => { // Note router.get('/notes/:note', async (ctx, next) => { - const note = await Notes.findOne(ctx.params.note); + const note = await Notes.findOneBy({ id: ctx.params.note }); if (note) { const _note = await Notes.pack(note); - const profile = await UserProfiles.findOneOrFail(note.userId); + const profile = await UserProfiles.findOneByOrFail({ userId: note.userId }); const meta = await fetchMeta(); await ctx.render('note', { note: _note, @@ -297,21 +298,21 @@ router.get('/notes/:note', async (ctx, next) => { // Page router.get('/@:user/pages/:page', async (ctx, next) => { const { username, host } = Acct.parse(ctx.params.user); - const user = await Users.findOne({ + const user = await Users.findOneBy({ usernameLower: username.toLowerCase(), - host, + host: host ?? IsNull(), }); if (user == null) return; - const page = await Pages.findOne({ + const page = await Pages.findOneBy({ name: ctx.params.page, userId: user.id, }); if (page) { const _page = await Pages.pack(page); - const profile = await UserProfiles.findOneOrFail(page.userId); + const profile = await UserProfiles.findOneByOrFail({ userId: page.userId }); const meta = await fetchMeta(); await ctx.render('page', { page: _page, @@ -336,13 +337,13 @@ router.get('/@:user/pages/:page', async (ctx, next) => { // Clip // TODO: 非publicなclipのハンドリング router.get('/clips/:clip', async (ctx, next) => { - const clip = await Clips.findOne({ + const clip = await Clips.findOneBy({ id: ctx.params.clip, }); if (clip) { const _clip = await Clips.pack(clip); - const profile = await UserProfiles.findOneOrFail(clip.userId); + const profile = await UserProfiles.findOneByOrFail({ userId: clip.userId }); const meta = await fetchMeta(); await ctx.render('clip', { clip: _clip, @@ -362,11 +363,11 @@ router.get('/clips/:clip', async (ctx, next) => { // Gallery post router.get('/gallery/:post', async (ctx, next) => { - const post = await GalleryPosts.findOne(ctx.params.post); + const post = await GalleryPosts.findOneBy({ id: ctx.params.post }); if (post) { const _post = await GalleryPosts.pack(post); - const profile = await UserProfiles.findOneOrFail(post.userId); + const profile = await UserProfiles.findOneByOrFail({ userId: post.userId }); const meta = await fetchMeta(); await ctx.render('gallery-post', { post: _post, @@ -386,7 +387,7 @@ router.get('/gallery/:post', async (ctx, next) => { // Channel router.get('/channels/:channel', async (ctx, next) => { - const channel = await Channels.findOne({ + const channel = await Channels.findOneBy({ id: ctx.params.channel, }); @@ -418,8 +419,8 @@ router.get('/_info_card_', async ctx => { version: config.version, host: config.host, meta: meta, - originalUsersCount: await Users.count({ host: null }), - originalNotesCount: await Notes.count({ userHost: null }), + originalUsersCount: await Users.countBy({ host: IsNull() }), + originalNotesCount: await Notes.countBy({ userHost: IsNull() }), }); }); diff --git a/packages/backend/src/server/well-known.ts b/packages/backend/src/server/well-known.ts index 7a5d085413..7530b4e0ba 100644 --- a/packages/backend/src/server/well-known.ts +++ b/packages/backend/src/server/well-known.ts @@ -6,6 +6,7 @@ import { links } from './nodeinfo.js'; import { escapeAttribute, escapeValue } from '@/prelude/xml.js'; import { Users } from '@/models/index.js'; import { User } from '@/models/entities/user.js'; +import { FindOptionsWhere, IsNull } from 'typeorm'; // Init router const router = new Router(); @@ -66,13 +67,13 @@ router.get('/.well-known/change-password', async ctx => { */ router.get(webFingerPath, async ctx => { - const fromId = (id: User['id']): Record => ({ + const fromId = (id: User['id']): FindOptionsWhere => ({ id, - host: null, + host: IsNull(), isSuspended: false, }); - const generateQuery = (resource: string) => + const generateQuery = (resource: string): FindOptionsWhere | number => resource.startsWith(`${config.url.toLowerCase()}/users/`) ? fromId(resource.split('/').pop()!) : fromAcct(Acct.parse( @@ -80,10 +81,10 @@ router.get(webFingerPath, async ctx => { resource.startsWith('acct:') ? resource.slice('acct:'.length) : resource)); - const fromAcct = (acct: Acct.Acct): Record | number => + const fromAcct = (acct: Acct.Acct): FindOptionsWhere | number => !acct.host || acct.host === config.host.toLowerCase() ? { usernameLower: acct.username, - host: null, + host: IsNull(), isSuspended: false, } : 422; @@ -99,7 +100,7 @@ router.get(webFingerPath, async ctx => { return; } - const user = await Users.findOne(query); + const user = await Users.findOneBy(query); if (user == null) { ctx.status = 404; diff --git a/packages/backend/src/services/add-note-to-antenna.ts b/packages/backend/src/services/add-note-to-antenna.ts index e88c387234..f86f394f80 100644 --- a/packages/backend/src/services/add-note-to-antenna.ts +++ b/packages/backend/src/services/add-note-to-antenna.ts @@ -33,10 +33,10 @@ export async function addNoteToAntenna(antenna: Antenna, note: Note, noteUser: { }; if (note.replyId != null) { - _note.reply = await Notes.findOneOrFail(note.replyId); + _note.reply = await Notes.findOneByOrFail({ id: note.replyId }); } if (note.renoteId != null) { - _note.renote = await Notes.findOneOrFail(note.renoteId); + _note.renote = await Notes.findOneByOrFail({ id: note.renoteId }); } if (isMutedUserRelated(_note, new Set(mutings.map(x => x.muteeId)))) { @@ -45,7 +45,7 @@ export async function addNoteToAntenna(antenna: Antenna, note: Note, noteUser: { // 2秒経っても既読にならなかったら通知 setTimeout(async () => { - const unread = await AntennaNotes.findOne({ antennaId: antenna.id, read: false }); + const unread = await AntennaNotes.findOneBy({ antennaId: antenna.id, read: false }); if (unread) { publishMainStream(antenna.userId, 'unreadAntenna', antenna); } diff --git a/packages/backend/src/services/blocking/create.ts b/packages/backend/src/services/blocking/create.ts index 198d28705e..86c7d7967b 100644 --- a/packages/backend/src/services/blocking/create.ts +++ b/packages/backend/src/services/blocking/create.ts @@ -34,7 +34,7 @@ export default async function(blocker: User, blockee: User) { } async function cancelRequest(follower: User, followee: User) { - const request = await FollowRequests.findOne({ + const request = await FollowRequests.findOneBy({ followeeId: followee.id, followerId: follower.id, }); @@ -77,7 +77,7 @@ async function cancelRequest(follower: User, followee: User) { } async function unFollow(follower: User, followee: User) { - const following = await Followings.findOne({ + const following = await Followings.findOneBy({ followerId: follower.id, followeeId: followee.id, }); @@ -116,7 +116,7 @@ async function unFollow(follower: User, followee: User) { } async function removeFromList(listOwner: User, user: User) { - const userLists = await UserLists.find({ + const userLists = await UserLists.findBy({ userId: listOwner.id, }); diff --git a/packages/backend/src/services/blocking/delete.ts b/packages/backend/src/services/blocking/delete.ts index c4f3784b05..d7b5ddd5ff 100644 --- a/packages/backend/src/services/blocking/delete.ts +++ b/packages/backend/src/services/blocking/delete.ts @@ -3,13 +3,13 @@ import renderBlock from '@/remote/activitypub/renderer/block.js'; import renderUndo from '@/remote/activitypub/renderer/undo.js'; import { deliver } from '@/queue/index.js'; import Logger from '../logger.js'; -import { User } from '@/models/entities/user.js'; +import { CacheableUser, User } from '@/models/entities/user.js'; import { Blockings, Users } from '@/models/index.js'; const logger = new Logger('blocking/delete'); -export default async function(blocker: User, blockee: User) { - const blocking = await Blockings.findOne({ +export default async function(blocker: CacheableUser, blockee: CacheableUser) { + const blocking = await Blockings.findOneBy({ blockerId: blocker.id, blockeeId: blockee.id, }); diff --git a/packages/backend/src/services/chart/charts/instance.ts b/packages/backend/src/services/chart/charts/instance.ts index f1257fdf14..fe29ba5228 100644 --- a/packages/backend/src/services/chart/charts/instance.ts +++ b/packages/backend/src/services/chart/charts/instance.ts @@ -22,11 +22,11 @@ export default class InstanceChart extends Chart { followersCount, driveFiles, ] = await Promise.all([ - Notes.count({ userHost: group }), - Users.count({ host: group }), - Followings.count({ followerHost: group }), - Followings.count({ followeeHost: group }), - DriveFiles.count({ userHost: group }), + Notes.countBy({ userHost: group }), + Users.countBy({ host: group }), + Followings.countBy({ followerHost: group }), + Followings.countBy({ followeeHost: group }), + DriveFiles.countBy({ userHost: group }), ]); return { diff --git a/packages/backend/src/services/chart/charts/notes.ts b/packages/backend/src/services/chart/charts/notes.ts index ab6a37e3c1..bb14b62f3c 100644 --- a/packages/backend/src/services/chart/charts/notes.ts +++ b/packages/backend/src/services/chart/charts/notes.ts @@ -15,8 +15,8 @@ export default class NotesChart extends Chart { protected async tickMajor(): Promise>> { const [localCount, remoteCount] = await Promise.all([ - Notes.count({ userHost: null }), - Notes.count({ userHost: Not(IsNull()) }), + Notes.countBy({ userHost: IsNull() }), + Notes.countBy({ userHost: Not(IsNull()) }), ]); return { diff --git a/packages/backend/src/services/chart/charts/per-user-drive.ts b/packages/backend/src/services/chart/charts/per-user-drive.ts index 131befa396..5f75dc6887 100644 --- a/packages/backend/src/services/chart/charts/per-user-drive.ts +++ b/packages/backend/src/services/chart/charts/per-user-drive.ts @@ -14,7 +14,7 @@ export default class PerUserDriveChart extends Chart { protected async tickMajor(group: string): Promise>> { const [count, size] = await Promise.all([ - DriveFiles.count({ userId: group }), + DriveFiles.countBy({ userId: group }), DriveFiles.calcDriveUsageOf(group), ]); diff --git a/packages/backend/src/services/chart/charts/per-user-following.ts b/packages/backend/src/services/chart/charts/per-user-following.ts index 5d5dd1fa1e..02b149f52a 100644 --- a/packages/backend/src/services/chart/charts/per-user-following.ts +++ b/packages/backend/src/services/chart/charts/per-user-following.ts @@ -20,10 +20,10 @@ export default class PerUserFollowingChart extends Chart { remoteFollowingsCount, remoteFollowersCount, ] = await Promise.all([ - Followings.count({ followerId: group, followeeHost: null }), - Followings.count({ followeeId: group, followerHost: null }), - Followings.count({ followerId: group, followeeHost: Not(IsNull()) }), - Followings.count({ followeeId: group, followerHost: Not(IsNull()) }), + Followings.countBy({ followerId: group, followeeHost: IsNull() }), + Followings.countBy({ followeeId: group, followerHost: IsNull() }), + Followings.countBy({ followerId: group, followeeHost: Not(IsNull()) }), + Followings.countBy({ followeeId: group, followerHost: Not(IsNull()) }), ]); return { diff --git a/packages/backend/src/services/chart/charts/per-user-notes.ts b/packages/backend/src/services/chart/charts/per-user-notes.ts index 9c5dea1aa9..b9191dd088 100644 --- a/packages/backend/src/services/chart/charts/per-user-notes.ts +++ b/packages/backend/src/services/chart/charts/per-user-notes.ts @@ -15,7 +15,7 @@ export default class PerUserNotesChart extends Chart { protected async tickMajor(group: string): Promise>> { const [count] = await Promise.all([ - Notes.count({ userId: group }), + Notes.countBy({ userId: group }), ]); return { diff --git a/packages/backend/src/services/chart/charts/users.ts b/packages/backend/src/services/chart/charts/users.ts index fb9d5e15fb..acb16ead87 100644 --- a/packages/backend/src/services/chart/charts/users.ts +++ b/packages/backend/src/services/chart/charts/users.ts @@ -15,8 +15,8 @@ export default class UsersChart extends Chart { protected async tickMajor(): Promise>> { const [localCount, remoteCount] = await Promise.all([ - Users.count({ host: null }), - Users.count({ host: Not(IsNull()) }), + Users.countBy({ host: IsNull() }), + Users.countBy({ host: Not(IsNull()) }), ]); return { diff --git a/packages/backend/src/services/chart/core.ts b/packages/backend/src/services/chart/core.ts index 39fad71dd7..cf69e2194d 100644 --- a/packages/backend/src/services/chart/core.ts +++ b/packages/backend/src/services/chart/core.ts @@ -6,9 +6,10 @@ import * as nestedProperty from 'nested-property'; import Logger from '../logger.js'; -import { EntitySchema, getRepository, Repository, LessThan, Between } from 'typeorm'; +import { EntitySchema, Repository, LessThan, Between } from 'typeorm'; import { dateUTC, isTimeSame, isTimeBefore, subtractTime, addTime } from '@/prelude/time.js'; import { getChartInsertLock } from '@/misc/app-lock.js'; +import { db } from '@/db/postgre.js'; const logger = new Logger('chart', 'white', process.env.NODE_ENV !== 'test'); @@ -241,8 +242,8 @@ export default abstract class Chart { this.schema = schema; const { hour, day } = Chart.schemaToEntity(name, schema, grouped); - this.repositoryForHour = getRepository<{ id: number; group?: string | null; date: number; }>(hour); - this.repositoryForDay = getRepository<{ id: number; group?: string | null; date: number; }>(day); + this.repositoryForHour = db.getRepository<{ id: number; group?: string | null; date: number; }>(hour); + this.repositoryForDay = db.getRepository<{ id: number; group?: string | null; date: number; }>(day); } private convertRawRecord(x: RawRecord): KVs { @@ -271,9 +272,10 @@ export default abstract class Chart { span === 'day' ? this.repositoryForDay : new Error('not happen') as never; - return repository.findOne(group ? { - group: group, - } : {}, { + return repository.findOne({ + where: group ? { + group: group, + } : {}, order: { date: -1, }, @@ -297,7 +299,7 @@ export default abstract class Chart { new Error('not happen') as never; // 現在(=今のHour or Day)のログ - const currentLog = await repository.findOne({ + const currentLog = await repository.findOneBy({ date: Chart.dateToTimestamp(current), ...(group ? { group: group } : {}), }) as RawRecord | undefined; @@ -337,7 +339,7 @@ export default abstract class Chart { const unlock = await getChartInsertLock(lockKey); try { // ロック内でもう1回チェックする - const currentLog = await repository.findOne({ + const currentLog = await repository.findOneBy({ date: date, ...(group ? { group: group } : {}), }) as RawRecord | undefined; @@ -356,7 +358,7 @@ export default abstract class Chart { date: date, ...(group ? { group: group } : {}), ...columns, - }).then(x => repository.findOneOrFail(x.identifiers[0])) as RawRecord; + }).then(x => repository.findOneByOrFail(x.identifiers[0])) as RawRecord; logger.info(`${this.name + (group ? `:${group}` : '')}(${span}): New commit created`); @@ -598,9 +600,10 @@ export default abstract class Chart { if (logs.length === 0) { // もっとも新しいログを持ってくる // (すくなくともひとつログが無いと隙間埋めできないため) - const recentLog = await repository.findOne(group ? { - group: group, - } : {}, { + const recentLog = await repository.findOne({ + where: group ? { + group: group, + } : {}, order: { date: -1, }, @@ -615,9 +618,10 @@ export default abstract class Chart { // 要求された範囲の最も古い箇所時点での最も新しいログを持ってきて末尾に追加する // (隙間埋めできないため) const outdatedLog = await repository.findOne({ - date: LessThan(Chart.dateToTimestamp(gt)), - ...(group ? { group: group } : {}), - }, { + where: { + date: LessThan(Chart.dateToTimestamp(gt)), + ...(group ? { group: group } : {}), + }, order: { date: -1, }, diff --git a/packages/backend/src/services/create-notification.ts b/packages/backend/src/services/create-notification.ts index 74874525e6..d53a4235b8 100644 --- a/packages/backend/src/services/create-notification.ts +++ b/packages/backend/src/services/create-notification.ts @@ -15,7 +15,7 @@ export async function createNotification( return null; } - const profile = await UserProfiles.findOne({ userId: notifieeId }); + const profile = await UserProfiles.findOneBy({ userId: notifieeId }); const isMuted = profile?.mutingNotificationTypes.includes(type); @@ -29,7 +29,7 @@ export async function createNotification( isRead: isMuted, ...data, } as Partial) - .then(x => Notifications.findOneOrFail(x.identifiers[0])); + .then(x => Notifications.findOneByOrFail(x.identifiers[0])); const packed = await Notifications.pack(notification, {}); @@ -38,12 +38,12 @@ export async function createNotification( // 2秒経っても(今回作成した)通知が既読にならなかったら「未読の通知がありますよ」イベントを発行する setTimeout(async () => { - const fresh = await Notifications.findOne(notification.id); + const fresh = await Notifications.findOneBy({ id: notification.id }); if (fresh == null) return; // 既に削除されているかもしれない if (fresh.isRead) return; //#region ただしミュートしているユーザーからの通知なら無視 - const mutings = await Mutings.find({ + const mutings = await Mutings.findBy({ muterId: notifieeId, }); if (data.notifierId && mutings.map(m => m.muteeId).includes(data.notifierId)) { @@ -54,8 +54,8 @@ export async function createNotification( publishMainStream(notifieeId, 'unreadNotification', packed); pushNotification(notifieeId, 'notification', packed); - if (type === 'follow') sendEmailNotification.follow(notifieeId, await Users.findOneOrFail(data.notifierId!)); - if (type === 'receiveFollowRequest') sendEmailNotification.receiveFollowRequest(notifieeId, await Users.findOneOrFail(data.notifierId!)); + if (type === 'follow') sendEmailNotification.follow(notifieeId, await Users.findOneByOrFail({ id: data.notifierId! })); + if (type === 'receiveFollowRequest') sendEmailNotification.receiveFollowRequest(notifieeId, await Users.findOneByOrFail({ id: data.notifierId! })); }, 2000); return notification; diff --git a/packages/backend/src/services/create-system-user.ts b/packages/backend/src/services/create-system-user.ts index 781e0560d1..bae91ec4c3 100644 --- a/packages/backend/src/services/create-system-user.ts +++ b/packages/backend/src/services/create-system-user.ts @@ -4,10 +4,11 @@ import generateNativeUserToken from '../server/api/common/generate-native-user-t import { genRsaKeyPair } from '@/misc/gen-key-pair.js'; import { User } from '@/models/entities/user.js'; import { UserProfile } from '@/models/entities/user-profile.js'; -import { getConnection, ObjectLiteral } from 'typeorm'; +import { IsNull } from 'typeorm'; import { genId } from '@/misc/gen-id.js'; import { UserKeypair } from '@/models/entities/user-keypair.js'; import { UsedUsername } from '@/models/entities/used-username.js'; +import { db } from '@/db/postgre.js'; export async function createSystemUser(username: string) { const password = uuid(); @@ -21,13 +22,13 @@ export async function createSystemUser(username: string) { const keyPair = await genRsaKeyPair(4096); - let account!: User | ObjectLiteral; + let account!: User; // Start transaction - await getConnection().transaction(async transactionalEntityManager => { - const exist = await transactionalEntityManager.findOne(User, { + await db.transaction(async transactionalEntityManager => { + const exist = await transactionalEntityManager.findOneBy(User, { usernameLower: username.toLowerCase(), - host: null, + host: IsNull(), }); if (exist) throw new Error('the user is already exists'); @@ -43,7 +44,7 @@ export async function createSystemUser(username: string) { isLocked: true, isExplorable: false, isBot: true, - }).then(x => transactionalEntityManager.findOneOrFail(User, x.identifiers[0])); + }).then(x => transactionalEntityManager.findOneByOrFail(User, x.identifiers[0])); await transactionalEntityManager.insert(UserKeypair, { publicKey: keyPair.publicKey, diff --git a/packages/backend/src/services/drive/add-file.ts b/packages/backend/src/services/drive/add-file.ts index 8397945668..549b11c9fe 100644 --- a/packages/backend/src/services/drive/add-file.ts +++ b/packages/backend/src/services/drive/add-file.ts @@ -21,6 +21,7 @@ import S3 from 'aws-sdk/clients/s3.js'; import { getS3 } from './s3.js'; import sharp from 'sharp'; import { FILE_TYPE_BROWSERSAFE } from '@/const.js'; +import { IsNull } from 'typeorm'; const logger = driveLogger.createSubLogger('register', 'yellow'); @@ -108,7 +109,7 @@ async function save(file: DriveFile, path: string, name: string, type: string, h file.size = size; file.storedInternal = false; - return await DriveFiles.insert(file).then(x => DriveFiles.findOneOrFail(x.identifiers[0])); + return await DriveFiles.insert(file).then(x => DriveFiles.findOneByOrFail(x.identifiers[0])); } else { // use internal storage const accessKey = uuid(); const thumbnailAccessKey = 'thumbnail-' + uuid(); @@ -142,7 +143,7 @@ async function save(file: DriveFile, path: string, name: string, type: string, h file.md5 = hash; file.size = size; - return await DriveFiles.insert(file).then(x => DriveFiles.findOneOrFail(x.identifiers[0])); + return await DriveFiles.insert(file).then(x => DriveFiles.findOneByOrFail(x.identifiers[0])); } } @@ -344,7 +345,7 @@ export async function addFile({ if (user && !force) { // Check if there is a file with the same hash - const much = await DriveFiles.findOne({ + const much = await DriveFiles.findOneBy({ md5: info.md5, userId: user.id, }); @@ -370,7 +371,7 @@ export async function addFile({ throw new Error('no-free-space'); } else { // (アバターまたはバナーを含まず)最も古いファイルを削除する - deleteOldFile(await Users.findOneOrFail(user.id) as IRemoteUser); + deleteOldFile(await Users.findOneByOrFail({ id: user.id }) as IRemoteUser); } } } @@ -381,9 +382,9 @@ export async function addFile({ return null; } - const driveFolder = await DriveFolders.findOne({ + const driveFolder = await DriveFolders.findOneBy({ id: folderId, - userId: user ? user.id : null, + userId: user ? user.id : IsNull(), }); if (driveFolder == null) throw new Error('folder-not-found'); @@ -405,7 +406,7 @@ export async function addFile({ properties['orientation'] = info.orientation; } - const profile = user ? await UserProfiles.findOne(user.id) : null; + const profile = user ? await UserProfiles.findOneBy({ userId: user.id }) : null; const folder = await fetchFolder(); @@ -450,15 +451,15 @@ export async function addFile({ file.type = info.type.mime; file.storedInternal = false; - file = await DriveFiles.insert(file).then(x => DriveFiles.findOneOrFail(x.identifiers[0])); + file = await DriveFiles.insert(file).then(x => DriveFiles.findOneByOrFail(x.identifiers[0])); } catch (err) { // duplicate key error (when already registered) if (isDuplicateKeyValueError(err)) { logger.info(`already registered ${file.uri}`); - file = await DriveFiles.findOne({ - uri: file.uri, - userId: user ? user.id : null, + file = await DriveFiles.findOneBy({ + uri: file.uri!, + userId: user ? user.id : IsNull(), }) as DriveFile; } else { logger.error(err as Error); diff --git a/packages/backend/src/services/fetch-instance-metadata.ts b/packages/backend/src/services/fetch-instance-metadata.ts index f3a0424abd..2b6f82a910 100644 --- a/packages/backend/src/services/fetch-instance-metadata.ts +++ b/packages/backend/src/services/fetch-instance-metadata.ts @@ -13,7 +13,7 @@ export async function fetchInstanceMetadata(instance: Instance, force = false): const unlock = await getFetchInstanceMetadataLock(instance.host); if (!force) { - const _instance = await Instances.findOne({ host: instance.host }); + const _instance = await Instances.findOneBy({ host: instance.host }); const now = Date.now(); if (_instance && _instance.infoUpdatedAt && (now - _instance.infoUpdatedAt.getTime() < 1000 * 60 * 60 * 24)) { unlock(); diff --git a/packages/backend/src/services/following/create.ts b/packages/backend/src/services/following/create.ts index a416412131..0daf30ddad 100644 --- a/packages/backend/src/services/following/create.ts +++ b/packages/backend/src/services/following/create.ts @@ -45,7 +45,7 @@ export async function insertFollowingDoc(followee: { id: User['id']; host: User[ } }); - const req = await FollowRequests.findOne({ + const req = await FollowRequests.findOneBy({ followeeId: followee.id, followerId: follower.id, }); @@ -108,17 +108,17 @@ export async function insertFollowingDoc(followee: { id: User['id']; host: User[ export default async function(_follower: { id: User['id'] }, _followee: { id: User['id'] }, requestId?: string) { const [follower, followee] = await Promise.all([ - Users.findOneOrFail(_follower.id), - Users.findOneOrFail(_followee.id), + Users.findOneByOrFail({ id: _follower.id }), + Users.findOneByOrFail({ id: _followee.id }), ]); // check blocking const [blocking, blocked] = await Promise.all([ - Blockings.findOne({ + Blockings.findOneBy({ blockerId: follower.id, blockeeId: followee.id, }), - Blockings.findOne({ + Blockings.findOneBy({ blockerId: followee.id, blockeeId: follower.id, }), @@ -138,7 +138,7 @@ export default async function(_follower: { id: User['id'] }, _followee: { id: Us if (blocked != null) throw new IdentifiableError('3338392a-f764-498d-8855-db939dcf8c48', 'blocked'); } - const followeeProfile = await UserProfiles.findOneOrFail(followee.id); + const followeeProfile = await UserProfiles.findOneByOrFail({ userId: followee.id }); // フォロー対象が鍵アカウントである or // フォロワーがBotであり、フォロー対象がBotからのフォローに慎重である or @@ -148,7 +148,7 @@ export default async function(_follower: { id: User['id'] }, _followee: { id: Us let autoAccept = false; // 鍵アカウントであっても、既にフォローされていた場合はスルー - const following = await Followings.findOne({ + const following = await Followings.findOneBy({ followerId: follower.id, followeeId: followee.id, }); @@ -158,7 +158,7 @@ export default async function(_follower: { id: User['id'] }, _followee: { id: Us // フォローしているユーザーは自動承認オプション if (!autoAccept && (Users.isLocalUser(followee) && followeeProfile.autoAcceptFollowed)) { - const followed = await Followings.findOne({ + const followed = await Followings.findOneBy({ followerId: followee.id, followeeId: follower.id, }); diff --git a/packages/backend/src/services/following/delete.ts b/packages/backend/src/services/following/delete.ts index d82c0be52d..35fd664b55 100644 --- a/packages/backend/src/services/following/delete.ts +++ b/packages/backend/src/services/following/delete.ts @@ -13,7 +13,7 @@ import { instanceChart, perUserFollowingChart } from '@/services/chart/index.js' const logger = new Logger('following/delete'); export default async function(follower: { id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox']; }, followee: { id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox']; }, silent = false) { - const following = await Followings.findOne({ + const following = await Followings.findOneBy({ followerId: follower.id, followeeId: followee.id, }); diff --git a/packages/backend/src/services/following/reject.ts b/packages/backend/src/services/following/reject.ts index 3b0cb2ba88..2d1db3c342 100644 --- a/packages/backend/src/services/following/reject.ts +++ b/packages/backend/src/services/following/reject.ts @@ -7,8 +7,17 @@ import { User, ILocalUser, IRemoteUser } from '@/models/entities/user.js'; import { Users, FollowRequests, Followings } from '@/models/index.js'; import { decrementFollowing } from './delete.js'; -type Local = ILocalUser | { id: User['id']; host: User['host']; uri: User['host'] }; -type Remote = IRemoteUser; +type Local = ILocalUser | { + id: ILocalUser['id']; + host: ILocalUser['host']; + uri: ILocalUser['uri'] +}; +type Remote = IRemoteUser | { + id: IRemoteUser['id']; + host: IRemoteUser['host']; + uri: IRemoteUser['uri']; + inbox: IRemoteUser['inbox']; +}; type Both = Local | Remote; /** @@ -54,7 +63,7 @@ export async function remoteReject(actor: Remote, follower: Local) { * Remove follow request record */ async function removeFollowRequest(followee: Both, follower: Both) { - const request = await FollowRequests.findOne({ + const request = await FollowRequests.findOneBy({ followeeId: followee.id, followerId: follower.id, }); @@ -68,7 +77,7 @@ async function removeFollowRequest(followee: Both, follower: Both) { * Remove follow record */ async function removeFollow(followee: Both, follower: Both) { - const following = await Followings.findOne({ + const following = await Followings.findOneBy({ followeeId: followee.id, followerId: follower.id, }); @@ -83,7 +92,7 @@ async function removeFollow(followee: Both, follower: Both) { * Deliver Reject to remote */ async function deliverReject(followee: Local, follower: Remote) { - const request = await FollowRequests.findOne({ + const request = await FollowRequests.findOneBy({ followeeId: followee.id, followerId: follower.id, }); diff --git a/packages/backend/src/services/following/requests/accept-all.ts b/packages/backend/src/services/following/requests/accept-all.ts index a240bec8f4..5fbb549e01 100644 --- a/packages/backend/src/services/following/requests/accept-all.ts +++ b/packages/backend/src/services/following/requests/accept-all.ts @@ -7,12 +7,12 @@ import { FollowRequests, Users } from '@/models/index.js'; * @param user ユーザー */ export default async function(user: { id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox']; }) { - const requests = await FollowRequests.find({ + const requests = await FollowRequests.findBy({ followeeId: user.id, }); for (const request of requests) { - const follower = await Users.findOneOrFail(request.followerId); + const follower = await Users.findOneByOrFail({ id: request.followerId }); accept(user, follower); } } diff --git a/packages/backend/src/services/following/requests/accept.ts b/packages/backend/src/services/following/requests/accept.ts index b8113cd1b1..20829f70c7 100644 --- a/packages/backend/src/services/following/requests/accept.ts +++ b/packages/backend/src/services/following/requests/accept.ts @@ -4,12 +4,12 @@ import renderAccept from '@/remote/activitypub/renderer/accept.js'; import { deliver } from '@/queue/index.js'; import { publishMainStream } from '@/services/stream.js'; import { insertFollowingDoc } from '../create.js'; -import { User, ILocalUser } from '@/models/entities/user.js'; +import { User, ILocalUser, CacheableUser } from '@/models/entities/user.js'; import { FollowRequests, Users } from '@/models/index.js'; import { IdentifiableError } from '@/misc/identifiable-error.js'; -export default async function(followee: { id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox']; }, follower: User) { - const request = await FollowRequests.findOne({ +export default async function(followee: { id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox']; }, follower: CacheableUser) { + const request = await FollowRequests.findOneBy({ followeeId: followee.id, followerId: follower.id, }); diff --git a/packages/backend/src/services/following/requests/cancel.ts b/packages/backend/src/services/following/requests/cancel.ts index ca9777d38b..56531fa1fd 100644 --- a/packages/backend/src/services/following/requests/cancel.ts +++ b/packages/backend/src/services/following/requests/cancel.ts @@ -16,7 +16,7 @@ export default async function(followee: { id: User['id']; host: User['host']; ur } } - const request = await FollowRequests.findOne({ + const request = await FollowRequests.findOneBy({ followeeId: followee.id, followerId: follower.id, }); diff --git a/packages/backend/src/services/following/requests/create.ts b/packages/backend/src/services/following/requests/create.ts index bca607d7e4..bda2f8f92d 100644 --- a/packages/backend/src/services/following/requests/create.ts +++ b/packages/backend/src/services/following/requests/create.ts @@ -12,11 +12,11 @@ export default async function(follower: { id: User['id']; host: User['host']; ur // check blocking const [blocking, blocked] = await Promise.all([ - Blockings.findOne({ + Blockings.findOneBy({ blockerId: follower.id, blockeeId: followee.id, }), - Blockings.findOne({ + Blockings.findOneBy({ blockerId: followee.id, blockeeId: follower.id, }), @@ -39,7 +39,7 @@ export default async function(follower: { id: User['id']; host: User['host']; ur followeeHost: followee.host, followeeInbox: Users.isRemoteUser(followee) ? followee.inbox : undefined, followeeSharedInbox: Users.isRemoteUser(followee) ? followee.sharedInbox : undefined, - }).then(x => FollowRequests.findOneOrFail(x.identifiers[0])); + }).then(x => FollowRequests.findOneByOrFail(x.identifiers[0])); // Publish receiveRequest event if (Users.isLocalUser(followee)) { diff --git a/packages/backend/src/services/i/pin.ts b/packages/backend/src/services/i/pin.ts index 06d7e79e89..f35392a34b 100644 --- a/packages/backend/src/services/i/pin.ts +++ b/packages/backend/src/services/i/pin.ts @@ -18,7 +18,7 @@ import { deliverToRelays } from '../relay.js'; */ export async function addPinned(user: { id: User['id']; host: User['host']; }, noteId: Note['id']) { // Fetch pinee - const note = await Notes.findOne({ + const note = await Notes.findOneBy({ id: noteId, userId: user.id, }); @@ -27,7 +27,7 @@ export async function addPinned(user: { id: User['id']; host: User['host']; }, n throw new IdentifiableError('70c4e51f-5bea-449c-a030-53bee3cce202', 'No such note.'); } - const pinings = await UserNotePinings.find({ userId: user.id }); + const pinings = await UserNotePinings.findBy({ userId: user.id }); if (pinings.length >= 5) { throw new IdentifiableError('15a018eb-58e5-4da1-93be-330fcc5e4e1a', 'You can not pin notes any more.'); @@ -57,7 +57,7 @@ export async function addPinned(user: { id: User['id']; host: User['host']; }, n */ export async function removePinned(user: { id: User['id']; host: User['host']; }, noteId: Note['id']) { // Fetch unpinee - const note = await Notes.findOne({ + const note = await Notes.findOneBy({ id: noteId, userId: user.id, }); @@ -78,7 +78,7 @@ export async function removePinned(user: { id: User['id']; host: User['host']; } } export async function deliverPinnedChange(userId: User['id'], noteId: Note['id'], isAddition: boolean) { - const user = await Users.findOne(userId); + const user = await Users.findOneBy({ id: userId }); if (user == null) throw new Error('user not found'); if (!Users.isLocalUser(user)) return; diff --git a/packages/backend/src/services/i/update.ts b/packages/backend/src/services/i/update.ts index 1fbaf40df1..27bd38bd39 100644 --- a/packages/backend/src/services/i/update.ts +++ b/packages/backend/src/services/i/update.ts @@ -7,7 +7,7 @@ import { deliverToFollowers } from '@/remote/activitypub/deliver-manager.js'; import { deliverToRelays } from '../relay.js'; export async function publishToFollowers(userId: User['id']) { - const user = await Users.findOne(userId); + const user = await Users.findOneBy({ id: userId }); if (user == null) throw new Error('user not found'); // フォロワーがリモートユーザーかつ投稿者がローカルユーザーならUpdateを配信 diff --git a/packages/backend/src/services/instance-actor.ts b/packages/backend/src/services/instance-actor.ts index e271710488..bddd0355a2 100644 --- a/packages/backend/src/services/instance-actor.ts +++ b/packages/backend/src/services/instance-actor.ts @@ -2,6 +2,7 @@ import { createSystemUser } from './create-system-user.js'; import { ILocalUser } from '@/models/entities/user.js'; import { Users } from '@/models/index.js'; import { Cache } from '@/misc/cache.js'; +import { IsNull } from 'typeorm'; const ACTOR_USERNAME = 'instance.actor' as const; @@ -11,8 +12,8 @@ export async function getInstanceActor(): Promise { const cached = cache.get(null); if (cached) return cached; - const user = await Users.findOne({ - host: null, + const user = await Users.findOneBy({ + host: IsNull(), username: ACTOR_USERNAME, }) as ILocalUser | undefined; diff --git a/packages/backend/src/services/messages/create.ts b/packages/backend/src/services/messages/create.ts index 094a00ae44..e6b3204922 100644 --- a/packages/backend/src/services/messages/create.ts +++ b/packages/backend/src/services/messages/create.ts @@ -1,4 +1,4 @@ -import { User } from '@/models/entities/user.js'; +import { CacheableUser, User } from '@/models/entities/user.js'; import { UserGroup } from '@/models/entities/user-group.js'; import { DriveFile } from '@/models/entities/drive-file.js'; import { MessagingMessages, UserGroupJoinings, Mutings, Users } from '@/models/index.js'; @@ -13,7 +13,7 @@ import renderCreate from '@/remote/activitypub/renderer/create.js'; import { renderActivity } from '@/remote/activitypub/renderer/index.js'; import { deliver } from '@/queue/index.js'; -export async function createMessage(user: { id: User['id']; host: User['host']; }, recipientUser: User | undefined, recipientGroup: UserGroup | undefined, text: string | null | undefined, file: DriveFile | null, uri?: string) { +export async function createMessage(user: { id: User['id']; host: User['host']; }, recipientUser: CacheableUser | undefined, recipientGroup: UserGroup | undefined, text: string | null | undefined, file: DriveFile | null, uri?: string) { const message = { id: genId(), createdAt: new Date(), @@ -50,7 +50,7 @@ export async function createMessage(user: { id: User['id']; host: User['host']; publishGroupMessagingStream(recipientGroup.id, 'message', messageObj); // メンバーのストリーム - const joinings = await UserGroupJoinings.find({ userGroupId: recipientGroup.id }); + const joinings = await UserGroupJoinings.findBy({ userGroupId: recipientGroup.id }); for (const joining of joinings) { publishMessagingIndexStream(joining.userId, 'message', messageObj); publishMainStream(joining.userId, 'messagingMessage', messageObj); @@ -59,14 +59,14 @@ export async function createMessage(user: { id: User['id']; host: User['host']; // 2秒経っても(今回作成した)メッセージが既読にならなかったら「未読のメッセージがありますよ」イベントを発行する setTimeout(async () => { - const freshMessage = await MessagingMessages.findOne(message.id); + const freshMessage = await MessagingMessages.findOneBy({ id: message.id }); if (freshMessage == null) return; // メッセージが削除されている場合もある if (recipientUser && Users.isLocalUser(recipientUser)) { if (freshMessage.isRead) return; // 既読 //#region ただしミュートされているなら発行しない - const mute = await Mutings.find({ + const mute = await Mutings.findBy({ muterId: recipientUser.id, }); if (mute.map(m => m.muteeId).includes(user.id)) return; @@ -75,7 +75,7 @@ export async function createMessage(user: { id: User['id']; host: User['host']; publishMainStream(recipientUser.id, 'unreadMessagingMessage', messageObj); pushNotification(recipientUser.id, 'unreadMessagingMessage', messageObj); } else if (recipientGroup) { - const joinings = await UserGroupJoinings.find({ userGroupId: recipientGroup.id, userId: Not(user.id) }); + const joinings = await UserGroupJoinings.findBy({ userGroupId: recipientGroup.id, userId: Not(user.id) }); for (const joining of joinings) { if (freshMessage.reads.includes(joining.userId)) return; // 既読 publishMainStream(joining.userId, 'unreadMessagingMessage', messageObj); diff --git a/packages/backend/src/services/messages/delete.ts b/packages/backend/src/services/messages/delete.ts index 82eb6cb21c..1e7ce1981c 100644 --- a/packages/backend/src/services/messages/delete.ts +++ b/packages/backend/src/services/messages/delete.ts @@ -14,8 +14,8 @@ export async function deleteMessage(message: MessagingMessage) { async function postDeleteMessage(message: MessagingMessage) { if (message.recipientId) { - const user = await Users.findOneOrFail(message.userId); - const recipient = await Users.findOneOrFail(message.recipientId); + const user = await Users.findOneByOrFail({ id: message.userId }); + const recipient = await Users.findOneByOrFail({ id: message.recipientId }); if (Users.isLocalUser(user)) publishMessagingStream(message.userId, message.recipientId, 'deleted', message.id); if (Users.isLocalUser(recipient)) publishMessagingStream(message.recipientId, message.userId, 'deleted', message.id); diff --git a/packages/backend/src/services/note/create.ts b/packages/backend/src/services/note/create.ts index b295534cd2..2ed194b7e9 100644 --- a/packages/backend/src/services/note/create.ts +++ b/packages/backend/src/services/note/create.ts @@ -19,7 +19,7 @@ import { Note, IMentionedRemoteUsers } from '@/models/entities/note.js'; import { Mutings, Users, NoteWatchings, Notes, Instances, UserProfiles, Antennas, Followings, MutedNotes, Channels, ChannelFollowings, Blockings, NoteThreadMutings } from '@/models/index.js'; import { DriveFile } from '@/models/entities/drive-file.js'; import { App } from '@/models/entities/app.js'; -import { Not, getConnection, In } from 'typeorm'; +import { Not, In } from 'typeorm'; import { User, ILocalUser, IRemoteUser } from '@/models/entities/user.js'; import { genId } from '@/misc/gen-id.js'; import { notesChart, perUserNotesChart, activeUsersChart, instanceChart } from '@/services/chart/index.js'; @@ -37,8 +37,7 @@ import { getAntennas } from '@/misc/antenna-cache.js'; import { endedPollNotificationQueue } from '@/queue/queues.js'; import { Cache } from '@/misc/cache.js'; import { UserProfile } from '@/models/entities/user-profile.js'; - -const usersCache = new Cache(Infinity); +import { db } from '@/db/postgre.js'; const mutedWordsCache = new Cache<{ userId: UserProfile['userId']; mutedWords: UserProfile['mutedWords']; }[]>(1000 * 60 * 5); @@ -80,7 +79,7 @@ class NotificationManager { public async deliver() { for (const x of this.queue) { // ミュート情報を取得 - const mentioneeMutes = await Mutings.find({ + const mentioneeMutes = await Mutings.findBy({ muterId: x.target, }); @@ -130,7 +129,7 @@ export default async (user: { id: User['id']; username: User['username']; host: // (クライアントサイドでやっても良い処理だと思うけどとりあえずサーバーサイドで) if (data.reply && data.channel && data.reply.channelId !== data.channel.id) { if (data.reply.channelId) { - data.channel = await Channels.findOne(data.reply.channelId); + data.channel = await Channels.findOneBy({ id: data.reply.channelId }); } else { data.channel = null; } @@ -139,7 +138,7 @@ export default async (user: { id: User['id']; username: User['username']; host: // チャンネル内にリプライしたら対象のスコープに合わせる // (クライアントサイドでやっても良い処理だと思うけどとりあえずサーバーサイドで) if (data.reply && (data.channel == null) && data.reply.channelId) { - data.channel = await Channels.findOne(data.reply.channelId); + data.channel = await Channels.findOneBy({ id: data.reply.channelId }); } if (data.createdAt == null) data.createdAt = new Date(); @@ -212,7 +211,7 @@ export default async (user: { id: User['id']; username: User['username']; host: tags = tags.filter(tag => Array.from(tag || '').length <= 128).splice(0, 32); if (data.reply && (user.id !== data.reply.userId) && !mentionedUsers.some(u => u.id === data.reply!.userId)) { - mentionedUsers.push(await usersCache.fetch(data.reply.userId, () => Users.findOneOrFail(data.reply!.userId))); + mentionedUsers.push(await Users.findOneByOrFail({ id: data.reply!.userId })); } if (data.visibility === 'specified') { @@ -225,7 +224,7 @@ export default async (user: { id: User['id']; username: User['username']; host: } if (data.reply && !data.visibleUsers.some(x => x.id === data.reply!.userId)) { - data.visibleUsers.push(await usersCache.fetch(data.reply.userId, () => Users.findOneOrFail(data.reply!.userId))); + data.visibleUsers.push(await Users.findOneByOrFail({ id: data.reply!.userId })); } } @@ -285,7 +284,7 @@ export default async (user: { id: User['id']; username: User['username']; host: // Channel if (note.channelId) { - ChannelFollowings.find({ followeeId: note.channelId }).then(followings => { + ChannelFollowings.findBy({ followeeId: note.channelId }).then(followings => { for (const following of followings) { insertNoteUnread(following.followerId, note, { isSpecified: false, @@ -358,7 +357,7 @@ export default async (user: { id: User['id']; username: User['username']; host: // 通知 if (data.reply.userHost === null) { - const threadMuted = await NoteThreadMutings.findOne({ + const threadMuted = await NoteThreadMutings.findOneBy({ userId: data.reply.userId, threadId: data.reply.threadId || data.reply.id, }); @@ -405,13 +404,13 @@ export default async (user: { id: User['id']; username: User['username']; host: // 投稿がリプライかつ投稿者がローカルユーザーかつリプライ先の投稿の投稿者がリモートユーザーなら配送 if (data.reply && data.reply.userHost !== null) { - const u = await Users.findOne(data.reply.userId); + const u = await Users.findOneBy({ id: data.reply.userId }); if (u && Users.isRemoteUser(u)) dm.addDirectRecipe(u); } // 投稿がRenoteかつ投稿者がローカルユーザーかつRenote元の投稿の投稿者がリモートユーザーなら配送 if (data.renote && data.renote.userHost !== null) { - const u = await Users.findOne(data.renote.userId); + const u = await Users.findOneBy({ id: data.renote.userId }); if (u && Users.isRemoteUser(u)) dm.addDirectRecipe(u); } @@ -436,7 +435,7 @@ export default async (user: { id: User['id']; username: User['username']; host: lastNotedAt: new Date(), }); - Notes.count({ + Notes.countBy({ userId: user.id, channelId: data.channel.id, }).then(count => { @@ -516,7 +515,7 @@ async function insertNote(user: { id: User['id']; host: User['host']; }, data: O // Append mentions data if (mentionedUsers.length > 0) { insert.mentions = mentionedUsers.map(u => u.id); - const profiles = await UserProfiles.find({ userId: In(insert.mentions) }); + const profiles = await UserProfiles.findBy({ userId: In(insert.mentions) }); insert.mentionedRemoteUsers = JSON.stringify(mentionedUsers.filter(u => Users.isRemoteUser(u)).map(u => { const profile = profiles.find(p => p.userId === u.id); const url = profile != null ? profile.url : null; @@ -533,7 +532,7 @@ async function insertNote(user: { id: User['id']; host: User['host']; }, data: O try { if (insert.hasPoll) { // Start transaction - await getConnection().transaction(async transactionalEntityManager => { + await db.transaction(async transactionalEntityManager => { await transactionalEntityManager.insert(Note, insert); const poll = new Poll({ @@ -583,7 +582,7 @@ function index(note: Note) { } async function notifyToWatchersOfRenotee(renote: Note, user: { id: User['id']; }, nm: NotificationManager, type: NotificationType) { - const watchers = await NoteWatchings.find({ + const watchers = await NoteWatchings.findBy({ noteId: renote.id, userId: Not(user.id), }); @@ -594,7 +593,7 @@ async function notifyToWatchersOfRenotee(renote: Note, user: { id: User['id']; } } async function notifyToWatchersOfReplyee(reply: Note, user: { id: User['id']; }, nm: NotificationManager) { - const watchers = await NoteWatchings.find({ + const watchers = await NoteWatchings.findBy({ noteId: reply.id, userId: Not(user.id), }); @@ -606,7 +605,7 @@ async function notifyToWatchersOfReplyee(reply: Note, user: { id: User['id']; }, async function createMentionedEvents(mentionedUsers: MinimumUser[], note: Note, nm: NotificationManager) { for (const u of mentionedUsers.filter(u => Users.isLocalUser(u))) { - const threadMuted = await NoteThreadMutings.findOne({ + const threadMuted = await NoteThreadMutings.findOneBy({ userId: u.id, threadId: note.threadId || note.id, }); diff --git a/packages/backend/src/services/note/delete.ts b/packages/backend/src/services/note/delete.ts index 356dc39727..ffd609dd84 100644 --- a/packages/backend/src/services/note/delete.ts +++ b/packages/backend/src/services/note/delete.ts @@ -20,7 +20,7 @@ import { Brackets, In } from 'typeorm'; * @param user 投稿者 * @param note 投稿 */ -export default async function(user: User, note: Note, quiet = false) { +export default async function(user: { id: User['id']; uri: User['uri']; host: User['host']; }, note: Note, quiet = false) { const deletedAt = new Date(); // この投稿を除く指定したユーザーによる指定したノートのリノートが存在しないとき @@ -40,11 +40,11 @@ export default async function(user: User, note: Note, quiet = false) { //#region ローカルの投稿なら削除アクティビティを配送 if (Users.isLocalUser(user) && !note.localOnly) { - let renote: Note | undefined; + let renote: Note | null; // if deletd note is renote if (note.renoteId && note.text == null && !note.hasPoll && (note.fileIds == null || note.fileIds.length === 0)) { - renote = await Notes.findOne({ + renote = await Notes.findOneBy({ id: note.renoteId, }); } @@ -131,7 +131,7 @@ async function getMentionedRemoteUsers(note: Note) { }) as IRemoteUser[]; } -async function deliverToConcerned(user: ILocalUser, note: Note, content: any) { +async function deliverToConcerned(user: { id: ILocalUser['id']; host: null; }, note: Note, content: any) { deliverToFollowers(user, content); deliverToRelays(user, content); const remoteUsers = await getMentionedRemoteUsers(note); diff --git a/packages/backend/src/services/note/polls/update.ts b/packages/backend/src/services/note/polls/update.ts index 88baf16b64..43ca3eff4d 100644 --- a/packages/backend/src/services/note/polls/update.ts +++ b/packages/backend/src/services/note/polls/update.ts @@ -7,10 +7,10 @@ import { deliverToFollowers } from '@/remote/activitypub/deliver-manager.js'; import { deliverToRelays } from '../../relay.js'; export async function deliverQuestionUpdate(noteId: Note['id']) { - const note = await Notes.findOne(noteId); + const note = await Notes.findOneBy({ id: noteId }); if (note == null) throw new Error('note not found'); - const user = await Users.findOne(note.userId); + const user = await Users.findOneBy({ id: note.userId }); if (user == null) throw new Error('note not found'); if (Users.isLocalUser(user)) { diff --git a/packages/backend/src/services/note/polls/vote.ts b/packages/backend/src/services/note/polls/vote.ts index 9b83b1953f..84d98769d9 100644 --- a/packages/backend/src/services/note/polls/vote.ts +++ b/packages/backend/src/services/note/polls/vote.ts @@ -1,13 +1,13 @@ import { publishNoteStream } from '@/services/stream.js'; -import { User } from '@/models/entities/user.js'; +import { CacheableUser, User } from '@/models/entities/user.js'; import { Note } from '@/models/entities/note.js'; import { PollVotes, NoteWatchings, Polls, Blockings } from '@/models/index.js'; import { Not } from 'typeorm'; import { genId } from '@/misc/gen-id.js'; import { createNotification } from '../../create-notification.js'; -export default async function(user: User, note: Note, choice: number) { - const poll = await Polls.findOne(note.id); +export default async function(user: CacheableUser, note: Note, choice: number) { + const poll = await Polls.findOneBy({ noteId: note.id }); if (poll == null) throw new Error('poll not found'); @@ -16,7 +16,7 @@ export default async function(user: User, note: Note, choice: number) { // Check blocking if (note.userId !== user.id) { - const block = await Blockings.findOne({ + const block = await Blockings.findOneBy({ blockerId: note.userId, blockeeId: user.id, }); @@ -26,7 +26,7 @@ export default async function(user: User, note: Note, choice: number) { } // if already voted - const exist = await PollVotes.find({ + const exist = await PollVotes.findBy({ noteId: note.id, userId: user.id, }); @@ -65,7 +65,7 @@ export default async function(user: User, note: Note, choice: number) { }); // Fetch watchers - NoteWatchings.find({ + NoteWatchings.findBy({ noteId: note.id, userId: Not(user.id), }) diff --git a/packages/backend/src/services/note/reaction/create.ts b/packages/backend/src/services/note/reaction/create.ts index 236aa79938..5a0948bca9 100644 --- a/packages/backend/src/services/note/reaction/create.ts +++ b/packages/backend/src/services/note/reaction/create.ts @@ -6,7 +6,7 @@ import { toDbReaction, decodeReaction } from '@/misc/reaction-lib.js'; import { User, IRemoteUser } from '@/models/entities/user.js'; import { Note } from '@/models/entities/note.js'; import { NoteReactions, Users, NoteWatchings, Notes, Emojis, Blockings } from '@/models/index.js'; -import { Not } from 'typeorm'; +import { IsNull, Not } from 'typeorm'; import { perUserReactionsChart } from '@/services/chart/index.js'; import { genId } from '@/misc/gen-id.js'; import { createNotification } from '../../create-notification.js'; @@ -18,7 +18,7 @@ import { IdentifiableError } from '@/misc/identifiable-error.js'; export default async (user: { id: User['id']; host: User['host']; }, note: Note, reaction?: string) => { // Check blocking if (note.userId !== user.id) { - const block = await Blockings.findOne({ + const block = await Blockings.findOneBy({ blockerId: note.userId, blockeeId: user.id, }); @@ -43,7 +43,7 @@ export default async (user: { id: User['id']; host: User['host']; }, note: Note, await NoteReactions.insert(record); } catch (e) { if (isDuplicateKeyValueError(e)) { - const exists = await NoteReactions.findOneOrFail({ + const exists = await NoteReactions.findOneByOrFail({ noteId: note.id, userId: user.id, }); @@ -79,7 +79,7 @@ export default async (user: { id: User['id']; host: User['host']; }, note: Note, const emoji = await Emojis.findOne({ where: { name: decodedReaction.name, - host: decodedReaction.host, + host: decodedReaction.host ?? IsNull(), }, select: ['name', 'host', 'originalUrl', 'publicUrl'], }); @@ -103,7 +103,7 @@ export default async (user: { id: User['id']; host: User['host']; }, note: Note, } // Fetch watchers - NoteWatchings.find({ + NoteWatchings.findBy({ noteId: note.id, userId: Not(user.id), }).then(watchers => { @@ -121,10 +121,19 @@ export default async (user: { id: User['id']; host: User['host']; }, note: Note, const content = renderActivity(await renderLike(record, note)); const dm = new DeliverManager(user, content); if (note.userHost !== null) { - const reactee = await Users.findOne(note.userId); + const reactee = await Users.findOneBy({ id: note.userId }); dm.addDirectRecipe(reactee as IRemoteUser); } - dm.addFollowersRecipe(); + + if (['public', 'home', 'followers'].includes(note.visibility)) { + dm.addFollowersRecipe(); + } else if (note.visibility === 'specified') { + const visibleUsers = await Promise.all(note.visibleUserIds.map(id => Users.findOneBy({ id }))); + for (const u of visibleUsers.filter(u => u && Users.isRemoteUser(u))) { + dm.addDirectRecipe(u as IRemoteUser); + } + } + dm.execute(); } //#endregion diff --git a/packages/backend/src/services/note/reaction/delete.ts b/packages/backend/src/services/note/reaction/delete.ts index 62b00f56fd..a7cbcb1c17 100644 --- a/packages/backend/src/services/note/reaction/delete.ts +++ b/packages/backend/src/services/note/reaction/delete.ts @@ -11,7 +11,7 @@ import { decodeReaction } from '@/misc/reaction-lib.js'; export default async (user: { id: User['id']; host: User['host']; }, note: Note) => { // if already unreacted - const exist = await NoteReactions.findOne({ + const exist = await NoteReactions.findOneBy({ noteId: note.id, userId: user.id, }); @@ -48,7 +48,7 @@ export default async (user: { id: User['id']; host: User['host']; }, note: Note) const content = renderActivity(renderUndo(await renderLike(exist, note), user)); const dm = new DeliverManager(user, content); if (note.userHost !== null) { - const reactee = await Users.findOne(note.userId); + const reactee = await Users.findOneBy({ id: note.userId }); dm.addDirectRecipe(reactee as IRemoteUser); } dm.addFollowersRecipe(); diff --git a/packages/backend/src/services/note/read.ts b/packages/backend/src/services/note/read.ts index 28827c5965..915a9e9eef 100644 --- a/packages/backend/src/services/note/read.ts +++ b/packages/backend/src/services/note/read.ts @@ -68,7 +68,7 @@ export default async function( // TODO: ↓まとめてクエリしたい - NoteUnreads.count({ + NoteUnreads.countBy({ userId: userId, isMentioned: true, }).then(mentionsCount => { @@ -78,7 +78,7 @@ export default async function( } }); - NoteUnreads.count({ + NoteUnreads.countBy({ userId: userId, isSpecified: true, }).then(specifiedCount => { @@ -88,7 +88,7 @@ export default async function( } }); - NoteUnreads.count({ + NoteUnreads.countBy({ userId: userId, noteChannelId: Not(IsNull()), }).then(channelNoteCount => { @@ -113,7 +113,7 @@ export default async function( // TODO: まとめてクエリしたい for (const antenna of myAntennas) { - const count = await AntennaNotes.count({ + const count = await AntennaNotes.countBy({ antennaId: antenna.id, read: false, }); diff --git a/packages/backend/src/services/note/unread.ts b/packages/backend/src/services/note/unread.ts index ef95dc7e8c..d9ed711e03 100644 --- a/packages/backend/src/services/note/unread.ts +++ b/packages/backend/src/services/note/unread.ts @@ -11,14 +11,14 @@ export async function insertNoteUnread(userId: User['id'], note: Note, params: { }) { //#region ミュートしているなら無視 // TODO: 現在の仕様ではChannelにミュートは適用されないのでよしなにケアする - const mute = await Mutings.find({ + const mute = await Mutings.findBy({ muterId: userId, }); if (mute.map(m => m.muteeId).includes(note.userId)) return; //#endregion // スレッドミュート - const threadMute = await NoteThreadMutings.findOne({ + const threadMute = await NoteThreadMutings.findOneBy({ userId: userId, threadId: note.threadId || note.id, }); @@ -38,7 +38,7 @@ export async function insertNoteUnread(userId: User['id'], note: Note, params: { // 2秒経っても既読にならなかったら「未読の投稿がありますよ」イベントを発行する setTimeout(async () => { - const exist = await NoteUnreads.findOne(unread.id); + const exist = await NoteUnreads.findOneBy({ id: unread.id }); if (exist == null) return; diff --git a/packages/backend/src/services/push-notification.ts b/packages/backend/src/services/push-notification.ts index b782b7a9f0..5c3bafbb34 100644 --- a/packages/backend/src/services/push-notification.ts +++ b/packages/backend/src/services/push-notification.ts @@ -47,7 +47,7 @@ export async function pushNotification(u meta.swPrivateKey); // Fetch - const subscriptions = await SwSubscriptions.find({ + const subscriptions = await SwSubscriptions.findBy({ userId: userId, }); diff --git a/packages/backend/src/services/register-or-fetch-instance-doc.ts b/packages/backend/src/services/register-or-fetch-instance-doc.ts index 152930dbd9..df7d125d0b 100644 --- a/packages/backend/src/services/register-or-fetch-instance-doc.ts +++ b/packages/backend/src/services/register-or-fetch-instance-doc.ts @@ -12,7 +12,7 @@ export async function registerOrFetchInstanceDoc(host: string): Promise Instances.findOneOrFail(x.identifiers[0])); + }).then(x => Instances.findOneByOrFail(x.identifiers[0])); cache.set(host, i); return i; diff --git a/packages/backend/src/services/relay.ts b/packages/backend/src/services/relay.ts index 6f0da503fc..1ab45588da 100644 --- a/packages/backend/src/services/relay.ts +++ b/packages/backend/src/services/relay.ts @@ -6,12 +6,17 @@ import { deliver } from '@/queue/index.js'; import { ILocalUser, User } from '@/models/entities/user.js'; import { Users, Relays } from '@/models/index.js'; import { genId } from '@/misc/gen-id.js'; +import { Cache } from '@/misc/cache.js'; +import { Relay } from '@/models/entities/relay.js'; +import { IsNull } from 'typeorm'; const ACTOR_USERNAME = 'relay.actor' as const; +const relaysCache = new Cache(1000 * 60 * 10); + export async function getRelayActor(): Promise { - const user = await Users.findOne({ - host: null, + const user = await Users.findOneBy({ + host: IsNull(), username: ACTOR_USERNAME, }); @@ -26,7 +31,7 @@ export async function addRelay(inbox: string) { id: genId(), inbox, status: 'requesting', - }).then(x => Relays.findOneOrFail(x.identifiers[0])); + }).then(x => Relays.findOneByOrFail(x.identifiers[0])); const relayActor = await getRelayActor(); const follow = await renderFollowRelay(relay, relayActor); @@ -37,7 +42,7 @@ export async function addRelay(inbox: string) { } export async function removeRelay(inbox: string) { - const relay = await Relays.findOne({ + const relay = await Relays.findOneBy({ inbox, }); @@ -78,9 +83,9 @@ export async function relayRejected(id: string) { export async function deliverToRelays(user: { id: User['id']; host: null; }, activity: any) { if (activity == null) return; - const relays = await Relays.find({ + const relays = await relaysCache.fetch(null, () => Relays.findBy({ status: 'accepted', - }); + })); if (relays.length === 0) return; const copy = JSON.parse(JSON.stringify(activity)); diff --git a/packages/backend/src/services/send-email-notification.ts b/packages/backend/src/services/send-email-notification.ts index debaf3476d..4a2f94b425 100644 --- a/packages/backend/src/services/send-email-notification.ts +++ b/packages/backend/src/services/send-email-notification.ts @@ -10,7 +10,7 @@ import * as Acct from '@/misc/acct.js'; async function follow(userId: User['id'], follower: User) { /* - const userProfile = await UserProfiles.findOneOrFail({ userId: userId }); + const userProfile = await UserProfiles.findOneByOrFail({ userId: userId }); if (!userProfile.email || !userProfile.emailNotificationTypes.includes('follow')) return; const locale = locales[userProfile.lang || 'ja-JP']; const i18n = new I18n(locale); @@ -21,7 +21,7 @@ async function follow(userId: User['id'], follower: User) { async function receiveFollowRequest(userId: User['id'], follower: User) { /* - const userProfile = await UserProfiles.findOneOrFail({ userId: userId }); + const userProfile = await UserProfiles.findOneByOrFail({ userId: userId }); if (!userProfile.email || !userProfile.emailNotificationTypes.includes('receiveFollowRequest')) return; const locale = locales[userProfile.lang || 'ja-JP']; const i18n = new I18n(locale); diff --git a/packages/backend/src/services/suspend-user.ts b/packages/backend/src/services/suspend-user.ts index 033311a3cc..e96b06a351 100644 --- a/packages/backend/src/services/suspend-user.ts +++ b/packages/backend/src/services/suspend-user.ts @@ -5,8 +5,11 @@ import config from '@/config/index.js'; import { User } from '@/models/entities/user.js'; import { Users, Followings } from '@/models/index.js'; import { Not, IsNull } from 'typeorm'; +import { publishInternalEvent } from '@/services/stream.js'; export async function doPostSuspend(user: { id: User['id']; host: User['host'] }) { + publishInternalEvent('userChangeSuspendedState', { id: user.id, isSuspended: true }); + if (Users.isLocalUser(user)) { // 知り得る全SharedInboxにDelete配信 const content = renderActivity(renderDelete(`${config.url}/users/${user.id}`, user)); diff --git a/packages/backend/src/services/unsuspend-user.ts b/packages/backend/src/services/unsuspend-user.ts index 3be081d0ed..44a0d01ca2 100644 --- a/packages/backend/src/services/unsuspend-user.ts +++ b/packages/backend/src/services/unsuspend-user.ts @@ -6,8 +6,11 @@ import config from '@/config/index.js'; import { User } from '@/models/entities/user.js'; import { Users, Followings } from '@/models/index.js'; import { Not, IsNull } from 'typeorm'; +import { publishInternalEvent } from '@/services/stream.js'; export async function doPostUnsuspend(user: User) { + publishInternalEvent('userChangeSuspendedState', { id: user.id, isSuspended: false }); + if (Users.isLocalUser(user)) { // 知り得る全SharedInboxにUndo Delete配信 const content = renderActivity(renderUndo(renderDelete(`${config.url}/users/${user.id}`, user), user)); diff --git a/packages/backend/src/services/update-hashtag.ts b/packages/backend/src/services/update-hashtag.ts index b6fb38bc5a..23b210b7a9 100644 --- a/packages/backend/src/services/update-hashtag.ts +++ b/packages/backend/src/services/update-hashtag.ts @@ -24,7 +24,7 @@ export async function updateUsertags(user: User, tags: string[]) { export async function updateHashtag(user: { id: User['id']; host: User['host']; }, tag: string, isUserAttached = false, inc = true) { tag = normalizeForSearch(tag); - const index = await Hashtags.findOne({ name: tag }); + const index = await Hashtags.findOneBy({ name: tag }); if (index == null && !inc) return; diff --git a/packages/backend/src/services/user-cache.ts b/packages/backend/src/services/user-cache.ts new file mode 100644 index 0000000000..407301f2fd --- /dev/null +++ b/packages/backend/src/services/user-cache.ts @@ -0,0 +1,44 @@ +import { CacheableLocalUser, CacheableUser, ILocalUser, User } from '@/models/entities/user.js'; +import { Users } from '@/models/index.js'; +import { Cache } from '@/misc/cache.js'; +import { subsdcriber } from '@/db/redis.js'; + +export const userByIdCache = new Cache(Infinity); +export const localUserByNativeTokenCache = new Cache(Infinity); +export const localUserByIdCache = new Cache(Infinity); +export const uriPersonCache = new Cache(Infinity); + +subsdcriber.on('message', async (_, data) => { + const obj = JSON.parse(data); + + if (obj.channel === 'internal') { + const { type, body } = obj.message; + switch (type) { + case 'userChangeSuspendedState': + case 'userChangeSilencedState': + case 'userChangeModeratorState': + case 'remoteUserUpdated': { + const user = await Users.findOneByOrFail({ id: body.id }); + userByIdCache.set(user.id, user); + for (const [k, v] of uriPersonCache.cache.entries()) { + if (v.value?.id === user.id) { + uriPersonCache.set(k, user); + } + } + if (Users.isLocalUser(user)) { + localUserByNativeTokenCache.set(user.token, user); + localUserByIdCache.set(user.id, user); + } + break; + } + case 'userTokenRegenerated': { + const user = await Users.findOneByOrFail({ id: body.id }) as ILocalUser; + localUserByNativeTokenCache.delete(body.oldToken); + localUserByNativeTokenCache.set(body.newToken, user); + break; + } + default: + break; + } + } +}); diff --git a/packages/backend/src/services/validate-email-for-account.ts b/packages/backend/src/services/validate-email-for-account.ts index a4193925f6..132168fb31 100644 --- a/packages/backend/src/services/validate-email-for-account.ts +++ b/packages/backend/src/services/validate-email-for-account.ts @@ -5,7 +5,7 @@ export async function validateEmailForAccount(emailAddress: string): Promise<{ available: boolean; reason: null | 'used' | 'format' | 'disposable' | 'mx' | 'smtp'; }> { - const exist = await UserProfiles.count({ + const exist = await UserProfiles.countBy({ emailVerified: true, email: emailAddress, }); diff --git a/packages/backend/src/tools/accept-migration.ts b/packages/backend/src/tools/accept-migration.ts deleted file mode 100644 index adbfcdadf7..0000000000 --- a/packages/backend/src/tools/accept-migration.ts +++ /dev/null @@ -1,25 +0,0 @@ -// ex) node built/tools/accept-migration Yo 1000000000001 - -import { createConnection } from 'typeorm'; -import config from '@/config/index.js'; - -createConnection({ - type: 'postgres', - host: config.db.host, - port: config.db.port, - username: config.db.user, - password: config.db.pass, - database: config.db.db, - extra: config.db.extra, - synchronize: false, - dropSchema: false, -}).then(c => { - c.query(`INSERT INTO migrations(timestamp,name) VALUES (${process.argv[3]}, '${process.argv[2]}${process.argv[3]}');`).then(() => { - console.log('done'); - process.exit(0); - }).catch(e => { - console.log('ERROR:'); - console.log(e); - process.exit(1); - }); -}); diff --git a/packages/backend/src/tools/demote-admin.ts b/packages/backend/src/tools/demote-admin.ts deleted file mode 100644 index 7f67222473..0000000000 --- a/packages/backend/src/tools/demote-admin.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { initDb } from '../db/postgre.js'; - -async function main(username: string) { - if (!username) throw `username required`; - username = username.replace(/^@/, ''); - - await initDb(); - const { Users } = await import('@/models/index'); - - const res = await Users.update({ - usernameLower: username.toLowerCase(), - host: null, - }, { - isAdmin: false, - }); - - if (res.affected !== 1) { - throw 'Failed'; - } -} - -const args = process.argv.slice(2); - -main(args[0]).then(() => { - console.log('Success'); - process.exit(0); -}).catch(e => { - console.error(`Error: ${e.message || e}`); - process.exit(1); -}); diff --git a/packages/backend/src/tools/mark-admin.ts b/packages/backend/src/tools/mark-admin.ts deleted file mode 100644 index 630179e7ab..0000000000 --- a/packages/backend/src/tools/mark-admin.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { initDb } from '../db/postgre.js'; - -async function main(username: string) { - if (!username) throw `username required`; - username = username.replace(/^@/, ''); - - await initDb(); - const { Users } = await import('@/models/index'); - - const res = await Users.update({ - usernameLower: username.toLowerCase(), - host: null, - }, { - isAdmin: true, - }); - - if (res.affected !== 1) { - throw 'Failed'; - } -} - -const args = process.argv.slice(2); - -main(args[0]).then(() => { - console.log('Success'); - process.exit(0); -}).catch(e => { - console.error(`Error: ${e.message || e}`); - process.exit(1); -}); diff --git a/packages/backend/src/tools/refresh-question.ts b/packages/backend/src/tools/refresh-question.ts deleted file mode 100644 index 0111a2257a..0000000000 --- a/packages/backend/src/tools/refresh-question.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { initDb } from '@/db/postgre.js'; - -async function main(uri: string): Promise { - await initDb(); - const { updateQuestion } = await import('@/remote/activitypub/models/question'); - - return await updateQuestion(uri); -} - -const args = process.argv.slice(2); -const uri = args[0]; - -main(uri).then(result => { - console.log(`Done: ${result}`); -}).catch(e => { - console.warn(e); -}); diff --git a/packages/backend/src/tools/resync-remote-user.ts b/packages/backend/src/tools/resync-remote-user.ts deleted file mode 100644 index 8c02ef7efc..0000000000 --- a/packages/backend/src/tools/resync-remote-user.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { initDb } from '@/db/postgre.js'; -import * as Acct from '@/misc/acct.js'; - -async function main(acct: string): Promise { - await initDb(); - const { resolveUser } = await import('@/remote/resolve-user'); - - const { username, host } = Acct.parse(acct); - await resolveUser(username, host, {}, true); -} - -// get args -const args = process.argv.slice(2); -let acct = args[0]; - -// normalize args -acct = acct.replace(/^@/, ''); - -// check args -if (!acct.match(/^\w+@\w/)) { - throw `Invalid acct format. Valid format are user@host`; -} - -console.log(`resync ${acct}`); - -main(acct).then(() => { - console.log('Done'); -}).catch(e => { - console.warn(e); -}); diff --git a/packages/backend/src/tools/show-signin-history.ts b/packages/backend/src/tools/show-signin-history.ts deleted file mode 100644 index c3388fd1b6..0000000000 --- a/packages/backend/src/tools/show-signin-history.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { initDb } from '@/db/postgre.js'; - -// node built/tools/show-signin-history username -// => {Success} {Date} {IPAddrsss} - -// node built/tools/show-signin-history username user-agent,x-forwarded-for -// with user-agent and x-forwarded-for - -// node built/tools/show-signin-history username all -// with full request headers - -async function main(username: string, headers?: string[]) { - await initDb(); - const { Users, Signins } = await import('@/models/index'); - - const user = await Users.findOne({ - host: null, - usernameLower: username.toLowerCase(), - }); - - if (user == null) throw new Error('User not found'); - - const history = await Signins.find({ - userId: user.id, - }); - - for (const signin of history) { - console.log(`${signin.success ? 'OK' : 'NG'} ${signin.createdAt ? signin.createdAt.toISOString() : 'Unknown'} ${signin.ip}`); - - // headers - if (headers != null) { - for (const key of Object.keys(signin.headers)) { - if (headers.includes('all') || headers.includes(key)) { - console.log(` ${key}: ${signin.headers[key]}`); - } - } - } - } -} - -// get args -const args = process.argv.slice(2); - -let username = args[0]; -let headers: string[] | undefined; - -if (args[1] != null) { - headers = args[1].split(/,/).map(header => header.toLowerCase()); -} - -// normalize args -username = username.replace(/^@/, ''); - -main(username, headers).then(() => { - process.exit(0); -}).catch(e => { - console.warn(e); - process.exit(1); -}); diff --git a/packages/backend/test/utils.ts b/packages/backend/test/utils.ts index 994c098b7b..32a030f933 100644 --- a/packages/backend/test/utils.ts +++ b/packages/backend/test/utils.ts @@ -7,7 +7,6 @@ import * as childProcess from 'child_process'; import * as http from 'http'; import loadConfig from '../src/config/load.js'; import { SIGKILL } from 'constants'; -import { createConnection, getConnection } from 'typeorm'; import { entities } from '../src/db/postgre.js'; const config = loadConfig(); diff --git a/packages/backend/yarn.lock b/packages/backend/yarn.lock index 3210259e48..3d5d38d695 100644 --- a/packages/backend/yarn.lock +++ b/packages/backend/yarn.lock @@ -35,20 +35,20 @@ lodash "^4.17.19" to-fast-properties "^2.0.0" -"@bull-board/api@3.10.0": - version "3.10.0" - resolved "https://registry.yarnpkg.com/@bull-board/api/-/api-3.10.0.tgz#036cb0daed908920acd356c8addc19bcaabda5f2" - integrity sha512-VAoTkb7hflJ1lYHGCMyhpZtUK7sqQqpTqqDU/yqn5+BpyVoPdQ+ULsyEuDotbthWLeegSJZ1gN35jLg/NTV71g== +"@bull-board/api@3.10.1": + version "3.10.1" + resolved "https://registry.yarnpkg.com/@bull-board/api/-/api-3.10.1.tgz#c9608d501c887abcfa8f1907bc3dedee179bdea3" + integrity sha512-ZYjNBdoBQu+UVbLAHQuEhJL96C+i7vYioc2n7FL/XoVea44XIw2WiKFcFxq0LnActPErja26QyZBQht23ph1lg== dependencies: redis-info "^3.0.8" -"@bull-board/koa@3.10.0": - version "3.10.0" - resolved "https://registry.yarnpkg.com/@bull-board/koa/-/koa-3.10.0.tgz#5e05bf491cebda8b451727ada8e1f9f07fcb63d7" - integrity sha512-+3PqgHw5kExGXFu025WOQf/1sdLeWuEimus0peyp9/arqaC2+eclqrA3OuB9HrDHGLd7hhq0rPkM1lwEtmQU/A== +"@bull-board/koa@3.10.1": + version "3.10.1" + resolved "https://registry.yarnpkg.com/@bull-board/koa/-/koa-3.10.1.tgz#205641ae9721ec71303c4f16dc27eca1f71ca131" + integrity sha512-+mxdnu7idjd75WqUklJbPzrQU6NJzgQCT+BLKCyqOBsWzpfEwaac6QaIXOiuPwgwG2VjH90HWIcWr+2BQB9c1w== dependencies: - "@bull-board/api" "3.10.0" - "@bull-board/ui" "3.10.0" + "@bull-board/api" "3.10.1" + "@bull-board/ui" "3.10.1" ejs "^3.1.6" koa "^2.13.1" koa-mount "^4.0.0" @@ -56,12 +56,12 @@ koa-static "^5.0.0" koa-views "^7.0.1" -"@bull-board/ui@3.10.0": - version "3.10.0" - resolved "https://registry.yarnpkg.com/@bull-board/ui/-/ui-3.10.0.tgz#5217a265e11bc3cfe41ae662fc9434a7769528af" - integrity sha512-0TkrMAe6p/j/Zy//YRUzFXW0jlAmBNzX8hVx9nQIYZm+o/gkk6a9PgVkhLsQS7AdWLzSKqB8YTRhkxm/8MjGqw== +"@bull-board/ui@3.10.1": + version "3.10.1" + resolved "https://registry.yarnpkg.com/@bull-board/ui/-/ui-3.10.1.tgz#edf7c7752a78d9829f7a944bb87a0e70812b749f" + integrity sha512-K2qEAvTuyHZxUdK31HaBb9sdTFSOSKAZkxsl/LeiT4FGNF/h54iYGmWF9+HSFytggcnGdM0XnK3wLihCaIQAOQ== dependencies: - "@bull-board/api" "3.10.0" + "@bull-board/api" "3.10.1" "@cspotcode/source-map-consumer@0.8.0": version "0.8.0" @@ -244,10 +244,10 @@ require-from-string "^2.0.2" uri-js "^4.2.2" -"@redocly/openapi-core@1.0.0-beta.88": - version "1.0.0-beta.88" - resolved "https://registry.yarnpkg.com/@redocly/openapi-core/-/openapi-core-1.0.0-beta.88.tgz#acce3d58451fea3964b448b169c0ef7fbe56f72a" - integrity sha512-E9vkLvumIkzII0ydDFGr6uYbZgI9rHMxBveefzM51OUvobvifryXb6VcnQ1T0P8VoHRiYwpgiWlmZeDsNAdZdg== +"@redocly/openapi-core@1.0.0-beta.90": + version "1.0.0-beta.90" + resolved "https://registry.yarnpkg.com/@redocly/openapi-core/-/openapi-core-1.0.0-beta.90.tgz#edf53b23314368e190b005e1958c1f4a7dfaa2c3" + integrity sha512-MvkME+AWCBexyJyNp/sVFRUBjxCSk5CQ+CAozkwm0t/HusXp9G+kH26+e9giD6Fms129smr1qp3pCAUbwJZzZA== dependencies: "@redocly/ajv" "^8.6.4" "@types/node" "^14.11.8" @@ -539,10 +539,10 @@ dependencies: "@types/node" "*" -"@types/koa-bodyparser@4.3.6": - version "4.3.6" - resolved "https://registry.yarnpkg.com/@types/koa-bodyparser/-/koa-bodyparser-4.3.6.tgz#99a7d215560fdc168334ebb6a259c6cec9381a56" - integrity sha512-keCpj2kmoooL2oHC9YIVvciN66uDT21uMp4rvrosyjLsHD1aAipn6cg3xSxav9tR2Ly/NMvs8jdlNPTTQvn8SA== +"@types/koa-bodyparser@4.3.7": + version "4.3.7" + resolved "https://registry.yarnpkg.com/@types/koa-bodyparser/-/koa-bodyparser-4.3.7.tgz#3ac41f2dec9d97db7a6f798bbb2e2368be762714" + integrity sha512-21NhEp7LjZm4zbNV5alHHmrNY4J+S7B8lYTO6CzRL8ShTMnl20Gd14dRgVhAxraLaW5iZMofox+BycbuiDvj2Q== dependencies: "@types/koa" "*" @@ -666,10 +666,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.6.2.tgz#331b7b9f8621c638284787c5559423822fdffc50" integrity sha512-LSw8TZt12ZudbpHc6EkIyDM3nHVWKYrAvGy6EAJfNfjusbwnThqjqxUKKRwuV3iWYeW/LYMzNgaq3MaLffQ2xA== -"@types/node@17.0.21": - version "17.0.21" - resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.21.tgz#864b987c0c68d07b4345845c3e63b75edd143644" - integrity sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ== +"@types/node@17.0.23": + version "17.0.23" + resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.23.tgz#3b41a6e643589ac6442bdbd7a4a3ded62f33f7da" + integrity sha512-UxDxWn7dl97rKVeVS61vErvw086aCYhDLyvRQZ5Rk65rZKepaFdm53GeqXaKBuOhED4e9uWq34IC3TdSdJJ2Gw== "@types/node@^14.11.8": version "14.17.9" @@ -792,10 +792,10 @@ dependencies: "@types/node" "*" -"@types/sinonjs__fake-timers@8.1.1": - version "8.1.1" - resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz#b49c2c70150141a15e0fa7e79cf1f92a72934ce3" - integrity sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g== +"@types/sinonjs__fake-timers@8.1.2": + version "8.1.2" + resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.2.tgz#bf2e02a3dbd4aecaf95942ecd99b7402e03fad5e" + integrity sha512-9GcLXF0/v3t80caGs5p2rRfkB+a8VBGLJZVih6CNFkx8IZ994wiKKLSRs9nuFwk1HevWs/1mnUmkApGrSGsShA== "@types/speakeasy@2.0.7": version "2.0.7" @@ -850,19 +850,14 @@ dependencies: "@types/node" "*" -"@types/zen-observable@^0.8.2": - version "0.8.2" - resolved "https://registry.yarnpkg.com/@types/zen-observable/-/zen-observable-0.8.2.tgz#808c9fa7e4517274ed555fa158f2de4b4f468e71" - integrity sha512-HrCIVMLjE1MOozVoD86622S7aunluLb2PJdPfb3nYiEtohm8mIB/vyv0Fd37AdeMFrTUQXEunw78YloMA3Qilg== - -"@typescript-eslint/eslint-plugin@5.15.0": - version "5.15.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.15.0.tgz#c28ef7f2e688066db0b6a9d95fb74185c114fb9a" - integrity sha512-u6Db5JfF0Esn3tiAKELvoU5TpXVSkOpZ78cEGn/wXtT2RVqs2vkt4ge6N8cRCyw7YVKhmmLDbwI2pg92mlv7cA== +"@typescript-eslint/eslint-plugin@5.16.0": + version "5.16.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.16.0.tgz#78f246dd8d1b528fc5bfca99a8a64d4023a3d86d" + integrity sha512-SJoba1edXvQRMmNI505Uo4XmGbxCK9ARQpkvOd00anxzri9RNQk0DDCxD+LIl+jYhkzOJiOMMKYEHnHEODjdCw== dependencies: - "@typescript-eslint/scope-manager" "5.15.0" - "@typescript-eslint/type-utils" "5.15.0" - "@typescript-eslint/utils" "5.15.0" + "@typescript-eslint/scope-manager" "5.16.0" + "@typescript-eslint/type-utils" "5.16.0" + "@typescript-eslint/utils" "5.16.0" debug "^4.3.2" functional-red-black-tree "^1.0.1" ignore "^5.1.8" @@ -870,69 +865,69 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/parser@5.15.0": - version "5.15.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.15.0.tgz#95f603f8fe6eca7952a99bfeef9b85992972e728" - integrity sha512-NGAYP/+RDM2sVfmKiKOCgJYPstAO40vPAgACoWPO/+yoYKSgAXIFaBKsV8P0Cc7fwKgvj27SjRNX4L7f4/jCKQ== +"@typescript-eslint/parser@5.16.0": + version "5.16.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.16.0.tgz#e4de1bde4b4dad5b6124d3da227347616ed55508" + integrity sha512-fkDq86F0zl8FicnJtdXakFs4lnuebH6ZADDw6CYQv0UZeIjHvmEw87m9/29nk2Dv5Lmdp0zQ3zDQhiMWQf/GbA== dependencies: - "@typescript-eslint/scope-manager" "5.15.0" - "@typescript-eslint/types" "5.15.0" - "@typescript-eslint/typescript-estree" "5.15.0" + "@typescript-eslint/scope-manager" "5.16.0" + "@typescript-eslint/types" "5.16.0" + "@typescript-eslint/typescript-estree" "5.16.0" debug "^4.3.2" -"@typescript-eslint/scope-manager@5.15.0": - version "5.15.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.15.0.tgz#d97afab5e0abf4018d1289bd711be21676cdd0ee" - integrity sha512-EFiZcSKrHh4kWk0pZaa+YNJosvKE50EnmN4IfgjkA3bTHElPtYcd2U37QQkNTqwMCS7LXeDeZzEqnsOH8chjSg== +"@typescript-eslint/scope-manager@5.16.0": + version "5.16.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.16.0.tgz#7e7909d64bd0c4d8aef629cdc764b9d3e1d3a69a" + integrity sha512-P+Yab2Hovg8NekLIR/mOElCDPyGgFZKhGoZA901Yax6WR6HVeGLbsqJkZ+Cvk5nts/dAlFKm8PfL43UZnWdpIQ== dependencies: - "@typescript-eslint/types" "5.15.0" - "@typescript-eslint/visitor-keys" "5.15.0" + "@typescript-eslint/types" "5.16.0" + "@typescript-eslint/visitor-keys" "5.16.0" -"@typescript-eslint/type-utils@5.15.0": - version "5.15.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.15.0.tgz#d2c02eb2bdf54d0a645ba3a173ceda78346cf248" - integrity sha512-KGeDoEQ7gHieLydujGEFLyLofipe9PIzfvA/41urz4hv+xVxPEbmMQonKSynZ0Ks2xDhJQ4VYjB3DnRiywvKDA== +"@typescript-eslint/type-utils@5.16.0": + version "5.16.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.16.0.tgz#b482bdde1d7d7c0c7080f7f2f67ea9580b9e0692" + integrity sha512-SKygICv54CCRl1Vq5ewwQUJV/8padIWvPgCxlWPGO/OgQLCijY9G7lDu6H+mqfQtbzDNlVjzVWQmeqbLMBLEwQ== dependencies: - "@typescript-eslint/utils" "5.15.0" + "@typescript-eslint/utils" "5.16.0" debug "^4.3.2" tsutils "^3.21.0" -"@typescript-eslint/types@5.15.0": - version "5.15.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.15.0.tgz#c7bdd103843b1abae97b5518219d3e2a0d79a501" - integrity sha512-yEiTN4MDy23vvsIksrShjNwQl2vl6kJeG9YkVJXjXZnkJElzVK8nfPsWKYxcsGWG8GhurYXP4/KGj3aZAxbeOA== +"@typescript-eslint/types@5.16.0": + version "5.16.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.16.0.tgz#5827b011982950ed350f075eaecb7f47d3c643ee" + integrity sha512-oUorOwLj/3/3p/HFwrp6m/J2VfbLC8gjW5X3awpQJ/bSG+YRGFS4dpsvtQ8T2VNveV+LflQHjlLvB6v0R87z4g== -"@typescript-eslint/typescript-estree@5.15.0": - version "5.15.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.15.0.tgz#81513a742a9c657587ad1ddbca88e76c6efb0aac" - integrity sha512-Hb0e3dGc35b75xLzixM3cSbG1sSbrTBQDfIScqdyvrfJZVEi4XWAT+UL/HMxEdrJNB8Yk28SKxPLtAhfCbBInA== +"@typescript-eslint/typescript-estree@5.16.0": + version "5.16.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.16.0.tgz#32259459ec62f5feddca66adc695342f30101f61" + integrity sha512-SE4VfbLWUZl9MR+ngLSARptUv2E8brY0luCdgmUevU6arZRY/KxYoLI/3V/yxaURR8tLRN7bmZtJdgmzLHI6pQ== dependencies: - "@typescript-eslint/types" "5.15.0" - "@typescript-eslint/visitor-keys" "5.15.0" + "@typescript-eslint/types" "5.16.0" + "@typescript-eslint/visitor-keys" "5.16.0" debug "^4.3.2" globby "^11.0.4" is-glob "^4.0.3" semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/utils@5.15.0": - version "5.15.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.15.0.tgz#468510a0974d3ced8342f37e6c662778c277f136" - integrity sha512-081rWu2IPKOgTOhHUk/QfxuFog8m4wxW43sXNOMSCdh578tGJ1PAaWPsj42LOa7pguh173tNlMigsbrHvh/mtA== +"@typescript-eslint/utils@5.16.0": + version "5.16.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.16.0.tgz#42218b459d6d66418a4eb199a382bdc261650679" + integrity sha512-iYej2ER6AwmejLWMWzJIHy3nPJeGDuCqf8Jnb+jAQVoPpmWzwQOfa9hWVB8GIQE5gsCv/rfN4T+AYb/V06WseQ== dependencies: "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.15.0" - "@typescript-eslint/types" "5.15.0" - "@typescript-eslint/typescript-estree" "5.15.0" + "@typescript-eslint/scope-manager" "5.16.0" + "@typescript-eslint/types" "5.16.0" + "@typescript-eslint/typescript-estree" "5.16.0" eslint-scope "^5.1.1" eslint-utils "^3.0.0" -"@typescript-eslint/visitor-keys@5.15.0": - version "5.15.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.15.0.tgz#5669739fbf516df060f978be6a6dce75855a8027" - integrity sha512-+vX5FKtgvyHbmIJdxMJ2jKm9z2BIlXJiuewI8dsDYMp5LzPUcuTT78Ya5iwvQg3VqSVdmxyM8Anj1Jeq7733ZQ== +"@typescript-eslint/visitor-keys@5.16.0": + version "5.16.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.16.0.tgz#f27dc3b943e6317264c7492e390c6844cd4efbbb" + integrity sha512-jqxO8msp5vZDhikTwq9ubyMHqZ67UIvawohr4qF3KhlpL7gzSjOd+8471H3nh5LyABkaI85laEKKU8SnGUK5/g== dependencies: - "@typescript-eslint/types" "5.15.0" + "@typescript-eslint/types" "5.16.0" eslint-visitor-keys "^3.0.0" "@ungap/promise-all-settled@1.1.2": @@ -1032,10 +1027,10 @@ ajv-keywords@^3.5.2: resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== -ajv@8.10.0: - version "8.10.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.10.0.tgz#e573f719bd3af069017e3b66538ab968d040e54d" - integrity sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw== +ajv@8.11.0: + version "8.11.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f" + integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg== dependencies: fast-deep-equal "^3.1.1" json-schema-traverse "^1.0.0" @@ -1276,10 +1271,10 @@ autwh@0.1.0: dependencies: oauth "0.9.15" -aws-sdk@2.1096.0: - version "2.1096.0" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1096.0.tgz#d41d6c6afe44b00977d4fe4c68e9450941d72931" - integrity sha512-q+hotU57U8bGpz1pf5CkO4z630ay0xGJ9HedahKPZ0Xk3/X0GH+QFYPBWJ5IMTtO30bjfPH0zTaL2vJmMXLBrQ== +aws-sdk@2.1100.0: + version "2.1100.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1100.0.tgz#20bbabc12fbc316067ba02af66bf371a455af9e3" + integrity sha512-StLSQCYFmFPxjoMntIb+8jUZ0vzmq3xkrwG5e/4qU1bSGWCmhhjvz6c+4j38AnIy8MFV1+tV8RArbhLUEV2dGw== dependencies: buffer "4.9.2" events "1.1.1" @@ -1500,10 +1495,10 @@ bufferutil@^4.0.1: dependencies: node-gyp-build "~3.7.0" -bull@4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/bull/-/bull-4.7.0.tgz#89442d4676117edd9f9a1359bb0edfb489595e70" - integrity sha512-rnJIsuXrDjDlz3HMHz6xobiRZAWe3o4MJBkzx7FdUjO+K2nSYrhR2KpcL+ZCNUMPKtONxL4DqmRjat5SBHFlAw== +bull@4.8.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/bull/-/bull-4.8.1.tgz#83daaefc3118876450b21d7a02bc11ea28a2440e" + integrity sha512-ojH5AfOchKQsQwwE+thViS1pMpvREGC+Ov1+3HXsQqn5Q27ZSGkgMriMqc6c9J9rvQ/+D732pZE+TN1+2LRWVg== dependencies: cron-parser "^4.2.1" debuglog "^1.0.0" @@ -2108,7 +2103,7 @@ data-urls@^3.0.1: whatwg-mimetype "^3.0.0" whatwg-url "^10.0.0" -date-fns@2.28.0: +date-fns@2.28.0, date-fns@^2.28.0: version "2.28.0" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.28.0.tgz#9570d656f5fc13143e50c975a3b6bbeb46cd08b2" integrity sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw== @@ -2155,6 +2150,13 @@ debug@^4.3.2: dependencies: ms "2.1.2" +debug@^4.3.3: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + debuglog@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" @@ -2431,10 +2433,10 @@ domutils@^2.5.2: domelementtype "^2.2.0" domhandler "^4.2.0" -dotenv@^8.2.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a" - integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw== +dotenv@^16.0.0: + version "16.0.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.0.tgz#c619001253be89ebb638d027b609c75c26e47411" + integrity sha512-qD9WU0MPM4SWLPJy/r2Be+2WgQj8plChsyrCNQzW/0WjvcJQiKQJ9mH3ZgB3fxbUUxgc/11ZJ0Fi5KiimWGz2Q== duplexer2@~0.1.4: version "0.1.4" @@ -2713,10 +2715,10 @@ eslint-visitor-keys@^3.3.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== -eslint@8.11.0: - version "8.11.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.11.0.tgz#88b91cfba1356fc10bb9eb592958457dfe09fb37" - integrity sha512-/KRpd9mIRg2raGxHRGwW9ZywYNAClZrHjdueHcrVDuO3a6bj83eoTirCCk0M0yPwOjWYKHwRVRid+xK4F/GHgA== +eslint@8.12.0: + version "8.12.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.12.0.tgz#c7a5bd1cfa09079aae64c9076c07eada66a46e8e" + integrity sha512-it1oBL9alZg1S8UycLm5YDMAkIhtH6FtAzuZs6YvoGVldWjbS08BkAdb/ymP9LlAyq8koANu32U7Ib/w+UNh8Q== dependencies: "@eslint/eslintrc" "^1.2.1" "@humanwhocodes/config-array" "^0.9.2" @@ -3040,9 +3042,9 @@ fluent-ffmpeg@2.1.2: which "^1.1.1" follow-redirects@^1.14.4: - version "1.14.7" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.7.tgz#2004c02eb9436eee9a21446a6477debf17e81685" - integrity sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ== + version "1.14.8" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.8.tgz#016996fb9a11a100566398b1c6839337d7bfa8fc" + integrity sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA== form-data-encoder@1.7.1: version "1.7.1" @@ -3227,7 +3229,7 @@ glob-parent@^6.0.1: dependencies: is-glob "^4.0.3" -glob@7.2.0: +glob@7.2.0, glob@^7.2.0: version "7.2.0" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== @@ -3239,7 +3241,7 @@ glob@7.2.0: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: +glob@^7.1.3, glob@^7.1.4: version "7.1.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== @@ -3314,10 +3316,10 @@ got@11.5.1: p-cancelable "^2.0.0" responselike "^2.0.0" -got@12.0.2: - version "12.0.2" - resolved "https://registry.yarnpkg.com/got/-/got-12.0.2.tgz#8ce4c3baa50bb18a0858d2539caa0fac19e109bf" - integrity sha512-Zi4yHiqCgaorUbknr/RHFBsC3XqjSodaw0F3qxlqAqyj+OGYZl37/uy01R0qz++KANKQYdY5FHJ0okXZpEzwWQ== +got@12.0.3: + version "12.0.3" + resolved "https://registry.yarnpkg.com/got/-/got-12.0.3.tgz#c7314daab26d42039e624adbf98f6d442e5de749" + integrity sha512-hmdcXi/S0gcAtDg4P8j/rM7+j3o1Aq6bXhjxkDhRY2ipe7PHpvx/14DgTY2czHOLaGeU8VRvRecidwfu9qdFug== dependencies: "@sindresorhus/is" "^4.6.0" "@szmarczak/http-timer" "^5.0.1" @@ -4026,7 +4028,7 @@ js-stringify@^1.0.2: resolved "https://registry.yarnpkg.com/js-stringify/-/js-stringify-1.0.2.tgz#1736fddfd9724f28a3682adc6230ae7e4e9679db" integrity sha1-Fzb939lyTyijaCrcYjCufk6Weds= -js-yaml@4.1.0, js-yaml@^4.0.0, js-yaml@^4.1.0: +js-yaml@4.1.0, js-yaml@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== @@ -4120,12 +4122,10 @@ json5-loader@4.0.1: loader-utils "^2.0.0" schema-utils "^3.0.0" -json5@2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" - integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== - dependencies: - minimist "^1.2.5" +json5@2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" + integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== json5@^1.0.1: version "1.0.1" @@ -4718,10 +4718,10 @@ minimatch@^3.0.4: dependencies: brace-expansion "^1.1.7" -minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== +minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5, minimist@^1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== minipass-collect@^1.0.2: version "1.0.2" @@ -4918,16 +4918,11 @@ nano-time@1.0.0: dependencies: big-integer "^1.6.16" -nanoid@3.3.1: +nanoid@3.3.1, nanoid@^3.1.30: version "3.3.1" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35" integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw== -nanoid@^3.1.30: - version "3.1.30" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.30.tgz#63f93cc548d2a113dc5dfbc63bfa09e2b9b64362" - integrity sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ== - napi-build-utils@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz#b1fddc0b2c46e380a0b7a76f984dd47c41a13806" @@ -5043,10 +5038,10 @@ node-gyp@^8.4.1: tar "^6.1.2" which "^2.0.2" -nodemailer@6.7.2: - version "6.7.2" - resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.7.2.tgz#44b2ad5f7ed71b7067f7a21c4fedabaec62b85e0" - integrity sha512-Dz7zVwlef4k5R71fdmxwR8Q39fiboGbu3xgswkzGwczUfjp873rVxt1O46+Fh0j1ORnAC6L9+heI8uUpO6DT7Q== +nodemailer@6.7.3: + version "6.7.3" + resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.7.3.tgz#b73f9a81b9c8fa8acb4ea14b608f5e725ea8e018" + integrity sha512-KUdDsspqx89sD4UUyUKzdlUOper3hRkDVkrKh/89G+d9WKsU5ox51NWS4tB1XR5dPUdR4SP0E3molyEfOvSa3g== nofilter@^2.0.3: version "2.0.3" @@ -6619,10 +6614,10 @@ syslog-pro@1.0.0: dependencies: moment "^2.22.2" -systeminformation@5.11.8: - version "5.11.8" - resolved "https://registry.yarnpkg.com/systeminformation/-/systeminformation-5.11.8.tgz#fd6244cd13e5fcb863e6dde9cb02edb4a5a3115b" - integrity sha512-u30rM0KwGKiJof44Ak25WeSh9661NU2GshXpHPpv/zGXvvSGI5eALjpVJ3EYnIroceToWzy9+xkuMfjHIx6OiQ== +systeminformation@5.11.9: + version "5.11.9" + resolved "https://registry.yarnpkg.com/systeminformation/-/systeminformation-5.11.9.tgz#95f2334e739dd224178948a2afaced7d9abfdf9d" + integrity sha512-eeMtL9UJFR/LYG+2rpeAgZ0Va4ojlNQTkYiQH/xbbPwDjDMsaetj3Pkc+C1aH5G8mav6HvDY8kI4Vl4noksSkA== tapable@^2.2.0: version "2.2.0" @@ -6826,14 +6821,14 @@ tsc-alias@1.4.1: mylas "^2.1.4" normalize-path "^3.0.0" -tsconfig-paths@3.14.0: - version "3.14.0" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.0.tgz#4fcc48f9ccea8826c41b9ca093479de7f5018976" - integrity sha512-cg/1jAZoL57R39+wiw4u/SCC6Ic9Q5NqjBOb+9xISedOYurfog9ZNmKJSxAnb2m/5Bq4lE9lhUcau33Ml8DM0g== +tsconfig-paths@3.14.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a" + integrity sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ== dependencies: "@types/json5" "^0.0.29" json5 "^1.0.1" - minimist "^1.2.0" + minimist "^1.2.6" strip-bom "^3.0.0" tsconfig-paths@^3.12.0: @@ -6851,10 +6846,10 @@ tslib@^1.8.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35" integrity sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA== -tslib@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c" - integrity sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w== +tslib@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" + integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== tsscmp@1.0.6: version "1.0.6" @@ -6944,33 +6939,33 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typeorm@0.2.45: - version "0.2.45" - resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.2.45.tgz#e5bbb3af822dc4646bad96cfa48cd22fa4687cea" - integrity sha512-c0rCO8VMJ3ER7JQ73xfk0zDnVv0WDjpsP6Q1m6CVKul7DB9iVdWLRjPzc8v2eaeBuomsbZ2+gTaYr8k1gm3bYA== +typeorm@0.3.4: + version "0.3.4" + resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.3.4.tgz#6608f7efb15c40f3fa2863cefb45ff78a208c40c" + integrity sha512-6v3HH12viDhIQwQDod/B0Plt1o7IYIVDxP7zwatD6fzN+IDdqTTinW/sWNw84Edpbhh2t7XILTaQEqj0NXFP/Q== dependencies: "@sqltools/formatter" "^1.2.2" app-root-path "^3.0.0" buffer "^6.0.3" chalk "^4.1.0" cli-highlight "^2.1.11" - debug "^4.3.1" - dotenv "^8.2.0" - glob "^7.1.6" - js-yaml "^4.0.0" + date-fns "^2.28.0" + debug "^4.3.3" + dotenv "^16.0.0" + glob "^7.2.0" + js-yaml "^4.1.0" mkdirp "^1.0.4" reflect-metadata "^0.1.13" sha.js "^2.4.11" - tslib "^2.1.0" + tslib "^2.3.1" uuid "^8.3.2" xml2js "^0.4.23" - yargs "^17.0.1" - zen-observable-ts "^1.0.0" + yargs "^17.3.1" -typescript@4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.2.tgz#fe12d2727b708f4eef40f51598b3398baa9611d4" - integrity sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg== +typescript@4.6.3: + version "4.6.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.3.tgz#eefeafa6afdd31d725584c67a0eaba80f6fc6c6c" + integrity sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw== ulid@2.3.0: version "2.3.0" @@ -7385,6 +7380,11 @@ yargs-parser@^18.1.2: camelcase "^5.0.0" decamelize "^1.2.0" +yargs-parser@^21.0.0: + version "21.0.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.0.1.tgz#0267f286c877a4f0f728fceb6f8a3e4cb95c6e35" + integrity sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg== + yargs-unparser@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" @@ -7425,18 +7425,18 @@ yargs@^15.3.1: y18n "^4.0.0" yargs-parser "^18.1.2" -yargs@^17.0.1: - version "17.1.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.1.1.tgz#c2a8091564bdb196f7c0a67c1d12e5b85b8067ba" - integrity sha512-c2k48R0PwKIqKhPMWjeiF6y2xY/gPMUlro0sgxqXpbOIohWiLNXWslsootttv7E1e73QPAMQSg5FeySbVcpsPQ== +yargs@^17.3.1: + version "17.4.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.4.0.tgz#9fc9efc96bd3aa2c1240446af28499f0e7593d00" + integrity sha512-WJudfrk81yWFSOkZYpAZx4Nt7V4xp7S/uJkX0CnxovMCt1wCE8LNftPpNuF9X/u9gN5nsD7ycYtRcDf2pL3UiA== dependencies: cliui "^7.0.2" escalade "^3.1.1" get-caller-file "^2.0.5" require-directory "^2.1.1" - string-width "^4.2.0" + string-width "^4.2.3" y18n "^5.0.5" - yargs-parser "^20.2.2" + yargs-parser "^21.0.0" ylru@^1.2.0: version "1.2.1" @@ -7448,19 +7448,6 @@ yn@3.1.1: resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== -zen-observable-ts@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-1.0.0.tgz#30d1202b81d8ba4c489e3781e8ca09abf0075e70" - integrity sha512-KmWcbz+9kKUeAQ8btY8m1SsEFgBcp7h/Uf3V5quhan7ZWdjGsf0JcGLULQiwOZibbFWnHkYq8Nn2AZbJabovQg== - dependencies: - "@types/zen-observable" "^0.8.2" - zen-observable "^0.8.15" - -zen-observable@^0.8.15: - version "0.8.15" - resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.15.tgz#96415c512d8e3ffd920afd3889604e30b9eaac15" - integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ== - zip-stream@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-4.1.0.tgz#51dd326571544e36aa3f756430b313576dc8fc79" diff --git a/packages/client/package.json b/packages/client/package.json index b9eb32d20d..6551b6aca0 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -11,7 +11,7 @@ }, "dependencies": { "@discordapp/twemoji": "13.1.1", - "@fortawesome/fontawesome-free": "6.1.0", + "@fortawesome/fontawesome-free": "6.1.1", "@syuilo/aiscript": "0.11.1", "@types/escape-regexp": "0.0.1", "@types/glob": "7.2.0", @@ -34,7 +34,7 @@ "@types/webpack-stream": "3.2.12", "@types/websocket": "1.0.5", "@types/ws": "8.5.3", - "@typescript-eslint/parser": "5.15.0", + "@typescript-eslint/parser": "5.16.0", "@vue/compiler-sfc": "3.2.31", "abort-controller": "3.0.0", "autobind-decorator": "2.4.0", @@ -44,12 +44,12 @@ "broadcast-channel": "4.10.0", "chart.js": "3.7.1", "chartjs-adapter-date-fns": "2.0.0", - "chartjs-plugin-gradient": "0.2.1", - "chartjs-plugin-zoom": "1.2.0", + "chartjs-plugin-gradient": "0.2.2", + "chartjs-plugin-zoom": "1.2.1", "compare-versions": "4.1.3", "content-disposition": "0.5.4", "css-loader": "6.7.1", - "cssnano": "5.1.4", + "cssnano": "5.1.5", "date-fns": "2.28.0", "escape-regexp": "0.0.1", "eslint": "8.11.0", @@ -60,7 +60,7 @@ "idb-keyval": "6.1.0", "insert-text-at-cursor": "0.3.0", "ip-cidr": "3.0.4", - "json5": "2.2.0", + "json5": "2.2.1", "json5-loader": "4.0.1", "katex": "0.15.3", "matter-js": "0.18.0", @@ -93,14 +93,14 @@ "style-loader": "3.3.1", "syuilo-password-strength": "0.0.1", "textarea-caret": "3.1.0", - "three": "0.138.3", + "three": "0.139.0", "throttle-debounce": "3.0.1", "tinycolor2": "1.4.2", "ts-loader": "9.2.8", "tsc-alias": "1.5.0", - "tsconfig-paths": "3.14.0", + "tsconfig-paths": "3.14.1", "twemoji-parser": "14.0.0", - "typescript": "4.6.2", + "typescript": "4.6.3", "uuid": "8.3.2", "v-debounce": "0.1.2", "vanilla-tilt": "1.7.2", @@ -117,7 +117,7 @@ "ws": "8.5.0" }, "devDependencies": { - "@typescript-eslint/eslint-plugin": "5.15.0", + "@typescript-eslint/eslint-plugin": "5.16.0", "cross-env": "7.0.3", "cypress": "9.5.2", "eslint-plugin-import": "2.25.4", diff --git a/packages/client/src/account.ts b/packages/client/src/account.ts index bcc8a43be0..4772c0baa5 100644 --- a/packages/client/src/account.ts +++ b/packages/client/src/account.ts @@ -2,7 +2,7 @@ import { del, get, set } from '@/scripts/idb-proxy'; import { reactive } from 'vue'; import * as misskey from 'misskey-js'; import { apiUrl } from '@/config'; -import { waiting, api, popup, popupMenu, success } from '@/os'; +import { waiting, api, popup, popupMenu, success, alert } from '@/os'; import { unisonReload, reloadChannel } from '@/scripts/unison-reload'; import { showSuspendedDialog } from './scripts/show-suspended-dialog'; import { i18n } from './i18n'; @@ -89,7 +89,11 @@ function fetchAccount(token): Promise { signout(); }); } else { - signout(); + alert({ + type: 'error', + title: i18n.ts.failedToFetchAccountInformation, + text: JSON.stringify(res.error), + }); } } else { res.token = token; diff --git a/packages/client/src/components/global/url.vue b/packages/client/src/components/global/url.vue index 56a8c3453a..55f6c5d5f9 100644 --- a/packages/client/src/components/global/url.vue +++ b/packages/client/src/components/global/url.vue @@ -24,6 +24,14 @@ import { url as local } from '@/config'; import * as os from '@/os'; import { useTooltip } from '@/scripts/use-tooltip'; +function safeURIDecode(str: string) { + try { + return decodeURIComponent(str); + } catch { + return str; + } +} + export default defineComponent({ props: { url: { @@ -54,9 +62,9 @@ export default defineComponent({ schema: url.protocol, hostname: decodePunycode(url.hostname), port: url.port, - pathname: decodeURIComponent(url.pathname), - query: decodeURIComponent(url.search), - hash: decodeURIComponent(url.hash), + pathname: safeURIDecode(url.pathname), + query: safeURIDecode(url.search), + hash: safeURIDecode(url.hash), self: self, attr: self ? 'to' : 'href', target: self ? null : '_blank', diff --git a/packages/client/src/components/launch-pad.vue b/packages/client/src/components/launch-pad.vue index 4fe36bfefc..ffefc1b085 100644 --- a/packages/client/src/components/launch-pad.vue +++ b/packages/client/src/components/launch-pad.vue @@ -1,5 +1,5 @@