From 7747ec5b6de17e8ce20e1cf59649e5e98aec9991 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 23 Jan 2021 20:05:44 +0900 Subject: [PATCH 001/665] Update ja-JP.yml --- locales/ja-JP.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index fa215847d..992f6c842 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -678,7 +678,7 @@ onlineUsersCount: "{n}人がオンライン" nUsers: "{n}ユーザー" nNotes: "{n}ノート" sendErrorReports: "エラーリポートを送信" -sendErrorReportsDescription: "オンにすると、問題が発生したときにエラーの詳細情報がMisskeyに共有され、ソフトウェアの品質向上に役立てることができます。" +sendErrorReportsDescription: "オンにすると、問題が発生したときにエラーの詳細情報がMisskeyに共有され、ソフトウェアの品質向上に役立てることができます。エラー情報には、OSのバージョン、ブラウザの種類、行動履歴などが含まれます。" myTheme: "マイテーマ" backgroundColor: "背景" accentColor: "アクセント" From 6d33b366f8f18b0724c4a3d8cbfa6a7a4112b805 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 17 Apr 2022 21:18:18 +0900 Subject: [PATCH 002/665] fix ogp rendering and refactor --- packages/backend/src/models/entities/user.ts | 4 +-- .../backend/src/models/repositories/user.ts | 28 +++++++++++++------ .../backend/src/server/api/common/signin.ts | 2 +- packages/backend/src/server/index.ts | 20 ++++++------- packages/backend/src/server/web/feed.ts | 6 ++-- packages/backend/src/server/web/index.ts | 19 ++++++++----- .../backend/src/server/web/views/clip.pug | 2 +- .../backend/src/server/web/views/note.pug | 2 +- .../backend/src/server/web/views/page.pug | 2 +- .../backend/src/server/web/views/user.pug | 3 +- 10 files changed, 51 insertions(+), 37 deletions(-) diff --git a/packages/backend/src/models/entities/user.ts b/packages/backend/src/models/entities/user.ts index c76824c97..29d9a0c2c 100644 --- a/packages/backend/src/models/entities/user.ts +++ b/packages/backend/src/models/entities/user.ts @@ -1,6 +1,6 @@ import { Entity, Column, Index, OneToOne, JoinColumn, PrimaryColumn } from 'typeorm'; -import { DriveFile } from './drive-file.js'; import { id } from '../id.js'; +import { DriveFile } from './drive-file.js'; @Entity() @Index(['usernameLower', 'host'], { unique: true }) @@ -207,7 +207,7 @@ export class User { @Column('boolean', { default: false, - comment: 'Whether to show users replying to other users in the timeline' + comment: 'Whether to show users replying to other users in the timeline', }) public showTimelineReplies: boolean; diff --git a/packages/backend/src/models/repositories/user.ts b/packages/backend/src/models/repositories/user.ts index 2f4b7d678..541fbaf00 100644 --- a/packages/backend/src/models/repositories/user.ts +++ b/packages/backend/src/models/repositories/user.ts @@ -1,7 +1,6 @@ import { EntityRepository, Repository, In, Not } from 'typeorm'; import Ajv from 'ajv'; import { User, ILocalUser, IRemoteUser } from '@/models/entities/user.js'; -import { Notes, NoteUnreads, FollowRequests, Notifications, MessagingMessages, UserNotePinings, Followings, Blockings, Mutings, UserProfiles, UserSecurityKeys, UserGroupJoinings, Pages, Announcements, AnnouncementReads, Antennas, AntennaNotes, ChannelFollowings, Instances, DriveFiles } from '../index.js'; import config from '@/config/index.js'; import { Packed } from '@/misc/schema.js'; import { awaitAll, Promiseable } from '@/prelude/await-all.js'; @@ -9,8 +8,9 @@ import { populateEmojis } from '@/misc/populate-emojis.js'; import { getAntennas } from '@/misc/antenna-cache.js'; import { USER_ACTIVE_THRESHOLD, USER_ONLINE_THRESHOLD } from '@/const.js'; import { Cache } from '@/misc/cache.js'; -import { Instance } from '../entities/instance.js'; import { db } from '@/db/postgre.js'; +import { Instance } from '../entities/instance.js'; +import { Notes, NoteUnreads, FollowRequests, Notifications, MessagingMessages, UserNotePinings, Followings, Blockings, Mutings, UserProfiles, UserSecurityKeys, UserGroupJoinings, Pages, Announcements, AnnouncementReads, Antennas, AntennaNotes, ChannelFollowings, Instances, DriveFiles } from '../index.js'; const userInstanceCache = new Cache(1000 * 60 * 60 * 3); @@ -112,7 +112,7 @@ export const UserRepository = db.getRepository(User).extend({ const joinings = await UserGroupJoinings.findBy({ userId: userId }); const groupQs = Promise.all(joinings.map(j => MessagingMessages.createQueryBuilder('message') - .where(`message.groupId = :groupId`, { groupId: j.userGroupId }) + .where('message.groupId = :groupId', { groupId: j.userGroupId }) .andWhere('message.userId != :userId', { userId: userId }) .andWhere('NOT (:userId = ANY(message.reads))', { userId: userId }) .andWhere('message.createdAt > :joinedAt', { joinedAt: j.createdAt }) // 自分が加入する前の会話については、未読扱いしない @@ -204,8 +204,18 @@ export const UserRepository = db.getRepository(User).extend({ ); }, - getAvatarUrl(user: User): string { - // TODO: avatarIdがあるがavatarがない(JOINされてない)場合のハンドリング + async getAvatarUrl(user: User): Promise { + if (user.avatar) { + return DriveFiles.getPublicUrl(user.avatar, true) || this.getIdenticonUrl(user.id); + } else if (user.avatarId) { + const avatar = await DriveFiles.findOneByOrFail({ id: user.avatarId }); + return DriveFiles.getPublicUrl(avatar, true) || this.getIdenticonUrl(user.id); + } else { + return this.getIdenticonUrl(user.id); + } + }, + + getAvatarUrlSync(user: User): string { if (user.avatar) { return DriveFiles.getPublicUrl(user.avatar, true) || this.getIdenticonUrl(user.id); } else { @@ -223,7 +233,7 @@ export const UserRepository = db.getRepository(User).extend({ options?: { detail?: D, includeSecrets?: boolean, - } + }, ): Promise> { const opts = Object.assign({ detail: false, @@ -274,7 +284,7 @@ export const UserRepository = db.getRepository(User).extend({ name: user.name, username: user.username, host: user.host, - avatarUrl: this.getAvatarUrl(user), + avatarUrl: this.getAvatarUrlSync(user), avatarBlurhash: user.avatar?.blurhash || null, avatarColor: null, // 後方互換性のため isAdmin: user.isAdmin || falsy, @@ -283,7 +293,7 @@ export const UserRepository = db.getRepository(User).extend({ isCat: user.isCat || falsy, instance: user.host ? userInstanceCache.fetch(user.host, () => Instances.findOneBy({ host: user.host! }), - v => v != null + v => v != null, ).then(instance => instance ? { name: instance.name, softwareName: instance.softwareName, @@ -403,7 +413,7 @@ export const UserRepository = db.getRepository(User).extend({ options?: { detail?: D, includeSecrets?: boolean, - } + }, ): Promise[]> { return Promise.all(users.map(u => this.pack(u, me, options))); }, diff --git a/packages/backend/src/server/api/common/signin.ts b/packages/backend/src/server/api/common/signin.ts index f1dccee2c..038fd8d96 100644 --- a/packages/backend/src/server/api/common/signin.ts +++ b/packages/backend/src/server/api/common/signin.ts @@ -9,7 +9,7 @@ import { publishMainStream } from '@/services/stream.js'; export default function(ctx: Koa.Context, user: ILocalUser, redirect = false) { if (redirect) { //#region Cookie - ctx.cookies.set('igi', user.token, { + ctx.cookies.set('igi', user.token!, { path: '/', // SEE: https://github.com/koajs/koa/issues/974 // When using a SSL proxy it should be configured to add the "X-Forwarded-Proto: https" header diff --git a/packages/backend/src/server/index.ts b/packages/backend/src/server/index.ts index a68cebfeb..b50e38a63 100644 --- a/packages/backend/src/server/index.ts +++ b/packages/backend/src/server/index.ts @@ -10,23 +10,23 @@ import mount from 'koa-mount'; import koaLogger from 'koa-logger'; import * as slow from 'koa-slow'; -import activityPub from './activitypub.js'; -import nodeinfo from './nodeinfo.js'; -import wellKnown from './well-known.js'; +import { IsNull } from 'typeorm'; import config from '@/config/index.js'; -import apiServer from './api/index.js'; -import fileServer from './file/index.js'; -import proxyServer from './proxy/index.js'; -import webServer from './web/index.js'; import Logger from '@/services/logger.js'; -import { envOption } from '../env.js'; import { UserProfiles, Users } from '@/models/index.js'; import { genIdenticon } from '@/misc/gen-identicon.js'; import { createTemp } from '@/misc/create-temp.js'; import { publishMainStream } from '@/services/stream.js'; import * as Acct from '@/misc/acct.js'; +import { envOption } from '../env.js'; +import activityPub from './activitypub.js'; +import nodeinfo from './nodeinfo.js'; +import wellKnown from './well-known.js'; +import apiServer from './api/index.js'; +import fileServer from './file/index.js'; +import proxyServer from './proxy/index.js'; +import webServer from './web/index.js'; import { initializeStreamingServer } from './api/streaming.js'; -import { IsNull } from 'typeorm'; export const serverLogger = new Logger('server', 'gray', false); @@ -81,7 +81,7 @@ router.get('/avatar/@:acct', async ctx => { }); if (user) { - ctx.redirect(Users.getAvatarUrl(user)); + ctx.redirect(Users.getAvatarUrlSync(user)); } else { ctx.redirect('/static-assets/user-unknown.png'); } diff --git a/packages/backend/src/server/web/feed.ts b/packages/backend/src/server/web/feed.ts index eba8dc58d..4abe2885c 100644 --- a/packages/backend/src/server/web/feed.ts +++ b/packages/backend/src/server/web/feed.ts @@ -1,8 +1,8 @@ import { Feed } from 'feed'; +import { In, IsNull } from 'typeorm'; import config from '@/config/index.js'; import { User } from '@/models/entities/user.js'; -import { Notes, DriveFiles, UserProfiles } from '@/models/index.js'; -import { In, IsNull } from 'typeorm'; +import { Notes, DriveFiles, UserProfiles, Users } from '@/models/index.js'; export default async function(user: User) { const author = { @@ -29,7 +29,7 @@ export default async function(user: User) { generator: 'Misskey', description: `${user.notesCount} Notes, ${profile.ffVisibility === 'public' ? user.followingCount : '?'} Following, ${profile.ffVisibility === 'public' ? user.followersCount : '?'} Followers${profile.description ? ` · ${profile.description}` : ''}`, link: author.link, - image: user.avatarUrl ? user.avatarUrl : undefined, + image: await Users.getAvatarUrl(user), feedLinks: { json: `${author.link}.json`, atom: `${author.link}.atom`, diff --git a/packages/backend/src/server/web/index.ts b/packages/backend/src/server/web/index.ts index 48bf6f733..34d56cfd0 100644 --- a/packages/backend/src/server/web/index.ts +++ b/packages/backend/src/server/web/index.ts @@ -11,20 +11,20 @@ import send from 'koa-send'; import favicon from 'koa-favicon'; import views from 'koa-views'; import { createBullBoard } from '@bull-board/api'; -import { BullAdapter } from '@bull-board/api/bullAdapter.js'; +import { BullAdapter } from '@bull-board/api/bullAdapter.js'; import { KoaAdapter } from '@bull-board/koa'; -import packFeed from './feed.js'; +import { IsNull } from 'typeorm'; import { fetchMeta } from '@/misc/fetch-meta.js'; -import { genOpenapiSpec } from '../api/openapi/gen-spec.js'; import config from '@/config/index.js'; import { Users, Notes, UserProfiles, Pages, Channels, Clips, GalleryPosts } from '@/models/index.js'; import * as Acct from '@/misc/acct.js'; import { getNoteSummary } from '@/misc/get-note-summary.js'; +import { queues } from '@/queue/queues.js'; +import { genOpenapiSpec } from '../api/openapi/gen-spec.js'; import { urlPreviewHandler } from './url-preview.js'; import { manifestHandler } from './manifest.js'; -import { queues } from '@/queue/queues.js'; -import { IsNull } from 'typeorm'; +import packFeed from './feed.js'; const _filename = fileURLToPath(import.meta.url); const _dirname = dirname(_filename); @@ -127,7 +127,7 @@ router.get('/twemoji/(.*)', async ctx => { return; } - ctx.set('Content-Security-Policy', `default-src 'none'; style-src 'unsafe-inline'`); + ctx.set('Content-Security-Policy', 'default-src \'none\'; style-src \'unsafe-inline\''); await send(ctx as any, path, { root: `${_dirname}/../../../node_modules/@discordapp/twemoji/dist/svg/`, @@ -235,6 +235,7 @@ router.get(['/@:user', '/@:user/:sub'], async (ctx, next) => { await ctx.render('user', { user, profile, me, + avatarUrl: await Users.getAvatarUrl(user), sub: ctx.params.sub, instanceName: meta.name || 'Misskey', icon: meta.iconUrl, @@ -274,6 +275,7 @@ router.get('/notes/:note', async (ctx, next) => { await ctx.render('note', { note: _note, profile, + avatarUrl: await Users.getAvatarUrl(await Users.findOneByOrFail({ id: note.userId })), // TODO: Let locale changeable by instance setting summary: getNoteSummary(_note), instanceName: meta.name || 'Misskey', @@ -315,6 +317,7 @@ router.get('/@:user/pages/:page', async (ctx, next) => { await ctx.render('page', { page: _page, profile, + avatarUrl: await Users.getAvatarUrl(await Users.findOneByOrFail({ id: page.userId })), instanceName: meta.name || 'Misskey', icon: meta.iconUrl, themeColor: meta.themeColor, @@ -346,6 +349,7 @@ router.get('/clips/:clip', async (ctx, next) => { await ctx.render('clip', { clip: _clip, profile, + avatarUrl: await Users.getAvatarUrl(await Users.findOneByOrFail({ id: clip.userId })), instanceName: meta.name || 'Misskey', icon: meta.iconUrl, themeColor: meta.themeColor, @@ -370,6 +374,7 @@ router.get('/gallery/:post', async (ctx, next) => { await ctx.render('gallery-post', { post: _post, profile, + avatarUrl: await Users.getAvatarUrl(await Users.findOneByOrFail({ id: post.userId })), instanceName: meta.name || 'Misskey', icon: meta.iconUrl, themeColor: meta.themeColor, @@ -434,7 +439,7 @@ router.get('/cli', async ctx => { }); }); -const override = (source: string, target: string, depth: number = 0) => +const override = (source: string, target: string, depth = 0) => [, ...target.split('/').filter(x => x), ...source.split('/').filter(x => x).splice(depth)].join('/'); router.get('/flush', async ctx => { diff --git a/packages/backend/src/server/web/views/clip.pug b/packages/backend/src/server/web/views/clip.pug index 7a84d50f6..4c692bf59 100644 --- a/packages/backend/src/server/web/views/clip.pug +++ b/packages/backend/src/server/web/views/clip.pug @@ -16,7 +16,7 @@ block og meta(property='og:title' content= title) meta(property='og:description' content= clip.description) meta(property='og:url' content= url) - meta(property='og:image' content= user.avatarUrl) + meta(property='og:image' content= avatarUrl) block meta if profile.noCrawle diff --git a/packages/backend/src/server/web/views/note.pug b/packages/backend/src/server/web/views/note.pug index 34b03f983..65696ea13 100644 --- a/packages/backend/src/server/web/views/note.pug +++ b/packages/backend/src/server/web/views/note.pug @@ -17,7 +17,7 @@ block og meta(property='og:title' content= title) meta(property='og:description' content= summary) meta(property='og:url' content= url) - meta(property='og:image' content= user.avatarUrl) + meta(property='og:image' content= avatarUrl) block meta if user.host || isRenote || profile.noCrawle diff --git a/packages/backend/src/server/web/views/page.pug b/packages/backend/src/server/web/views/page.pug index b6c954802..4219e76a5 100644 --- a/packages/backend/src/server/web/views/page.pug +++ b/packages/backend/src/server/web/views/page.pug @@ -16,7 +16,7 @@ block og meta(property='og:title' content= title) meta(property='og:description' content= page.summary) meta(property='og:url' content= url) - meta(property='og:image' content= page.eyeCatchingImage ? page.eyeCatchingImage.thumbnailUrl : user.avatarUrl) + meta(property='og:image' content= page.eyeCatchingImage ? page.eyeCatchingImage.thumbnailUrl : avatarUrl) block meta if profile.noCrawle diff --git a/packages/backend/src/server/web/views/user.pug b/packages/backend/src/server/web/views/user.pug index 2adec0f88..119993fdb 100644 --- a/packages/backend/src/server/web/views/user.pug +++ b/packages/backend/src/server/web/views/user.pug @@ -3,7 +3,6 @@ extends ./base block vars - const title = user.name ? `${user.name} (@${user.username})` : `@${user.username}`; - const url = `${config.url}/@${(user.host ? `${user.username}@${user.host}` : user.username)}`; - - const img = user.avatarUrl || null; block title = `${title} | ${instanceName}` @@ -16,7 +15,7 @@ block og meta(property='og:title' content= title) meta(property='og:description' content= profile.description) meta(property='og:url' content= url) - meta(property='og:image' content= img) + meta(property='og:image' content= avatarUrl) block meta if user.host || profile.noCrawle From dd86397e857f36fbc06d77feadef00f6c92a3e21 Mon Sep 17 00:00:00 2001 From: xianon Date: Tue, 19 Apr 2022 22:59:39 +0900 Subject: [PATCH 003/665] =?UTF-8?q?fix:=20=E3=82=A2=E3=83=B3=E3=83=86?= =?UTF-8?q?=E3=83=8A=E3=80=81=E3=82=AF=E3=83=AA=E3=83=83=E3=83=97=E3=80=81?= =?UTF-8?q?=E3=83=AA=E3=82=B9=E3=83=88=E3=81=AE=E8=A1=A8=E7=A4=BA=E3=82=92?= =?UTF-8?q?=E9=80=9F=E3=81=8F=E3=81=99=E3=82=8B=20(#8518)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * アンテナノートを取得するクエリがタイムアウトしないように速くする * テーブル名を直接指定しないようにする * クリップの取得を速くする * リストの取得を速くする --- .../backend/src/server/api/endpoints/antennas/notes.ts | 8 ++------ packages/backend/src/server/api/endpoints/clips/notes.ts | 8 ++------ .../src/server/api/endpoints/notes/user-list-timeline.ts | 8 ++------ 3 files changed, 6 insertions(+), 18 deletions(-) diff --git a/packages/backend/src/server/api/endpoints/antennas/notes.ts b/packages/backend/src/server/api/endpoints/antennas/notes.ts index 004e4c131..8aac55b4a 100644 --- a/packages/backend/src/server/api/endpoints/antennas/notes.ts +++ b/packages/backend/src/server/api/endpoints/antennas/notes.ts @@ -57,13 +57,9 @@ export default define(meta, paramDef, async (ps, user) => { throw new ApiError(meta.errors.noSuchAntenna); } - const antennaQuery = AntennaNotes.createQueryBuilder('joining') - .select('joining.noteId') - .where('joining.antennaId = :antennaId', { antennaId: antenna.id }); - const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) - .andWhere(`note.id IN (${ antennaQuery.getQuery() })`) + .innerJoin(AntennaNotes.metadata.targetName, 'antennaNote', 'antennaNote.noteId = note.id') .innerJoinAndSelect('note.user', 'user') .leftJoinAndSelect('user.avatar', 'avatar') .leftJoinAndSelect('user.banner', 'banner') @@ -75,7 +71,7 @@ export default define(meta, paramDef, async (ps, user) => { .leftJoinAndSelect('renote.user', 'renoteUser') .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner') - .setParameters(antennaQuery.getParameters()); + .andWhere('antennaNote.antennaId = :antennaId', { antennaId: antenna.id }); generateVisibilityQuery(query, user); generateMutedUserQuery(query, user); diff --git a/packages/backend/src/server/api/endpoints/clips/notes.ts b/packages/backend/src/server/api/endpoints/clips/notes.ts index 4b6782fca..4ace747ef 100644 --- a/packages/backend/src/server/api/endpoints/clips/notes.ts +++ b/packages/backend/src/server/api/endpoints/clips/notes.ts @@ -57,12 +57,8 @@ export default define(meta, paramDef, async (ps, user) => { throw new ApiError(meta.errors.noSuchClip); } - const clipQuery = ClipNotes.createQueryBuilder('joining') - .select('joining.noteId') - .where('joining.clipId = :clipId', { clipId: clip.id }); - const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) - .andWhere(`note.id IN (${ clipQuery.getQuery() })`) + .innerJoin(ClipNotes.metadata.targetName, 'clipNote', 'clipNote.noteId = note.id') .innerJoinAndSelect('note.user', 'user') .leftJoinAndSelect('user.avatar', 'avatar') .leftJoinAndSelect('user.banner', 'banner') @@ -74,7 +70,7 @@ export default define(meta, paramDef, async (ps, user) => { .leftJoinAndSelect('renote.user', 'renoteUser') .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner') - .setParameters(clipQuery.getParameters()); + .andWhere('clipNote.clipId = :clipId', { clipId: clip.id }); if (user) { generateVisibilityQuery(query, user); diff --git a/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts b/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts index 6c6402603..fd4a87903 100644 --- a/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts @@ -63,12 +63,8 @@ export default define(meta, paramDef, async (ps, user) => { } //#region Construct query - const listQuery = UserListJoinings.createQueryBuilder('joining') - .select('joining.userId') - .where('joining.userListId = :userListId', { userListId: list.id }); - const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) - .andWhere(`note.userId IN (${ listQuery.getQuery() })`) + .innerJoin(UserListJoinings.metadata.targetName, 'userListJoining', 'userListJoining.userId = note.userId') .innerJoinAndSelect('note.user', 'user') .leftJoinAndSelect('user.avatar', 'avatar') .leftJoinAndSelect('user.banner', 'banner') @@ -80,7 +76,7 @@ export default define(meta, paramDef, async (ps, user) => { .leftJoinAndSelect('renote.user', 'renoteUser') .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner') - .setParameters(listQuery.getParameters()); + .andWhere('userListJoining.userListId = :userListId', { userListId: list.id }); generateVisibilityQuery(query, user); From e213c2e8446971549ba8cb8969a3b38d15530b4e Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 16 Apr 2022 13:31:12 +0900 Subject: [PATCH 004/665] remove unused locale --- locales/eo-UY.yml | 126 ---------------------------------------------- locales/index.js | 1 - 2 files changed, 127 deletions(-) delete mode 100644 locales/eo-UY.yml diff --git a/locales/eo-UY.yml b/locales/eo-UY.yml deleted file mode 100644 index 65a593157..000000000 --- a/locales/eo-UY.yml +++ /dev/null @@ -1,126 +0,0 @@ ---- -ok: "Bone" -exportRequested: "Vi petis elporton. Ĝi povas bezoni longan tempon. Elportaĵo estos aldonita al disko post elportado." -importRequested: "Vi petis enportadon. Ĝi povas bezoni longan tempon. " -pageLoadError: "Fuŝiĝis enlegi paĝon." -pageLoadErrorDescription: "Ordinare tio okazas pro la retkondiĉo aŭ la staplo de retumilo.\nPurigu la staplon, aŭ refaru poste. " -youShouldUpgradeClient: "Por montri ĉi paĝon, bonvolu enlegi refoje kaj uzi klienton novversian." -flagAsCatDescription: "Flagu por montri ke la konton havas kato." -flagShowTimelineReplies: "Montri respondon de notoj en templinio." -intro: "Instalado de Misskey finiĝis! Kreu administran konton." -whenServerDisconnected: "Kiam vi malligiĝas de servilo" -caseSensitive: "Distingi usklecon" -markAsReadAllUnreadNotes: "Marki ĉiujn afiŝojn kiel legita" -checking: "kontrolante..." -signinFailed: "Fuŝiĝis ensaluti. Bonvolu kontroli uzantnomon kaj pasvorton." -promote: "Reklamata" -updateRemoteUser: "Aktualigi informon de foraj uzantoj" -yourAccountSuspendedTitle: "La konto estas frostigita." -tokenRequested: "Alirpermeso al konto" -abuseReports: "Raportoj" -reportAbuse: "Raportoj" -reportAbuseOf: "raporti {name}n" -reporter: "Informanto" -reporterOrigin: "Raportanto" -pollVotesCount: "Nombro de voĉdonado" -invalidValue: "Nevalida valoro" -notRecommended: "Evitindaj" -switchAccount: "Ŝanĝi konton" -configure: "Agordi" -popularPosts: "Populara noto" -expiration: "Limtempo" -priority: "Prioritato" -squareAvatars: "Montri bildsimbolon kiel kvadrata" -misskeyUpdated: "Misskey ĝisdatiĝis!" -whatIsNew: "Montri novaĵojn" -accountDeletionInProgress: "La konto estas forviŝanta." -resolved: "Solvita" -unresolved: "Nesolvita" -filter: "Filtrilo" -deleteAccountConfirm: "La konto estos forviŝita. Ĉu vi daŭrigas fari?" -voteConfirm: "Ĉu vi voĉdonas {choice}n?" -hide: "Kaŝi" -overridedDeviceKind: "tipo de aparato" -size: "Grandeco" -searchByGoogle: "Serĉi en Guglo-Serĉilo" -mutePeriod: "Daŭro de silentigo" -indefinitely: "Sen limdato" -tenMinutes: "Je 10 minutoj" -oneHour: "Je 1 horo" -oneDay: "Je 1 tago" -oneWeek: "Je 1 semajno" -failedToFetchAccountInformation: "Malsukcesas akiri informon de konto" -_emailUnavailable: - mx: "Ĉi retpoŝto-servilo ne estas uzebla." -_signup: - almostThere: "Preskaŭ plenumita" -_accountDelete: - requestAccountDelete: "Peti forviŝi konton" - started: "Forviŝado komenciĝis." -_gallery: - my: "Mia afiŝo" -_aboutMisskey: - donate: "Mondonaci al Misskey" -_channel: - notesCount: "{n} notoj" -_theme: - explore: "Serĉi koloraron" - install: "Instali koloraron" - installedThemes: "Instalita koloraro" - make: "Krei koloraron" - addConstant: "Aldoni konstanton" - constant: "Konstanto" - keys: - shadow: "Ombro" - infoBg: "Fono de informo" -_widgets: - photos: "Fotoj" -_cw: - chars: "{count} literoj" -_poll: - expiration: "Limtempo" -_pages: - script: - blocks: - _add: - arg1: "A" - arg2: "B" - _subtract: - arg1: "A" - arg2: "B" - _multiply: - arg1: "A" - arg2: "B" - _divide: - arg1: "A" - arg2: "B" - _mod: - arg1: "A" - arg2: "B" - _eq: - arg1: "A" - arg2: "B" - _notEq: - arg1: "A" - arg2: "B" - _and: - arg1: "A" - arg2: "B" - _or: - arg1: "A" - arg2: "B" - _lt: - arg1: "A" - arg2: "B" - _gt: - arg1: "A" - arg2: "B" - _ltEq: - arg1: "A" - arg2: "B" - _gtEq: - arg1: "A" - arg2: "B" -_notification: - _types: - pollEnded: "Enketo finiĝis" diff --git a/locales/index.js b/locales/index.js index b271b79b7..98c30fe01 100644 --- a/locales/index.js +++ b/locales/index.js @@ -19,7 +19,6 @@ const languages = [ 'da-DK', 'de-DE', 'en-US', - 'eo-UY', 'es-ES', 'fr-FR', 'id-ID', From 3658f19d9800f331b3331080ac700dbae5db987a Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 23 Apr 2022 19:54:09 +0900 Subject: [PATCH 005/665] 12.110.1 --- CHANGELOG.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 211710134..dff67b40d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,12 @@ You should also include the user name that made the change. --> +## 12.110.1 (2022/04/23) + +### Bugfixes +- Fix GOP rendering @syuilo +- Improve performance of antenna, clip, and list @xianon + ## 12.110.0 (2022/04/11) ### Improvements diff --git a/package.json b/package.json index 13d70929b..606e2b733 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "12.110.0", + "version": "12.110.1", "codename": "indigo", "repository": { "type": "git", From 9fc5e8688f99545086e9226cf3179486efd9255e Mon Sep 17 00:00:00 2001 From: Andreas Nedbal Date: Thu, 12 May 2022 19:31:26 +0200 Subject: [PATCH 006/665] fix(client): add setup attribute to notification page (#8648) --- packages/client/src/pages/settings/notifications.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/client/src/pages/settings/notifications.vue b/packages/client/src/pages/settings/notifications.vue index 6fe2ac55a..b8fff95a8 100644 --- a/packages/client/src/pages/settings/notifications.vue +++ b/packages/client/src/pages/settings/notifications.vue @@ -9,7 +9,7 @@ - + + + + + + + + + + + + From 7d08b936c6f3ef558283d26435e1332a9933c281 Mon Sep 17 00:00:00 2001 From: Andreas Nedbal Date: Tue, 17 May 2022 18:30:35 +0200 Subject: [PATCH 035/665] refactor(client): refactor my-antennas/index to use Composition API (#8679) --- .../client/src/pages/my-antennas/index.vue | 41 +++++++------------ 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/packages/client/src/pages/my-antennas/index.vue b/packages/client/src/pages/my-antennas/index.vue index 7138d269a..9f1e01f11 100644 --- a/packages/client/src/pages/my-antennas/index.vue +++ b/packages/client/src/pages/my-antennas/index.vue @@ -1,7 +1,7 @@ - From 21d54f2758903c31714c49f278141c00e33294c9 Mon Sep 17 00:00:00 2001 From: Johann150 Date: Sat, 28 May 2022 17:26:17 +0200 Subject: [PATCH 100/665] fix: validate text is not empty fix #8747 --- packages/backend/src/server/api/endpoints/notes/create.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/backend/src/server/api/endpoints/notes/create.ts b/packages/backend/src/server/api/endpoints/notes/create.ts index 955f53bbc..a13329416 100644 --- a/packages/backend/src/server/api/endpoints/notes/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/create.ts @@ -134,7 +134,7 @@ export const paramDef = { { // (re)note with text, files and poll are optional properties: { - text: { type: 'string', maxLength: MAX_NOTE_TEXT_LENGTH, nullable: false }, + text: { type: 'string', minLength: 1, maxLength: MAX_NOTE_TEXT_LENGTH, nullable: false }, }, required: ['text'], }, From e54aa56ee13eb146cc6244ff1eaf401a0765a899 Mon Sep 17 00:00:00 2001 From: Johann150 Date: Fri, 20 May 2022 11:11:27 +0200 Subject: [PATCH 101/665] chore: remove unused imports --- packages/backend/src/remote/activitypub/models/note.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/backend/src/remote/activitypub/models/note.ts b/packages/backend/src/remote/activitypub/models/note.ts index 097a71661..ad24bbcd6 100644 --- a/packages/backend/src/remote/activitypub/models/note.ts +++ b/packages/backend/src/remote/activitypub/models/note.ts @@ -3,9 +3,9 @@ import promiseLimit from 'promise-limit'; import config from '@/config/index.js'; import Resolver from '../resolver.js'; import post from '@/services/note/create.js'; -import { resolvePerson, updatePerson } from './person.js'; +import { resolvePerson } from './person.js'; import { resolveImage } from './image.js'; -import { CacheableRemoteUser, IRemoteUser } from '@/models/entities/user.js'; +import { CacheableRemoteUser } from '@/models/entities/user.js'; import { htmlToMfm } from '../misc/html-to-mfm.js'; import { extractApHashtags } from './tag.js'; import { unique, toArray, toSingle } from '@/prelude/array.js'; @@ -15,7 +15,7 @@ import { apLogger } from '../logger.js'; import { DriveFile } from '@/models/entities/drive-file.js'; import { deliverQuestionUpdate } from '@/services/note/polls/update.js'; import { extractDbHost, toPuny } from '@/misc/convert-host.js'; -import { Emojis, Polls, MessagingMessages, Users } from '@/models/index.js'; +import { Emojis, Polls, MessagingMessages } from '@/models/index.js'; import { Note } from '@/models/entities/note.js'; import { IObject, getOneApId, getApId, getOneApHrefNullable, validPost, IPost, isEmoji, getApType } from '../type.js'; import { Emoji } from '@/models/entities/emoji.js'; From 4917961736cb4d01da31183a90a0f33623684c72 Mon Sep 17 00:00:00 2001 From: tamaina Date: Sun, 29 May 2022 10:57:06 +0900 Subject: [PATCH 102/665] preload app css (#8752) --- packages/backend/src/config/load.ts | 2 +- packages/backend/src/server/web/index.ts | 4 +-- .../backend/src/server/web/views/base.pug | 32 ++++++++++++------- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/packages/backend/src/config/load.ts b/packages/backend/src/config/load.ts index c2e6bea45..9654a4f3b 100644 --- a/packages/backend/src/config/load.ts +++ b/packages/backend/src/config/load.ts @@ -46,7 +46,7 @@ export default function load() { mixin.authUrl = `${mixin.scheme}://${mixin.host}/auth`; mixin.driveUrl = `${mixin.scheme}://${mixin.host}/files`; mixin.userAgent = `Misskey/${meta.version} (${config.url})`; - mixin.clientEntry = clientManifest['src/init.ts'].file.replace(/^_client_dist_\//, ''); + mixin.clientEntry = clientManifest['src/init.ts']; if (!config.redis.prefix) config.redis.prefix = mixin.host; diff --git a/packages/backend/src/server/web/index.ts b/packages/backend/src/server/web/index.ts index 9e31f2389..0b2c62c04 100644 --- a/packages/backend/src/server/web/index.ts +++ b/packages/backend/src/server/web/index.ts @@ -74,9 +74,9 @@ app.use(views(_dirname + '/views', { extension: 'pug', options: { version: config.version, - clientEntry: () => process.env.NODE_ENV === 'production' ? + getClientEntry: () => process.env.NODE_ENV === 'production' ? config.clientEntry : - JSON.parse(readFileSync(`${_dirname}/../../../../../built/_client_dist_/manifest.json`, 'utf-8'))['src/init.ts'].file.replace(/^_client_dist_\//, ''), + JSON.parse(readFileSync(`${_dirname}/../../../../../built/_client_dist_/manifest.json`, 'utf-8'))['src/init.ts'], config, }, })); diff --git a/packages/backend/src/server/web/views/base.pug b/packages/backend/src/server/web/views/base.pug index a488e5117..69ddb73c0 100644 --- a/packages/backend/src/server/web/views/base.pug +++ b/packages/backend/src/server/web/views/base.pug @@ -1,17 +1,23 @@ block vars +block loadClientEntry + - const clientEntry = getClientEntry(); + doctype html -!= '\n' +// + - + + _____ _ _ + | |_|___ ___| |_ ___ _ _ + | | | | |_ -|_ -| \'_| -_| | | + |_|_|_|_|___|___|_,_|___|_ | + |___| + Thank you for using Misskey! + If you are reading this message... how about joining the development? + https://github.com/misskey-dev/misskey + + html @@ -30,9 +36,11 @@ html link(rel='prefetch' href='https://xn--931a.moe/assets/info.jpg') link(rel='prefetch' href='https://xn--931a.moe/assets/not-found.jpg') link(rel='prefetch' href='https://xn--931a.moe/assets/error.jpg') - link(rel='preload' href='/assets/fontawesome/css/all.css' as='style') link(rel='stylesheet' href='/assets/fontawesome/css/all.css') + each href in clientEntry.css + link(rel='preload' href=`/assets/${href}` as='style') + title block title = title || 'Misskey' @@ -52,7 +60,7 @@ html script. var VERSION = "#{version}"; - var CLIENT_ENTRY = "#{clientEntry()}"; + var CLIENT_ENTRY = "#{clientEntry.file}"; script include ../boot.js From f1d2398eacbc69a14d09ebe5e7040be891f9e143 Mon Sep 17 00:00:00 2001 From: tamaina Date: Sun, 29 May 2022 10:58:54 +0900 Subject: [PATCH 103/665] fix(client): Vite related boot mechanism revision (#8753) * preload app css * remove salt * APP_FETCH_FAILED error * set max-age to 15s --- packages/backend/src/server/web/boot.js | 13 +++---------- packages/backend/src/server/web/index.ts | 14 +++++++------- packages/backend/src/server/web/views/base.pug | 4 ++++ 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/packages/backend/src/server/web/boot.js b/packages/backend/src/server/web/boot.js index a9ee0df4f..94329e11c 100644 --- a/packages/backend/src/server/web/boot.js +++ b/packages/backend/src/server/web/boot.js @@ -54,14 +54,10 @@ //#endregion //#region Script - const salt = localStorage.getItem('salt') - ? `?salt=${localStorage.getItem('salt')}` - : ''; - - import(`/assets/${CLIENT_ENTRY}${salt}`) - .catch(async () => { + import(`/assets/${CLIENT_ENTRY}`) + .catch(async e => { await checkUpdate(); - renderError('APP_FETCH_FAILED'); + renderError('APP_FETCH_FAILED', JSON.stringify(e)); }) //#endregion @@ -142,9 +138,6 @@ // eslint-disable-next-line no-inner-declarations function refresh() { - // Random - localStorage.setItem('salt', Math.random().toString().substr(2, 8)); - // Clear cache (service worker) try { navigator.serviceWorker.controller.postMessage('clear'); diff --git a/packages/backend/src/server/web/index.ts b/packages/backend/src/server/web/index.ts index 0b2c62c04..2feee72be 100644 --- a/packages/backend/src/server/web/index.ts +++ b/packages/backend/src/server/web/index.ts @@ -247,7 +247,7 @@ router.get(['/@:user', '/@:user/:sub'], async (ctx, next) => { icon: meta.iconUrl, themeColor: meta.themeColor, }); - ctx.set('Cache-Control', 'public, max-age=30'); + ctx.set('Cache-Control', 'public, max-age=15'); } else { // リモートユーザーなので // モデレータがAPI経由で参照可能にするために404にはしない @@ -292,7 +292,7 @@ router.get('/notes/:note', async (ctx, next) => { themeColor: meta.themeColor, }); - ctx.set('Cache-Control', 'public, max-age=180'); + ctx.set('Cache-Control', 'public, max-age=15'); return; } @@ -329,7 +329,7 @@ router.get('/@:user/pages/:page', async (ctx, next) => { }); if (['public'].includes(page.visibility)) { - ctx.set('Cache-Control', 'public, max-age=180'); + ctx.set('Cache-Control', 'public, max-age=15'); } else { ctx.set('Cache-Control', 'private, max-age=0, must-revalidate'); } @@ -360,7 +360,7 @@ router.get('/clips/:clip', async (ctx, next) => { themeColor: meta.themeColor, }); - ctx.set('Cache-Control', 'public, max-age=180'); + ctx.set('Cache-Control', 'public, max-age=15'); return; } @@ -385,7 +385,7 @@ router.get('/gallery/:post', async (ctx, next) => { themeColor: meta.themeColor, }); - ctx.set('Cache-Control', 'public, max-age=180'); + ctx.set('Cache-Control', 'public, max-age=15'); return; } @@ -409,7 +409,7 @@ router.get('/channels/:channel', async (ctx, next) => { themeColor: meta.themeColor, }); - ctx.set('Cache-Control', 'public, max-age=180'); + ctx.set('Cache-Control', 'public, max-age=15'); return; } @@ -468,7 +468,7 @@ router.get('(.*)', async ctx => { icon: meta.iconUrl, themeColor: meta.themeColor, }); - ctx.set('Cache-Control', 'public, max-age=300'); + ctx.set('Cache-Control', 'public, max-age=15'); }); // Register router diff --git a/packages/backend/src/server/web/views/base.pug b/packages/backend/src/server/web/views/base.pug index 69ddb73c0..230ed1578 100644 --- a/packages/backend/src/server/web/views/base.pug +++ b/packages/backend/src/server/web/views/base.pug @@ -37,6 +37,10 @@ html link(rel='prefetch' href='https://xn--931a.moe/assets/not-found.jpg') link(rel='prefetch' href='https://xn--931a.moe/assets/error.jpg') link(rel='stylesheet' href='/assets/fontawesome/css/all.css') + link(rel='modulepreload' href=`/assets/${clientEntry.file}`) + + each href in clientEntry.css + link(rel='preload' href=`/assets/${href}` as='style') each href in clientEntry.css link(rel='preload' href=`/assets/${href}` as='style') From 804fa33535baa9e5cdf49070a50a555cf2c3b1ea Mon Sep 17 00:00:00 2001 From: Johann150 Date: Sun, 29 May 2022 08:15:52 +0200 Subject: [PATCH 104/665] refactor: improve code quality (#8751) * remove unnecessary if `Array.prototype.some` already returns a boolean so an if to return true or false is completely unnecessary in this case. * perf: use count instead of find When using `count` instead of `findOneBy`, the data is not unnecessarily loaded. * remove duplicate null check The variable is checked for null in the lines above and the function returns if so. Therefore, it can not be null at this point. * simplify `getJsonSchema` Because the assigned value is `null` and the used keys are only shallow, use of `nestedProperty.set` seems inappropriate. Because the value is not read, the initial for loop can be replaced by a `for..in` loop. Since all keys will be assigned `null`, the condition of the ternary expression in the nested function will always be true. Therefore the recursion case will never happen. With this the nested function can be eliminated. * remove duplicate condition The code above already checks `dragging` and returns if it is truthy. Checking it again later is therefore unnecessary. To make this more obvious the `return` is removed in favour of using an if...else construct. * remove impossible "unknown" time The `ago` variable will always be a number and all non-negative numbers are already covered by other cases, the negative case is handled with `future` so there is no case when `unkown` could be achieved. --- locales/ja-JP.yml | 1 - .../backend/src/models/repositories/note.ts | 19 ++-- .../backend/src/models/repositories/user.ts | 91 +++++++++++-------- .../src/remote/activitypub/renderer/index.ts | 2 +- packages/backend/src/services/chart/core.ts | 27 ++---- .../client/src/components/global/time.vue | 3 +- packages/client/src/ui/deck/column.vue | 13 ++- 7 files changed, 77 insertions(+), 79 deletions(-) diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 6354fcfda..9cd1d1eed 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1111,7 +1111,6 @@ _sfx: channel: "チャンネル通知" _ago: - unknown: "謎" future: "未来" justNow: "たった今" secondsAgo: "{n}秒前" diff --git a/packages/backend/src/models/repositories/note.ts b/packages/backend/src/models/repositories/note.ts index 638d78f62..c0abbb4f9 100644 --- a/packages/backend/src/models/repositories/note.ts +++ b/packages/backend/src/models/repositories/note.ts @@ -144,13 +144,7 @@ export const NoteRepository = db.getRepository(Note).extend({ return true; } else { // 指定されているかどうか - const specified = note.visibleUserIds.some((id: any) => meId === id); - - if (specified) { - return true; - } else { - return false; - } + return note.visibleUserIds.some((id: any) => meId === id); } } @@ -169,9 +163,12 @@ export const NoteRepository = db.getRepository(Note).extend({ } else { // フォロワーかどうか const [following, user] = await Promise.all([ - Followings.findOneBy({ - followeeId: note.userId, - followerId: meId, + Followings.count({ + where: { + followeeId: note.userId, + followerId: meId, + }, + take: 1, }), Users.findOneByOrFail({ id: meId }), ]); @@ -183,7 +180,7 @@ export const NoteRepository = db.getRepository(Note).extend({ in which case we can never know the following. Instead we have to assume that the users are following each other. */ - return following != null || (note.userHost != null && user.host != null); + return following > 0 || (note.userHost != null && user.host != null); } } diff --git a/packages/backend/src/models/repositories/user.ts b/packages/backend/src/models/repositories/user.ts index 541fbaf00..8a4e48efd 100644 --- a/packages/backend/src/models/repositories/user.ts +++ b/packages/backend/src/models/repositories/user.ts @@ -61,47 +61,58 @@ export const UserRepository = db.getRepository(User).extend({ //#endregion async getRelation(me: User['id'], target: User['id']) { - const [following1, following2, followReq1, followReq2, toBlocking, fromBlocked, mute] = await Promise.all([ - Followings.findOneBy({ - followerId: me, - followeeId: target, - }), - Followings.findOneBy({ - followerId: target, - followeeId: me, - }), - FollowRequests.findOneBy({ - followerId: me, - followeeId: target, - }), - FollowRequests.findOneBy({ - followerId: target, - followeeId: me, - }), - Blockings.findOneBy({ - blockerId: me, - blockeeId: target, - }), - Blockings.findOneBy({ - blockerId: target, - blockeeId: me, - }), - Mutings.findOneBy({ - muterId: me, - muteeId: target, - }), - ]); - - return { + return awaitAll({ id: target, - isFollowing: following1 != null, - hasPendingFollowRequestFromYou: followReq1 != null, - hasPendingFollowRequestToYou: followReq2 != null, - isFollowed: following2 != null, - isBlocking: toBlocking != null, - isBlocked: fromBlocked != null, - isMuted: mute != null, - }; + isFollowing: Followings.count({ + where: { + followerId: me, + followeeId: target, + }, + take: 1, + }).then(n => n > 0), + isFollowed: Followings.count({ + where: { + followerId: target, + followeeId: me, + }, + take: 1, + }).then(n => n > 0), + hasPendingFollowRequestFromYou: FollowRequests.count({ + where: { + followerId: me, + followeeId: target, + }, + take: 1, + }).then(n => n > 0), + hasPendingFollowRequestToYou: FollowRequests.count({ + where: { + followerId: target, + followeeId: me, + }, + take: 1, + }).then(n => n > 0), + isBlocking: Blockings.count({ + where: { + blockerId: me, + blockeeId: target, + }, + take: 1, + }).then(n => n > 0), + isBlocked: Blockings.count({ + where: { + blockerId: target, + blockeeId: me, + }, + take: 1, + }).then(n => n > 0), + isMuted: Mutings.count({ + where: { + muterId: me, + muteeId: target, + }, + take: 1, + }).then(n => n > 0), + }); }, async getHasUnreadMessagingMessage(userId: User['id']): Promise { diff --git a/packages/backend/src/remote/activitypub/renderer/index.ts b/packages/backend/src/remote/activitypub/renderer/index.ts index 5f6933226..f100b77ce 100644 --- a/packages/backend/src/remote/activitypub/renderer/index.ts +++ b/packages/backend/src/remote/activitypub/renderer/index.ts @@ -8,7 +8,7 @@ import { User } from '@/models/entities/user.js'; export const renderActivity = (x: any): IActivity | null => { if (x == null) return null; - if (x !== null && typeof x === 'object' && x.id == null) { + if (typeof x === 'object' && x.id == null) { x.id = `${config.url}/${uuid()}`; } diff --git a/packages/backend/src/services/chart/core.ts b/packages/backend/src/services/chart/core.ts index cf69e2194..2960bac8f 100644 --- a/packages/backend/src/services/chart/core.ts +++ b/packages/backend/src/services/chart/core.ts @@ -91,27 +91,20 @@ type ToJsonSchema = { }; export function getJsonSchema(schema: S): ToJsonSchema>> { - const object = {}; - for (const [k, v] of Object.entries(schema)) { - nestedProperty.set(object, k, null); - } + const jsonSchema = { + type: 'object', + properties: {} as Record, + required: [], + }; - function f(obj: Record>) { - const jsonSchema = { - type: 'object', - properties: {} as Record, - required: [], + for (const k in schema) { + jsonSchema.properties[k] = { + type: 'array', + items: { type: 'number' }, }; - for (const [k, v] of Object.entries(obj)) { - jsonSchema.properties[k] = v === null ? { - type: 'array', - items: { type: 'number' }, - } : f(v as Record>); - } - return jsonSchema; } - return f(object) as ToJsonSchema>>; + return jsonSchema as ToJsonSchema>>; } /** diff --git a/packages/client/src/components/global/time.vue b/packages/client/src/components/global/time.vue index 02351deb5..a7f142f96 100644 --- a/packages/client/src/components/global/time.vue +++ b/packages/client/src/components/global/time.vue @@ -32,8 +32,7 @@ const relative = $computed(() => { ago >= 60 ? i18n.t('_ago.minutesAgo', { n: (~~(ago / 60)).toString() }) : ago >= 10 ? i18n.t('_ago.secondsAgo', { n: (~~(ago % 60)).toString() }) : ago >= -1 ? i18n.ts._ago.justNow : - ago < -1 ? i18n.ts._ago.future : - i18n.ts._ago.unknown); + i18n.ts._ago.future); }); function tick() { diff --git a/packages/client/src/ui/deck/column.vue b/packages/client/src/ui/deck/column.vue index fbaea64f5..31063a753 100644 --- a/packages/client/src/ui/deck/column.vue +++ b/packages/client/src/ui/deck/column.vue @@ -213,14 +213,13 @@ function onDragover(ev) { if (dragging) { // 自分自身にはドロップさせない ev.dataTransfer.dropEffect = 'none'; - return; + } else { + const isDeckColumn = ev.dataTransfer.types[0] === _DATA_TRANSFER_DECK_COLUMN_; + + ev.dataTransfer.dropEffect = isDeckColumn ? 'move' : 'none'; + + if (isDeckColumn) draghover = true; } - - const isDeckColumn = ev.dataTransfer.types[0] === _DATA_TRANSFER_DECK_COLUMN_; - - ev.dataTransfer.dropEffect = isDeckColumn ? 'move' : 'none'; - - if (!dragging && isDeckColumn) draghover = true; } function onDragleave() { From d2784030ec898e0b4e391f2eb840646f72cd7d6b Mon Sep 17 00:00:00 2001 From: futchitwo <74236683+futchitwo@users.noreply.github.com> Date: Sun, 29 May 2022 19:21:36 +0900 Subject: [PATCH 105/665] fix(client): fix popout url (#8494) --- packages/client/src/pages/theme-editor.vue | 2 +- packages/client/src/scripts/popout.ts | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/client/src/pages/theme-editor.vue b/packages/client/src/pages/theme-editor.vue index 2ee530597..b7b537cea 100644 --- a/packages/client/src/pages/theme-editor.vue +++ b/packages/client/src/pages/theme-editor.vue @@ -126,7 +126,7 @@ let changed = $ref(false); useLeaveGuard($$(changed)); function showPreview() { - os.pageWindow('preview'); + os.pageWindow('/preview'); } function setBgColor(color: typeof bgColors[number]) { diff --git a/packages/client/src/scripts/popout.ts b/packages/client/src/scripts/popout.ts index b8286a2a7..580031d0a 100644 --- a/packages/client/src/scripts/popout.ts +++ b/packages/client/src/scripts/popout.ts @@ -1,8 +1,9 @@ import * as config from '@/config'; +import { appendQuery } from './url'; export function popout(path: string, w?: HTMLElement) { - let url = path.startsWith('http://') || path.startsWith('https://') ? path : config.url + "/" + path; - url += '?zen'; + let url = path.startsWith('http://') || path.startsWith('https://') ? path : config.url + path; + url = appendQuery(url, 'zen'); if (w) { const position = w.getBoundingClientRect(); const width = parseInt(getComputedStyle(w, '').width, 10); From feba678e03d3c7635d6f9f130ea4355af245e70a Mon Sep 17 00:00:00 2001 From: Johann150 Date: Sun, 29 May 2022 14:26:29 +0200 Subject: [PATCH 106/665] enhance(dev): ask for log snippets --- .github/ISSUE_TEMPLATE/01_bug-report.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/01_bug-report.md b/.github/ISSUE_TEMPLATE/01_bug-report.md index 8734fc0c3..0fecce2ee 100644 --- a/.github/ISSUE_TEMPLATE/01_bug-report.md +++ b/.github/ISSUE_TEMPLATE/01_bug-report.md @@ -22,7 +22,10 @@ First, in order to avoid duplicate Issues, please search to see if the problem y ## 🤬 Actual Behavior - + ## 📝 Steps to Reproduce From ebc2566130c785924380d504c76b270198bdc2c2 Mon Sep 17 00:00:00 2001 From: Johann150 Date: Sun, 29 May 2022 14:32:52 +0200 Subject: [PATCH 107/665] fix: add missing import fix #8756 --- .../backend/src/queue/processors/db/export-custom-emojis.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 97ba62dcf..8ce1d0527 100644 --- a/packages/backend/src/queue/processors/db/export-custom-emojis.ts +++ b/packages/backend/src/queue/processors/db/export-custom-emojis.ts @@ -9,7 +9,7 @@ import { addFile } from '@/services/drive/add-file.js'; import { format as dateFormat } from 'date-fns'; import { Users, Emojis } from '@/models/index.js'; import { } from '@/queue/types.js'; -import { createTempDir } from '@/misc/create-temp.js'; +import { createTemp, createTempDir } from '@/misc/create-temp.js'; import { downloadUrl } from '@/misc/download-url.js'; import config from '@/config/index.js'; import { IsNull } from 'typeorm'; From 39051854635617d1b95d85b759e3c1aa6f827b4b Mon Sep 17 00:00:00 2001 From: Andreas Nedbal Date: Mon, 30 May 2022 04:37:34 +0200 Subject: [PATCH 108/665] fix(client): import shared ESLint config in client package (#8761) --- packages/client/.eslintrc.js | 105 +++++++++++++++++++--------------- packages/client/tsconfig.json | 1 + 2 files changed, 59 insertions(+), 47 deletions(-) diff --git a/packages/client/.eslintrc.js b/packages/client/.eslintrc.js index a6e23e517..1c2ab0a42 100644 --- a/packages/client/.eslintrc.js +++ b/packages/client/.eslintrc.js @@ -1,68 +1,79 @@ module.exports = { root: true, env: { - "node": false + 'node': false, }, - parser: "vue-eslint-parser", + parser: 'vue-eslint-parser', parserOptions: { - "parser": "@typescript-eslint/parser", + 'parser': '@typescript-eslint/parser', tsconfigRootDir: __dirname, - //project: ['./tsconfig.json'], + project: ['./tsconfig.json'], + extraFileExtensions: ['.vue'], }, extends: [ - //"../shared/.eslintrc.js", - "plugin:vue/vue3-recommended" + '../shared/.eslintrc.js', + 'plugin:vue/vue3-recommended', ], rules: { // window の禁止理由: グローバルスコープと衝突し、予期せぬ結果を招くため // data の禁止理由: 抽象的すぎるため // e の禁止理由: error や event など、複数のキーワードの頭文字であり分かりにくいため - "id-denylist": ["error", "window", "data", "e"], + 'id-denylist': ['error', 'window', 'data', 'e'], 'eqeqeq': ['error', 'always', { 'null': 'ignore' }], - "no-shadow": ["warn"], - "vue/attributes-order": ["error", { - "alphabetical": false + 'no-shadow': ['warn'], + 'vue/attributes-order': ['error', { + 'alphabetical': false, }], - "vue/no-use-v-if-with-v-for": ["error", { - "allowUsingIterationVar": false + 'vue/no-use-v-if-with-v-for': ['error', { + 'allowUsingIterationVar': false, }], - "vue/no-ref-as-operand": "error", - "vue/no-multi-spaces": ["error", { - "ignoreProperties": false + 'vue/no-ref-as-operand': 'error', + 'vue/no-multi-spaces': ['error', { + 'ignoreProperties': false, }], - "vue/no-v-html": "error", - "vue/order-in-components": "error", - "vue/html-indent": ["warn", "tab", { - "attribute": 1, - "baseIndent": 0, - "closeBracket": 0, - "alignAttributesVertically": true, - "ignores": [] + 'vue/no-v-html': 'error', + 'vue/order-in-components': 'error', + 'vue/html-indent': ['warn', 'tab', { + 'attribute': 1, + 'baseIndent': 0, + 'closeBracket': 0, + 'alignAttributesVertically': true, + 'ignores': [], }], - "vue/html-closing-bracket-spacing": ["warn", { - "startTag": "never", - "endTag": "never", - "selfClosingTag": "never" + 'vue/html-closing-bracket-spacing': ['warn', { + 'startTag': 'never', + 'endTag': 'never', + 'selfClosingTag': 'never', }], - "vue/multi-word-component-names": "warn", - "vue/require-v-for-key": "warn", - "vue/no-unused-components": "warn", - "vue/valid-v-for": "warn", - "vue/return-in-computed-property": "warn", - "vue/no-setup-props-destructure": "warn", - "vue/max-attributes-per-line": "off", - "vue/html-self-closing": "off", - "vue/singleline-html-element-content-newline": "off", + 'vue/multi-word-component-names': 'warn', + 'vue/require-v-for-key': 'warn', + 'vue/no-unused-components': 'warn', + 'vue/valid-v-for': 'warn', + 'vue/return-in-computed-property': 'warn', + 'vue/no-setup-props-destructure': 'warn', + 'vue/max-attributes-per-line': 'off', + 'vue/html-self-closing': 'off', + 'vue/singleline-html-element-content-newline': 'off', }, globals: { - "require": false, - "_DEV_": false, - "_LANGS_": false, - "_VERSION_": false, - "_ENV_": false, - "_PERF_PREFIX_": false, - "_DATA_TRANSFER_DRIVE_FILE_": false, - "_DATA_TRANSFER_DRIVE_FOLDER_": false, - "_DATA_TRANSFER_DECK_COLUMN_": false - } -} + // Node.js + 'module': false, + 'require': false, + '__dirname': false, + + // Vue + '$$': false, + '$ref': false, + '$computed': false, + + // Misskey + '_DEV_': false, + '_LANGS_': false, + '_VERSION_': false, + '_ENV_': false, + '_PERF_PREFIX_': false, + '_DATA_TRANSFER_DRIVE_FILE_': false, + '_DATA_TRANSFER_DRIVE_FOLDER_': false, + '_DATA_TRANSFER_DECK_COLUMN_': false, + }, +}; diff --git a/packages/client/tsconfig.json b/packages/client/tsconfig.json index 2c387286a..f7320a725 100644 --- a/packages/client/tsconfig.json +++ b/packages/client/tsconfig.json @@ -39,6 +39,7 @@ }, "compileOnSave": false, "include": [ + ".eslintrc.js", "./**/*.ts", "./**/*.vue" ] From 9759ca7d24d4a7b7154043160a8d8ba34b2505dc Mon Sep 17 00:00:00 2001 From: tamaina Date: Mon, 30 May 2022 05:53:36 +0000 Subject: [PATCH 109/665] chore: remove packages/sw/webpack.config.js --- packages/sw/webpack.config.js | 71 ----------------------------------- 1 file changed, 71 deletions(-) delete mode 100644 packages/sw/webpack.config.js diff --git a/packages/sw/webpack.config.js b/packages/sw/webpack.config.js deleted file mode 100644 index a4bcf96dd..000000000 --- a/packages/sw/webpack.config.js +++ /dev/null @@ -1,71 +0,0 @@ -/** - * webpack configuration - */ - -const fs = require('fs'); -const webpack = require('webpack'); - -class WebpackOnBuildPlugin { - constructor(callback) { - this.callback = callback; - } - - apply(compiler) { - compiler.hooks.done.tap('WebpackOnBuildPlugin', this.callback); - } -} - -const isProduction = process.env.NODE_ENV === 'production'; - -const locales = require('../../locales'); -const meta = require('../../package.json'); - -module.exports = { - target: 'webworker', - entry: { - ['sw-lib']: './src/lib.ts' - }, - module: { - rules: [{ - test: /\.ts$/, - exclude: /node_modules/, - use: [{ - loader: 'ts-loader', - options: { - happyPackMode: true, - transpileOnly: true, - configFile: __dirname + '/tsconfig.json', - } - }] - }] - }, - plugins: [ - new webpack.ProgressPlugin({}), - new webpack.DefinePlugin({ - _VERSION_: JSON.stringify(meta.version), - _LANGS_: JSON.stringify(Object.entries(locales).map(([k, v]) => [k, v._lang_])), - _ENV_: JSON.stringify(process.env.NODE_ENV), - _DEV_: process.env.NODE_ENV !== 'production', - _PERF_PREFIX_: JSON.stringify('Misskey:'), - }), - ], - output: { - path: __dirname + '/../../built/_sw_dist_', - filename: `[name].js`, - publicPath: `/`, - pathinfo: false, - }, - resolve: { - extensions: [ - '.js', '.ts', '.json' - ], - alias: { - '@': __dirname + '/src/', - } - }, - resolveLoader: { - modules: ['node_modules'] - }, - devtool: false, //'source-map', - mode: isProduction ? 'production' : 'development' -}; From 857055a9dd50bbc3331d2454da3897d855fdebfe Mon Sep 17 00:00:00 2001 From: tamaina Date: Mon, 30 May 2022 12:09:22 +0000 Subject: [PATCH 110/665] chore: fix import tinycolor --- packages/client/src/pages/settings/drive.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/client/src/pages/settings/drive.vue b/packages/client/src/pages/settings/drive.vue index f235ace7c..09a2537ed 100644 --- a/packages/client/src/pages/settings/drive.vue +++ b/packages/client/src/pages/settings/drive.vue @@ -35,7 +35,7 @@ diff --git a/packages/client/src/components/note-detailed.vue b/packages/client/src/components/note-detailed.vue index 14bbbd4f3..6234b710d 100644 --- a/packages/client/src/components/note-detailed.vue +++ b/packages/client/src/components/note-detailed.vue @@ -222,7 +222,7 @@ function react(viaKeyboard = false): void { reactionPicker.show(reactButton.value, reaction => { os.api('notes/reactions/create', { noteId: appearNote.id, - reaction: reaction + reaction: reaction, }); }, () => { focus(); @@ -233,7 +233,7 @@ function undoReact(note): void { const oldReaction = note.myReaction; if (!oldReaction) return; os.api('notes/reactions/delete', { - noteId: note.id + noteId: note.id, }); } @@ -257,7 +257,7 @@ function onContextmenu(ev: MouseEvent): void { function menu(viaKeyboard = false): void { os.popupMenu(getNoteMenu({ note: note, translating, translation, menuButton }), menuButton.value, { - viaKeyboard + viaKeyboard, }).then(focus); } @@ -269,12 +269,12 @@ function showRenoteMenu(viaKeyboard = false): void { danger: true, action: () => { os.api('notes/delete', { - noteId: note.id + noteId: note.id, }); isDeleted.value = true; - } + }, }], renoteTime.value, { - viaKeyboard: viaKeyboard + viaKeyboard: viaKeyboard, }); } @@ -288,14 +288,14 @@ function blur() { os.api('notes/children', { noteId: appearNote.id, - limit: 30 + limit: 30, }).then(res => { replies.value = res; }); if (appearNote.replyId) { os.api('notes/conversation', { - noteId: appearNote.replyId + noteId: appearNote.replyId, }).then(res => { conversation.value = res.reverse(); }); diff --git a/packages/client/src/components/note.vue b/packages/client/src/components/note.vue index bc8a0dd19..e5744d1ce 100644 --- a/packages/client/src/components/note.vue +++ b/packages/client/src/components/note.vue @@ -210,7 +210,7 @@ function react(viaKeyboard = false): void { reactionPicker.show(reactButton.value, reaction => { os.api('notes/reactions/create', { noteId: appearNote.id, - reaction: reaction + reaction: reaction, }); }, () => { focus(); @@ -221,7 +221,7 @@ function undoReact(note): void { const oldReaction = note.myReaction; if (!oldReaction) return; os.api('notes/reactions/delete', { - noteId: note.id + noteId: note.id, }); } @@ -245,7 +245,7 @@ function onContextmenu(ev: MouseEvent): void { function menu(viaKeyboard = false): void { os.popupMenu(getNoteMenu({ note: note, translating, translation, menuButton }), menuButton.value, { - viaKeyboard + viaKeyboard, }).then(focus); } @@ -257,12 +257,12 @@ function showRenoteMenu(viaKeyboard = false): void { danger: true, action: () => { os.api('notes/delete', { - noteId: note.id + noteId: note.id, }); isDeleted.value = true; - } + }, }], renoteTime.value, { - viaKeyboard: viaKeyboard + viaKeyboard: viaKeyboard, }); } @@ -284,7 +284,7 @@ function focusAfter() { function readPromo() { os.api('promo/read', { - noteId: appearNote.id + noteId: appearNote.id, }); isDeleted.value = true; } diff --git a/packages/client/src/components/notification-setting-window.vue b/packages/client/src/components/notification-setting-window.vue index ec1efec26..64d828394 100644 --- a/packages/client/src/components/notification-setting-window.vue +++ b/packages/client/src/components/notification-setting-window.vue @@ -1,5 +1,6 @@