From 7747ec5b6de17e8ce20e1cf59649e5e98aec9991 Mon Sep 17 00:00:00 2001
From: syuilo
Date: Sat, 23 Jan 2021 20:05:44 +0900
Subject: [PATCH 001/553] 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/553] 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/553] =?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/553] 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/553] 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 118f3546616ab71e37e02eaf2330ccb195b57f04 Mon Sep 17 00:00:00 2001
From: Johann150
Date: Wed, 1 Jun 2022 08:51:00 +0200
Subject: [PATCH 006/553] fix: server metrics widget
---
packages/client/src/widgets/server-metric/net.vue | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/packages/client/src/widgets/server-metric/net.vue b/packages/client/src/widgets/server-metric/net.vue
index 82b3a67d7..b698953f9 100644
--- a/packages/client/src/widgets/server-metric/net.vue
+++ b/packages/client/src/widgets/server-metric/net.vue
@@ -94,10 +94,10 @@ function onStats(connStats) {
inPolygonPoints = `${viewBoxX - (stats.length - 1)},${viewBoxY} ${inPolylinePoints} ${viewBoxX},${viewBoxY}`;
outPolygonPoints = `${viewBoxX - (stats.length - 1)},${viewBoxY} ${outPolylinePoints} ${viewBoxX},${viewBoxY}`;
- inHeadX = inPolylinePoints[inPolylinePoints.length - 1][0];
- inHeadY = inPolylinePoints[inPolylinePoints.length - 1][1];
- outHeadX = outPolylinePoints[outPolylinePoints.length - 1][0];
- outHeadY = outPolylinePoints[outPolylinePoints.length - 1][1];
+ inHeadX = inPolylinePointsStats[inPolylinePointsStats.length - 1][0];
+ inHeadY = inPolylinePointsStats[inPolylinePointsStats.length - 1][1];
+ outHeadX = outPolylinePointsStats[outPolylinePointsStats.length - 1][0];
+ outHeadY = outPolylinePointsStats[outPolylinePointsStats.length - 1][1];
inRecent = connStats.net.rx;
outRecent = connStats.net.tx;
From 0263a783a6ef7cb8ebab8aa5e745ba2ed48528a1 Mon Sep 17 00:00:00 2001
From: Johann150
Date: Wed, 1 Jun 2022 09:34:40 +0200
Subject: [PATCH 007/553] fix(dev): no labels for l10n_develop
---
.github/workflows/labeler.yml | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml
index 057208eda..fa4a58c3a 100644
--- a/.github/workflows/labeler.yml
+++ b/.github/workflows/labeler.yml
@@ -1,6 +1,8 @@
name: "Pull Request Labeler"
on:
-- pull_request_target
+ pull_request_target:
+ branches-ignore:
+ - 'l10n_develop'
jobs:
triage:
From df3bbfb4161ac53bdff8fbc5c78c4e1c8f5173f8 Mon Sep 17 00:00:00 2001
From: sn0w <92278018+realsn0w@users.noreply.github.com>
Date: Fri, 3 Jun 2022 14:22:03 +0200
Subject: [PATCH 008/553] fix(client): correctly handle MiAuth URLs with query
string (#8772)
---
packages/client/src/pages/miauth.vue | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/packages/client/src/pages/miauth.vue b/packages/client/src/pages/miauth.vue
index 6e85b784f..4032d7723 100644
--- a/packages/client/src/pages/miauth.vue
+++ b/packages/client/src/pages/miauth.vue
@@ -42,6 +42,7 @@ import MkSignin from '@/components/signin.vue';
import MkButton from '@/components/ui/button.vue';
import * as os from '@/os';
import { login } from '@/account';
+import { appendQuery, query } from '@/scripts/url';
export default defineComponent({
components: {
@@ -82,7 +83,9 @@ export default defineComponent({
this.state = 'accepted';
if (this.callback) {
- location.href = `${this.callback}?session=${this.session}`;
+ location.href = appendQuery(this.callback, query({
+ session: this.session
+ }));
}
},
deny() {
From a3fed7d0fbb551e7cf42b648a841f7d78f7d5659 Mon Sep 17 00:00:00 2001
From: syuilo
Date: Fri, 3 Jun 2022 23:08:15 +0900
Subject: [PATCH 009/553] fix(test): reset redis in e2e test
#7986
---
packages/backend/src/db/postgre.ts | 2 ++
1 file changed, 2 insertions(+)
diff --git a/packages/backend/src/db/postgre.ts b/packages/backend/src/db/postgre.ts
index e09e93f04..50a85d626 100644
--- a/packages/backend/src/db/postgre.ts
+++ b/packages/backend/src/db/postgre.ts
@@ -73,6 +73,7 @@ import { entities as charts } from '@/services/chart/entities.js';
import { Webhook } from '@/models/entities/webhook.js';
import { envOption } from '../env.js';
import { dbLogger } from './logger.js';
+import { redisClient } from './redis.js';
const sqlLogger = dbLogger.createSubLogger('sql', 'gray', false);
@@ -217,6 +218,7 @@ export async function initDb() {
export async function resetDb() {
const reset = async () => {
+ await redisClient.FLUSHDB();
const tables = await db.query(`SELECT relname AS "table"
FROM pg_class C LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
WHERE nspname NOT IN ('pg_catalog', 'information_schema')
From 6061937996ec90c4d59cab5d199760bc20ffae6e Mon Sep 17 00:00:00 2001
From: PikaDude
Date: Sat, 4 Jun 2022 00:14:50 +1000
Subject: [PATCH 010/553] User moderation details (#8762)
* add more user details for admins to see
* fix some issues
* small style fix
as suggested by Johann150
Co-authored-by: Johann150
* fix
Co-authored-by: Johann150
Co-authored-by: Johann150
---
.../server/api/endpoints/admin/show-user.ts | 42 ++++++++++++++++---
packages/client/src/pages/user-info.vue | 3 ++
2 files changed, 40 insertions(+), 5 deletions(-)
diff --git a/packages/backend/src/server/api/endpoints/admin/show-user.ts b/packages/backend/src/server/api/endpoints/admin/show-user.ts
index bf6cc1653..78033aed5 100644
--- a/packages/backend/src/server/api/endpoints/admin/show-user.ts
+++ b/packages/backend/src/server/api/endpoints/admin/show-user.ts
@@ -1,5 +1,5 @@
+import { Signins, UserProfiles, Users } from '@/models/index.js';
import define from '../../define.js';
-import { Users } from '@/models/index.js';
export const meta = {
tags: ['admin'],
@@ -23,9 +23,12 @@ export const paramDef = {
// eslint-disable-next-line import/no-default-export
export default define(meta, paramDef, async (ps, me) => {
- const user = await Users.findOneBy({ id: ps.userId });
+ const [user, profile] = await Promise.all([
+ Users.findOneBy({ id: ps.userId }),
+ UserProfiles.findOneBy({ userId: ps.userId })
+ ]);
- if (user == null) {
+ if (user == null || profile == null) {
throw new Error('user not found');
}
@@ -34,8 +37,37 @@ export default define(meta, paramDef, async (ps, me) => {
throw new Error('cannot show info of admin');
}
+ if (!_me.isAdmin) {
+ return {
+ isModerator: user.isModerator,
+ isSilenced: user.isSilenced,
+ isSuspended: user.isSuspended,
+ };
+ }
+
+ const maskedKeys = ['accessToken', 'accessTokenSecret', 'refreshToken'];
+ Object.keys(profile.integrations).forEach(integration => {
+ maskedKeys.forEach(key => profile.integrations[integration][key] = '');
+ });
+
+ const signins = await Signins.findBy({ userId: user.id });
+
return {
- ...user,
- token: user.token != null ? '' : user.token,
+ email: profile.email,
+ emailVerified: profile.emailVerified,
+ autoAcceptFollowed: profile.autoAcceptFollowed,
+ noCrawle: profile.noCrawle,
+ alwaysMarkNsfw: profile.alwaysMarkNsfw,
+ carefulBot: profile.carefulBot,
+ injectFeaturedNote: profile.injectFeaturedNote,
+ receiveAnnouncementEmail: profile.receiveAnnouncementEmail,
+ integrations: profile.integrations,
+ mutedWords: profile.mutedWords,
+ mutedInstances: profile.mutedInstances,
+ mutingNotificationTypes: profile.mutingNotificationTypes,
+ isModerator: user.isModerator,
+ isSilenced: user.isSilenced,
+ isSuspended: user.isSuspended,
+ signins,
};
});
diff --git a/packages/client/src/pages/user-info.vue b/packages/client/src/pages/user-info.vue
index 1b2682ed2..54e1f1302 100644
--- a/packages/client/src/pages/user-info.vue
+++ b/packages/client/src/pages/user-info.vue
@@ -54,6 +54,9 @@
{{ $ts.updateRemoteUser }}
+
+
+
From 81109b14b585b2ca6ba85ebedcb41f9b8cca5382 Mon Sep 17 00:00:00 2001
From: Johann150
Date: Fri, 3 Jun 2022 16:18:44 +0200
Subject: [PATCH 011/553] fix: correctly render empty note text (#8746)
Ensure that the _misskey_content attribute will always exist. Because
the API endpoint does not require the existence of the `text` field,
that field may be `undefined`. By using `?? null` it can be ensured
that the value is at least `null`.
Furthermore, the rendered HTML of a note with empty text will also be
the empty string. From git blame it seems that this behaviour was added
because of a Mastodon bug that might have previously existed. Hoever,
this seems to be no longer the case as I can find mastodon posts that
have empty content.
The code could be made a bit more succinct by using the null coercion
operator.
---
.../backend/src/remote/activitypub/misc/get-note-html.ts | 6 ++----
packages/backend/src/remote/activitypub/renderer/note.ts | 6 +++---
2 files changed, 5 insertions(+), 7 deletions(-)
diff --git a/packages/backend/src/remote/activitypub/misc/get-note-html.ts b/packages/backend/src/remote/activitypub/misc/get-note-html.ts
index 3800b4060..389039ebe 100644
--- a/packages/backend/src/remote/activitypub/misc/get-note-html.ts
+++ b/packages/backend/src/remote/activitypub/misc/get-note-html.ts
@@ -3,8 +3,6 @@ import { Note } from '@/models/entities/note.js';
import { toHtml } from '../../../mfm/to-html.js';
export default function(note: Note) {
- let html = note.text ? toHtml(mfm.parse(note.text), JSON.parse(note.mentionedRemoteUsers)) : null;
- if (html == null) html = '.
';
-
- return html;
+ if (!note.text) return '';
+ return toHtml(mfm.parse(note.text), JSON.parse(note.mentionedRemoteUsers));
}
diff --git a/packages/backend/src/remote/activitypub/renderer/note.ts b/packages/backend/src/remote/activitypub/renderer/note.ts
index e8d429e5d..b7df0e9a3 100644
--- a/packages/backend/src/remote/activitypub/renderer/note.ts
+++ b/packages/backend/src/remote/activitypub/renderer/note.ts
@@ -82,15 +82,15 @@ export default async function renderNote(note: Note, dive = true, isTalk = false
const files = await getPromisedFiles(note.fileIds);
- const text = note.text;
+ // text should never be undefined
+ const text = note.text ?? null;
let poll: Poll | null = null;
if (note.hasPoll) {
poll = await Polls.findOneBy({ noteId: note.id });
}
- let apText = text;
- if (apText == null) apText = '';
+ let apText = text ?? '';
if (quote) {
apText += `\n\nRE: ${quote}`;
From 9954c054a7e9fa8148345c7ff3d0bfaaee05fcb1 Mon Sep 17 00:00:00 2001
From: Johann150
Date: Sat, 4 Jun 2022 04:29:20 +0200
Subject: [PATCH 012/553] fix: ensure resolver does not fetch local resources
via HTTP(S) (#8733)
* refactor: parseUri types and checks
The type has been refined to better represent what it actually is. Uses of
parseUri are now also checking the parsed object type before resolving.
* cannot resolve URLs with fragments
* also take remaining part of URL into account
Needed for parsing the follows URIs.
* Resolver uses DbResolver for local
* remove unnecessary use of DbResolver
Using DbResolver would mean that the URL is parsed and handled again.
This duplicated processing can be avoided by querying the database directly.
* fix missing property name
---
.../src/remote/activitypub/db-resolver.ts | 101 +++++++++---------
.../src/remote/activitypub/resolver.ts | 64 ++++++++++-
2 files changed, 115 insertions(+), 50 deletions(-)
diff --git a/packages/backend/src/remote/activitypub/db-resolver.ts b/packages/backend/src/remote/activitypub/db-resolver.ts
index ef07966e4..a9ed1a4a8 100644
--- a/packages/backend/src/remote/activitypub/db-resolver.ts
+++ b/packages/backend/src/remote/activitypub/db-resolver.ts
@@ -13,6 +13,44 @@ import { uriPersonCache, userByIdCache } from '@/services/user-cache.js';
const publicKeyCache = new Cache(Infinity);
const publicKeyByUserIdCache = new Cache(Infinity);
+export type UriParseResult = {
+ /** wether the URI was generated by us */
+ local: true;
+ /** id in DB */
+ id: string;
+ /** hint of type, e.g. "notes", "users" */
+ type: string;
+ /** any remaining text after type and id, not including the slash after id. undefined if empty */
+ rest?: string;
+} | {
+ /** wether the URI was generated by us */
+ local: false;
+ /** uri in DB */
+ uri: string;
+};
+
+export function parseUri(url: string) : UriParseResult {
+ const uri = getApId(value);
+
+ // the host part of a URL is case insensitive, so use the 'i' flag.
+ const localRegex = new RegExp('^' + escapeRegexp(config.url) + '/(\\w+)/(\\w+)(?:\/(.+))?', 'i');
+ const matchLocal = uri.match(localRegex);
+
+ if (matchLocal) {
+ return {
+ local: true,
+ type: matchLocal[1],
+ id: matchLocal[2],
+ rest: matchLocal[3],
+ };
+ } else {
+ return {
+ local: false,
+ uri,
+ };
+ }
+}
+
export default class DbResolver {
constructor() {
}
@@ -21,60 +59,54 @@ export default class DbResolver {
* AP Note => Misskey Note in DB
*/
public async getNoteFromApId(value: string | IObject): Promise {
- const parsed = this.parseUri(value);
+ const parsed = parseUri(value);
+
+ if (parsed.local) {
+ if (parsed.type !== 'notes') return null;
- if (parsed.id) {
return await Notes.findOneBy({
id: parsed.id,
});
- }
-
- if (parsed.uri) {
+ } else {
return await Notes.findOneBy({
uri: parsed.uri,
});
}
-
- return null;
}
public async getMessageFromApId(value: string | IObject): Promise {
- const parsed = this.parseUri(value);
+ const parsed = parseUri(value);
+
+ if (parsed.local) {
+ if (parsed.type !== 'notes') return null;
- if (parsed.id) {
return await MessagingMessages.findOneBy({
id: parsed.id,
});
- }
-
- if (parsed.uri) {
+ } else {
return await MessagingMessages.findOneBy({
uri: parsed.uri,
});
}
-
- return null;
}
/**
* AP Person => Misskey User in DB
*/
public async getUserFromApId(value: string | IObject): Promise {
- const parsed = this.parseUri(value);
+ const parsed = parseUri(value);
+
+ if (parsed.local) {
+ if (parsed.type !== 'users') return null;
- if (parsed.id) {
return await userByIdCache.fetchMaybe(parsed.id, () => Users.findOneBy({
id: parsed.id,
}).then(x => x ?? undefined)) ?? null;
- }
-
- if (parsed.uri) {
+ } else {
return await uriPersonCache.fetch(parsed.uri, () => Users.findOneBy({
uri: parsed.uri,
}));
}
-
- return null;
}
/**
@@ -120,31 +152,4 @@ export default class DbResolver {
key,
};
}
-
- public parseUri(value: string | IObject): UriParseResult {
- const uri = getApId(value);
-
- const localRegex = new RegExp('^' + escapeRegexp(config.url) + '/' + '(\\w+)' + '/' + '(\\w+)');
- const matchLocal = uri.match(localRegex);
-
- if (matchLocal) {
- return {
- type: matchLocal[1],
- id: matchLocal[2],
- };
- } else {
- return {
- uri,
- };
- }
- }
}
-
-type UriParseResult = {
- /** id in DB (local object only) */
- id?: string;
- /** uri in DB (remote object only) */
- uri?: string;
- /** hint of type (local object only, ex: notes, users) */
- type?: string
-};
diff --git a/packages/backend/src/remote/activitypub/resolver.ts b/packages/backend/src/remote/activitypub/resolver.ts
index 334eae984..2f9af43c0 100644
--- a/packages/backend/src/remote/activitypub/resolver.ts
+++ b/packages/backend/src/remote/activitypub/resolver.ts
@@ -3,9 +3,18 @@ import { getJson } from '@/misc/fetch.js';
import { ILocalUser } from '@/models/entities/user.js';
import { getInstanceActor } from '@/services/instance-actor.js';
import { fetchMeta } from '@/misc/fetch-meta.js';
-import { extractDbHost } from '@/misc/convert-host.js';
+import { extractDbHost, isSelfHost } from '@/misc/convert-host.js';
import { signedGet } from './request.js';
import { IObject, isCollectionOrOrderedCollection, ICollection, IOrderedCollection } from './type.js';
+import { FollowRequests, Notes, NoteReactions, Polls, Users } from '@/models/index.js';
+import { parseUri } from './db-resolver.js';
+import renderNote from '@/remote/activitypub/renderer/note.js';
+import { renderLike } from '@/remote/activitypub/renderer/like.js';
+import { renderPerson } from '@/remote/activitypub/renderer/person.js';
+import renderQuestion from '@/remote/activitypub/renderer/question.js';
+import renderCreate from '@/remote/activitypub/renderer/create.js';
+import { renderActivity } from '@/remote/activitypub/renderer/index.js';
+import renderFollow from '@/remote/activitypub/renderer/follow.js';
export default class Resolver {
private history: Set;
@@ -40,14 +49,25 @@ export default class Resolver {
return value;
}
+ if (value.includes('#')) {
+ // URLs with fragment parts cannot be resolved correctly because
+ // the fragment part does not get transmitted over HTTP(S).
+ // Avoid strange behaviour by not trying to resolve these at all.
+ throw new Error(`cannot resolve URL with fragment: ${value}`);
+ }
+
if (this.history.has(value)) {
throw new Error('cannot resolve already resolved one');
}
this.history.add(value);
- const meta = await fetchMeta();
const host = extractDbHost(value);
+ if (isSelfHost(host)) {
+ return await this.resolveLocal(value);
+ }
+
+ const meta = await fetchMeta();
if (meta.blockedHosts.includes(host)) {
throw new Error('Instance is blocked');
}
@@ -70,4 +90,44 @@ export default class Resolver {
return object;
}
+
+ private resolveLocal(url: string): Promise {
+ const parsed = parseUri(url);
+ if (!parsed.local) throw new Error('resolveLocal: not local');
+
+ switch (parsed.type) {
+ case 'notes':
+ return Notes.findOneByOrFail({ id: parsed.id })
+ .then(note => {
+ if (parsed.rest === 'activity') {
+ // this refers to the create activity and not the note itself
+ return renderActivity(renderCreate(renderNote(note)));
+ } else {
+ return renderNote(note);
+ }
+ });
+ case 'users':
+ return Users.findOneByOrFail({ id: parsed.id })
+ .then(user => renderPerson(user as ILocalUser));
+ case 'questions':
+ // Polls are indexed by the note they are attached to.
+ return Promise.all([
+ Notes.findOneByOrFail({ id: parsed.id }),
+ Polls.findOneByOrFail({ noteId: parsed.id }),
+ ])
+ .then(([note, poll]) => renderQuestion({ id: note.userId }, note, poll));
+ case 'likes':
+ return NoteReactions.findOneByOrFail({ id: parsed.id }).then(reaction => renderActivity(renderLike(reaction, { uri: null })));
+ case 'follows':
+ // rest should be
+ if (parsed.rest == null || !/^\w+$/.test(parsed.rest)) throw new Error('resolveLocal: invalid follow URI');
+
+ return Promise.all(
+ [parsed.id, parsed.rest].map(id => Users.findOneByOrFail({ id }))
+ )
+ .then(([follower, followee]) => renderActivity(renderFollow(follower, followee, url)));
+ default:
+ throw new Error(`resolveLocal: type ${type} unhandled`);
+ }
+ }
}
From 32dff2846003bb079891593b660869511fca5f01 Mon Sep 17 00:00:00 2001
From: Johann150
Date: Sat, 4 Jun 2022 06:52:42 +0200
Subject: [PATCH 013/553] fix: add id for activitypub follows (#8689)
* add id for activitypub follows
* fix lint
* fix: follower must be local, followee must be remote
Misskey will only use ActivityPub follow requests for users that are local
and are requesting to follow a remote user. This check is to ensure that
this endpoint can not be used by other services or instances.
* fix: missing import
* render block with id
* fix comment
---
.../src/remote/activitypub/renderer/block.ts | 24 +++++++++++----
.../src/remote/activitypub/renderer/follow.ts | 3 +-
packages/backend/src/server/activitypub.ts | 29 ++++++++++++++++++-
.../backend/src/services/blocking/create.ts | 13 ++++++---
.../backend/src/services/blocking/delete.ts | 9 ++++--
5 files changed, 63 insertions(+), 15 deletions(-)
diff --git a/packages/backend/src/remote/activitypub/renderer/block.ts b/packages/backend/src/remote/activitypub/renderer/block.ts
index 10a4fde51..13815fb76 100644
--- a/packages/backend/src/remote/activitypub/renderer/block.ts
+++ b/packages/backend/src/remote/activitypub/renderer/block.ts
@@ -1,8 +1,20 @@
import config from '@/config/index.js';
-import { ILocalUser, IRemoteUser } from '@/models/entities/user.js';
+import { Blocking } from '@/models/entities/blocking.js';
-export default (blocker: ILocalUser, blockee: IRemoteUser) => ({
- type: 'Block',
- actor: `${config.url}/users/${blocker.id}`,
- object: blockee.uri,
-});
+/**
+ * Renders a block into its ActivityPub representation.
+ *
+ * @param block The block to be rendered. The blockee relation must be loaded.
+ */
+export function renderBlock(block: Blocking) {
+ if (block.blockee?.url == null) {
+ throw new Error('renderBlock: missing blockee uri');
+ }
+
+ return {
+ type: 'Block',
+ id: `${config.url}/blocks/${block.id}`,
+ actor: `${config.url}/users/${block.blockerId}`,
+ object: block.blockee.uri,
+ };
+}
diff --git a/packages/backend/src/remote/activitypub/renderer/follow.ts b/packages/backend/src/remote/activitypub/renderer/follow.ts
index 9e9692b77..00fac18ad 100644
--- a/packages/backend/src/remote/activitypub/renderer/follow.ts
+++ b/packages/backend/src/remote/activitypub/renderer/follow.ts
@@ -4,12 +4,11 @@ import { Users } from '@/models/index.js';
export default (follower: { id: User['id']; host: User['host']; uri: User['host'] }, followee: { id: User['id']; host: User['host']; uri: User['host'] }, requestId?: string) => {
const follow = {
+ id: requestId ?? `${config.url}/follows/${follower.id}/${followee.id}`,
type: 'Follow',
actor: Users.isLocalUser(follower) ? `${config.url}/users/${follower.id}` : follower.uri,
object: Users.isLocalUser(followee) ? `${config.url}/users/${followee.id}` : followee.uri,
} as any;
- if (requestId) follow.id = requestId;
-
return follow;
};
diff --git a/packages/backend/src/server/activitypub.ts b/packages/backend/src/server/activitypub.ts
index a48c2d412..cd5f917c4 100644
--- a/packages/backend/src/server/activitypub.ts
+++ b/packages/backend/src/server/activitypub.ts
@@ -15,9 +15,10 @@ import { inbox as processInbox } from '@/queue/index.js';
import { isSelfHost } from '@/misc/convert-host.js';
import { Notes, Users, Emojis, NoteReactions } from '@/models/index.js';
import { ILocalUser, User } from '@/models/entities/user.js';
-import { In, IsNull } from 'typeorm';
+import { In, IsNull, Not } from 'typeorm';
import { renderLike } from '@/remote/activitypub/renderer/like.js';
import { getUserKeypair } from '@/misc/keypair-store.js';
+import renderFollow from '@/remote/activitypub/renderer/follow.js';
// Init router
const router = new Router();
@@ -224,4 +225,30 @@ router.get('/likes/:like', async ctx => {
setResponseType(ctx);
});
+// follow
+router.get('/follows/:follower/:followee', async ctx => {
+ // This may be used before the follow is completed, so we do not
+ // check if the following exists.
+
+ const [follower, followee] = await Promise.all([
+ Users.findOneBy({
+ id: ctx.params.follower,
+ host: IsNull(),
+ }),
+ Users.findOneBy({
+ id: ctx.params.followee,
+ host: Not(IsNull()),
+ }),
+ ]);
+
+ if (follower == null || followee == null) {
+ ctx.status = 404;
+ return;
+ }
+
+ ctx.body = renderActivity(renderFollow(follower, followee));
+ ctx.set('Cache-Control', 'public, max-age=180');
+ setResponseType(ctx);
+});
+
export default router;
diff --git a/packages/backend/src/services/blocking/create.ts b/packages/backend/src/services/blocking/create.ts
index b2be78b22..a2c61cca2 100644
--- a/packages/backend/src/services/blocking/create.ts
+++ b/packages/backend/src/services/blocking/create.ts
@@ -2,9 +2,10 @@ import { publishMainStream, publishUserEvent } from '@/services/stream.js';
import { renderActivity } from '@/remote/activitypub/renderer/index.js';
import renderFollow from '@/remote/activitypub/renderer/follow.js';
import renderUndo from '@/remote/activitypub/renderer/undo.js';
-import renderBlock from '@/remote/activitypub/renderer/block.js';
+import { renderBlock } from '@/remote/activitypub/renderer/block.js';
import { deliver } from '@/queue/index.js';
import renderReject from '@/remote/activitypub/renderer/reject.js';
+import { Blocking } from '@/models/entities/blocking.js';
import { User } from '@/models/entities/user.js';
import { Blockings, Users, FollowRequests, Followings, UserListJoinings, UserLists } from '@/models/index.js';
import { perUserFollowingChart } from '@/services/chart/index.js';
@@ -22,15 +23,19 @@ export default async function(blocker: User, blockee: User) {
removeFromList(blockee, blocker),
]);
- await Blockings.insert({
+ const blocking = {
id: genId(),
createdAt: new Date(),
+ blocker,
blockerId: blocker.id,
+ blockee,
blockeeId: blockee.id,
- });
+ } as Blocking;
+
+ await Blockings.insert(blocking);
if (Users.isLocalUser(blocker) && Users.isRemoteUser(blockee)) {
- const content = renderActivity(renderBlock(blocker, blockee));
+ const content = renderActivity(renderBlock(blocking));
deliver(blocker, content, blockee.inbox);
}
}
diff --git a/packages/backend/src/services/blocking/delete.ts b/packages/backend/src/services/blocking/delete.ts
index d7b5ddd5f..cb16651bc 100644
--- a/packages/backend/src/services/blocking/delete.ts
+++ b/packages/backend/src/services/blocking/delete.ts
@@ -1,5 +1,5 @@
import { renderActivity } from '@/remote/activitypub/renderer/index.js';
-import renderBlock from '@/remote/activitypub/renderer/block.js';
+import { renderBlock } from '@/remote/activitypub/renderer/block.js';
import renderUndo from '@/remote/activitypub/renderer/undo.js';
import { deliver } from '@/queue/index.js';
import Logger from '../logger.js';
@@ -19,11 +19,16 @@ export default async function(blocker: CacheableUser, blockee: CacheableUser) {
return;
}
+ // Since we already have the blocker and blockee, we do not need to fetch
+ // them in the query above and can just manually insert them here.
+ blocking.blocker = blocker;
+ blocking.blockee = blockee;
+
Blockings.delete(blocking.id);
// deliver if remote bloking
if (Users.isLocalUser(blocker) && Users.isRemoteUser(blockee)) {
- const content = renderActivity(renderUndo(renderBlock(blocker, blockee), blocker));
+ const content = renderActivity(renderUndo(renderBlock(blocking), blocker));
deliver(blocker, content, blockee.inbox);
}
}
From e675ffcf38b07f5c70d00b49c171c7ab3460e810 Mon Sep 17 00:00:00 2001
From: Balazs Nadasdi
Date: Sat, 4 Jun 2022 06:57:09 +0200
Subject: [PATCH 014/553] feat: option to collapse long notes (#8561)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* feat: option to collapse long notes
Closes #8559
* do not collapse if cw exists
* use '閉じる' to close / show less.
* make it sticky
* Change style of the Show less button
---
locales/ja-JP.yml | 1 +
packages/client/src/components/note.vue | 27 ++++++++++++++++++++++---
2 files changed, 25 insertions(+), 3 deletions(-)
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 9cd1d1eed..57be9bfcb 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -52,6 +52,7 @@ searchUser: "ユーザーを検索"
reply: "返信"
loadMore: "もっと見る"
showMore: "もっと見る"
+showLess: "閉じる"
youGotNewFollower: "フォローされました"
receiveFollowRequest: "フォローリクエストされました"
followRequestAccepted: "フォローが承認されました"
diff --git a/packages/client/src/components/note.vue b/packages/client/src/components/note.vue
index bc8a0dd19..4840b0dc2 100644
--- a/packages/client/src/components/note.vue
+++ b/packages/client/src/components/note.vue
@@ -46,7 +46,7 @@
-
+
({{ i18n.ts.private }})
@@ -66,9 +66,12 @@
-
{{ appearNote.channel.name }}
@@ -166,7 +169,8 @@ const reactButton = ref
();
let appearNote = $computed(() => isRenote ? note.renote as misskey.entities.Note : note);
const isMyRenote = $i && ($i.id === note.userId);
const showContent = ref(false);
-const collapsed = ref(appearNote.cw == null && appearNote.text != null && (
+const collapsed = ref(appearNote.cw == null);
+const isLong = ref(appearNote.cw == null && appearNote.text != null && (
(appearNote.text.split('\n').length > 9) ||
(appearNote.text.length > 500)
));
@@ -452,6 +456,23 @@ function readPromo() {
}
> .content {
+ &.isLong {
+ > .showLess {
+ width: 100%;
+ margin-top: 1em;
+ position: sticky;
+ bottom: 1em;
+
+ > span {
+ display: inline-block;
+ background: var(--panel);
+ padding: 6px 10px;
+ font-size: 0.8em;
+ border-radius: 999px;
+ box-shadow: 0 0 7px 7px var(--bg);
+ }
+ }
+ }
&.collapsed {
position: relative;
max-height: 9em;
From 702edfd3d3424a666091dd29dd5b4a9beaa822db Mon Sep 17 00:00:00 2001
From: syuilo
Date: Sat, 4 Jun 2022 14:25:30 +0900
Subject: [PATCH 015/553] fix test
---
packages/backend/test/activitypub.ts | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/packages/backend/test/activitypub.ts b/packages/backend/test/activitypub.ts
index 5d8b28ec7..f4ae27e5e 100644
--- a/packages/backend/test/activitypub.ts
+++ b/packages/backend/test/activitypub.ts
@@ -2,11 +2,13 @@ process.env.NODE_ENV = 'test';
import * as assert from 'assert';
import rndstr from 'rndstr';
+import { initDb } from '../src/db/postgre.js';
import { initTestDb } from './utils.js';
describe('ActivityPub', () => {
before(async () => {
- await initTestDb();
+ //await initTestDb();
+ await initDb();
});
describe('Parse minimum object', () => {
From 11afdf7e24549b66c000f4e1e598d82d92bc9f7e Mon Sep 17 00:00:00 2001
From: syuilo
Date: Sat, 4 Jun 2022 15:15:44 +0900
Subject: [PATCH 016/553] fix bug
---
packages/backend/src/remote/activitypub/db-resolver.ts | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/packages/backend/src/remote/activitypub/db-resolver.ts b/packages/backend/src/remote/activitypub/db-resolver.ts
index a9ed1a4a8..1a02f675c 100644
--- a/packages/backend/src/remote/activitypub/db-resolver.ts
+++ b/packages/backend/src/remote/activitypub/db-resolver.ts
@@ -5,10 +5,10 @@ import { User, IRemoteUser, CacheableRemoteUser, CacheableUser } from '@/models/
import { UserPublickey } from '@/models/entities/user-publickey.js';
import { MessagingMessage } from '@/models/entities/messaging-message.js';
import { Notes, Users, UserPublickeys, MessagingMessages } from '@/models/index.js';
-import { IObject, getApId } from './type.js';
-import { resolvePerson } from './models/person.js';
import { Cache } from '@/misc/cache.js';
import { uriPersonCache, userByIdCache } from '@/services/user-cache.js';
+import { IObject, getApId } from './type.js';
+import { resolvePerson } from './models/person.js';
const publicKeyCache = new Cache(Infinity);
const publicKeyByUserIdCache = new Cache(Infinity);
@@ -29,7 +29,7 @@ export type UriParseResult = {
uri: string;
};
-export function parseUri(url: string) : UriParseResult {
+export function parseUri(value: string | IObject): UriParseResult {
const uri = getApId(value);
// the host part of a URL is case insensitive, so use the 'i' flag.
From 71150f21cd91df7bdd78a8f708db092418e85baa Mon Sep 17 00:00:00 2001
From: syuilo
Date: Sat, 4 Jun 2022 15:23:53 +0900
Subject: [PATCH 017/553] Revert "feat: option to collapse long notes (#8561)"
This reverts commit e675ffcf38b07f5c70d00b49c171c7ab3460e810.
---
locales/ja-JP.yml | 1 -
packages/client/src/components/note.vue | 27 +++----------------------
2 files changed, 3 insertions(+), 25 deletions(-)
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 57be9bfcb..9cd1d1eed 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -52,7 +52,6 @@ searchUser: "ユーザーを検索"
reply: "返信"
loadMore: "もっと見る"
showMore: "もっと見る"
-showLess: "閉じる"
youGotNewFollower: "フォローされました"
receiveFollowRequest: "フォローリクエストされました"
followRequestAccepted: "フォローが承認されました"
diff --git a/packages/client/src/components/note.vue b/packages/client/src/components/note.vue
index 4840b0dc2..bc8a0dd19 100644
--- a/packages/client/src/components/note.vue
+++ b/packages/client/src/components/note.vue
@@ -46,7 +46,7 @@
-
+
({{ i18n.ts.private }})
@@ -66,12 +66,9 @@
-
+
{{ i18n.ts.showMore }}
-
- {{ i18n.ts.showLess }}
-
{{ appearNote.channel.name }}
@@ -169,8 +166,7 @@ const reactButton = ref
();
let appearNote = $computed(() => isRenote ? note.renote as misskey.entities.Note : note);
const isMyRenote = $i && ($i.id === note.userId);
const showContent = ref(false);
-const collapsed = ref(appearNote.cw == null);
-const isLong = ref(appearNote.cw == null && appearNote.text != null && (
+const collapsed = ref(appearNote.cw == null && appearNote.text != null && (
(appearNote.text.split('\n').length > 9) ||
(appearNote.text.length > 500)
));
@@ -456,23 +452,6 @@ function readPromo() {
}
> .content {
- &.isLong {
- > .showLess {
- width: 100%;
- margin-top: 1em;
- position: sticky;
- bottom: 1em;
-
- > span {
- display: inline-block;
- background: var(--panel);
- padding: 6px 10px;
- font-size: 0.8em;
- border-radius: 999px;
- box-shadow: 0 0 7px 7px var(--bg);
- }
- }
- }
&.collapsed {
position: relative;
max-height: 9em;
From bb3c6785c93084da5f56372ff6e5235877210620 Mon Sep 17 00:00:00 2001
From: syuilo
Date: Sat, 4 Jun 2022 15:47:10 +0900
Subject: [PATCH 018/553] Update CHANGELOG.md
---
CHANGELOG.md | 44 +++++++++++++++++++++++++++++---------------
1 file changed, 29 insertions(+), 15 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 968759501..299cbd091 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,14 +14,17 @@ You should also include the user name that made the change.
- From this version, Node 18.0.0 or later is required.
### Improvements
-- enhance: ドライブに画像ファイルをアップロードするときオリジナル画像を破棄してwebpublicのみ保持するオプション @tamaina
-- enhance: API: notifications/readは配列でも受け付けるように #7667 @tamaina
-- enhance: プッシュ通知を複数アカウント対応に #7667 @tamaina
-- enhance: プッシュ通知にクリックやactionを設定 #7667 @tamaina
-- replaced webpack with Vite @tamaina
-- update dependencies @syuilo
-- enhance: display URL of QR code for TOTP registration @syuilo
-- enhance: Supports Unicode Emoji 14.0 @mei23
+- Supports Unicode Emoji 14.0 @mei23
+- プッシュ通知を複数アカウント対応に #7667 @tamaina
+- プッシュ通知にクリックやactionを設定 #7667 @tamaina
+- ドライブに画像ファイルをアップロードするときオリジナル画像を破棄してwebpublicのみ保持するオプション @tamaina
+- Server: always remove completed tasks of job queue @Johann150
+- Server: アンテナ、クリップ、リストの表示を速くする @xianonn
+- Client: make emoji stand out more on reaction button @Johann150
+- Client: display URL of QR code for TOTP registration @tamaina
+- API: notifications/readは配列でも受け付けるように #7667 @tamaina
+- API: ユーザー検索で、クエリがusernameの条件を満たす場合はusernameもLIKE検索するように @tamaina
+- MFM: Allow speed changes in all animated MFMs @Johann150
- The theme color is now better validated. @Johann150
Your own theme color may be unset if it was in an invalid format.
Admins should check their instance settings if in doubt.
@@ -30,20 +33,31 @@ You should also include the user name that made the change.
Admins should make sure the reverse proxy sets the `X-Forwarded-For` header to the original address.
### Bugfixes
-- Client: fix settings page @tamaina
-- Client: fix profile tabs @futchitwo
+- Server: keep file order of note attachement @Johann150
+- Server: fix caching @Johann150
- Server: await promises when following or unfollowing users @Johann150
-- Client: fix abuse reports page to be able to show all reports @Johann150
-- Federation: Add rel attribute to host-meta @mei23
-- Client: fix profile picture height in mentions @tamaina
-- MFM: more animated functions support `speed` parameter @futchitwo
-- Federation: Fix quote renotes containing no text being federated correctly @Johann150
- Server: fix missing foreign key for reports leading to reports page being unusable @Johann150
- Server: fix internal in-memory caching @Johann150
- Server: use correct order of attachments on notes @Johann150
- Server: prevent crash when processing certain PNGs @syuilo
- Server: Fix unable to generate video thumbnails @mei23
- Server: Fix `Cannot find module` issue @mei23
+- Federation: Add rel attribute to host-meta @mei23
+- Federation: add id for activitypub follows @Johann150
+- Federation: ensure resolver does not fetch local resources via HTTP(S) @Johann150
+- Federation: correctly render empty note text @Johann150
+- Federation: Fix quote renotes containing no text being federated correctly @Johann150
+- Federation: remove duplicate br tag/newline @Johann150
+- Federation: add missing authorization checks @Johann150
+- Client: fix profile picture height in mentions @tamaina
+- Client: fix abuse reports page to be able to show all reports @Johann150
+- Client: fix settings page @tamaina
+- Client: fix profile tabs @futchitwo
+- Client: fix popout URL @futchitwo
+- Client: correctly handle MiAuth URLs with query string @sn0w
+- Client: ノート詳細ページの新しいノートを表示する機能の動作が正しくなるように修正する @xianonn
+- MFM: more animated functions support `speed` parameter @futchitwo
+- MFM: limit large MFM @Johann150
## 12.110.1 (2022/04/23)
From 0946d5091329815f49da3973f6925adad137777b Mon Sep 17 00:00:00 2001
From: syuilo
Date: Sat, 4 Jun 2022 16:01:11 +0900
Subject: [PATCH 019/553] Update CONTRIBUTING.md
---
CONTRIBUTING.md | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 135a3e140..adbdb1cab 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -71,13 +71,15 @@ For now, basically only @syuilo has the authority to merge PRs into develop beca
However, minor fixes, refactoring, and urgent changes may be merged at the discretion of a contributor.
## Release
-For now, basically only @syuilo has the authority to release Misskey.
-However, in case of emergency, a release can be made at the discretion of a contributor.
-
### Release Instructions
-1. commit version changes in the `develop` branch ([package.json](https://github.com/misskey-dev/misskey/blob/develop/package.json))
-2. follow the `master` branch to the `develop` branch.
-3. Create a [release of GitHub](https://github.com/misskey-dev/misskey/releases)
+1. Commit version changes in the `develop` branch ([package.json](https://github.com/misskey-dev/misskey/blob/develop/package.json))
+2. Create a release PR.
+ - Into `master` from `develop` branch.
+ - The title must be in the format `Release: x.y.z`.
+ - `x.y.z` is the new version you are trying to release.
+ - Assign about 2~3 reviewers.
+3. The release PR is approved, merge it.
+4. Create a [release of GitHub](https://github.com/misskey-dev/misskey/releases)
- The target branch must be `master`
- The tag name must be the version
From b62a050b2ccbb886ee75aac4bf9f6cb0af5c46be Mon Sep 17 00:00:00 2001
From: syuilo
Date: Sat, 4 Jun 2022 16:01:27 +0900
Subject: [PATCH 020/553] Update CONTRIBUTING.md
---
CONTRIBUTING.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index adbdb1cab..f70e2df00 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -80,8 +80,8 @@ However, minor fixes, refactoring, and urgent changes may be merged at the discr
- Assign about 2~3 reviewers.
3. The release PR is approved, merge it.
4. Create a [release of GitHub](https://github.com/misskey-dev/misskey/releases)
- - The target branch must be `master`
- - The tag name must be the version
+ - The target branch must be `master`
+ - The tag name must be the version
## Localization (l10n)
Misskey uses [Crowdin](https://crowdin.com/project/misskey) for localization management.
From 7aae9987d5043f037a099c7b0e67c1152767ebfb Mon Sep 17 00:00:00 2001
From: syuilo
Date: Sat, 4 Jun 2022 16:04:59 +0900
Subject: [PATCH 021/553] Update CHANGELOG.md
---
CHANGELOG.md | 1 -
1 file changed, 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 299cbd091..05158278d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,7 +19,6 @@ You should also include the user name that made the change.
- プッシュ通知にクリックやactionを設定 #7667 @tamaina
- ドライブに画像ファイルをアップロードするときオリジナル画像を破棄してwebpublicのみ保持するオプション @tamaina
- Server: always remove completed tasks of job queue @Johann150
-- Server: アンテナ、クリップ、リストの表示を速くする @xianonn
- Client: make emoji stand out more on reaction button @Johann150
- Client: display URL of QR code for TOTP registration @tamaina
- API: notifications/readは配列でも受け付けるように #7667 @tamaina
From abcd5bc9515b47a579d1cc88003108418febb33b Mon Sep 17 00:00:00 2001
From: syuilo
Date: Sat, 4 Jun 2022 17:24:41 +0900
Subject: [PATCH 022/553] update summaly
---
packages/backend/package.json | 2 +-
packages/backend/yarn.lock | 9 +++++----
2 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/packages/backend/package.json b/packages/backend/package.json
index 4e0d60b74..32e4cf201 100644
--- a/packages/backend/package.json
+++ b/packages/backend/package.json
@@ -101,7 +101,7 @@
"strict-event-emitter-types": "2.0.0",
"stringz": "2.1.0",
"style-loader": "3.3.1",
- "summaly": "2.5.0",
+ "summaly": "2.5.1",
"syslog-pro": "1.0.0",
"systeminformation": "5.11.15",
"tinycolor2": "1.4.2",
diff --git a/packages/backend/yarn.lock b/packages/backend/yarn.lock
index d131f70e3..303843c34 100644
--- a/packages/backend/yarn.lock
+++ b/packages/backend/yarn.lock
@@ -6520,16 +6520,17 @@ style-loader@3.3.1:
resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.3.1.tgz#057dfa6b3d4d7c7064462830f9113ed417d38575"
integrity sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ==
-summaly@2.5.0:
- version "2.5.0"
- resolved "https://registry.yarnpkg.com/summaly/-/summaly-2.5.0.tgz#ec5af6e84857efcb6c844d896e83569e64a923ea"
- integrity sha512-IzvO2s7yj/PUyH42qWjVjSPpIiPlgTRWGh33t4cIZKOqPQJ2INo7e83hXhHFr4hXTb3JRcIdCuM1ELjlrujiUQ==
+summaly@2.5.1:
+ version "2.5.1"
+ resolved "https://registry.yarnpkg.com/summaly/-/summaly-2.5.1.tgz#742fe6631987f84ad2e95d2b0f7902ec57e0f6b3"
+ integrity sha512-WWvl7rLs3wm61Xc2JqgTbSuqtIOmGqKte+rkbnxe6ISy4089lQ+7F2ajooQNee6PWHl9kZ27SDd1ZMoL3/6R4A==
dependencies:
cheerio "0.22.0"
debug "4.3.3"
escape-regexp "0.0.1"
got "11.5.1"
html-entities "2.3.2"
+ iconv-lite "0.6.3"
jschardet "3.0.0"
koa "2.13.4"
private-ip "2.3.3"
From 89419c05b27d5419af75b3759bf62e2c4c3a29c3 Mon Sep 17 00:00:00 2001
From: syuilo
Date: Sat, 4 Jun 2022 17:26:56 +0900
Subject: [PATCH 023/553] use node 16
---
.node-version | 2 +-
CHANGELOG.md | 3 ---
packages/backend/src/models/repositories/drive-file.ts | 4 +++-
packages/backend/src/server/web/manifest.ts | 4 +++-
packages/backend/src/services/relay.ts | 8 +++++---
5 files changed, 12 insertions(+), 9 deletions(-)
diff --git a/.node-version b/.node-version
index 658984787..c9b6b29e0 100644
--- a/.node-version
+++ b/.node-version
@@ -1 +1 @@
-v18.0.0
+v16.0.0
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 05158278d..c58714fd2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,9 +10,6 @@ You should also include the user name that made the change.
-->
## 12.x.x (unreleased)
-### NOTE
-- From this version, Node 18.0.0 or later is required.
-
### Improvements
- Supports Unicode Emoji 14.0 @mei23
- プッシュ通知を複数アカウント対応に #7667 @tamaina
diff --git a/packages/backend/src/models/repositories/drive-file.ts b/packages/backend/src/models/repositories/drive-file.ts
index b626359d9..0d589d4f1 100644
--- a/packages/backend/src/models/repositories/drive-file.ts
+++ b/packages/backend/src/models/repositories/drive-file.ts
@@ -29,7 +29,9 @@ export const DriveFileRepository = db.getRepository(DriveFile).extend({
getPublicProperties(file: DriveFile): DriveFile['properties'] {
if (file.properties.orientation != null) {
- const properties = structuredClone(file.properties);
+ // TODO
+ //const properties = structuredClone(file.properties);
+ const properties = JSON.parse(JSON.stringify(file.properties));
if (file.properties.orientation >= 5) {
[properties.width, properties.height] = [properties.height, properties.width];
}
diff --git a/packages/backend/src/server/web/manifest.ts b/packages/backend/src/server/web/manifest.ts
index 61d766006..ee568b807 100644
--- a/packages/backend/src/server/web/manifest.ts
+++ b/packages/backend/src/server/web/manifest.ts
@@ -3,7 +3,9 @@ import { fetchMeta } from '@/misc/fetch-meta.js';
import manifest from './manifest.json' assert { type: 'json' };
export const manifestHandler = async (ctx: Koa.Context) => {
- const res = structuredClone(manifest);
+ // TODO
+ //const res = structuredClone(manifest);
+ const res = JSON.parse(JSON.stringify(manifest));
const instance = await fetchMeta(true);
diff --git a/packages/backend/src/services/relay.ts b/packages/backend/src/services/relay.ts
index 08bf72cc2..6bc430443 100644
--- a/packages/backend/src/services/relay.ts
+++ b/packages/backend/src/services/relay.ts
@@ -1,4 +1,4 @@
-import { createSystemUser } from './create-system-user.js';
+import { IsNull } from 'typeorm';
import { renderFollowRelay } from '@/remote/activitypub/renderer/follow-relay.js';
import { renderActivity, attachLdSignature } from '@/remote/activitypub/renderer/index.js';
import renderUndo from '@/remote/activitypub/renderer/undo.js';
@@ -8,7 +8,7 @@ import { Users, Relays } from '@/models/index.js';
import { genId } from '@/misc/gen-id.js';
import { Cache } from '@/misc/cache.js';
import { Relay } from '@/models/entities/relay.js';
-import { IsNull } from 'typeorm';
+import { createSystemUser } from './create-system-user.js';
const ACTOR_USERNAME = 'relay.actor' as const;
@@ -88,7 +88,9 @@ export async function deliverToRelays(user: { id: User['id']; host: null; }, act
}));
if (relays.length === 0) return;
- const copy = structuredClone(activity);
+ // TODO
+ //const copy = structuredClone(activity);
+ const copy = JSON.parse(JSON.stringify(activity));
if (!copy.to) copy.to = ['https://www.w3.org/ns/activitystreams#Public'];
const signed = await attachLdSignature(copy, user);
From adf3190859191775d7056f000a3508aac9712dfa Mon Sep 17 00:00:00 2001
From: syuilo
Date: Sun, 5 Jun 2022 12:23:57 +0900
Subject: [PATCH 024/553] chore(client): fix menu item style
---
packages/client/src/components/ui/menu.vue | 21 +++++++++++----------
1 file changed, 11 insertions(+), 10 deletions(-)
diff --git a/packages/client/src/components/ui/menu.vue b/packages/client/src/components/ui/menu.vue
index ca5604826..dad5dfa8b 100644
--- a/packages/client/src/components/ui/menu.vue
+++ b/packages/client/src/components/ui/menu.vue
@@ -1,5 +1,6 @@
-
Date: Sun, 5 Jun 2022 12:26:36 +0900
Subject: [PATCH 025/553] chore: lint fixes
---
.../client/src/components/modal-page-window.vue | 16 ++++++++--------
packages/client/src/components/note-detailed.vue | 16 ++++++++--------
packages/client/src/components/note.vue | 14 +++++++-------
.../components/notification-setting-window.vue | 15 ++++++++-------
packages/client/src/components/notification.vue | 9 +++++----
packages/client/src/components/notifications.vue | 7 +++----
packages/client/src/components/number-diff.vue | 4 ++--
7 files changed, 41 insertions(+), 40 deletions(-)
diff --git a/packages/client/src/components/modal-page-window.vue b/packages/client/src/components/modal-page-window.vue
index 2e17d5d03..21bdb657b 100644
--- a/packages/client/src/components/modal-page-window.vue
+++ b/packages/client/src/components/modal-page-window.vue
@@ -39,8 +39,8 @@ export default defineComponent({
inject: {
sideViewHook: {
- default: null
- }
+ default: null,
+ },
},
provide() {
@@ -94,31 +94,31 @@ export default defineComponent({
}, {
icon: 'fas fa-expand-alt',
text: this.$ts.showInPage,
- action: this.expand
+ action: this.expand,
}, this.sideViewHook ? {
icon: 'fas fa-columns',
text: this.$ts.openInSideView,
action: () => {
this.sideViewHook(this.path);
this.$refs.window.close();
- }
+ },
} : undefined, {
icon: 'fas fa-external-link-alt',
text: this.$ts.popout,
- action: this.popout
+ action: this.popout,
}, null, {
icon: 'fas fa-external-link-alt',
text: this.$ts.openInNewTab,
action: () => {
window.open(this.url, '_blank');
this.$refs.window.close();
- }
+ },
}, {
icon: 'fas fa-link',
text: this.$ts.copyLink,
action: () => {
copyToClipboard(this.url);
- }
+ },
}];
},
},
@@ -155,7 +155,7 @@ export default defineComponent({
onContextmenu(ev: MouseEvent) {
os.contextMenu(this.contextmenu, ev);
- }
+ },
},
});
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 @@
-
import { defineComponent, PropType } from 'vue';
-import XModalWindow from '@/components/ui/modal-window.vue';
+import { notificationTypes } from 'misskey-js';
import MkSwitch from './form/switch.vue';
import MkInfo from './ui/info.vue';
import MkButton from './ui/button.vue';
-import { notificationTypes } from 'misskey-js';
+import XModalWindow from '@/components/ui/modal-window.vue';
export default defineComponent({
components: {
XModalWindow,
MkSwitch,
MkInfo,
- MkButton
+ MkButton,
},
props: {
@@ -53,7 +54,7 @@ export default defineComponent({
type: Boolean,
required: false,
default: true,
- }
+ },
},
emits: ['done', 'closed'],
@@ -93,7 +94,7 @@ export default defineComponent({
for (const type in this.typesMap) {
this.typesMap[type as typeof notificationTypes[number]] = true;
}
- }
- }
+ },
+ },
});
diff --git a/packages/client/src/components/notification.vue b/packages/client/src/components/notification.vue
index 3791c576e..cbfd809f3 100644
--- a/packages/client/src/components/notification.vue
+++ b/packages/client/src/components/notification.vue
@@ -16,7 +16,8 @@
-
import { defineComponent, ref, onMounted, onUnmounted, watch } from 'vue';
import * as misskey from 'misskey-js';
-import { getNoteSummary } from '@/scripts/get-note-summary';
import XReactionIcon from './reaction-icon.vue';
import MkFollowButton from './follow-button.vue';
import XReactionTooltip from './reaction-tooltip.vue';
+import { getNoteSummary } from '@/scripts/get-note-summary';
import { notePage } from '@/filters/note';
import { userPage } from '@/filters/user';
import { i18n } from '@/i18n';
@@ -87,7 +88,7 @@ import { useTooltip } from '@/scripts/use-tooltip';
export default defineComponent({
components: {
- XReactionIcon, MkFollowButton
+ XReactionIcon, MkFollowButton,
},
props: {
@@ -116,7 +117,7 @@ export default defineComponent({
const readObserver = new IntersectionObserver((entries, observer) => {
if (!entries.some(entry => entry.isIntersecting)) return;
stream.send('readNotification', {
- id: props.notification.id
+ id: props.notification.id,
});
observer.disconnect();
});
diff --git a/packages/client/src/components/notifications.vue b/packages/client/src/components/notifications.vue
index dc900a670..8eb569c36 100644
--- a/packages/client/src/components/notifications.vue
+++ b/packages/client/src/components/notifications.vue
@@ -19,8 +19,7 @@
From 09b749eb97cfec32b06e0a31f51064f32584ebc8 Mon Sep 17 00:00:00 2001
From: syuilo
Date: Sun, 5 Jun 2022 19:46:52 +0900
Subject: [PATCH 026/553] Update .mocharc.json
---
packages/backend/.mocharc.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/backend/.mocharc.json b/packages/backend/.mocharc.json
index 589522216..87c571cfd 100644
--- a/packages/backend/.mocharc.json
+++ b/packages/backend/.mocharc.json
@@ -5,6 +5,6 @@
"loader=./test/loader.js"
],
"slow": 1000,
- "timeout": 3000,
+ "timeout": 10000,
"exit": true
}
From d17298d3b5b5fb7377ad34fe7c2b8613bbf478de Mon Sep 17 00:00:00 2001
From: syuilo
Date: Sun, 5 Jun 2022 20:37:24 +0900
Subject: [PATCH 027/553] fix(test): make chart tests working
---
packages/backend/src/db/postgre.ts | 10 +-
.../backend/src/services/chart/entities.ts | 12 +++
packages/backend/test/chart.ts | 96 +++++++++----------
3 files changed, 65 insertions(+), 53 deletions(-)
diff --git a/packages/backend/src/db/postgre.ts b/packages/backend/src/db/postgre.ts
index 50a85d626..298f6713e 100644
--- a/packages/backend/src/db/postgre.ts
+++ b/packages/backend/src/db/postgre.ts
@@ -208,7 +208,15 @@ export const db = new DataSource({
migrations: ['../../migration/*.js'],
});
-export async function initDb() {
+export async function initDb(force = false) {
+ if (force) {
+ if (db.isInitialized) {
+ await db.destroy();
+ }
+ await db.initialize();
+ return;
+ }
+
if (db.isInitialized) {
// nop
} else {
diff --git a/packages/backend/src/services/chart/entities.ts b/packages/backend/src/services/chart/entities.ts
index 13e994cb6..a9eeabd63 100644
--- a/packages/backend/src/services/chart/entities.ts
+++ b/packages/backend/src/services/chart/entities.ts
@@ -11,6 +11,11 @@ import { entity as PerUserFollowingChart } from './charts/entities/per-user-foll
import { entity as PerUserDriveChart } from './charts/entities/per-user-drive.js';
import { entity as ApRequestChart } from './charts/entities/ap-request.js';
+import { entity as TestChart } from './charts/entities/test.js';
+import { entity as TestGroupedChart } from './charts/entities/test-grouped.js';
+import { entity as TestUniqueChart } from './charts/entities/test-unique.js';
+import { entity as TestIntersectionChart } from './charts/entities/test-intersection.js';
+
export const entities = [
FederationChart.hour, FederationChart.day,
NotesChart.hour, NotesChart.day,
@@ -24,4 +29,11 @@ export const entities = [
PerUserFollowingChart.hour, PerUserFollowingChart.day,
PerUserDriveChart.hour, PerUserDriveChart.day,
ApRequestChart.hour, ApRequestChart.day,
+
+ ...(process.env.NODE_ENV === 'test' ? [
+ TestChart.hour, TestChart.day,
+ TestGroupedChart.hour, TestGroupedChart.day,
+ TestUniqueChart.hour, TestUniqueChart.day,
+ TestIntersectionChart.hour, TestIntersectionChart.day,
+ ] : []),
];
diff --git a/packages/backend/test/chart.ts b/packages/backend/test/chart.ts
index 823e388a8..ac0844679 100644
--- a/packages/backend/test/chart.ts
+++ b/packages/backend/test/chart.ts
@@ -6,26 +6,17 @@ import TestChart from '../src/services/chart/charts/test.js';
import TestGroupedChart from '../src/services/chart/charts/test-grouped.js';
import TestUniqueChart from '../src/services/chart/charts/test-unique.js';
import TestIntersectionChart from '../src/services/chart/charts/test-intersection.js';
-import * as _TestChart from '../src/services/chart/charts/entities/test.js';
-import * as _TestGroupedChart from '../src/services/chart/charts/entities/test-grouped.js';
-import * as _TestUniqueChart from '../src/services/chart/charts/entities/test-unique.js';
-import * as _TestIntersectionChart from '../src/services/chart/charts/entities/test-intersection.js';
-import { async, initTestDb } from './utils.js';
+import { initDb } from '../src/db/postgre.js';
describe('Chart', () => {
let testChart: TestChart;
let testGroupedChart: TestGroupedChart;
let testUniqueChart: TestUniqueChart;
let testIntersectionChart: TestIntersectionChart;
- let clock: lolex.Clock;
+ let clock: lolex.InstalledClock;
- beforeEach(async(async () => {
- await initTestDb(false, [
- _TestChart.entity.hour, _TestChart.entity.day,
- _TestGroupedChart.entity.hour, _TestGroupedChart.entity.day,
- _TestUniqueChart.entity.hour, _TestUniqueChart.entity.day,
- _TestIntersectionChart.entity.hour, _TestIntersectionChart.entity.day,
- ]);
+ beforeEach(async () => {
+ await initDb(true);
testChart = new TestChart();
testGroupedChart = new TestGroupedChart();
@@ -34,14 +25,15 @@ describe('Chart', () => {
clock = lolex.install({
now: new Date(Date.UTC(2000, 0, 1, 0, 0, 0)),
+ shouldClearNativeTimers: true,
});
- }));
+ });
- afterEach(async(async () => {
+ afterEach(() => {
clock.uninstall();
- }));
+ });
- it('Can updates', async(async () => {
+ it('Can updates', async () => {
await testChart.increment();
await testChart.save();
@@ -63,9 +55,9 @@ describe('Chart', () => {
total: [1, 0, 0],
},
});
- }));
+ });
- it('Can updates (dec)', async(async () => {
+ it('Can updates (dec)', async () => {
await testChart.decrement();
await testChart.save();
@@ -87,9 +79,9 @@ describe('Chart', () => {
total: [-1, 0, 0],
},
});
- }));
+ });
- it('Empty chart', async(async () => {
+ it('Empty chart', async () => {
const chartHours = await testChart.getChart('hour', 3, null);
const chartDays = await testChart.getChart('day', 3, null);
@@ -108,9 +100,9 @@ describe('Chart', () => {
total: [0, 0, 0],
},
});
- }));
+ });
- it('Can updates at multiple times at same time', async(async () => {
+ it('Can updates at multiple times at same time', async () => {
await testChart.increment();
await testChart.increment();
await testChart.increment();
@@ -134,9 +126,9 @@ describe('Chart', () => {
total: [3, 0, 0],
},
});
- }));
+ });
- it('複数回saveされてもデータの更新は一度だけ', async(async () => {
+ it('複数回saveされてもデータの更新は一度だけ', async () => {
await testChart.increment();
await testChart.save();
await testChart.save();
@@ -160,9 +152,9 @@ describe('Chart', () => {
total: [1, 0, 0],
},
});
- }));
+ });
- it('Can updates at different times', async(async () => {
+ it('Can updates at different times', async () => {
await testChart.increment();
await testChart.save();
@@ -189,11 +181,11 @@ describe('Chart', () => {
total: [2, 0, 0],
},
});
- }));
+ });
// 仕様上はこうなってほしいけど、実装は難しそうなのでskip
/*
- it('Can updates at different times without save', async(async () => {
+ it('Can updates at different times without save', async () => {
await testChart.increment();
clock.tick('01:00:00');
@@ -219,10 +211,10 @@ describe('Chart', () => {
total: [2, 0, 0]
},
});
- }));
+ });
*/
- it('Can padding', async(async () => {
+ it('Can padding', async () => {
await testChart.increment();
await testChart.save();
@@ -249,10 +241,10 @@ describe('Chart', () => {
total: [2, 0, 0],
},
});
- }));
+ });
// 要求された範囲にログがひとつもない場合でもパディングできる
- it('Can padding from past range', async(async () => {
+ it('Can padding from past range', async () => {
await testChart.increment();
await testChart.save();
@@ -276,11 +268,11 @@ describe('Chart', () => {
total: [1, 0, 0],
},
});
- }));
+ });
// 要求された範囲の最も古い箇所に位置するログが存在しない場合でもパディングできる
// Issue #3190
- it('Can padding from past range 2', async(async () => {
+ it('Can padding from past range 2', async () => {
await testChart.increment();
await testChart.save();
@@ -307,9 +299,9 @@ describe('Chart', () => {
total: [2, 0, 0],
},
});
- }));
+ });
- it('Can specify offset', async(async () => {
+ it('Can specify offset', async () => {
await testChart.increment();
await testChart.save();
@@ -336,9 +328,9 @@ describe('Chart', () => {
total: [2, 0, 0],
},
});
- }));
+ });
- it('Can specify offset (floor time)', async(async () => {
+ it('Can specify offset (floor time)', async () => {
clock.tick('00:30:00');
await testChart.increment();
@@ -367,10 +359,10 @@ describe('Chart', () => {
total: [2, 0, 0],
},
});
- }));
+ });
describe('Grouped', () => {
- it('Can updates', async(async () => {
+ it('Can updates', async () => {
await testGroupedChart.increment('alice');
await testGroupedChart.save();
@@ -410,11 +402,11 @@ describe('Chart', () => {
total: [0, 0, 0],
},
});
- }));
+ });
});
describe('Unique increment', () => {
- it('Can updates', async(async () => {
+ it('Can updates', async () => {
await testUniqueChart.uniqueIncrement('alice');
await testUniqueChart.uniqueIncrement('alice');
await testUniqueChart.uniqueIncrement('bob');
@@ -430,10 +422,10 @@ describe('Chart', () => {
assert.deepStrictEqual(chartDays, {
foo: [2, 0, 0],
});
- }));
+ });
describe('Intersection', () => {
- it('条件が満たされていない場合はカウントされない', async(async () => {
+ it('条件が満たされていない場合はカウントされない', async () => {
await testIntersectionChart.addA('alice');
await testIntersectionChart.addA('bob');
await testIntersectionChart.addB('carol');
@@ -453,9 +445,9 @@ describe('Chart', () => {
b: [1, 0, 0],
aAndB: [0, 0, 0],
});
- }));
+ });
- it('条件が満たされている場合にカウントされる', async(async () => {
+ it('条件が満たされている場合にカウントされる', async () => {
await testIntersectionChart.addA('alice');
await testIntersectionChart.addA('bob');
await testIntersectionChart.addB('carol');
@@ -476,12 +468,12 @@ describe('Chart', () => {
b: [2, 0, 0],
aAndB: [1, 0, 0],
});
- }));
+ });
});
});
describe('Resync', () => {
- it('Can resync', async(async () => {
+ it('Can resync', async () => {
testChart.total = 1;
await testChart.resync();
@@ -504,9 +496,9 @@ describe('Chart', () => {
total: [1, 0, 0],
},
});
- }));
+ });
- it('Can resync (2)', async(async () => {
+ it('Can resync (2)', async () => {
await testChart.increment();
await testChart.save();
@@ -534,6 +526,6 @@ describe('Chart', () => {
total: [100, 0, 0],
},
});
- }));
+ });
});
});
From aea2f01ef7909885cf20df9bc2d27bb77863b35b Mon Sep 17 00:00:00 2001
From: syuilo
Date: Mon, 6 Jun 2022 21:01:00 +0900
Subject: [PATCH 028/553] Update .node-version
---
.node-version | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.node-version b/.node-version
index c9b6b29e0..7fd023741 100644
--- a/.node-version
+++ b/.node-version
@@ -1 +1 @@
-v16.0.0
+v16.15.0
From 0fa2a52facaeab21ea51e4fbb8d441a3f68f0239 Mon Sep 17 00:00:00 2001
From: Johann150
Date: Wed, 8 Jun 2022 10:59:48 +0200
Subject: [PATCH 029/553] refactor: use awaitAll to reduce duplication (#8791)
* refactor: use awaitAll to reduce duplication
* fix lint
* fix typo
---
.../src/server/api/endpoints/users/stats.ts | 86 ++++++-------------
1 file changed, 25 insertions(+), 61 deletions(-)
diff --git a/packages/backend/src/server/api/endpoints/users/stats.ts b/packages/backend/src/server/api/endpoints/users/stats.ts
index d138019a7..59283e4f2 100644
--- a/packages/backend/src/server/api/endpoints/users/stats.ts
+++ b/packages/backend/src/server/api/endpoints/users/stats.ts
@@ -1,6 +1,7 @@
import define from '../../define.js';
import { ApiError } from '../../error.js';
import { DriveFiles, Followings, NoteFavorites, NoteReactions, Notes, PageLikes, PollVotes, Users } from '@/models/index.js';
+import { awaitAll } from '@/prelude/await-all.js';
export const meta = {
tags: ['users'],
@@ -31,109 +32,72 @@ export default define(meta, paramDef, async (ps, me) => {
throw new ApiError(meta.errors.noSuchUser);
}
- const [
- notesCount,
- repliesCount,
- renotesCount,
- repliedCount,
- renotedCount,
- pollVotesCount,
- pollVotedCount,
- localFollowingCount,
- remoteFollowingCount,
- localFollowersCount,
- remoteFollowersCount,
- sentReactionsCount,
- receivedReactionsCount,
- noteFavoritesCount,
- pageLikesCount,
- pageLikedCount,
- driveFilesCount,
- driveUsage,
- ] = await Promise.all([
- Notes.createQueryBuilder('note')
+ const result = await awaitAll({
+ notesCount: Notes.createQueryBuilder('note')
.where('note.userId = :userId', { userId: user.id })
.getCount(),
- Notes.createQueryBuilder('note')
+ repliesCount: Notes.createQueryBuilder('note')
.where('note.userId = :userId', { userId: user.id })
.andWhere('note.replyId IS NOT NULL')
.getCount(),
- Notes.createQueryBuilder('note')
+ renotesCount: Notes.createQueryBuilder('note')
.where('note.userId = :userId', { userId: user.id })
.andWhere('note.renoteId IS NOT NULL')
.getCount(),
- Notes.createQueryBuilder('note')
+ repliedCount: Notes.createQueryBuilder('note')
.where('note.replyUserId = :userId', { userId: user.id })
.getCount(),
- Notes.createQueryBuilder('note')
+ renotedCount: Notes.createQueryBuilder('note')
.where('note.renoteUserId = :userId', { userId: user.id })
.getCount(),
- PollVotes.createQueryBuilder('vote')
+ pollVotesCount: PollVotes.createQueryBuilder('vote')
.where('vote.userId = :userId', { userId: user.id })
.getCount(),
- PollVotes.createQueryBuilder('vote')
+ pollVotedCount: PollVotes.createQueryBuilder('vote')
.innerJoin('vote.note', 'note')
.where('note.userId = :userId', { userId: user.id })
.getCount(),
- Followings.createQueryBuilder('following')
+ localFollowingCount: Followings.createQueryBuilder('following')
.where('following.followerId = :userId', { userId: user.id })
.andWhere('following.followeeHost IS NULL')
.getCount(),
- Followings.createQueryBuilder('following')
+ remoteFollowingCount: Followings.createQueryBuilder('following')
.where('following.followerId = :userId', { userId: user.id })
.andWhere('following.followeeHost IS NOT NULL')
.getCount(),
- Followings.createQueryBuilder('following')
+ localFollowersCount: Followings.createQueryBuilder('following')
.where('following.followeeId = :userId', { userId: user.id })
.andWhere('following.followerHost IS NULL')
.getCount(),
- Followings.createQueryBuilder('following')
+ remoteFollowersCount: Followings.createQueryBuilder('following')
.where('following.followeeId = :userId', { userId: user.id })
.andWhere('following.followerHost IS NOT NULL')
.getCount(),
- NoteReactions.createQueryBuilder('reaction')
+ sentReactionsCount: NoteReactions.createQueryBuilder('reaction')
.where('reaction.userId = :userId', { userId: user.id })
.getCount(),
- NoteReactions.createQueryBuilder('reaction')
+ receivedReactionsCount: NoteReactions.createQueryBuilder('reaction')
.innerJoin('reaction.note', 'note')
.where('note.userId = :userId', { userId: user.id })
.getCount(),
- NoteFavorites.createQueryBuilder('favorite')
+ noteFavoritesCount: NoteFavorites.createQueryBuilder('favorite')
.where('favorite.userId = :userId', { userId: user.id })
.getCount(),
- PageLikes.createQueryBuilder('like')
+ pageLikesCount: PageLikes.createQueryBuilder('like')
.where('like.userId = :userId', { userId: user.id })
.getCount(),
- PageLikes.createQueryBuilder('like')
+ pageLikedCount: PageLikes.createQueryBuilder('like')
.innerJoin('like.page', 'page')
.where('page.userId = :userId', { userId: user.id })
.getCount(),
- DriveFiles.createQueryBuilder('file')
+ driveFilesCount: DriveFiles.createQueryBuilder('file')
.where('file.userId = :userId', { userId: user.id })
.getCount(),
- DriveFiles.calcDriveUsageOf(user),
- ]);
+ driveUsage: DriveFiles.calcDriveUsageOf(user),
+ });
- return {
- notesCount,
- repliesCount,
- renotesCount,
- repliedCount,
- renotedCount,
- pollVotesCount,
- pollVotedCount,
- localFollowingCount,
- remoteFollowingCount,
- localFollowersCount,
- remoteFollowersCount,
- followingCount: localFollowingCount + remoteFollowingCount,
- followersCount: localFollowersCount + remoteFollowersCount,
- sentReactionsCount,
- receivedReactionsCount,
- noteFavoritesCount,
- pageLikesCount,
- pageLikedCount,
- driveFilesCount,
- driveUsage,
- };
+ result.followingCount = result.localFollowingCount + result.remoteFollowingCount;
+ result.followersCount = result.localFollowersCount + result.remoteFollowersCount;
+
+ return result;
});
From 4800dd06e5576e29c28c683ce20b001b78f12da4 Mon Sep 17 00:00:00 2001
From: Johann150
Date: Wed, 8 Jun 2022 13:20:37 +0200
Subject: [PATCH 030/553] fix: try to prevent autocomplete for emoji search
(#8798)
---
packages/client/src/components/emoji-picker.vue | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/client/src/components/emoji-picker.vue b/packages/client/src/components/emoji-picker.vue
index 522f63647..64732e703 100644
--- a/packages/client/src/components/emoji-picker.vue
+++ b/packages/client/src/components/emoji-picker.vue
@@ -1,6 +1,6 @@
-
+
From 3dba63afbbff8278bb53147e0900b9c324feba01 Mon Sep 17 00:00:00 2001
From: syuilo
Date: Wed, 8 Jun 2022 22:23:43 +0900
Subject: [PATCH 031/553] Update CONTRIBUTING.md
---
CONTRIBUTING.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index f70e2df00..3c17e6120 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -77,9 +77,9 @@ However, minor fixes, refactoring, and urgent changes may be merged at the discr
- Into `master` from `develop` branch.
- The title must be in the format `Release: x.y.z`.
- `x.y.z` is the new version you are trying to release.
- - Assign about 2~3 reviewers.
-3. The release PR is approved, merge it.
-4. Create a [release of GitHub](https://github.com/misskey-dev/misskey/releases)
+3. ~~Deploy and perform a simple QA check. Also verify that the tests passed.~~ (TODO)
+4. Merge it.
+5. Create a [release of GitHub](https://github.com/misskey-dev/misskey/releases)
- The target branch must be `master`
- The tag name must be the version
From 327c62337e3bc63616153bbe5512ff235be9fc7e Mon Sep 17 00:00:00 2001
From: Takuya Yoshida
Date: Thu, 9 Jun 2022 00:50:23 +0900
Subject: [PATCH 032/553] ok-to-test with okteto (#8799)
---
.github/workflows/ok-to-test.yml | 36 ++++++++++++
.github/workflows/pr-preview-deploy.yml | 70 +++++++++++++++++++++++
.github/workflows/pr-preview-destroy.yml | 21 +++++++
okteto.yml => .okteto/okteto-pipeline.yml | 0
4 files changed, 127 insertions(+)
create mode 100644 .github/workflows/ok-to-test.yml
create mode 100644 .github/workflows/pr-preview-deploy.yml
create mode 100644 .github/workflows/pr-preview-destroy.yml
rename okteto.yml => .okteto/okteto-pipeline.yml (100%)
diff --git a/.github/workflows/ok-to-test.yml b/.github/workflows/ok-to-test.yml
new file mode 100644
index 000000000..63ae05cbd
--- /dev/null
+++ b/.github/workflows/ok-to-test.yml
@@ -0,0 +1,36 @@
+# If someone with write access comments "/ok-to-test" on a pull request, emit a repository_dispatch event
+name: Ok To Test
+
+on:
+ issue_comment:
+ types: [created]
+
+jobs:
+ ok-to-test:
+ runs-on: ubuntu-latest
+ # Only run for PRs, not issue comments
+ if: ${{ github.event.issue.pull_request }}
+ steps:
+ # Generate a GitHub App installation access token from an App ID and private key
+ # To create a new GitHub App:
+ # https://developer.github.com/apps/building-github-apps/creating-a-github-app/
+ # See app.yml for an example app manifest
+ - name: Generate token
+ id: generate_token
+ uses: tibdex/github-app-token@v1
+ with:
+ app_id: ${{ secrets.APP_ID }}
+ private_key: ${{ secrets.PRIVATE_KEY }}
+
+ - name: Slash Command Dispatch
+ uses: peter-evans/slash-command-dispatch@v1
+ env:
+ TOKEN: ${{ steps.generate_token.outputs.token }}
+ with:
+ token: ${{ env.TOKEN }} # GitHub App installation access token
+ # token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} # PAT or OAuth token will also work
+ reaction-token: ${{ secrets.GITHUB_TOKEN }}
+ issue-type: pull-request
+ commands: ok-to-test
+ named-args: true
+ permission: write
diff --git a/.github/workflows/pr-preview-deploy.yml b/.github/workflows/pr-preview-deploy.yml
new file mode 100644
index 000000000..589006576
--- /dev/null
+++ b/.github/workflows/pr-preview-deploy.yml
@@ -0,0 +1,70 @@
+# Run secret-dependent integration tests only after /ok-to-test approval
+on:
+ repository_dispatch:
+ types: [ok-to-test-command]
+
+name: Deploy preview environment
+
+jobs:
+ # Repo owner has commented /ok-to-test on a (fork-based) pull request
+ deploy-preview-environment:
+ runs-on: ubuntu-latest
+ if:
+ github.event_name == 'repository_dispatch' &&
+ github.event.client_payload.slash_command.sha != '' &&
+ contains(github.event.client_payload.pull_request.head.sha, github.event.client_payload.slash_command.sha)
+ steps:
+
+ # Check out merge commit
+ - name: Fork based /ok-to-test checkout
+ uses: actions/checkout@v2
+ with:
+ ref: 'refs/pull/${{ github.event.client_payload.pull_request.number }}/merge'
+
+ #
+ - name: Context
+ uses: okteto/context@latest
+ with:
+ token: ${{ secrets.OKTETO_TOKEN }}
+
+ - name: Deploy preview environment
+ uses: ikuradon/deploy-preview@latest
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ name: pr-${{ github.event.client_payload.pull_request.number }}-misskey-dev
+ timeout: 15m
+
+ # Update check run called "integration-fork"
+ - uses: actions/github-script@v5
+ id: update-check-run
+ if: ${{ always() }}
+ env:
+ number: ${{ github.event.client_payload.pull_request.number }}
+ job: ${{ github.job }}
+ # Conveniently, job.status maps to https://developer.github.com/v3/checks/runs/#update-a-check-run
+ conclusion: ${{ job.status }}
+ with:
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ script: |
+ const { data: pull } = await github.rest.pulls.get({
+ ...context.repo,
+ pull_number: process.env.number
+ });
+ const ref = pull.head.sha;
+
+ const { data: checks } = await github.rest.checks.listForRef({
+ ...context.repo,
+ ref
+ });
+
+ const check = checks.check_runs.filter(c => c.name === process.env.job);
+
+ const { data: result } = await github.rest.checks.update({
+ ...context.repo,
+ check_run_id: check[0].id,
+ status: 'completed',
+ conclusion: process.env.conclusion
+ });
+
+ return result;
diff --git a/.github/workflows/pr-preview-destroy.yml b/.github/workflows/pr-preview-destroy.yml
new file mode 100644
index 000000000..fa872715d
--- /dev/null
+++ b/.github/workflows/pr-preview-destroy.yml
@@ -0,0 +1,21 @@
+# file: .github/workflows/preview-closed.yaml
+on:
+ pull_request:
+ types:
+ - closed
+
+name: Destroy preview environment
+
+jobs:
+ destroy-preview-environment:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Context
+ uses: okteto/context@latest
+ with:
+ token: ${{ secrets.OKTETO_TOKEN }}
+
+ - name: Destroy preview environment
+ uses: okteto/destroy-preview@latest
+ with:
+ name: pr-${{ github.event.number }}-misskey-dev
diff --git a/okteto.yml b/.okteto/okteto-pipeline.yml
similarity index 100%
rename from okteto.yml
rename to .okteto/okteto-pipeline.yml
From 2d6de2299c74b872c5c36b0e34b936c865689260 Mon Sep 17 00:00:00 2001
From: syuilo
Date: Thu, 9 Jun 2022 01:35:57 +0900
Subject: [PATCH 033/553] chore(dev): update okteto workflow
---
.github/workflows/ok-to-test.yml | 6 +++---
.github/workflows/pr-preview-deploy.yml | 2 +-
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/.github/workflows/ok-to-test.yml b/.github/workflows/ok-to-test.yml
index 63ae05cbd..87af3a6ba 100644
--- a/.github/workflows/ok-to-test.yml
+++ b/.github/workflows/ok-to-test.yml
@@ -19,8 +19,8 @@ jobs:
id: generate_token
uses: tibdex/github-app-token@v1
with:
- app_id: ${{ secrets.APP_ID }}
- private_key: ${{ secrets.PRIVATE_KEY }}
+ app_id: ${{ secrets.DEPLOYBOT_APP_ID }}
+ private_key: ${{ secrets.DEPLOYBOT_PRIVATE_KEY }}
- name: Slash Command Dispatch
uses: peter-evans/slash-command-dispatch@v1
@@ -31,6 +31,6 @@ jobs:
# token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} # PAT or OAuth token will also work
reaction-token: ${{ secrets.GITHUB_TOKEN }}
issue-type: pull-request
- commands: ok-to-test
+ commands: deploy
named-args: true
permission: write
diff --git a/.github/workflows/pr-preview-deploy.yml b/.github/workflows/pr-preview-deploy.yml
index 589006576..53f670652 100644
--- a/.github/workflows/pr-preview-deploy.yml
+++ b/.github/workflows/pr-preview-deploy.yml
@@ -30,7 +30,7 @@ jobs:
- name: Deploy preview environment
uses: ikuradon/deploy-preview@latest
env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
name: pr-${{ github.event.client_payload.pull_request.number }}-misskey-dev
timeout: 15m
From d8eb610aaba10174b6e1d6204e775b6032086bd8 Mon Sep 17 00:00:00 2001
From: syuilo
Date: Thu, 9 Jun 2022 01:43:35 +0900
Subject: [PATCH 034/553] Update pr-preview-deploy.yml
---
.github/workflows/pr-preview-deploy.yml | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/.github/workflows/pr-preview-deploy.yml b/.github/workflows/pr-preview-deploy.yml
index 53f670652..126665850 100644
--- a/.github/workflows/pr-preview-deploy.yml
+++ b/.github/workflows/pr-preview-deploy.yml
@@ -1,12 +1,12 @@
-# Run secret-dependent integration tests only after /ok-to-test approval
+# Run secret-dependent integration tests only after /deploy approval
on:
repository_dispatch:
- types: [ok-to-test-command]
+ types: [deploy-command]
name: Deploy preview environment
jobs:
- # Repo owner has commented /ok-to-test on a (fork-based) pull request
+ # Repo owner has commented /deploy on a (fork-based) pull request
deploy-preview-environment:
runs-on: ubuntu-latest
if:
@@ -16,7 +16,7 @@ jobs:
steps:
# Check out merge commit
- - name: Fork based /ok-to-test checkout
+ - name: Fork based /deploy checkout
uses: actions/checkout@v2
with:
ref: 'refs/pull/${{ github.event.client_payload.pull_request.number }}/merge'
From 79de4d77f6a403b0ca6b32d82bb213a7f627416f Mon Sep 17 00:00:00 2001
From: syuilo
Date: Thu, 9 Jun 2022 01:48:00 +0900
Subject: [PATCH 035/553] chore(dev): update okteto workflow
---
.github/workflows/pr-preview-deploy.yml | 2 +-
.github/workflows/pr-preview-destroy.yml | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/pr-preview-deploy.yml b/.github/workflows/pr-preview-deploy.yml
index 126665850..1b399264d 100644
--- a/.github/workflows/pr-preview-deploy.yml
+++ b/.github/workflows/pr-preview-deploy.yml
@@ -32,7 +32,7 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
- name: pr-${{ github.event.client_payload.pull_request.number }}-misskey-dev
+ name: pr-${{ github.event.client_payload.pull_request.number }}-syuilo
timeout: 15m
# Update check run called "integration-fork"
diff --git a/.github/workflows/pr-preview-destroy.yml b/.github/workflows/pr-preview-destroy.yml
index fa872715d..c14c3db5c 100644
--- a/.github/workflows/pr-preview-destroy.yml
+++ b/.github/workflows/pr-preview-destroy.yml
@@ -18,4 +18,4 @@ jobs:
- name: Destroy preview environment
uses: okteto/destroy-preview@latest
with:
- name: pr-${{ github.event.number }}-misskey-dev
+ name: pr-${{ github.event.number }}-syuilo
From 065aa0f9b6f9a12c67dd2c0cfe338a78575b244b Mon Sep 17 00:00:00 2001
From: tamaina
Date: Thu, 9 Jun 2022 05:49:00 +0900
Subject: [PATCH 036/553] Display the deploy status on checks (#8803)
* Display deploy status on check suite
* Display deploy status on check suite
* fix
* fix
---
.github/workflows/pr-preview-deploy.yml | 57 ++++++++++++++++++-------
1 file changed, 41 insertions(+), 16 deletions(-)
diff --git a/.github/workflows/pr-preview-deploy.yml b/.github/workflows/pr-preview-deploy.yml
index 1b399264d..fd43bce9e 100644
--- a/.github/workflows/pr-preview-deploy.yml
+++ b/.github/workflows/pr-preview-deploy.yml
@@ -1,5 +1,7 @@
# Run secret-dependent integration tests only after /deploy approval
on:
+ pull_request:
+ types: [opened, reopened, synchronize]
repository_dispatch:
types: [deploy-command]
@@ -14,6 +16,43 @@ jobs:
github.event.client_payload.slash_command.sha != '' &&
contains(github.event.client_payload.pull_request.head.sha, github.event.client_payload.slash_command.sha)
steps:
+ - uses: actions/github-script@v5
+ id: check-id
+ env:
+ number: ${{ github.event.client_payload.pull_request.number }}
+ job: ${{ github.job }}
+ with:
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ result-encoding: string
+ script: |
+ const { data: pull } = await github.rest.pulls.get({
+ ...context.repo,
+ pull_number: process.env.number
+ });
+ const ref = pull.head.sha;
+
+ const { data: checks } = await github.rest.checks.listForRef({
+ ...context.repo,
+ ref
+ });
+
+ const check = checks.check_runs.filter(c => c.name === process.env.job);
+
+ return check[0].id;
+
+ - uses: actions/github-script@v5
+ env:
+ check_id: ${{ steps.check-id.outputs.result }}
+ details_url: ${{ github.server_url }}/${{ github.repository }}/runs/${{ github.run_id }}
+ with:
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ script: |
+ await github.rest.checks.update({
+ ...context.repo,
+ check_run_id: process.env.check_id,
+ status: 'in_progress',
+ details_url: process.env.details_url
+ });
# Check out merge commit
- name: Fork based /deploy checkout
@@ -40,29 +79,15 @@ jobs:
id: update-check-run
if: ${{ always() }}
env:
- number: ${{ github.event.client_payload.pull_request.number }}
- job: ${{ github.job }}
# Conveniently, job.status maps to https://developer.github.com/v3/checks/runs/#update-a-check-run
conclusion: ${{ job.status }}
+ check_id: ${{ steps.check-id.outputs.result }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
- const { data: pull } = await github.rest.pulls.get({
- ...context.repo,
- pull_number: process.env.number
- });
- const ref = pull.head.sha;
-
- const { data: checks } = await github.rest.checks.listForRef({
- ...context.repo,
- ref
- });
-
- const check = checks.check_runs.filter(c => c.name === process.env.job);
-
const { data: result } = await github.rest.checks.update({
...context.repo,
- check_run_id: check[0].id,
+ check_run_id: process.env.check_id,
status: 'completed',
conclusion: process.env.conclusion
});
From c6e0430aa7e05bf302af0c558aaeb26a6635a76b Mon Sep 17 00:00:00 2001
From: syuilo
Date: Thu, 9 Jun 2022 05:55:58 +0900
Subject: [PATCH 037/553] Update CONTRIBUTING.md
---
CONTRIBUTING.md | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 3c17e6120..a37df3bde 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -66,6 +66,13 @@ Be willing to comment on the good points and not just the things you want fixed
- Are there any omissions or gaps?
- Does it check for anomalies?
+## Deploy
+The `/deploy` command by issue comment can be used to deploy the contents of a PR to the preview environment.
+```
+/deploy sha=
+```
+An actual domain will be assigned so you can test the federation.
+
## Merge
For now, basically only @syuilo has the authority to merge PRs into develop because he is most familiar with the codebase.
However, minor fixes, refactoring, and urgent changes may be merged at the discretion of a contributor.
@@ -77,7 +84,7 @@ However, minor fixes, refactoring, and urgent changes may be merged at the discr
- Into `master` from `develop` branch.
- The title must be in the format `Release: x.y.z`.
- `x.y.z` is the new version you are trying to release.
-3. ~~Deploy and perform a simple QA check. Also verify that the tests passed.~~ (TODO)
+3. Deploy and perform a simple QA check. Also verify that the tests passed.
4. Merge it.
5. Create a [release of GitHub](https://github.com/misskey-dev/misskey/releases)
- The target branch must be `master`
From eec7a0a1f6d31c2d669fcdb29596ab69d70d3635 Mon Sep 17 00:00:00 2001
From: Johann150
Date: Thu, 9 Jun 2022 16:35:58 +0200
Subject: [PATCH 038/553] properly display alt text for videos (#8802)
The alt text is already properly federated and given by the API,
it is just not displayed properly by the client.
---
packages/client/src/components/media-video.vue | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/packages/client/src/components/media-video.vue b/packages/client/src/components/media-video.vue
index 680eb27e6..5c38691e6 100644
--- a/packages/client/src/components/media-video.vue
+++ b/packages/client/src/components/media-video.vue
@@ -8,7 +8,8 @@