diff --git a/CHANGELOG.md b/CHANGELOG.md index 12d686841b..fe5bece0c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,9 +15,13 @@ ### Changes - Room機能が削除されました - 後日別リポジトリとして復活予定です +- リバーシ機能が削除されました + - 後日別リポジトリとして復活予定です - Chat UIが削除されました ### Improvements +- カスタム絵文字一括編集機能 +- カスタム絵文字一括インポート ### Bugfixes diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 6fb1e7f2ca..02d7f71d7d 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -242,7 +242,6 @@ uploadFromUrlDescription: "アップロードしたいファイルのURL" uploadFromUrlRequested: "アップロードをリクエストしました" uploadFromUrlMayTakeTime: "アップロードが完了するまで時間がかかる場合があります。" explore: "みつける" -games: "Misskey Games" messageRead: "既読" noMoreHistory: "これより過去の履歴はありません" startMessaging: "チャットを開始" @@ -669,7 +668,6 @@ emailVerified: "メールアドレスが確認されました" noteFavoritesCount: "お気に入りノートの数" pageLikesCount: "Pageにいいねした数" pageLikedCount: "Pageにいいねされた数" -reversiCount: "リバーシの対局数" contact: "連絡先" useSystemFont: "システムのデフォルトのフォントを使う" clips: "クリップ" @@ -957,40 +955,6 @@ _mfm: rotate: "回転" rotateDescription: "指定した角度で回転させます。" -_reversi: - reversi: "リバーシ" - gameSettings: "対局の設定" - chooseBoard: "ボードを選択" - blackOrWhite: "先行/後攻" - blackIs: "{name}が黒(先行)" - rules: "ルール" - botSettings: "Botのオプション" - thisGameIsStartedSoon: "対局は数秒後に開始されます" - waitingForOther: "相手の準備が完了するのを待っています" - waitingForMe: "あなたの準備が完了するのを待っています" - waitingBoth: "準備してください" - ready: "準備完了" - cancelReady: "準備を再開" - opponentTurn: "相手のターンです" - myTurn: "あなたのターンです" - turnOf: "{name}のターンです" - pastTurnOf: "{name}のターン" - surrender: "投了" - surrendered: "投了により" - drawn: "引き分け" - won: "{name}の勝ち" - black: "黒" - white: "白" - total: "合計" - turnCount: "{count}ターン目" - myGames: "自分の対局" - allGames: "みんなの対局" - ended: "終了" - playing: "対局中" - isLlotheo: "石の少ない方が勝ち(ロセオ)" - loopedMap: "ループマップ" - canPutEverywhere: "どこでも置けるモード" - _instanceTicker: none: "表示しない" remote: "リモートユーザーに表示" @@ -1118,8 +1082,6 @@ _sfx: chatBg: "チャット(バックグラウンド)" antenna: "アンテナ受信" channel: "チャンネル通知" - reversiPutBlack: "リバーシ: 黒が打ったとき" - reversiPutWhite: "リバーシ: 白が打ったとき" _ago: unknown: "謎" diff --git a/packages/backend/package.json b/packages/backend/package.json index 65da382e2d..c940e98301 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -180,6 +180,7 @@ "typeorm": "0.2.39", "typescript": "4.4.4", "ulid": "2.3.0", + "unzipper": "0.10.11", "uuid": "8.3.2", "web-push": "3.4.5", "websocket": "1.0.34", diff --git a/packages/backend/src/db/postgre.ts b/packages/backend/src/db/postgre.ts index b5f228d919..1692b26219 100644 --- a/packages/backend/src/db/postgre.ts +++ b/packages/backend/src/db/postgre.ts @@ -40,8 +40,6 @@ import { Signin } from '@/models/entities/signin'; import { AuthSession } from '@/models/entities/auth-session'; import { FollowRequest } from '@/models/entities/follow-request'; import { Emoji } from '@/models/entities/emoji'; -import { ReversiGame } from '@/models/entities/games/reversi/game'; -import { ReversiMatching } from '@/models/entities/games/reversi/matching'; import { UserNotePining } from '@/models/entities/user-note-pining'; import { Poll } from '@/models/entities/poll'; import { UserKeypair } from '@/models/entities/user-keypair'; @@ -166,8 +164,6 @@ export const entities = [ AntennaNote, PromoNote, PromoRead, - ReversiGame, - ReversiMatching, Relay, MutedNote, Channel, diff --git a/packages/backend/src/games/reversi/core.ts b/packages/backend/src/games/reversi/core.ts deleted file mode 100644 index 0cf7714543..0000000000 --- a/packages/backend/src/games/reversi/core.ts +++ /dev/null @@ -1,263 +0,0 @@ -import { count, concat } from '@/prelude/array'; - -// MISSKEY REVERSI ENGINE - -/** - * true ... 黒 - * false ... 白 - */ -export type Color = boolean; -const BLACK = true; -const WHITE = false; - -export type MapPixel = 'null' | 'empty'; - -export type Options = { - isLlotheo: boolean; - canPutEverywhere: boolean; - loopedBoard: boolean; -}; - -export type Undo = { - /** - * 色 - */ - color: Color; - - /** - * どこに打ったか - */ - pos: number; - - /** - * 反転した石の位置の配列 - */ - effects: number[]; - - /** - * ターン - */ - turn: Color | null; -}; - -/** - * リバーシエンジン - */ -export default class Reversi { - public map: MapPixel[]; - public mapWidth: number; - public mapHeight: number; - public board: (Color | null | undefined)[]; - public turn: Color | null = BLACK; - public opts: Options; - - public prevPos = -1; - public prevColor: Color | null = null; - - private logs: Undo[] = []; - - /** - * ゲームを初期化します - */ - constructor(map: string[], opts: Options) { - //#region binds - this.put = this.put.bind(this); - //#endregion - - //#region Options - this.opts = opts; - if (this.opts.isLlotheo == null) this.opts.isLlotheo = false; - if (this.opts.canPutEverywhere == null) this.opts.canPutEverywhere = false; - if (this.opts.loopedBoard == null) this.opts.loopedBoard = false; - //#endregion - - //#region Parse map data - this.mapWidth = map[0].length; - this.mapHeight = map.length; - const mapData = map.join(''); - - this.board = mapData.split('').map(d => d === '-' ? null : d === 'b' ? BLACK : d === 'w' ? WHITE : undefined); - - this.map = mapData.split('').map(d => d === '-' || d === 'b' || d === 'w' ? 'empty' : 'null'); - //#endregion - - // ゲームが始まった時点で片方の色の石しかないか、始まった時点で勝敗が決定するようなマップの場合がある - if (!this.canPutSomewhere(BLACK)) this.turn = this.canPutSomewhere(WHITE) ? WHITE : null; - } - - /** - * 黒石の数 - */ - public get blackCount() { - return count(BLACK, this.board); - } - - /** - * 白石の数 - */ - public get whiteCount() { - return count(WHITE, this.board); - } - - public transformPosToXy(pos: number): number[] { - const x = pos % this.mapWidth; - const y = Math.floor(pos / this.mapWidth); - return [x, y]; - } - - public transformXyToPos(x: number, y: number): number { - return x + (y * this.mapWidth); - } - - /** - * 指定のマスに石を打ちます - * @param color 石の色 - * @param pos 位置 - */ - public put(color: Color, pos: number) { - this.prevPos = pos; - this.prevColor = color; - - this.board[pos] = color; - - // 反転させられる石を取得 - const effects = this.effects(color, pos); - - // 反転させる - for (const pos of effects) { - this.board[pos] = color; - } - - const turn = this.turn; - - this.logs.push({ - color, - pos, - effects, - turn, - }); - - this.calcTurn(); - } - - private calcTurn() { - // ターン計算 - this.turn = - this.canPutSomewhere(!this.prevColor) ? !this.prevColor : - this.canPutSomewhere(this.prevColor!) ? this.prevColor : - null; - } - - public undo() { - const undo = this.logs.pop()!; - this.prevColor = undo.color; - this.prevPos = undo.pos; - this.board[undo.pos] = null; - for (const pos of undo.effects) { - const color = this.board[pos]; - this.board[pos] = !color; - } - this.turn = undo.turn; - } - - /** - * 指定した位置のマップデータのマスを取得します - * @param pos 位置 - */ - public mapDataGet(pos: number): MapPixel { - const [x, y] = this.transformPosToXy(pos); - return x < 0 || y < 0 || x >= this.mapWidth || y >= this.mapHeight ? 'null' : this.map[pos]; - } - - /** - * 打つことができる場所を取得します - */ - public puttablePlaces(color: Color): number[] { - return Array.from(this.board.keys()).filter(i => this.canPut(color, i)); - } - - /** - * 打つことができる場所があるかどうかを取得します - */ - public canPutSomewhere(color: Color): boolean { - return this.puttablePlaces(color).length > 0; - } - - /** - * 指定のマスに石を打つことができるかどうかを取得します - * @param color 自分の色 - * @param pos 位置 - */ - public canPut(color: Color, pos: number): boolean { - return ( - this.board[pos] !== null ? false : // 既に石が置いてある場所には打てない - this.opts.canPutEverywhere ? this.mapDataGet(pos) == 'empty' : // 挟んでなくても置けるモード - this.effects(color, pos).length !== 0); // 相手の石を1つでも反転させられるか - } - - /** - * 指定のマスに石を置いた時の、反転させられる石を取得します - * @param color 自分の色 - * @param initPos 位置 - */ - public effects(color: Color, initPos: number): number[] { - const enemyColor = !color; - - const diffVectors: [number, number][] = [ - [ 0, -1], // 上 - [ +1, -1], // 右上 - [ +1, 0], // 右 - [ +1, +1], // 右下 - [ 0, +1], // 下 - [ -1, +1], // 左下 - [ -1, 0], // 左 - [ -1, -1], // 左上 - ]; - - const effectsInLine = ([dx, dy]: [number, number]): number[] => { - const nextPos = (x: number, y: number): [number, number] => [x + dx, y + dy]; - - const found: number[] = []; // 挟めるかもしれない相手の石を入れておく配列 - let [x, y] = this.transformPosToXy(initPos); - while (true) { - [x, y] = nextPos(x, y); - - // 座標が指し示す位置がボード外に出たとき - if (this.opts.loopedBoard && this.transformXyToPos( - (x = ((x % this.mapWidth) + this.mapWidth) % this.mapWidth), - (y = ((y % this.mapHeight) + this.mapHeight) % this.mapHeight)) === initPos) { - // 盤面の境界でループし、自分が石を置く位置に戻ってきたとき、挟めるようにしている (ref: Test4のマップ) - return found; - } else if (x === -1 || y === -1 || x === this.mapWidth || y === this.mapHeight) { - return []; // 挟めないことが確定 (盤面外に到達) - } - - const pos = this.transformXyToPos(x, y); - if (this.mapDataGet(pos) === 'null') return []; // 挟めないことが確定 (配置不可能なマスに到達) - const stone = this.board[pos]; - if (stone === null) return []; // 挟めないことが確定 (石が置かれていないマスに到達) - if (stone === enemyColor) found.push(pos); // 挟めるかもしれない (相手の石を発見) - if (stone === color) return found; // 挟めることが確定 (対となる自分の石を発見) - } - }; - - return concat(diffVectors.map(effectsInLine)); - } - - /** - * ゲームが終了したか否か - */ - public get isEnded(): boolean { - return this.turn === null; - } - - /** - * ゲームの勝者 (null = 引き分け) - */ - public get winner(): Color | null { - return this.isEnded ? - this.blackCount == this.whiteCount ? null : - this.opts.isLlotheo === this.blackCount > this.whiteCount ? WHITE : BLACK : - undefined as never; - } -} diff --git a/packages/backend/src/games/reversi/maps.ts b/packages/backend/src/games/reversi/maps.ts deleted file mode 100644 index 8442c6d741..0000000000 --- a/packages/backend/src/games/reversi/maps.ts +++ /dev/null @@ -1,896 +0,0 @@ -/** - * 組み込みマップ定義 - * - * データ値: - * (スペース) ... マス無し - * - ... マス - * b ... 初期配置される黒石 - * w ... 初期配置される白石 - */ - -export type Map = { - name?: string; - category?: string; - author?: string; - data: string[]; -}; - -export const fourfour: Map = { - name: '4x4', - category: '4x4', - data: [ - '----', - '-wb-', - '-bw-', - '----', - ], -}; - -export const sixsix: Map = { - name: '6x6', - category: '6x6', - data: [ - '------', - '------', - '--wb--', - '--bw--', - '------', - '------', - ], -}; - -export const roundedSixsix: Map = { - name: '6x6 rounded', - category: '6x6', - author: 'syuilo', - data: [ - ' ---- ', - '------', - '--wb--', - '--bw--', - '------', - ' ---- ', - ], -}; - -export const roundedSixsix2: Map = { - name: '6x6 rounded 2', - category: '6x6', - author: 'syuilo', - data: [ - ' -- ', - ' ---- ', - '--wb--', - '--bw--', - ' ---- ', - ' -- ', - ], -}; - -export const eighteight: Map = { - name: '8x8', - category: '8x8', - data: [ - '--------', - '--------', - '--------', - '---wb---', - '---bw---', - '--------', - '--------', - '--------', - ], -}; - -export const eighteightH1: Map = { - name: '8x8 handicap 1', - category: '8x8', - data: [ - 'b-------', - '--------', - '--------', - '---wb---', - '---bw---', - '--------', - '--------', - '--------', - ], -}; - -export const eighteightH2: Map = { - name: '8x8 handicap 2', - category: '8x8', - data: [ - 'b-------', - '--------', - '--------', - '---wb---', - '---bw---', - '--------', - '--------', - '-------b', - ], -}; - -export const eighteightH3: Map = { - name: '8x8 handicap 3', - category: '8x8', - data: [ - 'b------b', - '--------', - '--------', - '---wb---', - '---bw---', - '--------', - '--------', - '-------b', - ], -}; - -export const eighteightH4: Map = { - name: '8x8 handicap 4', - category: '8x8', - data: [ - 'b------b', - '--------', - '--------', - '---wb---', - '---bw---', - '--------', - '--------', - 'b------b', - ], -}; - -export const eighteightH28: Map = { - name: '8x8 handicap 28', - category: '8x8', - data: [ - 'bbbbbbbb', - 'b------b', - 'b------b', - 'b--wb--b', - 'b--bw--b', - 'b------b', - 'b------b', - 'bbbbbbbb', - ], -}; - -export const roundedEighteight: Map = { - name: '8x8 rounded', - category: '8x8', - author: 'syuilo', - data: [ - ' ------ ', - '--------', - '--------', - '---wb---', - '---bw---', - '--------', - '--------', - ' ------ ', - ], -}; - -export const roundedEighteight2: Map = { - name: '8x8 rounded 2', - category: '8x8', - author: 'syuilo', - data: [ - ' ---- ', - ' ------ ', - '--------', - '---wb---', - '---bw---', - '--------', - ' ------ ', - ' ---- ', - ], -}; - -export const roundedEighteight3: Map = { - name: '8x8 rounded 3', - category: '8x8', - author: 'syuilo', - data: [ - ' -- ', - ' ---- ', - ' ------ ', - '---wb---', - '---bw---', - ' ------ ', - ' ---- ', - ' -- ', - ], -}; - -export const eighteightWithNotch: Map = { - name: '8x8 with notch', - category: '8x8', - author: 'syuilo', - data: [ - '--- ---', - '--------', - '--------', - ' --wb-- ', - ' --bw-- ', - '--------', - '--------', - '--- ---', - ], -}; - -export const eighteightWithSomeHoles: Map = { - name: '8x8 with some holes', - category: '8x8', - author: 'syuilo', - data: [ - '--- ----', - '----- --', - '-- -----', - '---wb---', - '---bw- -', - ' -------', - '--- ----', - '--------', - ], -}; - -export const circle: Map = { - name: 'Circle', - category: '8x8', - author: 'syuilo', - data: [ - ' -- ', - ' ------ ', - ' ------ ', - '---wb---', - '---bw---', - ' ------ ', - ' ------ ', - ' -- ', - ], -}; - -export const smile: Map = { - name: 'Smile', - category: '8x8', - author: 'syuilo', - data: [ - ' ------ ', - '--------', - '-- -- --', - '---wb---', - '-- bw --', - '--- ---', - '--------', - ' ------ ', - ], -}; - -export const window: Map = { - name: 'Window', - category: '8x8', - author: 'syuilo', - data: [ - '--------', - '- -- -', - '- -- -', - '---wb---', - '---bw---', - '- -- -', - '- -- -', - '--------', - ], -}; - -export const reserved: Map = { - name: 'Reserved', - category: '8x8', - author: 'Aya', - data: [ - 'w------b', - '--------', - '--------', - '---wb---', - '---bw---', - '--------', - '--------', - 'b------w', - ], -}; - -export const x: Map = { - name: 'X', - category: '8x8', - author: 'Aya', - data: [ - 'w------b', - '-w----b-', - '--w--b--', - '---wb---', - '---bw---', - '--b--w--', - '-b----w-', - 'b------w', - ], -}; - -export const parallel: Map = { - name: 'Parallel', - category: '8x8', - author: 'Aya', - data: [ - '--------', - '--------', - '--------', - '---bb---', - '---ww---', - '--------', - '--------', - '--------', - ], -}; - -export const lackOfBlack: Map = { - name: 'Lack of Black', - category: '8x8', - data: [ - '--------', - '--------', - '--------', - '---w----', - '---bw---', - '--------', - '--------', - '--------', - ], -}; - -export const squareParty: Map = { - name: 'Square Party', - category: '8x8', - author: 'syuilo', - data: [ - '--------', - '-wwwbbb-', - '-w-wb-b-', - '-wwwbbb-', - '-bbbwww-', - '-b-bw-w-', - '-bbbwww-', - '--------', - ], -}; - -export const minesweeper: Map = { - name: 'Minesweeper', - category: '8x8', - author: 'syuilo', - data: [ - 'b-b--w-w', - '-w-wb-b-', - 'w-b--w-b', - '-b-wb-w-', - '-w-bw-b-', - 'b-w--b-w', - '-b-bw-w-', - 'w-w--b-b', - ], -}; - -export const tenthtenth: Map = { - name: '10x10', - category: '10x10', - data: [ - '----------', - '----------', - '----------', - '----------', - '----wb----', - '----bw----', - '----------', - '----------', - '----------', - '----------', - ], -}; - -export const hole: Map = { - name: 'The Hole', - category: '10x10', - author: 'syuilo', - data: [ - '----------', - '----------', - '--wb--wb--', - '--bw--bw--', - '---- ----', - '---- ----', - '--wb--wb--', - '--bw--bw--', - '----------', - '----------', - ], -}; - -export const grid: Map = { - name: 'Grid', - category: '10x10', - author: 'syuilo', - data: [ - '----------', - '- - -- - -', - '----------', - '- - -- - -', - '----wb----', - '----bw----', - '- - -- - -', - '----------', - '- - -- - -', - '----------', - ], -}; - -export const cross: Map = { - name: 'Cross', - category: '10x10', - author: 'Aya', - data: [ - ' ---- ', - ' ---- ', - ' ---- ', - '----------', - '----wb----', - '----bw----', - '----------', - ' ---- ', - ' ---- ', - ' ---- ', - ], -}; - -export const charX: Map = { - name: 'Char X', - category: '10x10', - author: 'syuilo', - data: [ - '--- ---', - '---- ----', - '----------', - ' -------- ', - ' --wb-- ', - ' --bw-- ', - ' -------- ', - '----------', - '---- ----', - '--- ---', - ], -}; - -export const charY: Map = { - name: 'Char Y', - category: '10x10', - author: 'syuilo', - data: [ - '--- ---', - '---- ----', - '----------', - ' -------- ', - ' --wb-- ', - ' --bw-- ', - ' ------ ', - ' ------ ', - ' ------ ', - ' ------ ', - ], -}; - -export const walls: Map = { - name: 'Walls', - category: '10x10', - author: 'Aya', - data: [ - ' bbbbbbbb ', - 'w--------w', - 'w--------w', - 'w--------w', - 'w---wb---w', - 'w---bw---w', - 'w--------w', - 'w--------w', - 'w--------w', - ' bbbbbbbb ', - ], -}; - -export const cpu: Map = { - name: 'CPU', - category: '10x10', - author: 'syuilo', - data: [ - ' b b b b ', - 'w--------w', - ' -------- ', - 'w--------w', - ' ---wb--- ', - ' ---bw--- ', - 'w--------w', - ' -------- ', - 'w--------w', - ' b b b b ', - ], -}; - -export const checker: Map = { - name: 'Checker', - category: '10x10', - author: 'Aya', - data: [ - '----------', - '----------', - '----------', - '---wbwb---', - '---bwbw---', - '---wbwb---', - '---bwbw---', - '----------', - '----------', - '----------', - ], -}; - -export const japaneseCurry: Map = { - name: 'Japanese curry', - category: '10x10', - author: 'syuilo', - data: [ - 'w-b-b-b-b-', - '-w-b-b-b-b', - 'w-w-b-b-b-', - '-w-w-b-b-b', - 'w-w-wwb-b-', - '-w-wbb-b-b', - 'w-w-w-b-b-', - '-w-w-w-b-b', - 'w-w-w-w-b-', - '-w-w-w-w-b', - ], -}; - -export const mosaic: Map = { - name: 'Mosaic', - category: '10x10', - author: 'syuilo', - data: [ - '- - - - - ', - ' - - - - -', - '- - - - - ', - ' - w w - -', - '- - b b - ', - ' - w w - -', - '- - b b - ', - ' - - - - -', - '- - - - - ', - ' - - - - -', - ], -}; - -export const arena: Map = { - name: 'Arena', - category: '10x10', - author: 'syuilo', - data: [ - '- - -- - -', - ' - - - - ', - '- ------ -', - ' -------- ', - '- --wb-- -', - '- --bw-- -', - ' -------- ', - '- ------ -', - ' - - - - ', - '- - -- - -', - ], -}; - -export const reactor: Map = { - name: 'Reactor', - category: '10x10', - author: 'syuilo', - data: [ - '-w------b-', - 'b- - - -w', - '- --wb-- -', - '---b w---', - '- b wb w -', - '- w bw b -', - '---w b---', - '- --bw-- -', - 'w- - - -b', - '-b------w-', - ], -}; - -export const sixeight: Map = { - name: '6x8', - category: 'Special', - data: [ - '------', - '------', - '------', - '--wb--', - '--bw--', - '------', - '------', - '------', - ], -}; - -export const spark: Map = { - name: 'Spark', - category: 'Special', - author: 'syuilo', - data: [ - ' - - ', - '----------', - ' -------- ', - ' -------- ', - ' ---wb--- ', - ' ---bw--- ', - ' -------- ', - ' -------- ', - '----------', - ' - - ', - ], -}; - -export const islands: Map = { - name: 'Islands', - category: 'Special', - author: 'syuilo', - data: [ - '-------- ', - '---wb--- ', - '---bw--- ', - '-------- ', - ' - - ', - ' - - ', - ' --------', - ' --------', - ' --------', - ' --------', - ], -}; - -export const galaxy: Map = { - name: 'Galaxy', - category: 'Special', - author: 'syuilo', - data: [ - ' ------ ', - ' --www--- ', - ' ------w--- ', - '---bbb--w---', - '--b---b-w-b-', - '-b--wwb-w-b-', - '-b-w-bww--b-', - '-b-w-b---b--', - '---w--bbb---', - ' ---w------ ', - ' ---www-- ', - ' ------ ', - ], -}; - -export const triangle: Map = { - name: 'Triangle', - category: 'Special', - author: 'syuilo', - data: [ - ' -- ', - ' -- ', - ' ---- ', - ' ---- ', - ' --wb-- ', - ' --bw-- ', - ' -------- ', - ' -------- ', - '----------', - '----------', - ], -}; - -export const iphonex: Map = { - name: 'iPhone X', - category: 'Special', - author: 'syuilo', - data: [ - ' -- -- ', - '--------', - '--------', - '--------', - '--------', - '---wb---', - '---bw---', - '--------', - '--------', - '--------', - '--------', - ' ------ ', - ], -}; - -export const dealWithIt: Map = { - name: 'Deal with it!', - category: 'Special', - author: 'syuilo', - data: [ - '------------', - '--w-b-------', - ' --b-w------', - ' --w-b---- ', - ' ------- ', - ], -}; - -export const experiment: Map = { - name: 'Let\'s experiment', - category: 'Special', - author: 'syuilo', - data: [ - ' ------------ ', - '------wb------', - '------bw------', - '--------------', - ' - - ', - '------ ------', - 'bbbbbb wwwwww', - 'bbbbbb wwwwww', - 'bbbbbb wwwwww', - 'bbbbbb wwwwww', - 'wwwwww bbbbbb', - ], -}; - -export const bigBoard: Map = { - name: 'Big board', - category: 'Special', - data: [ - '----------------', - '----------------', - '----------------', - '----------------', - '----------------', - '----------------', - '----------------', - '-------wb-------', - '-------bw-------', - '----------------', - '----------------', - '----------------', - '----------------', - '----------------', - '----------------', - '----------------', - ], -}; - -export const twoBoard: Map = { - name: 'Two board', - category: 'Special', - author: 'Aya', - data: [ - '-------- --------', - '-------- --------', - '-------- --------', - '---wb--- ---wb---', - '---bw--- ---bw---', - '-------- --------', - '-------- --------', - '-------- --------', - ], -}; - -export const test1: Map = { - name: 'Test1', - category: 'Test', - data: [ - '--------', - '---wb---', - '---bw---', - '--------', - ], -}; - -export const test2: Map = { - name: 'Test2', - category: 'Test', - data: [ - '------', - '------', - '-b--w-', - '-w--b-', - '-w--b-', - ], -}; - -export const test3: Map = { - name: 'Test3', - category: 'Test', - data: [ - '-w-', - '--w', - 'w--', - '-w-', - '--w', - 'w--', - '-w-', - '--w', - 'w--', - '-w-', - '---', - 'b--', - ], -}; - -export const test4: Map = { - name: 'Test4', - category: 'Test', - data: [ - '-w--b-', - '-w--b-', - '------', - '-w--b-', - '-w--b-', - ], -}; - -// 検証用: この盤面で藍(lv3)が黒で始めると何故か(?)A1に打ってしまう -export const test6: Map = { - name: 'Test6', - category: 'Test', - data: [ - '--wwwww-', - 'wwwwwwww', - 'wbbbwbwb', - 'wbbbbwbb', - 'wbwbbwbb', - 'wwbwbbbb', - '--wbbbbb', - '-wwwww--', - ], -}; - -// 検証用: この盤面で藍(lv3)が黒で始めると何故か(?)G7に打ってしまう -export const test7: Map = { - name: 'Test7', - category: 'Test', - data: [ - 'b--w----', - 'b-wwww--', - 'bwbwwwbb', - 'wbwwwwb-', - 'wwwwwww-', - '-wwbbwwb', - '--wwww--', - '--wwww--', - ], -}; - -// 検証用: この盤面で藍(lv5)が黒で始めると何故か(?)A1に打ってしまう -export const test8: Map = { - name: 'Test8', - category: 'Test', - data: [ - '--------', - '-----w--', - 'w--www--', - 'wwwwww--', - 'bbbbwww-', - 'wwwwww--', - '--www---', - '--ww----', - ], -}; diff --git a/packages/backend/src/games/reversi/package.json b/packages/backend/src/games/reversi/package.json deleted file mode 100644 index a4415ad141..0000000000 --- a/packages/backend/src/games/reversi/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "misskey-reversi", - "version": "0.0.5", - "description": "Misskey reversi engine", - "keywords": [ - "misskey" - ], - "author": "syuilo ", - "license": "MIT", - "repository": "https://github.com/misskey-dev/misskey.git", - "bugs": "https://github.com/misskey-dev/misskey/issues", - "main": "./built/core.js", - "types": "./built/core.d.ts", - "scripts": { - "build": "tsc" - }, - "dependencies": {} -} diff --git a/packages/backend/src/games/reversi/tsconfig.json b/packages/backend/src/games/reversi/tsconfig.json deleted file mode 100644 index 851fb6b7e4..0000000000 --- a/packages/backend/src/games/reversi/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "compilerOptions": { - "noEmitOnError": false, - "noImplicitAny": false, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "experimentalDecorators": true, - "declaration": true, - "sourceMap": false, - "target": "es2017", - "module": "commonjs", - "removeComments": false, - "noLib": false, - "outDir": "./built", - "rootDir": "./" - }, - "compileOnSave": false, - "include": [ - "./core.ts" - ] -} diff --git a/packages/backend/src/misc/gen-avatar.ts b/packages/backend/src/misc/gen-identicon.ts similarity index 90% rename from packages/backend/src/misc/gen-avatar.ts rename to packages/backend/src/misc/gen-identicon.ts index 8838ec8d15..5cedd7afaf 100644 --- a/packages/backend/src/misc/gen-avatar.ts +++ b/packages/backend/src/misc/gen-identicon.ts @@ -1,5 +1,6 @@ /** - * Random avatar generator + * Identicon generator + * https://en.wikipedia.org/wiki/Identicon */ import * as p from 'pureimage'; @@ -34,9 +35,9 @@ const cellSize = actualSize / n; const sideN = Math.floor(n / 2); /** - * Generate buffer of random avatar by seed + * Generate buffer of an identicon by seed */ -export function genAvatar(seed: string, stream: WriteStream): Promise { +export function genIdenticon(seed: string, stream: WriteStream): Promise { const rand = gen.create(seed); const canvas = p.make(size, size); const ctx = canvas.getContext('2d'); diff --git a/packages/backend/src/misc/schema.ts b/packages/backend/src/misc/schema.ts index 4131875ef7..ae6f1bac86 100644 --- a/packages/backend/src/misc/schema.ts +++ b/packages/backend/src/misc/schema.ts @@ -22,8 +22,6 @@ import { packedFederationInstanceSchema } from '@/models/repositories/federation import { packedQueueCountSchema } from '@/models/repositories/queue'; import { packedGalleryPostSchema } from '@/models/repositories/gallery-post'; import { packedEmojiSchema } from '@/models/repositories/emoji'; -import { packedReversiGameSchema } from '@/models/repositories/games/reversi/game'; -import { packedReversiMatchingSchema } from '@/models/repositories/games/reversi/matching'; export const refs = { User: packedUserSchema, @@ -49,8 +47,6 @@ export const refs = { FederationInstance: packedFederationInstanceSchema, GalleryPost: packedGalleryPostSchema, Emoji: packedEmojiSchema, - ReversiGame: packedReversiGameSchema, - ReversiMatching: packedReversiMatchingSchema, }; export type Packed = ObjType<(typeof refs[x])['properties']>; diff --git a/packages/backend/src/models/entities/games/reversi/game.ts b/packages/backend/src/models/entities/games/reversi/game.ts deleted file mode 100644 index fe9b8a5ba5..0000000000 --- a/packages/backend/src/models/entities/games/reversi/game.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from '../../user'; -import { id } from '../../../id'; - -@Entity() -export class ReversiGame { - @PrimaryColumn(id()) - public id: string; - - @Index() - @Column('timestamp with time zone', { - comment: 'The created date of the ReversiGame.', - }) - public createdAt: Date; - - @Column('timestamp with time zone', { - nullable: true, - comment: 'The started date of the ReversiGame.', - }) - public startedAt: Date | null; - - @Column(id()) - public user1Id: User['id']; - - @ManyToOne(type => User, { - onDelete: 'CASCADE', - }) - @JoinColumn() - public user1: User | null; - - @Column(id()) - public user2Id: User['id']; - - @ManyToOne(type => User, { - onDelete: 'CASCADE', - }) - @JoinColumn() - public user2: User | null; - - @Column('boolean', { - default: false, - }) - public user1Accepted: boolean; - - @Column('boolean', { - default: false, - }) - public user2Accepted: boolean; - - /** - * どちらのプレイヤーが先行(黒)か - * 1 ... user1 - * 2 ... user2 - */ - @Column('integer', { - nullable: true, - }) - public black: number | null; - - @Column('boolean', { - default: false, - }) - public isStarted: boolean; - - @Column('boolean', { - default: false, - }) - public isEnded: boolean; - - @Column({ - ...id(), - nullable: true, - }) - public winnerId: User['id'] | null; - - @Column({ - ...id(), - nullable: true, - }) - public surrendered: User['id'] | null; - - @Column('jsonb', { - default: [], - }) - public logs: { - at: Date; - color: boolean; - pos: number; - }[]; - - @Column('varchar', { - array: true, length: 64, - }) - public map: string[]; - - @Column('varchar', { - length: 32, - }) - public bw: string; - - @Column('boolean', { - default: false, - }) - public isLlotheo: boolean; - - @Column('boolean', { - default: false, - }) - public canPutEverywhere: boolean; - - @Column('boolean', { - default: false, - }) - public loopedBoard: boolean; - - @Column('jsonb', { - nullable: true, default: null, - }) - public form1: any | null; - - @Column('jsonb', { - nullable: true, default: null, - }) - public form2: any | null; - - /** - * ログのposを文字列としてすべて連結したもののCRC32値 - */ - @Column('varchar', { - length: 32, nullable: true, - }) - public crc32: string | null; -} diff --git a/packages/backend/src/models/entities/games/reversi/matching.ts b/packages/backend/src/models/entities/games/reversi/matching.ts deleted file mode 100644 index 70bb555e2f..0000000000 --- a/packages/backend/src/models/entities/games/reversi/matching.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { User } from '../../user'; -import { id } from '../../../id'; - -@Entity() -export class ReversiMatching { - @PrimaryColumn(id()) - public id: string; - - @Index() - @Column('timestamp with time zone', { - comment: 'The created date of the ReversiMatching.', - }) - public createdAt: Date; - - @Index() - @Column(id()) - public parentId: User['id']; - - @ManyToOne(type => User, { - onDelete: 'CASCADE', - }) - @JoinColumn() - public parent: User | null; - - @Index() - @Column(id()) - public childId: User['id']; - - @ManyToOne(type => User, { - onDelete: 'CASCADE', - }) - @JoinColumn() - public child: User | null; -} diff --git a/packages/backend/src/models/index.ts b/packages/backend/src/models/index.ts index 7154cca550..67da347395 100644 --- a/packages/backend/src/models/index.ts +++ b/packages/backend/src/models/index.ts @@ -18,7 +18,6 @@ import { AccessToken } from './entities/access-token'; import { UserNotePining } from './entities/user-note-pining'; import { SigninRepository } from './repositories/signin'; import { MessagingMessageRepository } from './repositories/messaging-message'; -import { ReversiGameRepository } from './repositories/games/reversi/game'; import { UserListRepository } from './repositories/user-list'; import { UserListJoining } from './entities/user-list-joining'; import { UserGroupRepository } from './repositories/user-group'; @@ -30,7 +29,6 @@ import { BlockingRepository } from './repositories/blocking'; import { NoteReactionRepository } from './repositories/note-reaction'; import { NotificationRepository } from './repositories/notification'; import { NoteFavoriteRepository } from './repositories/note-favorite'; -import { ReversiMatchingRepository } from './repositories/games/reversi/matching'; import { UserPublickey } from './entities/user-publickey'; import { UserKeypair } from './entities/user-keypair'; import { AppRepository } from './repositories/app'; @@ -107,8 +105,6 @@ export const AuthSessions = getCustomRepository(AuthSessionRepository); export const AccessTokens = getRepository(AccessToken); export const Signins = getCustomRepository(SigninRepository); export const MessagingMessages = getCustomRepository(MessagingMessageRepository); -export const ReversiGames = getCustomRepository(ReversiGameRepository); -export const ReversiMatchings = getCustomRepository(ReversiMatchingRepository); export const Pages = getCustomRepository(PageRepository); export const PageLikes = getCustomRepository(PageLikeRepository); export const GalleryPosts = getCustomRepository(GalleryPostRepository); diff --git a/packages/backend/src/models/repositories/games/reversi/game.ts b/packages/backend/src/models/repositories/games/reversi/game.ts deleted file mode 100644 index a9e0496760..0000000000 --- a/packages/backend/src/models/repositories/games/reversi/game.ts +++ /dev/null @@ -1,191 +0,0 @@ -import { User } from '@/models/entities/user'; -import { EntityRepository, Repository } from 'typeorm'; -import { Users } from '../../../index'; -import { ReversiGame } from '@/models/entities/games/reversi/game'; -import { Packed } from '@/misc/schema'; - -@EntityRepository(ReversiGame) -export class ReversiGameRepository extends Repository { - public async pack( - src: ReversiGame['id'] | ReversiGame, - me?: { id: User['id'] } | null | undefined, - options?: { - detail?: boolean - } - ): Promise> { - const opts = Object.assign({ - detail: true, - }, options); - - const game = typeof src === 'object' ? src : await this.findOneOrFail(src); - - return { - id: game.id, - createdAt: game.createdAt.toISOString(), - startedAt: game.startedAt && game.startedAt.toISOString(), - isStarted: game.isStarted, - isEnded: game.isEnded, - form1: game.form1, - form2: game.form2, - user1Accepted: game.user1Accepted, - user2Accepted: game.user2Accepted, - user1Id: game.user1Id, - user2Id: game.user2Id, - user1: await Users.pack(game.user1Id, me), - user2: await Users.pack(game.user2Id, me), - winnerId: game.winnerId, - winner: game.winnerId ? await Users.pack(game.winnerId, me) : null, - surrendered: game.surrendered, - black: game.black, - bw: game.bw, - isLlotheo: game.isLlotheo, - canPutEverywhere: game.canPutEverywhere, - loopedBoard: game.loopedBoard, - ...(opts.detail ? { - logs: game.logs.map(log => ({ - at: log.at.toISOString(), - color: log.color, - pos: log.pos, - })), - map: game.map, - } : {}), - }; - } -} - -export const packedReversiGameSchema = { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: { - id: { - type: 'string' as const, - optional: false as const, nullable: false as const, - format: 'id', - example: 'xxxxxxxxxx', - }, - createdAt: { - type: 'string' as const, - optional: false as const, nullable: false as const, - format: 'date-time', - }, - startedAt: { - type: 'string' as const, - optional: false as const, nullable: true as const, - format: 'date-time', - }, - isStarted: { - type: 'boolean' as const, - optional: false as const, nullable: false as const, - }, - isEnded: { - type: 'boolean' as const, - optional: false as const, nullable: false as const, - }, - form1: { - type: 'any' as const, - optional: false as const, nullable: true as const, - }, - form2: { - type: 'any' as const, - optional: false as const, nullable: true as const, - }, - user1Accepted: { - type: 'boolean' as const, - optional: false as const, nullable: false as const, - }, - user2Accepted: { - type: 'boolean' as const, - optional: false as const, nullable: false as const, - }, - user1Id: { - type: 'string' as const, - optional: false as const, nullable: false as const, - format: 'id', - example: 'xxxxxxxxxx', - }, - user2Id: { - type: 'string' as const, - optional: false as const, nullable: false as const, - format: 'id', - example: 'xxxxxxxxxx', - }, - user1: { - type: 'object' as const, - optional: false as const, nullable: false as const, - ref: 'User' as const, - }, - user2: { - type: 'object' as const, - optional: false as const, nullable: false as const, - ref: 'User' as const, - }, - winnerId: { - type: 'string' as const, - optional: false as const, nullable: true as const, - format: 'id', - example: 'xxxxxxxxxx', - }, - winner: { - type: 'object' as const, - optional: false as const, nullable: true as const, - ref: 'User' as const, - }, - surrendered: { - type: 'string' as const, - optional: false as const, nullable: true as const, - format: 'id', - example: 'xxxxxxxxxx', - }, - black: { - type: 'number' as const, - optional: false as const, nullable: true as const, - }, - bw: { - type: 'string' as const, - optional: false as const, nullable: false as const, - }, - isLlotheo: { - type: 'boolean' as const, - optional: false as const, nullable: false as const, - }, - canPutEverywhere: { - type: 'boolean' as const, - optional: false as const, nullable: false as const, - }, - loopedBoard: { - type: 'boolean' as const, - optional: false as const, nullable: false as const, - }, - logs: { - type: 'array' as const, - optional: true as const, nullable: false as const, - items: { - type: 'object' as const, - optional: true as const, nullable: false as const, - properties: { - at: { - type: 'string' as const, - optional: false as const, nullable: false as const, - format: 'date-time', - }, - color: { - type: 'boolean' as const, - optional: false as const, nullable: false as const, - }, - pos: { - type: 'number' as const, - optional: false as const, nullable: false as const, - }, - }, - }, - }, - map: { - type: 'array' as const, - optional: true as const, nullable: false as const, - items: { - type: 'string' as const, - optional: false as const, nullable: false as const, - }, - }, - }, -}; diff --git a/packages/backend/src/models/repositories/games/reversi/matching.ts b/packages/backend/src/models/repositories/games/reversi/matching.ts deleted file mode 100644 index b55f598068..0000000000 --- a/packages/backend/src/models/repositories/games/reversi/matching.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { EntityRepository, Repository } from 'typeorm'; -import { ReversiMatching } from '@/models/entities/games/reversi/matching'; -import { Users } from '../../../index'; -import { awaitAll } from '@/prelude/await-all'; -import { User } from '@/models/entities/user'; -import { Packed } from '@/misc/schema'; - -@EntityRepository(ReversiMatching) -export class ReversiMatchingRepository extends Repository { - public async pack( - src: ReversiMatching['id'] | ReversiMatching, - me: { id: User['id'] } - ): Promise> { - const matching = typeof src === 'object' ? src : await this.findOneOrFail(src); - - return await awaitAll({ - id: matching.id, - createdAt: matching.createdAt.toISOString(), - parentId: matching.parentId, - parent: Users.pack(matching.parentId, me, { - detail: true, - }), - childId: matching.childId, - child: Users.pack(matching.childId, me, { - detail: true, - }), - }); - } -} - -export const packedReversiMatchingSchema = { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: { - id: { - type: 'string' as const, - optional: false as const, nullable: false as const, - format: 'id', - example: 'xxxxxxxxxx', - }, - createdAt: { - type: 'string' as const, - optional: false as const, nullable: false as const, - format: 'date-time', - }, - parentId: { - type: 'string' as const, - optional: false as const, nullable: false as const, - format: 'id', - example: 'xxxxxxxxxx', - }, - parent: { - type: 'object' as const, - optional: false as const, nullable: true as const, - ref: 'User' as const, - }, - childId: { - type: 'string' as const, - optional: false as const, nullable: false as const, - format: 'id', - example: 'xxxxxxxxxx', - }, - child: { - type: 'object' as const, - optional: false as const, nullable: false as const, - ref: 'User' as const, - }, - }, -}; diff --git a/packages/backend/src/models/repositories/user.ts b/packages/backend/src/models/repositories/user.ts index 3dc7c67ec2..85141cdc41 100644 --- a/packages/backend/src/models/repositories/user.ts +++ b/packages/backend/src/models/repositories/user.ts @@ -159,7 +159,7 @@ export class UserRepository extends Repository { if (user.avatarUrl) { return user.avatarUrl; } else { - return `${config.url}/random-avatar/${user.id}`; + return `${config.url}/identicon/${user.id}`; } } diff --git a/packages/backend/src/queue/index.ts b/packages/backend/src/queue/index.ts index 2fbc1b1c01..f9994c3b59 100644 --- a/packages/backend/src/queue/index.ts +++ b/packages/backend/src/queue/index.ts @@ -213,6 +213,16 @@ export function createImportUserListsJob(user: ThinUser, fileId: DriveFile['id'] }); } +export function createImportCustomEmojisJob(user: ThinUser, fileId: DriveFile['id']) { + return dbQueue.add('importCustomEmojis', { + user: user, + fileId: fileId, + }, { + removeOnComplete: true, + removeOnFail: true, + }); +} + export function createDeleteAccountJob(user: ThinUser, opts: { soft?: boolean; } = {}) { return dbQueue.add('deleteAccount', { user: user, 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 3930b9d6d4..a420866dcf 100644 --- a/packages/backend/src/queue/processors/db/export-custom-emojis.ts +++ b/packages/backend/src/queue/processors/db/export-custom-emojis.ts @@ -52,7 +52,7 @@ export async function exportCustomEmojis(job: Bull.Job, done: () => void): Promi }); }; - await writeMeta(`{"metaVersion":1,"emojis":[`); + await writeMeta(`{"metaVersion":2,"emojis":[`); const customEmojis = await Emojis.find({ where: { @@ -64,9 +64,9 @@ export async function exportCustomEmojis(job: Bull.Job, done: () => void): Promi }); for (const emoji of customEmojis) { - const exportId = ulid().toLowerCase(); const ext = mime.extension(emoji.type); - const emojiPath = path + '/' + exportId + (ext ? '.' + ext : ''); + const fileName = emoji.name + (ext ? '.' + ext : ''); + const emojiPath = path + '/' + fileName; fs.writeFileSync(emojiPath, '', 'binary'); let downloaded = false; @@ -77,8 +77,12 @@ export async function exportCustomEmojis(job: Bull.Job, done: () => void): Promi logger.error(e); } + if (!downloaded) { + fs.unlinkSync(emojiPath); + } + const content = JSON.stringify({ - id: exportId, + fileName: fileName, downloaded: downloaded, emoji: emoji, }); diff --git a/packages/backend/src/queue/processors/db/import-custom-emojis.ts b/packages/backend/src/queue/processors/db/import-custom-emojis.ts new file mode 100644 index 0000000000..eb386bbb42 --- /dev/null +++ b/packages/backend/src/queue/processors/db/import-custom-emojis.ts @@ -0,0 +1,84 @@ +import * as Bull from 'bull'; +import * as tmp from 'tmp'; +import * as fs from 'fs'; +const unzipper = require('unzipper'); +import { getConnection } from 'typeorm'; + +import { queueLogger } from '../../logger'; +import { downloadUrl } from '@/misc/download-url'; +import { DriveFiles, Emojis } from '@/models/index'; +import { DbUserImportJobData } from '@/queue/types'; +import addFile from '@/services/drive/add-file'; +import { genId } from '@/misc/gen-id'; + +const logger = queueLogger.createSubLogger('import-custom-emojis'); + +// TODO: 名前衝突時の動作を選べるようにする +export async function importCustomEmojis(job: Bull.Job, done: any): Promise { + logger.info(`Importing custom emojis ...`); + + const file = await DriveFiles.findOne({ + id: job.data.fileId, + }); + if (file == null) { + done(); + return; + } + + // Create temp dir + const [path, cleanup] = await new Promise<[string, () => void]>((res, rej) => { + tmp.dir((e, path, cleanup) => { + if (e) return rej(e); + res([path, cleanup]); + }); + }); + + logger.info(`Temp dir is ${path}`); + + const destPath = path + '/emojis.zip'; + + try { + fs.writeFileSync(destPath, '', 'binary'); + await downloadUrl(file.url, destPath); + } catch (e) { // TODO: 何度か再試行 + logger.error(e); + throw e; + } + + const outputPath = path + '/emojis'; + const unzipStream = fs.createReadStream(destPath); + const extractor = unzipper.Extract({ path: outputPath }); + extractor.on('close', async () => { + const metaRaw = fs.readFileSync(outputPath + '/meta.json', 'utf-8'); + const meta = JSON.parse(metaRaw); + + for (const record of meta.emojis) { + if (!record.downloaded) continue; + const emojiInfo = record.emoji; + const emojiPath = outputPath + '/' + record.fileName; + await Emojis.delete({ + name: emojiInfo.name, + }); + const driveFile = await addFile(null, emojiPath, record.fileName, null, null, true); + const emoji = await Emojis.insert({ + id: genId(), + updatedAt: new Date(), + name: emojiInfo.name, + category: emojiInfo.category, + host: null, + aliases: emojiInfo.aliases, + url: driveFile.url, + type: driveFile.type, + }).then(x => Emojis.findOneOrFail(x.identifiers[0])); + } + + await getConnection().queryResultCache!.remove(['meta_emojis']); + + cleanup(); + + logger.succ('Imported'); + done(); + }); + unzipStream.pipe(extractor); + logger.succ(`Unzipping to ${outputPath}`); +} diff --git a/packages/backend/src/queue/processors/db/index.ts b/packages/backend/src/queue/processors/db/index.ts index 1542f401ef..5fffa378f5 100644 --- a/packages/backend/src/queue/processors/db/index.ts +++ b/packages/backend/src/queue/processors/db/index.ts @@ -12,6 +12,7 @@ import { importUserLists } from './import-user-lists'; import { deleteAccount } from './delete-account'; import { importMuting } from './import-muting'; import { importBlocking } from './import-blocking'; +import { importCustomEmojis } from './import-custom-emojis'; const jobs = { deleteDriveFiles, @@ -25,6 +26,7 @@ const jobs = { importMuting, importBlocking, importUserLists, + importCustomEmojis, deleteAccount, } as Record | Bull.ProcessPromiseFunction>; 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 new file mode 100644 index 0000000000..ef0f315022 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/admin/emoji/add-aliases-bulk.ts @@ -0,0 +1,39 @@ +import $ from 'cafy'; +import define from '../../../define'; +import { ID } from '@/misc/cafy-id'; +import { Emojis } from '@/models/index'; +import { getConnection, In } from 'typeorm'; +import { ApiError } from '../../../error'; + +export const meta = { + tags: ['admin'], + + requireCredential: true as const, + requireModerator: true, + + params: { + ids: { + validator: $.arr($.type(ID)), + }, + + aliases: { + validator: $.arr($.str), + }, + }, +}; + +// eslint-disable-next-line import/no-default-export +export default define(meta, async (ps) => { + const emojis = await Emojis.find({ + id: In(ps.ids), + }); + + for (const emoji of emojis) { + await Emojis.update(emoji.id, { + updatedAt: new Date(), + aliases: [...new Set(emoji.aliases.concat(ps.aliases))], + }); + } + + await getConnection().queryResultCache!.remove(['meta_emojis']); +}); 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 new file mode 100644 index 0000000000..a99cd3c978 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/admin/emoji/delete-bulk.ts @@ -0,0 +1,37 @@ +import $ from 'cafy'; +import define from '../../../define'; +import { ID } from '@/misc/cafy-id'; +import { Emojis } from '@/models/index'; +import { getConnection, In } from 'typeorm'; +import { insertModerationLog } from '@/services/insert-moderation-log'; +import { ApiError } from '../../../error'; + +export const meta = { + tags: ['admin'], + + requireCredential: true as const, + requireModerator: true, + + params: { + ids: { + validator: $.arr($.type(ID)), + }, + }, +}; + +// eslint-disable-next-line import/no-default-export +export default define(meta, async (ps, me) => { + const emojis = await Emojis.find({ + id: In(ps.ids), + }); + + for (const emoji of emojis) { + await Emojis.delete(emoji.id); + + await getConnection().queryResultCache!.remove(['meta_emojis']); + + insertModerationLog(me, 'deleteEmoji', { + emoji: emoji, + }); + } +}); diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/remove.ts b/packages/backend/src/server/api/endpoints/admin/emoji/delete.ts similarity index 95% rename from packages/backend/src/server/api/endpoints/admin/emoji/remove.ts rename to packages/backend/src/server/api/endpoints/admin/emoji/delete.ts index 440c1008c7..870245ac92 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/remove.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/delete.ts @@ -37,7 +37,7 @@ export default define(meta, async (ps, me) => { await getConnection().queryResultCache!.remove(['meta_emojis']); - insertModerationLog(me, 'removeEmoji', { + insertModerationLog(me, 'deleteEmoji', { emoji: emoji, }); }); diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/import-zip.ts b/packages/backend/src/server/api/endpoints/admin/emoji/import-zip.ts new file mode 100644 index 0000000000..04895b8f20 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/admin/emoji/import-zip.ts @@ -0,0 +1,21 @@ +import $ from 'cafy'; +import define from '../../../define'; +import { createImportCustomEmojisJob } from '@/queue/index'; +import ms from 'ms'; +import { ID } from '@/misc/cafy-id'; + +export const meta = { + secure: true, + requireCredential: true as const, + requireModerator: true, + params: { + fileId: { + validator: $.type(ID), + }, + }, +}; + +// eslint-disable-next-line import/no-default-export +export default define(meta, async (ps, user) => { + createImportCustomEmojisJob(user, ps.fileId); +}); 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 new file mode 100644 index 0000000000..4c771b4e42 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/admin/emoji/remove-aliases-bulk.ts @@ -0,0 +1,39 @@ +import $ from 'cafy'; +import define from '../../../define'; +import { ID } from '@/misc/cafy-id'; +import { Emojis } from '@/models/index'; +import { getConnection, In } from 'typeorm'; +import { ApiError } from '../../../error'; + +export const meta = { + tags: ['admin'], + + requireCredential: true as const, + requireModerator: true, + + params: { + ids: { + validator: $.arr($.type(ID)), + }, + + aliases: { + validator: $.arr($.str), + }, + }, +}; + +// eslint-disable-next-line import/no-default-export +export default define(meta, async (ps) => { + const emojis = await Emojis.find({ + id: In(ps.ids), + }); + + for (const emoji of emojis) { + await Emojis.update(emoji.id, { + updatedAt: new Date(), + aliases: emoji.aliases.filter(x => !ps.aliases.includes(x)), + }); + } + + await getConnection().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 new file mode 100644 index 0000000000..33dccbc642 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/admin/emoji/set-aliases-bulk.ts @@ -0,0 +1,35 @@ +import $ from 'cafy'; +import define from '../../../define'; +import { ID } from '@/misc/cafy-id'; +import { Emojis } from '@/models/index'; +import { getConnection, In } from 'typeorm'; +import { ApiError } from '../../../error'; + +export const meta = { + tags: ['admin'], + + requireCredential: true as const, + requireModerator: true, + + params: { + ids: { + validator: $.arr($.type(ID)), + }, + + aliases: { + validator: $.arr($.str), + }, + }, +}; + +// eslint-disable-next-line import/no-default-export +export default define(meta, async (ps) => { + await Emojis.update({ + id: In(ps.ids), + }, { + updatedAt: new Date(), + aliases: ps.aliases, + }); + + await getConnection().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 new file mode 100644 index 0000000000..d40ed52da7 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/admin/emoji/set-category-bulk.ts @@ -0,0 +1,35 @@ +import $ from 'cafy'; +import define from '../../../define'; +import { ID } from '@/misc/cafy-id'; +import { Emojis } from '@/models/index'; +import { getConnection, In } from 'typeorm'; +import { ApiError } from '../../../error'; + +export const meta = { + tags: ['admin'], + + requireCredential: true as const, + requireModerator: true, + + params: { + ids: { + validator: $.arr($.type(ID)), + }, + + category: { + validator: $.optional.nullable.str, + }, + }, +}; + +// eslint-disable-next-line import/no-default-export +export default define(meta, async (ps) => { + await Emojis.update({ + id: In(ps.ids), + }, { + updatedAt: new Date(), + category: ps.category, + }); + + await getConnection().queryResultCache!.remove(['meta_emojis']); +}); diff --git a/packages/backend/src/server/api/endpoints/games/reversi/games.ts b/packages/backend/src/server/api/endpoints/games/reversi/games.ts deleted file mode 100644 index 8b0e812ca9..0000000000 --- a/packages/backend/src/server/api/endpoints/games/reversi/games.ts +++ /dev/null @@ -1,157 +0,0 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { ReversiGames } from '@/models/index'; -import { makePaginationQuery } from '../../../common/make-pagination-query'; -import { Brackets } from 'typeorm'; - -export const meta = { - tags: ['games'], - - params: { - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - - my: { - validator: $.optional.bool, - default: false, - }, - }, - - res: { - type: 'array' as const, - optional: false as const, nullable: false as const, - items: { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: { - id: { - type: 'string' as const, - optional: false as const, nullable: false as const, - format: 'id', - }, - createdAt: { - type: 'string' as const, - optional: false as const, nullable: false as const, - format: 'date-time', - }, - startedAt: { - type: 'string' as const, - optional: false as const, nullable: false as const, - format: 'date-time', - }, - isStarted: { - type: 'boolean' as const, - optional: false as const, nullable: false as const, - }, - isEnded: { - type: 'boolean' as const, - optional: false as const, nullable: false as const, - }, - form1: { - type: 'any' as const, - optional: false as const, nullable: true as const, - }, - form2: { - type: 'any' as const, - optional: false as const, nullable: true as const, - }, - user1Accepted: { - type: 'boolean' as const, - optional: false as const, nullable: false as const, - default: false, - }, - user2Accepted: { - type: 'boolean' as const, - optional: false as const, nullable: false as const, - default: false, - }, - user1Id: { - type: 'string' as const, - optional: false as const, nullable: false as const, - format: 'id', - }, - user2Id: { - type: 'string' as const, - optional: false as const, nullable: false as const, - format: 'id', - }, - user1: { - type: 'object' as const, - optional: false as const, nullable: false as const, - ref: 'User', - }, - user2: { - type: 'object' as const, - optional: false as const, nullable: false as const, - ref: 'User', - }, - winnerId: { - type: 'string' as const, - optional: false as const, nullable: true as const, - format: 'id', - }, - winner: { - type: 'object' as const, - optional: false as const, nullable: true as const, - ref: 'User', - }, - surrendered: { - type: 'string' as const, - optional: false as const, nullable: true as const, - format: 'id', - }, - black: { - type: 'number' as const, - optional: false as const, nullable: true as const, - }, - bw: { - type: 'string' as const, - optional: false as const, nullable: false as const, - }, - isLlotheo: { - type: 'boolean' as const, - optional: false as const, nullable: false as const, - }, - canPutEverywhere: { - type: 'boolean' as const, - optional: false as const, nullable: false as const, - }, - loopedBoard: { - type: 'boolean' as const, - optional: false as const, nullable: false as const, - }, - }, - }, - }, -}; - -// eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { - const query = makePaginationQuery(ReversiGames.createQueryBuilder('game'), ps.sinceId, ps.untilId) - .andWhere('game.isStarted = TRUE'); - - if (ps.my && user) { - query.andWhere(new Brackets(qb => { qb - .where('game.user1Id = :userId', { userId: user.id }) - .orWhere('game.user2Id = :userId', { userId: user.id }); - })); - } - - // Fetch games - const games = await query.take(ps.limit!).getMany(); - - return await Promise.all(games.map((g) => ReversiGames.pack(g, user, { - detail: false, - }))); -}); diff --git a/packages/backend/src/server/api/endpoints/games/reversi/games/show.ts b/packages/backend/src/server/api/endpoints/games/reversi/games/show.ts deleted file mode 100644 index 020e9e6fc2..0000000000 --- a/packages/backend/src/server/api/endpoints/games/reversi/games/show.ts +++ /dev/null @@ -1,169 +0,0 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import Reversi from '../../../../../../games/reversi/core'; -import define from '../../../../define'; -import { ApiError } from '../../../../error'; -import { ReversiGames } from '@/models/index'; - -export const meta = { - tags: ['games'], - - params: { - gameId: { - validator: $.type(ID), - }, - }, - - errors: { - noSuchGame: { - message: 'No such game.', - code: 'NO_SUCH_GAME', - id: 'f13a03db-fae1-46c9-87f3-43c8165419e1', - }, - }, - - res: { - type: 'array' as const, - optional: false as const, nullable: false as const, - items: { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: { - id: { - type: 'string' as const, - optional: false as const, nullable: false as const, - format: 'id', - }, - createdAt: { - type: 'string' as const, - optional: false as const, nullable: false as const, - format: 'date-time', - }, - startedAt: { - type: 'string' as const, - optional: false as const, nullable: false as const, - format: 'date-time', - }, - isStarted: { - type: 'boolean' as const, - optional: false as const, nullable: false as const, - }, - isEnded: { - type: 'boolean' as const, - optional: false as const, nullable: false as const, - }, - form1: { - type: 'any' as const, - optional: false as const, nullable: true as const, - }, - form2: { - type: 'any' as const, - optional: false as const, nullable: true as const, - }, - user1Accepted: { - type: 'boolean' as const, - optional: false as const, nullable: false as const, - default: false, - }, - user2Accepted: { - type: 'boolean' as const, - optional: false as const, nullable: false as const, - default: false, - }, - user1Id: { - type: 'string' as const, - optional: false as const, nullable: false as const, - format: 'id', - }, - user2Id: { - type: 'string' as const, - optional: false as const, nullable: false as const, - format: 'id', - }, - user1: { - type: 'object' as const, - optional: false as const, nullable: false as const, - ref: 'User', - }, - user2: { - type: 'object' as const, - optional: false as const, nullable: false as const, - ref: 'User', - }, - winnerId: { - type: 'string' as const, - optional: false as const, nullable: true as const, - format: 'id', - }, - winner: { - type: 'object' as const, - optional: false as const, nullable: true as const, - ref: 'User', - }, - surrendered: { - type: 'string' as const, - optional: false as const, nullable: true as const, - format: 'id', - }, - black: { - type: 'number' as const, - optional: false as const, nullable: true as const, - }, - bw: { - type: 'string' as const, - optional: false as const, nullable: false as const, - }, - isLlotheo: { - type: 'boolean' as const, - optional: false as const, nullable: false as const, - }, - canPutEverywhere: { - type: 'boolean' as const, - optional: false as const, nullable: false as const, - }, - loopedBoard: { - type: 'boolean' as const, - optional: false as const, nullable: false as const, - }, - board: { - type: 'array' as const, - optional: false as const, nullable: false as const, - items: { - type: 'any' as const, - optional: false as const, nullable: false as const, - }, - }, - turn: { - type: 'any' as const, - optional: false as const, nullable: false as const, - }, - }, - }, - }, -}; - -// eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { - const game = await ReversiGames.findOne(ps.gameId); - - if (game == null) { - throw new ApiError(meta.errors.noSuchGame); - } - - const o = new Reversi(game.map, { - isLlotheo: game.isLlotheo, - canPutEverywhere: game.canPutEverywhere, - loopedBoard: game.loopedBoard, - }); - - for (const log of game.logs) { - o.put(log.color, log.pos); - } - - const packed = await ReversiGames.pack(game, user); - - return Object.assign({ - board: o.board, - turn: o.turn, - }, packed); -}); diff --git a/packages/backend/src/server/api/endpoints/games/reversi/games/surrender.ts b/packages/backend/src/server/api/endpoints/games/reversi/games/surrender.ts deleted file mode 100644 index a0eb4705ba..0000000000 --- a/packages/backend/src/server/api/endpoints/games/reversi/games/surrender.ts +++ /dev/null @@ -1,68 +0,0 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import { publishReversiGameStream } from '@/services/stream'; -import define from '../../../../define'; -import { ApiError } from '../../../../error'; -import { ReversiGames } from '@/models/index'; - -export const meta = { - tags: ['games'], - - requireCredential: true as const, - - params: { - gameId: { - validator: $.type(ID), - }, - }, - - errors: { - noSuchGame: { - message: 'No such game.', - code: 'NO_SUCH_GAME', - id: 'ace0b11f-e0a6-4076-a30d-e8284c81b2df', - }, - - alreadyEnded: { - message: 'That game has already ended.', - code: 'ALREADY_ENDED', - id: '6c2ad4a6-cbf1-4a5b-b187-b772826cfc6d', - }, - - accessDenied: { - message: 'Access denied.', - code: 'ACCESS_DENIED', - id: '6e04164b-a992-4c93-8489-2123069973e1', - }, - }, -}; - -// eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { - const game = await ReversiGames.findOne(ps.gameId); - - if (game == null) { - throw new ApiError(meta.errors.noSuchGame); - } - - if (game.isEnded) { - throw new ApiError(meta.errors.alreadyEnded); - } - - if ((game.user1Id !== user.id) && (game.user2Id !== user.id)) { - throw new ApiError(meta.errors.accessDenied); - } - - const winnerId = game.user1Id === user.id ? game.user2Id : game.user1Id; - - await ReversiGames.update(game.id, { - surrendered: user.id, - isEnded: true, - winnerId: winnerId, - }); - - publishReversiGameStream(game.id, 'ended', { - winnerId: winnerId, - game: await ReversiGames.pack(game.id, user), - }); -}); diff --git a/packages/backend/src/server/api/endpoints/games/reversi/invitations.ts b/packages/backend/src/server/api/endpoints/games/reversi/invitations.ts deleted file mode 100644 index 0285a2f63b..0000000000 --- a/packages/backend/src/server/api/endpoints/games/reversi/invitations.ts +++ /dev/null @@ -1,59 +0,0 @@ -import define from '../../../define'; -import { ReversiMatchings } from '@/models/index'; - -export const meta = { - tags: ['games'], - - requireCredential: true as const, - - res: { - type: 'array' as const, - optional: false as const, nullable: false as const, - items: { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: { - id: { - type: 'string' as const, - optional: false as const, nullable: false as const, - format: 'id', - }, - createdAt: { - type: 'string' as const, - optional: false as const, nullable: false as const, - format: 'date-time', - }, - parentId: { - type: 'string' as const, - optional: false as const, nullable: false as const, - format: 'id', - }, - parent: { - type: 'object' as const, - optional: false as const, nullable: false as const, - ref: 'User', - }, - childId: { - type: 'string' as const, - optional: false as const, nullable: false as const, - format: 'id', - }, - child: { - type: 'object' as const, - optional: false as const, nullable: false as const, - ref: 'User', - }, - }, - }, - }, -}; - -// eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { - // Find session - const invitations = await ReversiMatchings.find({ - childId: user.id, - }); - - return await Promise.all(invitations.map((i) => ReversiMatchings.pack(i, user))); -}); diff --git a/packages/backend/src/server/api/endpoints/games/reversi/match.ts b/packages/backend/src/server/api/endpoints/games/reversi/match.ts deleted file mode 100644 index b1d958306d..0000000000 --- a/packages/backend/src/server/api/endpoints/games/reversi/match.ts +++ /dev/null @@ -1,109 +0,0 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import { publishMainStream, publishReversiStream } from '@/services/stream'; -import { eighteight } from '../../../../../games/reversi/maps'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { getUser } from '../../../common/getters'; -import { genId } from '@/misc/gen-id'; -import { ReversiMatchings, ReversiGames } from '@/models/index'; -import { ReversiGame } from '@/models/entities/games/reversi/game'; -import { ReversiMatching } from '@/models/entities/games/reversi/matching'; - -export const meta = { - tags: ['games'], - - requireCredential: true as const, - - params: { - userId: { - validator: $.type(ID), - }, - }, - - errors: { - noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: '0b4f0559-b484-4e31-9581-3f73cee89b28', - }, - - isYourself: { - message: 'Target user is yourself.', - code: 'TARGET_IS_YOURSELF', - id: '96fd7bd6-d2bc-426c-a865-d055dcd2828e', - }, - }, -}; - -// eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { - // Myself - if (ps.userId === user.id) { - throw new ApiError(meta.errors.isYourself); - } - - // Find session - const exist = await ReversiMatchings.findOne({ - parentId: ps.userId, - childId: user.id, - }); - - if (exist) { - // Destroy session - ReversiMatchings.delete(exist.id); - - // Create game - const game = await ReversiGames.save({ - id: genId(), - createdAt: new Date(), - user1Id: exist.parentId, - user2Id: user.id, - user1Accepted: false, - user2Accepted: false, - isStarted: false, - isEnded: false, - logs: [], - map: eighteight.data, - bw: 'random', - isLlotheo: false, - } as Partial); - - publishReversiStream(exist.parentId, 'matched', await ReversiGames.pack(game, { id: exist.parentId })); - - const other = await ReversiMatchings.count({ - childId: user.id, - }); - - if (other == 0) { - publishMainStream(user.id, 'reversiNoInvites'); - } - - return await ReversiGames.pack(game, user); - } else { - // Fetch child - const child = await getUser(ps.userId).catch(e => { - if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); - throw e; - }); - - // 以前のセッションはすべて削除しておく - await ReversiMatchings.delete({ - parentId: user.id, - }); - - // セッションを作成 - const matching = await ReversiMatchings.save({ - id: genId(), - createdAt: new Date(), - parentId: user.id, - childId: child.id, - } as ReversiMatching); - - const packed = await ReversiMatchings.pack(matching, child); - publishReversiStream(child.id, 'invited', packed); - publishMainStream(child.id, 'reversiInvited', packed); - - return; - } -}); diff --git a/packages/backend/src/server/api/endpoints/games/reversi/match/cancel.ts b/packages/backend/src/server/api/endpoints/games/reversi/match/cancel.ts deleted file mode 100644 index 3ef753bcd0..0000000000 --- a/packages/backend/src/server/api/endpoints/games/reversi/match/cancel.ts +++ /dev/null @@ -1,15 +0,0 @@ -import define from '../../../../define'; -import { ReversiMatchings } from '@/models/index'; - -export const meta = { - tags: ['games'], - - requireCredential: true as const, -}; - -// eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { - await ReversiMatchings.delete({ - parentId: user.id, - }); -}); diff --git a/packages/backend/src/server/api/endpoints/users/stats.ts b/packages/backend/src/server/api/endpoints/users/stats.ts index bd62e7fb21..84bbd16f0b 100644 --- a/packages/backend/src/server/api/endpoints/users/stats.ts +++ b/packages/backend/src/server/api/endpoints/users/stats.ts @@ -2,7 +2,7 @@ import $ from 'cafy'; import define from '../../define'; import { ApiError } from '../../error'; import { ID } from '@/misc/cafy-id'; -import { DriveFiles, Followings, NoteFavorites, NoteReactions, Notes, PageLikes, PollVotes, ReversiGames, Users } from '@/models/index'; +import { DriveFiles, Followings, NoteFavorites, NoteReactions, Notes, PageLikes, PollVotes, Users } from '@/models/index'; export const meta = { tags: ['users'], @@ -50,7 +50,6 @@ export default define(meta, async (ps, me) => { pageLikedCount, driveFilesCount, driveUsage, - reversiCount, ] = await Promise.all([ Notes.createQueryBuilder('note') .where('note.userId = :userId', { userId: user.id }) @@ -113,10 +112,6 @@ export default define(meta, async (ps, me) => { .where('file.userId = :userId', { userId: user.id }) .getCount(), DriveFiles.calcDriveUsageOf(user), - ReversiGames.createQueryBuilder('game') - .where('game.user1Id = :userId', { userId: user.id }) - .orWhere('game.user2Id = :userId', { userId: user.id }) - .getCount(), ]); return { @@ -140,6 +135,5 @@ export default define(meta, async (ps, me) => { pageLikedCount, driveFilesCount, driveUsage, - reversiCount, }; }); diff --git a/packages/backend/src/server/api/stream/channels/games/reversi-game.ts b/packages/backend/src/server/api/stream/channels/games/reversi-game.ts deleted file mode 100644 index 314db48b5e..0000000000 --- a/packages/backend/src/server/api/stream/channels/games/reversi-game.ts +++ /dev/null @@ -1,372 +0,0 @@ -import autobind from 'autobind-decorator'; -import * as CRC32 from 'crc-32'; -import { publishReversiGameStream } from '@/services/stream'; -import Reversi from '../../../../../games/reversi/core'; -import * as maps from '../../../../../games/reversi/maps'; -import Channel from '../../channel'; -import { ReversiGame } from '@/models/entities/games/reversi/game'; -import { ReversiGames, Users } from '@/models/index'; -import { User } from '@/models/entities/user'; - -export default class extends Channel { - public readonly chName = 'gamesReversiGame'; - public static shouldShare = false; - public static requireCredential = false; - - private gameId: ReversiGame['id'] | null = null; - private watchers: Record = {}; - private emitWatchersIntervalId: ReturnType; - - @autobind - public async init(params: any) { - this.gameId = params.gameId; - - // Subscribe game stream - this.subscriber.on(`reversiGameStream:${this.gameId}`, this.onEvent); - this.emitWatchersIntervalId = setInterval(this.emitWatchers, 5000); - - const game = await ReversiGames.findOne(this.gameId!); - if (game == null) throw new Error('game not found'); - - // 観戦者イベント - this.watch(game); - } - - @autobind - private onEvent(data: any) { - if (data.type === 'watching') { - const id = data.body; - this.watchers[id] = new Date(); - } else { - this.send(data); - } - } - - @autobind - private async emitWatchers() { - const now = new Date(); - - // Remove not watching users - for (const [userId, date] of Object.entries(this.watchers)) { - if (now.getTime() - date.getTime() > 5000) delete this.watchers[userId]; - } - - const users = await Users.packMany(Object.keys(this.watchers), null, { detail: false }); - - this.send({ - type: 'watchers', - body: users, - }); - } - - @autobind - public dispose() { - // Unsubscribe events - this.subscriber.off(`reversiGameStream:${this.gameId}`, this.onEvent); - clearInterval(this.emitWatchersIntervalId); - } - - @autobind - public onMessage(type: string, body: any) { - switch (type) { - case 'accept': this.accept(true); break; - case 'cancelAccept': this.accept(false); break; - case 'updateSettings': this.updateSettings(body.key, body.value); break; - case 'initForm': this.initForm(body); break; - case 'updateForm': this.updateForm(body.id, body.value); break; - case 'message': this.message(body); break; - case 'set': this.set(body.pos); break; - case 'check': this.check(body.crc32); break; - } - } - - @autobind - private async updateSettings(key: string, value: any) { - if (this.user == null) return; - - const game = await ReversiGames.findOne(this.gameId!); - if (game == null) throw new Error('game not found'); - - if (game.isStarted) return; - if ((game.user1Id !== this.user.id) && (game.user2Id !== this.user.id)) return; - if ((game.user1Id === this.user.id) && game.user1Accepted) return; - if ((game.user2Id === this.user.id) && game.user2Accepted) return; - - if (!['map', 'bw', 'isLlotheo', 'canPutEverywhere', 'loopedBoard'].includes(key)) return; - - await ReversiGames.update(this.gameId!, { - [key]: value, - }); - - publishReversiGameStream(this.gameId!, 'updateSettings', { - key: key, - value: value, - }); - } - - @autobind - private async initForm(form: any) { - if (this.user == null) return; - - const game = await ReversiGames.findOne(this.gameId!); - if (game == null) throw new Error('game not found'); - - if (game.isStarted) return; - if ((game.user1Id !== this.user.id) && (game.user2Id !== this.user.id)) return; - - const set = game.user1Id === this.user.id ? { - form1: form, - } : { - form2: form, - }; - - await ReversiGames.update(this.gameId!, set); - - publishReversiGameStream(this.gameId!, 'initForm', { - userId: this.user.id, - form, - }); - } - - @autobind - private async updateForm(id: string, value: any) { - if (this.user == null) return; - - const game = await ReversiGames.findOne(this.gameId!); - if (game == null) throw new Error('game not found'); - - if (game.isStarted) return; - if ((game.user1Id !== this.user.id) && (game.user2Id !== this.user.id)) return; - - const form = game.user1Id === this.user.id ? game.form2 : game.form1; - - const item = form.find((i: any) => i.id == id); - - if (item == null) return; - - item.value = value; - - const set = game.user1Id === this.user.id ? { - form2: form, - } : { - form1: form, - }; - - await ReversiGames.update(this.gameId!, set); - - publishReversiGameStream(this.gameId!, 'updateForm', { - userId: this.user.id, - id, - value, - }); - } - - @autobind - private async message(message: any) { - if (this.user == null) return; - - message.id = Math.random(); - publishReversiGameStream(this.gameId!, 'message', { - userId: this.user.id, - message, - }); - } - - @autobind - private async accept(accept: boolean) { - if (this.user == null) return; - - const game = await ReversiGames.findOne(this.gameId!); - if (game == null) throw new Error('game not found'); - - if (game.isStarted) return; - - let bothAccepted = false; - - if (game.user1Id === this.user.id) { - await ReversiGames.update(this.gameId!, { - user1Accepted: accept, - }); - - publishReversiGameStream(this.gameId!, 'changeAccepts', { - user1: accept, - user2: game.user2Accepted, - }); - - if (accept && game.user2Accepted) bothAccepted = true; - } else if (game.user2Id === this.user.id) { - await ReversiGames.update(this.gameId!, { - user2Accepted: accept, - }); - - publishReversiGameStream(this.gameId!, 'changeAccepts', { - user1: game.user1Accepted, - user2: accept, - }); - - if (accept && game.user1Accepted) bothAccepted = true; - } else { - return; - } - - if (bothAccepted) { - // 3秒後、まだacceptされていたらゲーム開始 - setTimeout(async () => { - const freshGame = await ReversiGames.findOne(this.gameId!); - if (freshGame == null || freshGame.isStarted || freshGame.isEnded) return; - if (!freshGame.user1Accepted || !freshGame.user2Accepted) return; - - let bw: number; - if (freshGame.bw == 'random') { - bw = Math.random() > 0.5 ? 1 : 2; - } else { - bw = parseInt(freshGame.bw, 10); - } - - function getRandomMap() { - const mapCount = Object.entries(maps).length; - const rnd = Math.floor(Math.random() * mapCount); - return Object.values(maps)[rnd].data; - } - - const map = freshGame.map != null ? freshGame.map : getRandomMap(); - - await ReversiGames.update(this.gameId!, { - startedAt: new Date(), - isStarted: true, - black: bw, - map: map, - }); - - //#region 盤面に最初から石がないなどして始まった瞬間に勝敗が決定する場合があるのでその処理 - const o = new Reversi(map, { - isLlotheo: freshGame.isLlotheo, - canPutEverywhere: freshGame.canPutEverywhere, - loopedBoard: freshGame.loopedBoard, - }); - - if (o.isEnded) { - let winner; - if (o.winner === true) { - winner = freshGame.black == 1 ? freshGame.user1Id : freshGame.user2Id; - } else if (o.winner === false) { - winner = freshGame.black == 1 ? freshGame.user2Id : freshGame.user1Id; - } else { - winner = null; - } - - await ReversiGames.update(this.gameId!, { - isEnded: true, - winnerId: winner, - }); - - publishReversiGameStream(this.gameId!, 'ended', { - winnerId: winner, - game: await ReversiGames.pack(this.gameId!, this.user), - }); - } - //#endregion - - publishReversiGameStream(this.gameId!, 'started', - await ReversiGames.pack(this.gameId!, this.user)); - }, 3000); - } - } - - // 石を打つ - @autobind - private async set(pos: number) { - if (this.user == null) return; - - const game = await ReversiGames.findOne(this.gameId!); - if (game == null) throw new Error('game not found'); - - if (!game.isStarted) return; - if (game.isEnded) return; - if ((game.user1Id !== this.user.id) && (game.user2Id !== this.user.id)) return; - - const myColor = - ((game.user1Id === this.user.id) && game.black == 1) || ((game.user2Id === this.user.id) && game.black == 2) - ? true - : false; - - const o = new Reversi(game.map, { - isLlotheo: game.isLlotheo, - canPutEverywhere: game.canPutEverywhere, - loopedBoard: game.loopedBoard, - }); - - // 盤面の状態を再生 - for (const log of game.logs) { - o.put(log.color, log.pos); - } - - if (o.turn !== myColor) return; - - if (!o.canPut(myColor, pos)) return; - o.put(myColor, pos); - - let winner; - if (o.isEnded) { - if (o.winner === true) { - winner = game.black == 1 ? game.user1Id : game.user2Id; - } else if (o.winner === false) { - winner = game.black == 1 ? game.user2Id : game.user1Id; - } else { - winner = null; - } - } - - const log = { - at: new Date(), - color: myColor, - pos, - }; - - const crc32 = CRC32.str(game.logs.map(x => x.pos.toString()).join('') + pos.toString()).toString(); - - game.logs.push(log); - - await ReversiGames.update(this.gameId!, { - crc32, - isEnded: o.isEnded, - winnerId: winner, - logs: game.logs, - }); - - publishReversiGameStream(this.gameId!, 'set', Object.assign(log, { - next: o.turn, - })); - - if (o.isEnded) { - publishReversiGameStream(this.gameId!, 'ended', { - winnerId: winner, - game: await ReversiGames.pack(this.gameId!, this.user), - }); - } - } - - @autobind - private async check(crc32: string | number) { - const game = await ReversiGames.findOne(this.gameId!); - if (game == null) throw new Error('game not found'); - - if (!game.isStarted) return; - - if (crc32.toString() !== game.crc32) { - this.send('rescue', await ReversiGames.pack(game, this.user)); - } - - // ついでに観戦者イベントを発行 - this.watch(game); - } - - @autobind - private watch(game: ReversiGame) { - if (this.user != null) { - if ((game.user1Id !== this.user.id) && (game.user2Id !== this.user.id)) { - publishReversiGameStream(this.gameId!, 'watching', this.user.id); - } - } - } -} diff --git a/packages/backend/src/server/api/stream/channels/games/reversi.ts b/packages/backend/src/server/api/stream/channels/games/reversi.ts deleted file mode 100644 index 121560ff87..0000000000 --- a/packages/backend/src/server/api/stream/channels/games/reversi.ts +++ /dev/null @@ -1,34 +0,0 @@ -import autobind from 'autobind-decorator'; -import { publishMainStream } from '@/services/stream'; -import Channel from '../../channel'; -import { ReversiMatchings } from '@/models/index'; - -export default class extends Channel { - public readonly chName = 'gamesReversi'; - public static shouldShare = true; - public static requireCredential = true; - - @autobind - public async init(params: any) { - // Subscribe reversi stream - this.subscriber.on(`reversiStream:${this.user!.id}`, data => { - this.send(data); - }); - } - - @autobind - public async onMessage(type: string, body: any) { - switch (type) { - case 'ping': { - if (body.id == null) return; - const matching = await ReversiMatchings.findOne({ - parentId: this.user!.id, - childId: body.id, - }); - if (matching == null) return; - publishMainStream(matching.childId, 'reversiInvited', await ReversiMatchings.pack(matching, { id: matching.childId })); - break; - } - } - } -} diff --git a/packages/backend/src/server/api/stream/channels/index.ts b/packages/backend/src/server/api/stream/channels/index.ts index 89d93f2da3..f3826c4cf7 100644 --- a/packages/backend/src/server/api/stream/channels/index.ts +++ b/packages/backend/src/server/api/stream/channels/index.ts @@ -13,8 +13,6 @@ import drive from './drive'; import hashtag from './hashtag'; import channel from './channel'; import admin from './admin'; -import gamesReversi from './games/reversi'; -import gamesReversiGame from './games/reversi-game'; export default { main, @@ -32,6 +30,4 @@ export default { hashtag, channel, admin, - gamesReversi, - gamesReversiGame, }; diff --git a/packages/backend/src/server/api/stream/types.ts b/packages/backend/src/server/api/stream/types.ts index f4302f64a0..168f1b3448 100644 --- a/packages/backend/src/server/api/stream/types.ts +++ b/packages/backend/src/server/api/stream/types.ts @@ -11,7 +11,6 @@ import { Emoji } from '@/models/entities/emoji'; import { UserList } from '@/models/entities/user-list'; import { MessagingMessage } from '@/models/entities/messaging-message'; import { UserGroup } from '@/models/entities/user-group'; -import { ReversiGame } from '@/models/entities/games/reversi/game'; import { AbuseUserReport } from '@/models/entities/abuse-user-report'; import { Signin } from '@/models/entities/signin'; import { Page } from '@/models/entities/page'; @@ -77,8 +76,6 @@ export interface MainStreamTypes { readAllChannels: undefined; unreadChannel: Note['id']; myTokenRegenerated: undefined; - reversiNoInvites: undefined; - reversiInvited: Packed<'ReversiMatching'>; signin: Signin; registryUpdated: { scope?: string[]; @@ -158,47 +155,6 @@ export interface MessagingIndexStreamTypes { message: Packed<'MessagingMessage'>; } -export interface ReversiStreamTypes { - matched: Packed<'ReversiGame'>; - invited: Packed<'ReversiMatching'>; -} - -export interface ReversiGameStreamTypes { - started: Packed<'ReversiGame'>; - ended: { - winnerId?: User['id'] | null, - game: Packed<'ReversiGame'>; - }; - updateSettings: { - key: string; - value: FIXME; - }; - initForm: { - userId: User['id']; - form: FIXME; - }; - updateForm: { - userId: User['id']; - id: string; - value: FIXME; - }; - message: { - userId: User['id']; - message: FIXME; - }; - changeAccepts: { - user1: boolean; - user2: boolean; - }; - set: { - at: Date; - color: boolean; - pos: number; - next: boolean; - }; - watching: User['id']; -} - export interface AdminStreamTypes { newAbuseUserReport: { id: AbuseUserReport['id']; @@ -268,14 +224,6 @@ export type StreamMessages = { name: `messagingIndexStream:${User['id']}`; payload: EventUnionFromDictionary; }; - reversi: { - name: `reversiStream:${User['id']}`; - payload: EventUnionFromDictionary; - }; - reversiGame: { - name: `reversiGameStream:${ReversiGame['id']}`; - payload: EventUnionFromDictionary; - }; admin: { name: `adminStream:${User['id']}`; payload: EventUnionFromDictionary; diff --git a/packages/backend/src/server/index.ts b/packages/backend/src/server/index.ts index 85fe21accb..764306c7d8 100644 --- a/packages/backend/src/server/index.ts +++ b/packages/backend/src/server/index.ts @@ -23,7 +23,7 @@ import Logger from '@/services/logger'; import { envOption } from '../env'; import { UserProfiles, Users } from '@/models/index'; import { networkChart } from '@/services/chart/index'; -import { genAvatar } from '@/misc/gen-avatar'; +import { genIdenticon } from '@/misc/gen-identicon'; import { createTemp } from '@/misc/create-temp'; import { publishMainStream } from '@/services/stream'; import * as Acct from 'misskey-js/built/acct'; @@ -84,9 +84,9 @@ router.get('/avatar/@:acct', async ctx => { } }); -router.get('/random-avatar/:x', async ctx => { +router.get('/identicon/:x', async ctx => { const [temp] = await createTemp(); - await genAvatar(ctx.params.x, fs.createWriteStream(temp)); + await genIdenticon(ctx.params.x, fs.createWriteStream(temp)); ctx.set('Content-Type', 'image/png'); ctx.body = fs.createReadStream(temp); }); diff --git a/packages/backend/src/server/web/index.ts b/packages/backend/src/server/web/index.ts index 105bc3659e..34e9e2d388 100644 --- a/packages/backend/src/server/web/index.ts +++ b/packages/backend/src/server/web/index.ts @@ -396,9 +396,6 @@ router.get('/cli', async ctx => { const override = (source: string, target: string, depth: number = 0) => [, ...target.split('/').filter(x => x), ...source.split('/').filter(x => x).splice(depth)].join('/'); -router.get('/othello', async ctx => ctx.redirect(override(ctx.URL.pathname, 'games/reversi', 1))); -router.get('/reversi', async ctx => ctx.redirect(override(ctx.URL.pathname, 'games'))); - router.get('/flush', async ctx => { await ctx.render('flush'); }); diff --git a/packages/backend/src/services/stream.ts b/packages/backend/src/services/stream.ts index 7d11ff3f45..c0cefe9af4 100644 --- a/packages/backend/src/services/stream.ts +++ b/packages/backend/src/services/stream.ts @@ -2,7 +2,6 @@ import { redisClient } from '../db/redis'; import { User } from '@/models/entities/user'; import { Note } from '@/models/entities/note'; import { UserList } from '@/models/entities/user-list'; -import { ReversiGame } from '@/models/entities/games/reversi/game'; import { UserGroup } from '@/models/entities/user-group'; import config from '@/config/index'; import { Antenna } from '@/models/entities/antenna'; @@ -20,8 +19,6 @@ import { MessagingIndexStreamTypes, MessagingStreamTypes, NoteStreamTypes, - ReversiGameStreamTypes, - ReversiStreamTypes, UserListStreamTypes, UserStreamTypes, } from '@/server/api/stream/types'; @@ -90,14 +87,6 @@ class Publisher { this.publish(`messagingIndexStream:${userId}`, type, typeof value === 'undefined' ? null : value); }; - public publishReversiStream = (userId: User['id'], type: K, value?: ReversiStreamTypes[K]): void => { - this.publish(`reversiStream:${userId}`, type, typeof value === 'undefined' ? null : value); - }; - - public publishReversiGameStream = (gameId: ReversiGame['id'], type: K, value?: ReversiGameStreamTypes[K]): void => { - this.publish(`reversiGameStream:${gameId}`, type, typeof value === 'undefined' ? null : value); - }; - public publishNotesStream = (note: Packed<'Note'>): void => { this.publish('notesStream', null, note); }; @@ -124,6 +113,4 @@ export const publishAntennaStream = publisher.publishAntennaStream; export const publishMessagingStream = publisher.publishMessagingStream; export const publishGroupMessagingStream = publisher.publishGroupMessagingStream; export const publishMessagingIndexStream = publisher.publishMessagingIndexStream; -export const publishReversiStream = publisher.publishReversiStream; -export const publishReversiGameStream = publisher.publishReversiGameStream; export const publishAdminStream = publisher.publishAdminStream; diff --git a/packages/backend/yarn.lock b/packages/backend/yarn.lock index 16144b6d57..9e21fb29e3 100644 --- a/packages/backend/yarn.lock +++ b/packages/backend/yarn.lock @@ -1522,6 +1522,11 @@ big-integer@^1.6.16: resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.48.tgz#8fd88bd1632cba4a1c8c3e3d7159f08bb95b4b9e" integrity sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w== +big-integer@^1.6.17: + version "1.6.51" + resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686" + integrity sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg== + big.js@^5.2.2: version "5.2.2" resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" @@ -1532,6 +1537,14 @@ binary-extensions@^2.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c" integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow== +binary@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/binary/-/binary-0.3.0.tgz#9f60553bc5ce8c3386f3b553cff47462adecaa79" + integrity sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk= + dependencies: + buffers "~0.1.1" + chainsaw "~0.1.0" + bl@^4.0.1, bl@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/bl/-/bl-4.0.3.tgz#12d6287adc29080e22a705e5764b2a9522cdc489" @@ -1546,6 +1559,11 @@ bluebird@^3.7.2: resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== +bluebird@~3.4.1: + version "3.4.7" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3" + integrity sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM= + blurhash@1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/blurhash/-/blurhash-1.1.4.tgz#a7010ceb3019cd2c9809b17c910ebf6175d29244" @@ -1677,6 +1695,11 @@ buffer-from@^1.0.0, buffer-from@^1.1.1: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== +buffer-indexof-polyfill@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz#d2732135c5999c64b277fcf9b1abe3498254729c" + integrity sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A== + buffer-writer@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/buffer-writer/-/buffer-writer-2.0.0.tgz#ce7eb81a38f7829db09c873f2fbb792c0c98ec04" @@ -1707,6 +1730,11 @@ buffer@^6.0.3: base64-js "^1.3.1" ieee754 "^1.2.1" +buffers@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/buffers/-/buffers-0.1.1.tgz#b24579c3bed4d6d396aeee6d9a8ae7f5482ab7bb" + integrity sha1-skV5w77U1tOWru5tmorn9Ugqt7s= + bufferutil@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.1.tgz#3a177e8e5819a1243fe16b63a199951a7ad8d4a7" @@ -1875,6 +1903,13 @@ cbor@8.1.0: dependencies: nofilter "^3.1.0" +chainsaw@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/chainsaw/-/chainsaw-0.1.0.tgz#5eab50b28afe58074d0d58291388828b5e5fbc98" + integrity sha1-XqtQsor+WAdNDVgpE4iCi15fvJg= + dependencies: + traverse ">=0.3.0 <0.4" + chalk@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.0.0.tgz#6e98081ed2d17faab615eb52ac66ec1fe6209e72" @@ -2789,6 +2824,13 @@ dotenv@^8.2.0: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a" integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw== +duplexer2@~0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1" + integrity sha1-ixLauHjA1p4+eJEFFmKjL8a93ME= + dependencies: + readable-stream "^2.0.2" + ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" @@ -3480,6 +3522,16 @@ fsevents@~2.1.2: resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e" integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ== +fstream@^1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045" + integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg== + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" @@ -3690,7 +3742,7 @@ graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.4: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== -graceful-fs@^4.2.0: +graceful-fs@^4.2.0, graceful-fs@^4.2.2: version "4.2.8" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== @@ -4007,7 +4059,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -4800,6 +4852,11 @@ lilconfig@^2.0.3: resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.3.tgz#68f3005e921dafbd2a2afb48379986aa6d2579fd" integrity sha512-EHKqr/+ZvdKCifpNrJCKxBTgk5XupZA3y/aCPY9mxfgBzmgh93Mt/WqjjQ38oMxXuvDokaKiM3lAgvSH2sjtHg== +listenercount@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/listenercount/-/listenercount-1.0.1.tgz#84c8a72ab59c4725321480c975e6508342e70937" + integrity sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc= + loader-runner@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.2.0.tgz#d7022380d66d14c5fb1d496b89864ebcfd478384" @@ -5204,7 +5261,7 @@ mkdirp-classic@^0.5.3: resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== -mkdirp@0.x, mkdirp@^0.5.4: +mkdirp@0.x, "mkdirp@>=0.5 0", mkdirp@^0.5.4: version "0.5.5" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== @@ -6598,7 +6655,7 @@ readable-stream@1.1.x: isarray "0.0.1" string_decoder "~0.10.x" -readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.2.2: +readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.2.2, readable-stream@~2.3.6: version "2.3.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== @@ -6780,6 +6837,13 @@ reusify@^1.0.4: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== +rimraf@2: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" @@ -6914,7 +6978,7 @@ set-blocking@^2.0.0, set-blocking@~2.0.0: resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= -setimmediate@^1.0.5: +setimmediate@^1.0.5, setimmediate@~1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= @@ -7584,6 +7648,11 @@ trace-redirect@1.0.6: resolved "https://registry.yarnpkg.com/trace-redirect/-/trace-redirect-1.0.6.tgz#ac629b5bf8247d30dde5a35fe9811b811075b504" integrity sha512-UUfa1DjjU5flcjMdaFIiIEGDTyu2y/IiMjOX4uGXa7meKBS4vD4f2Uy/tken9Qkd4Jsm4sRsfZcIIPqrRVF3Mg== +"traverse@>=0.3.0 <0.4": + version "0.3.9" + resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.3.9.tgz#717b8f220cc0bb7b44e40514c22b2e8bbc70d8b9" + integrity sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk= + ts-jest@^25.2.1: version "25.5.1" resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-25.5.1.tgz#2913afd08f28385d54f2f4e828be4d261f4337c7" @@ -7827,6 +7896,22 @@ unpipe@1.0.0: resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= +unzipper@0.10.11: + version "0.10.11" + resolved "https://registry.yarnpkg.com/unzipper/-/unzipper-0.10.11.tgz#0b4991446472cbdb92ee7403909f26c2419c782e" + integrity sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw== + dependencies: + big-integer "^1.6.17" + binary "~0.3.0" + bluebird "~3.4.1" + buffer-indexof-polyfill "~1.0.0" + duplexer2 "~0.1.4" + fstream "^1.0.12" + graceful-fs "^4.2.2" + listenercount "~1.0.1" + readable-stream "~2.3.6" + setimmediate "~1.0.4" + uri-js@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" diff --git a/packages/client/.eslintrc.js b/packages/client/.eslintrc.js index 8e4ff6e455..e0113019ac 100644 --- a/packages/client/.eslintrc.js +++ b/packages/client/.eslintrc.js @@ -14,6 +14,10 @@ module.exports = { "plugin:vue/vue3-recommended" ], rules: { + // window の禁止理由: グローバルスコープと衝突し、予期せぬ結果を招くため + // data の禁止理由: 抽象的すぎるため + // e の禁止理由: error や event など、複数のキーワードの頭文字であり分かりにくいため + "id-denylist": ["error", "window", "data", "e"], "vue/attributes-order": ["error", { "alphabetical": false }], diff --git a/packages/client/package.json b/packages/client/package.json index 167ab2e816..e105ffcae7 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -21,7 +21,6 @@ "@types/katex": "0.11.1", "@types/matter-js": "0.17.6", "@types/mocha": "8.2.3", - "@types/node": "16.11.12", "@types/oauth": "0.9.1", "@types/parse5": "6.0.3", "@types/punycode": "2.1.0", @@ -75,7 +74,7 @@ "ms": "2.1.3", "nested-property": "4.0.0", "parse5": "6.0.1", - "photoswipe": "git://github.com/dimsemenov/photoswipe#v5-beta", + "photoswipe": "git+https://github.com/dimsemenov/photoswipe#v5-beta", "portscanner": "2.2.0", "postcss": "8.4.5", "postcss-loader": "6.2.1", diff --git a/packages/client/src/components/note.sub.vue b/packages/client/src/components/MkNoteSub.vue similarity index 66% rename from packages/client/src/components/note.sub.vue rename to packages/client/src/components/MkNoteSub.vue index de4218e535..30c27e6235 100644 --- a/packages/client/src/components/note.sub.vue +++ b/packages/client/src/components/MkNoteSub.vue @@ -10,13 +10,13 @@

- +
{{ $ts.continueThread }} @@ -24,63 +24,36 @@
- \ No newline at end of file + diff --git a/packages/client/src/pages/featured.vue b/packages/client/src/pages/featured.vue index efa74ca599..725c70f0f7 100644 --- a/packages/client/src/pages/featured.vue +++ b/packages/client/src/pages/featured.vue @@ -10,7 +10,7 @@ import * as symbols from '@/symbols'; import { i18n } from '@/i18n'; const pagination = { - endpoint: 'notes/featured', + endpoint: 'notes/featured' as const, limit: 10, offsetMode: true, }; diff --git a/packages/client/src/pages/federation.vue b/packages/client/src/pages/federation.vue index 9815e68986..6a4a28b6b4 100644 --- a/packages/client/src/pages/federation.vue +++ b/packages/client/src/pages/federation.vue @@ -95,8 +95,8 @@ - diff --git a/packages/client/src/pages/follow-requests.vue b/packages/client/src/pages/follow-requests.vue index 54d695091d..764daa0d3e 100644 --- a/packages/client/src/pages/follow-requests.vue +++ b/packages/client/src/pages/follow-requests.vue @@ -1,6 +1,6 @@ - diff --git a/packages/client/src/pages/my-antennas/index.vue b/packages/client/src/pages/my-antennas/index.vue index d185e796c3..7138d269a9 100644 --- a/packages/client/src/pages/my-antennas/index.vue +++ b/packages/client/src/pages/my-antennas/index.vue @@ -38,7 +38,7 @@ export default defineComponent({ } }, pagination: { - endpoint: 'antennas/list', + endpoint: 'antennas/list' as const, limit: 10, }, }; diff --git a/packages/client/src/pages/my-clips/index.vue b/packages/client/src/pages/my-clips/index.vue index a5bbc3fd2d..97b563f6f8 100644 --- a/packages/client/src/pages/my-clips/index.vue +++ b/packages/client/src/pages/my-clips/index.vue @@ -3,7 +3,7 @@
{{ $ts.add }} - + {{ item.name }}
{{ item.description }}
@@ -13,71 +13,64 @@ - diff --git a/packages/client/src/pages/my-groups/index.vue b/packages/client/src/pages/my-groups/index.vue index db5ccde466..4b2b2963a8 100644 --- a/packages/client/src/pages/my-groups/index.vue +++ b/packages/client/src/pages/my-groups/index.vue @@ -87,15 +87,15 @@ export default defineComponent({ })), tab: 'owned', ownedPagination: { - endpoint: 'users/groups/owned', + endpoint: 'users/groups/owned' as const, limit: 10, }, joinedPagination: { - endpoint: 'users/groups/joined', + endpoint: 'users/groups/joined' as const, limit: 10, }, invitationPagination: { - endpoint: 'i/user-group-invites', + endpoint: 'i/user-group-invites' as const, limit: 10, }, }; diff --git a/packages/client/src/pages/my-lists/index.vue b/packages/client/src/pages/my-lists/index.vue index 94a869b9ff..e6fcba1b34 100644 --- a/packages/client/src/pages/my-lists/index.vue +++ b/packages/client/src/pages/my-lists/index.vue @@ -3,7 +3,7 @@
{{ $ts.createList }} - +
{{ list.name }}
@@ -13,50 +13,41 @@ - diff --git a/packages/client/src/pages/note.vue b/packages/client/src/pages/note.vue index d40082381c..72ac85ee90 100644 --- a/packages/client/src/pages/note.vue +++ b/packages/client/src/pages/note.vue @@ -82,21 +82,21 @@ export default defineComponent({ showNext: false, error: null, prev: { - endpoint: 'users/notes', + endpoint: 'users/notes' as const, limit: 10, - params: init => ({ + params: computed(() => ({ userId: this.note.userId, untilId: this.note.id, - }) + })), }, next: { reversed: true, - endpoint: 'users/notes', + endpoint: 'users/notes' as const, limit: 10, - params: init => ({ + params: computed(() => ({ userId: this.note.userId, sinceId: this.note.id, - }) + })), }, }; }, diff --git a/packages/client/src/pages/notifications.vue b/packages/client/src/pages/notifications.vue index 695c54a535..090e80f99a 100644 --- a/packages/client/src/pages/notifications.vue +++ b/packages/client/src/pages/notifications.vue @@ -6,70 +6,62 @@ - diff --git a/packages/client/src/pages/page.vue b/packages/client/src/pages/page.vue index 5cb3948f1c..429d1ddea2 100644 --- a/packages/client/src/pages/page.vue +++ b/packages/client/src/pages/page.vue @@ -106,7 +106,7 @@ export default defineComponent({ page: null, error: null, otherPostsPagination: { - endpoint: 'users/pages', + endpoint: 'users/pages' as const, limit: 6, params: computed(() => ({ userId: this.page.user.id diff --git a/packages/client/src/pages/pages.vue b/packages/client/src/pages/pages.vue index f1dd64f119..dcccf7f7c4 100644 --- a/packages/client/src/pages/pages.vue +++ b/packages/client/src/pages/pages.vue @@ -62,15 +62,15 @@ export default defineComponent({ })), tab: 'featured', featuredPagesPagination: { - endpoint: 'pages/featured', + endpoint: 'pages/featured' as const, noPaging: true, }, myPagesPagination: { - endpoint: 'i/pages', + endpoint: 'i/pages' as const, limit: 5, }, likedPagesPagination: { - endpoint: 'i/page-likes', + endpoint: 'i/page-likes' as const, limit: 5, }, }; diff --git a/packages/client/src/pages/preview.vue b/packages/client/src/pages/preview.vue index 9d1ebb74ed..8eb4549516 100644 --- a/packages/client/src/pages/preview.vue +++ b/packages/client/src/pages/preview.vue @@ -4,24 +4,18 @@
- diff --git a/packages/client/src/pages/reset-password.vue b/packages/client/src/pages/reset-password.vue index e0608654c7..8ef73858f6 100644 --- a/packages/client/src/pages/reset-password.vue +++ b/packages/client/src/pages/reset-password.vue @@ -3,62 +3,51 @@
- + - {{ $ts.save }} + {{ i18n.locale.save }}
- diff --git a/packages/client/src/pages/reversi/game.setting.vue b/packages/client/src/pages/reversi/game.setting.vue deleted file mode 100644 index 28bc598cfd..0000000000 --- a/packages/client/src/pages/reversi/game.setting.vue +++ /dev/null @@ -1,390 +0,0 @@ - - - - - diff --git a/packages/client/src/pages/reversi/game.vue b/packages/client/src/pages/reversi/game.vue deleted file mode 100644 index 697d2898b9..0000000000 --- a/packages/client/src/pages/reversi/game.vue +++ /dev/null @@ -1,77 +0,0 @@ - - - diff --git a/packages/client/src/pages/reversi/index.vue b/packages/client/src/pages/reversi/index.vue deleted file mode 100644 index 93c22c02f3..0000000000 --- a/packages/client/src/pages/reversi/index.vue +++ /dev/null @@ -1,280 +0,0 @@ - - - - - diff --git a/packages/client/src/pages/search.vue b/packages/client/src/pages/search.vue index 771d0b557e..ce2b7035da 100644 --- a/packages/client/src/pages/search.vue +++ b/packages/client/src/pages/search.vue @@ -6,31 +6,31 @@
- diff --git a/packages/client/src/pages/settings/account-info.vue b/packages/client/src/pages/settings/account-info.vue index 1d6afd9d58..c98ad056f6 100644 --- a/packages/client/src/pages/settings/account-info.vue +++ b/packages/client/src/pages/settings/account-info.vue @@ -94,10 +94,6 @@ - - - - @@ -158,8 +154,6 @@ export default defineComponent({ }, mounted() { - this.$emit('info', this[symbols.PAGE_INFO]); - os.api('users/stats', { userId: this.$i.id }).then(stats => { diff --git a/packages/client/src/pages/settings/accounts.vue b/packages/client/src/pages/settings/accounts.vue index 9ff11adda3..c795ede8ac 100644 --- a/packages/client/src/pages/settings/accounts.vue +++ b/packages/client/src/pages/settings/accounts.vue @@ -53,10 +53,6 @@ export default defineComponent({ }; }, - mounted() { - this.$emit('info', this[symbols.PAGE_INFO]); - }, - methods: { menu(account, ev) { os.popupMenu([{ diff --git a/packages/client/src/pages/settings/api.vue b/packages/client/src/pages/settings/api.vue index 1a51b526f2..20ff2a8d96 100644 --- a/packages/client/src/pages/settings/api.vue +++ b/packages/client/src/pages/settings/api.vue @@ -32,10 +32,6 @@ export default defineComponent({ }; }, - mounted() { - this.$emit('info', this[symbols.PAGE_INFO]); - }, - methods: { generateToken() { os.popup(import('@/components/token-generate-window.vue'), {}, { diff --git a/packages/client/src/pages/settings/apps.vue b/packages/client/src/pages/settings/apps.vue index 68952bbbdb..9c0fa8a54d 100644 --- a/packages/client/src/pages/settings/apps.vue +++ b/packages/client/src/pages/settings/apps.vue @@ -58,7 +58,7 @@ export default defineComponent({ bg: 'var(--bg)', }, pagination: { - endpoint: 'i/apps', + endpoint: 'i/apps' as const, limit: 100, params: { sort: '+lastUsedAt' @@ -67,10 +67,6 @@ export default defineComponent({ }; }, - mounted() { - this.$emit('info', this[symbols.PAGE_INFO]); - }, - methods: { revoke(token) { os.api('i/revoke-token', { tokenId: token.id }).then(() => { diff --git a/packages/client/src/pages/settings/custom-css.vue b/packages/client/src/pages/settings/custom-css.vue index 6dbb8c2ae9..556ee30c1d 100644 --- a/packages/client/src/pages/settings/custom-css.vue +++ b/packages/client/src/pages/settings/custom-css.vue @@ -37,8 +37,6 @@ export default defineComponent({ }, mounted() { - this.$emit('info', this[symbols.PAGE_INFO]); - this.$watch('localCustomCss', this.apply); }, diff --git a/packages/client/src/pages/settings/deck.vue b/packages/client/src/pages/settings/deck.vue index e290b095ac..46b90d3d1a 100644 --- a/packages/client/src/pages/settings/deck.vue +++ b/packages/client/src/pages/settings/deck.vue @@ -83,10 +83,6 @@ export default defineComponent({ } }, - mounted() { - this.$emit('info', this[symbols.PAGE_INFO]); - }, - methods: { async setProfile() { const { canceled, result: name } = await os.inputText({ diff --git a/packages/client/src/pages/settings/delete-account.vue b/packages/client/src/pages/settings/delete-account.vue index 17501d9510..7edc81a309 100644 --- a/packages/client/src/pages/settings/delete-account.vue +++ b/packages/client/src/pages/settings/delete-account.vue @@ -33,10 +33,6 @@ export default defineComponent({ } }, - mounted() { - this.$emit('info', this[symbols.PAGE_INFO]); - }, - methods: { async deleteAccount() { { diff --git a/packages/client/src/pages/settings/drive.vue b/packages/client/src/pages/settings/drive.vue index c123159b61..f1016ebd84 100644 --- a/packages/client/src/pages/settings/drive.vue +++ b/packages/client/src/pages/settings/drive.vue @@ -99,10 +99,6 @@ export default defineComponent({ } }, - mounted() { - this.$emit('info', this[symbols.PAGE_INFO]); - }, - methods: { chooseUploadFolder() { os.selectDriveFolder(false).then(async folder => { diff --git a/packages/client/src/pages/settings/email.vue b/packages/client/src/pages/settings/email.vue index e9010fbe42..54557f8773 100644 --- a/packages/client/src/pages/settings/email.vue +++ b/packages/client/src/pages/settings/email.vue @@ -111,8 +111,6 @@ export default defineComponent({ }); onMounted(() => { - context.emit('info', INFO); - watch(emailAddress, () => { saveEmailAddress(); }); diff --git a/packages/client/src/pages/settings/general.vue b/packages/client/src/pages/settings/general.vue index 734bc78442..2e159e56a9 100644 --- a/packages/client/src/pages/settings/general.vue +++ b/packages/client/src/pages/settings/general.vue @@ -195,10 +195,6 @@ export default defineComponent({ }, }, - mounted() { - this.$emit('info', this[symbols.PAGE_INFO]); - }, - methods: { async reloadAsk() { const { canceled } = await os.confirm({ diff --git a/packages/client/src/pages/settings/import-export.vue b/packages/client/src/pages/settings/import-export.vue index a1dd6a1539..21031c559e 100644 --- a/packages/client/src/pages/settings/import-export.vue +++ b/packages/client/src/pages/settings/import-export.vue @@ -133,10 +133,6 @@ export default defineComponent({ os.api('i/import-blocking', { fileId: file.id }).then(onImportSuccess).catch(onError); }; - onMounted(() => { - context.emit('info', INFO); - }); - return { [symbols.PAGE_INFO]: INFO, excludeMutingUsers, diff --git a/packages/client/src/pages/settings/index.vue b/packages/client/src/pages/settings/index.vue index c9acf2c63c..66c8b147bb 100644 --- a/packages/client/src/pages/settings/index.vue +++ b/packages/client/src/pages/settings/index.vue @@ -14,7 +14,7 @@
- +
@@ -250,8 +250,9 @@ export default defineComponent({ const emailNotConfigured = computed(() => instance.enableEmail && ($i.email == null || !$i.emailVerified)); - const onInfo = (info) => { - childInfo.value = info; + const pageChanged = (page) => { + if (page == null) return; + childInfo.value = page[symbols.PAGE_INFO]; }; return { @@ -264,7 +265,7 @@ export default defineComponent({ pageProps, component, emailNotConfigured, - onInfo, + pageChanged, childInfo, }; }, diff --git a/packages/client/src/pages/settings/instance-mute.vue b/packages/client/src/pages/settings/instance-mute.vue index 584a21e4bd..f84a209b60 100644 --- a/packages/client/src/pages/settings/instance-mute.vue +++ b/packages/client/src/pages/settings/instance-mute.vue @@ -47,11 +47,6 @@ export default defineComponent({ }, }, - mounted() { - this.$emit('info', this[symbols.PAGE_INFO]); - }, - - async created() { this.instanceMutes = this.$i.mutedInstances.join('\n'); }, diff --git a/packages/client/src/pages/settings/integration.vue b/packages/client/src/pages/settings/integration.vue index e3dbc6fde9..ca36c91665 100644 --- a/packages/client/src/pages/settings/integration.vue +++ b/packages/client/src/pages/settings/integration.vue @@ -73,8 +73,6 @@ export default defineComponent({ }, mounted() { - this.$emit('info', this[symbols.PAGE_INFO]); - document.cookie = `igi=${this.$i.token}; path=/;` + ` max-age=31536000;` + (document.location.protocol.startsWith('https') ? ' secure' : ''); diff --git a/packages/client/src/pages/settings/menu.vue b/packages/client/src/pages/settings/menu.vue index 26404f3adf..6e38cd5dfe 100644 --- a/packages/client/src/pages/settings/menu.vue +++ b/packages/client/src/pages/settings/menu.vue @@ -67,10 +67,6 @@ export default defineComponent({ }, }, - mounted() { - this.$emit('info', this[symbols.PAGE_INFO]); - }, - methods: { async addItem() { const menu = Object.keys(this.menuDef).filter(k => !this.$store.state.menu.includes(k)); diff --git a/packages/client/src/pages/settings/mute-block.vue b/packages/client/src/pages/settings/mute-block.vue index 6a63c9eb21..f4f9ebf8dd 100644 --- a/packages/client/src/pages/settings/mute-block.vue +++ b/packages/client/src/pages/settings/mute-block.vue @@ -27,8 +27,8 @@ - diff --git a/packages/client/src/pages/settings/notifications.vue b/packages/client/src/pages/settings/notifications.vue index ab26d7d558..12171530bb 100644 --- a/packages/client/src/pages/settings/notifications.vue +++ b/packages/client/src/pages/settings/notifications.vue @@ -37,10 +37,6 @@ export default defineComponent({ } }, - mounted() { - this.$emit('info', this[symbols.PAGE_INFO]); - }, - methods: { readAllUnreadNotes() { os.api('i/read-all-unread-notes'); diff --git a/packages/client/src/pages/settings/other.vue b/packages/client/src/pages/settings/other.vue index 7547013832..6e48cb58a6 100644 --- a/packages/client/src/pages/settings/other.vue +++ b/packages/client/src/pages/settings/other.vue @@ -47,10 +47,6 @@ export default defineComponent({ reportError: defaultStore.makeGetterSetter('reportError'), }, - mounted() { - this.$emit('info', this[symbols.PAGE_INFO]); - }, - methods: { changeDebug(v) { console.log(v); diff --git a/packages/client/src/pages/settings/plugin.install.vue b/packages/client/src/pages/settings/plugin.install.vue index bf494fa719..d35d20d17a 100644 --- a/packages/client/src/pages/settings/plugin.install.vue +++ b/packages/client/src/pages/settings/plugin.install.vue @@ -45,10 +45,6 @@ export default defineComponent({ } }, - mounted() { - this.$emit('info', this[symbols.PAGE_INFO]); - }, - methods: { installPlugin({ id, meta, ast, token }) { ColdDeviceStorage.set('plugins', ColdDeviceStorage.get('plugins').concat({ diff --git a/packages/client/src/pages/settings/plugin.vue b/packages/client/src/pages/settings/plugin.vue index d411ad2961..7a3ab9d152 100644 --- a/packages/client/src/pages/settings/plugin.vue +++ b/packages/client/src/pages/settings/plugin.vue @@ -64,10 +64,6 @@ export default defineComponent({ } }, - mounted() { - this.$emit('info', this[symbols.PAGE_INFO]); - }, - methods: { uninstall(plugin) { ColdDeviceStorage.set('plugins', this.plugins.filter(x => x.id !== plugin.id)); diff --git a/packages/client/src/pages/settings/privacy.vue b/packages/client/src/pages/settings/privacy.vue index 78a0ea8b8d..dd13ba4bd0 100644 --- a/packages/client/src/pages/settings/privacy.vue +++ b/packages/client/src/pages/settings/privacy.vue @@ -47,8 +47,8 @@ - diff --git a/packages/client/src/pages/settings/profile.vue b/packages/client/src/pages/settings/profile.vue index 2eaf9a9f83..9a2395872e 100644 --- a/packages/client/src/pages/settings/profile.vue +++ b/packages/client/src/pages/settings/profile.vue @@ -132,10 +132,6 @@ export default defineComponent({ this.$watch('alwaysMarkNsfw', this.save); }, - mounted() { - this.$emit('info', this[symbols.PAGE_INFO]); - }, - methods: { changeAvatar(e) { selectFile(e.currentTarget || e.target, this.$ts.avatar).then(file => { diff --git a/packages/client/src/pages/settings/reaction.vue b/packages/client/src/pages/settings/reaction.vue index 0d4db46936..e5b1189947 100644 --- a/packages/client/src/pages/settings/reaction.vue +++ b/packages/client/src/pages/settings/reaction.vue @@ -100,10 +100,6 @@ export default defineComponent({ } }, - mounted() { - this.$emit('info', this[symbols.PAGE_INFO]); - }, - methods: { save() { this.$store.set('reactions', this.reactions); diff --git a/packages/client/src/pages/settings/security.vue b/packages/client/src/pages/settings/security.vue index 03f2d6300b..6fb3f1c413 100644 --- a/packages/client/src/pages/settings/security.vue +++ b/packages/client/src/pages/settings/security.vue @@ -66,16 +66,12 @@ export default defineComponent({ bg: 'var(--bg)', }, pagination: { - endpoint: 'i/signin-history', + endpoint: 'i/signin-history' as const, limit: 5, }, } }, - mounted() { - this.$emit('info', this[symbols.PAGE_INFO]); - }, - methods: { async change() { const { canceled: canceled1, result: currentPassword } = await os.inputText({ diff --git a/packages/client/src/pages/settings/sounds.vue b/packages/client/src/pages/settings/sounds.vue index 0977dd8322..490a1b5514 100644 --- a/packages/client/src/pages/settings/sounds.vue +++ b/packages/client/src/pages/settings/sounds.vue @@ -94,12 +94,6 @@ export default defineComponent({ this.sounds.chatBg = ColdDeviceStorage.get('sound_chatBg'); this.sounds.antenna = ColdDeviceStorage.get('sound_antenna'); this.sounds.channel = ColdDeviceStorage.get('sound_channel'); - this.sounds.reversiPutBlack = ColdDeviceStorage.get('sound_reversiPutBlack'); - this.sounds.reversiPutWhite = ColdDeviceStorage.get('sound_reversiPutWhite'); - }, - - mounted() { - this.$emit('info', this[symbols.PAGE_INFO]); }, methods: { diff --git a/packages/client/src/pages/settings/theme.install.vue b/packages/client/src/pages/settings/theme.install.vue index 52935c75dc..e2a3f042b9 100644 --- a/packages/client/src/pages/settings/theme.install.vue +++ b/packages/client/src/pages/settings/theme.install.vue @@ -1,18 +1,18 @@ - diff --git a/packages/client/src/pages/settings/theme.manage.vue b/packages/client/src/pages/settings/theme.manage.vue index a913ba4748..a1e849b540 100644 --- a/packages/client/src/pages/settings/theme.manage.vue +++ b/packages/client/src/pages/settings/theme.manage.vue @@ -78,10 +78,6 @@ export default defineComponent({ }, }, - mounted() { - this.$emit('info', this[symbols.PAGE_INFO]); - }, - methods: { copyThemeCode() { copyToClipboard(this.selectedThemeCode); diff --git a/packages/client/src/pages/settings/theme.vue b/packages/client/src/pages/settings/theme.vue index 6c88b65699..658e36ec05 100644 --- a/packages/client/src/pages/settings/theme.vue +++ b/packages/client/src/pages/settings/theme.vue @@ -163,10 +163,6 @@ export default defineComponent({ location.reload(); }); - onMounted(() => { - emit('info', INFO); - }); - onActivated(() => { fetchThemes().then(() => { installedThemes.value = getThemes(); diff --git a/packages/client/src/pages/settings/word-mute.vue b/packages/client/src/pages/settings/word-mute.vue index 34edd0492c..19980dea14 100644 --- a/packages/client/src/pages/settings/word-mute.vue +++ b/packages/client/src/pages/settings/word-mute.vue @@ -87,10 +87,6 @@ export default defineComponent({ this.hardWordMutedNotesCount = (await os.api('i/get-word-muted-notes-count', {})).count; }, - mounted() { - this.$emit('info', this[symbols.PAGE_INFO]); - }, - methods: { async save() { this.$store.set('mutedWords', this.softMutedWords.trim().split('\n').map(x => x.trim().split(' '))); diff --git a/packages/client/src/pages/share.vue b/packages/client/src/pages/share.vue index bdd8500ee4..5df6256fb2 100644 --- a/packages/client/src/pages/share.vue +++ b/packages/client/src/pages/share.vue @@ -169,7 +169,7 @@ export default defineComponent({ window.close(); // 閉じなければ100ms後タイムラインに - setTimeout(() => { + window.setTimeout(() => { this.$router.push('/'); }, 100); } diff --git a/packages/client/src/pages/signup-complete.vue b/packages/client/src/pages/signup-complete.vue index 89375e05d2..a10af1a4cc 100644 --- a/packages/client/src/pages/signup-complete.vue +++ b/packages/client/src/pages/signup-complete.vue @@ -1,50 +1,36 @@ - diff --git a/packages/client/src/pages/tag.vue b/packages/client/src/pages/tag.vue index a9497ae801..8d8dc0a65c 100644 --- a/packages/client/src/pages/tag.vue +++ b/packages/client/src/pages/tag.vue @@ -4,37 +4,28 @@ - diff --git a/packages/client/src/pages/theme-editor.vue b/packages/client/src/pages/theme-editor.vue index c4917e2270..80b8c7806c 100644 --- a/packages/client/src/pages/theme-editor.vue +++ b/packages/client/src/pages/theme-editor.vue @@ -2,7 +2,7 @@
- +
- diff --git a/packages/client/src/pages/timeline.vue b/packages/client/src/pages/timeline.vue index 216b3c34ea..ecd1ae6257 100644 --- a/packages/client/src/pages/timeline.vue +++ b/packages/client/src/pages/timeline.vue @@ -1,6 +1,6 @@ - diff --git a/packages/client/src/pages/user/clips.vue b/packages/client/src/pages/user/clips.vue index aad5317ce0..870e6f7174 100644 --- a/packages/client/src/pages/user/clips.vue +++ b/packages/client/src/pages/user/clips.vue @@ -28,7 +28,7 @@ export default defineComponent({ data() { return { pagination: { - endpoint: 'users/clips', + endpoint: 'users/clips' as const, limit: 20, params: { userId: this.user.id, diff --git a/packages/client/src/pages/user/follow-list.vue b/packages/client/src/pages/user/follow-list.vue index e12ea477ca..98a1fc0f86 100644 --- a/packages/client/src/pages/user/follow-list.vue +++ b/packages/client/src/pages/user/follow-list.vue @@ -8,47 +8,32 @@
-