From ecaa6a1ae0446657ac473fde55cd2234d217c337 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 17 Oct 2021 01:33:15 +0900 Subject: [PATCH 01/46] =?UTF-8?q?feat:=20=E3=83=A6=E3=83=BC=E3=82=B6?= =?UTF-8?q?=E3=83=BC=E3=81=AE=E3=83=AA=E3=82=A2=E3=82=AF=E3=82=B7=E3=83=A7?= =?UTF-8?q?=E3=83=B3=E4=B8=80=E8=A6=A7=E3=82=92=E8=A6=8B=E3=82=8C=E3=82=8B?= =?UTF-8?q?=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 9 ++- src/client/pages/user/index.vue | 7 ++ src/client/pages/user/reactions.vue | 81 +++++++++++++++++++++ src/models/repositories/note-reaction.ts | 14 +++- src/server/api/endpoints/users/reactions.ts | 67 +++++++++++++++++ 5 files changed, 175 insertions(+), 3 deletions(-) create mode 100644 src/client/pages/user/reactions.vue create mode 100644 src/server/api/endpoints/users/reactions.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 873716a3d..1139707b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,12 +2,19 @@ ## 12.x.x (unreleased) ### Improvements -- ページロードエラーページにリロードボタンを追加 ### Bugfixes --> +## 12.x.x (unreleased) + +### Improvements +- クライアント: ユーザーのリアクション一覧を見れるように +- API: ユーザーのリアクション一覧を取得する users/reactions を追加 + +### Bugfixes + ## 12.92.0 (2021/10/16) ### Improvements diff --git a/src/client/pages/user/index.vue b/src/client/pages/user/index.vue index 0ddf73d57..6811dff2d 100644 --- a/src/client/pages/user/index.vue +++ b/src/client/pages/user/index.vue @@ -181,6 +181,7 @@ + @@ -223,6 +224,7 @@ export default defineComponent({ MkTab, MkInfo, XFollowList: defineAsyncComponent(() => import('./follow-list.vue')), + XReactions: defineAsyncComponent(() => import('./reactions.vue')), XClips: defineAsyncComponent(() => import('./clips.vue')), XPages: defineAsyncComponent(() => import('./pages.vue')), XGallery: defineAsyncComponent(() => import('./gallery.vue')), @@ -268,6 +270,11 @@ export default defineComponent({ title: this.$ts.overview, icon: 'fas fa-home', onClick: () => { this.$router.push('/@' + getAcct(this.user)); }, + }, { + active: this.page === 'reactions', + title: this.$ts.reaction, + icon: 'fas fa-laugh', + onClick: () => { this.$router.push('/@' + getAcct(this.user) + '/reactions'); }, }, { active: this.page === 'clips', title: this.$ts.clips, diff --git a/src/client/pages/user/reactions.vue b/src/client/pages/user/reactions.vue new file mode 100644 index 000000000..5ac7e0102 --- /dev/null +++ b/src/client/pages/user/reactions.vue @@ -0,0 +1,81 @@ + + + + + diff --git a/src/models/repositories/note-reaction.ts b/src/models/repositories/note-reaction.ts index ba74076f6..5d8606552 100644 --- a/src/models/repositories/note-reaction.ts +++ b/src/models/repositories/note-reaction.ts @@ -1,6 +1,6 @@ import { EntityRepository, Repository } from 'typeorm'; import { NoteReaction } from '@/models/entities/note-reaction'; -import { Users } from '../index'; +import { Notes, Users } from '../index'; import { Packed } from '@/misc/schema'; import { convertLegacyReaction } from '@/misc/reaction-lib'; import { User } from '@/models/entities/user'; @@ -9,8 +9,15 @@ import { User } from '@/models/entities/user'; export class NoteReactionRepository extends Repository { public async pack( src: NoteReaction['id'] | NoteReaction, - me?: { id: User['id'] } | null | undefined + me?: { id: User['id'] } | null | undefined, + options?: { + withNote: boolean; + }, ): Promise> { + const opts = Object.assign({ + withNote: false, + }, options); + const reaction = typeof src === 'object' ? src : await this.findOneOrFail(src); return { @@ -18,6 +25,9 @@ export class NoteReactionRepository extends Repository { createdAt: reaction.createdAt.toISOString(), user: await Users.pack(reaction.userId, me), type: convertLegacyReaction(reaction.reaction), + ...(opts.withNote ? { + note: await Notes.pack(reaction.noteId, me), + } : {}) }; } } diff --git a/src/server/api/endpoints/users/reactions.ts b/src/server/api/endpoints/users/reactions.ts new file mode 100644 index 000000000..44d788748 --- /dev/null +++ b/src/server/api/endpoints/users/reactions.ts @@ -0,0 +1,67 @@ +import $ from 'cafy'; +import { ID } from '@/misc/cafy-id'; +import define from '../../define'; +import { NoteReactions } from '@/models/index'; +import { makePaginationQuery } from '../../common/make-pagination-query'; +import { generateVisibilityQuery } from '../../common/generate-visibility-query'; + +export const meta = { + tags: ['users', 'reactions'], + + requireCredential: false as const, + + params: { + userId: { + validator: $.type(ID), + }, + + limit: { + validator: $.optional.num.range(1, 100), + default: 10, + }, + + sinceId: { + validator: $.optional.type(ID), + }, + + untilId: { + validator: $.optional.type(ID), + }, + + sinceDate: { + validator: $.optional.num, + }, + + untilDate: { + validator: $.optional.num, + }, + }, + + res: { + type: 'array' as const, + optional: false as const, nullable: false as const, + items: { + type: 'object' as const, + optional: false as const, nullable: false as const, + ref: 'NoteReaction', + } + }, + + errors: { + } +}; + +export default define(meta, async (ps, me) => { + const query = makePaginationQuery(NoteReactions.createQueryBuilder('reaction'), + ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) + .andWhere(`reaction.userId = :userId`, { userId: ps.userId }) + .leftJoinAndSelect('reaction.note', 'note'); + + generateVisibilityQuery(query, me); + + const reactions = await query + .take(ps.limit!) + .getMany(); + + return await Promise.all(reactions.map(reaction => NoteReactions.pack(reaction, me, { withNote: true }))); +}); From dbc7f23e66884e935bfdf9caa5419aeacd8ad6ea Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 17 Oct 2021 05:21:36 +0900 Subject: [PATCH 02/46] Update CONTRIBUTING.md --- CONTRIBUTING.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f5e0eece1..3ec8baaac 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,9 +9,9 @@ It will also allow the reader to use the translation tool of their preference if ## Issues Before creating an issue, please check the following: - To avoid duplication, please search for similar issues before creating a new issue. -- Do not use Issues as a question. - - Issues should only be used to feature requests, suggestions, and report problems. - - Please ask questions in the [Misskey Forum](https://forum.misskey.io/) or [Discord](https://discord.gg/Wp8gVStHW3). +- Do not use Issues to ask questions or troubleshooting. + - Issues should only be used to feature requests, suggestions, and bug tracking. + - Please ask questions or troubleshooting in the [Misskey Forum](https://forum.misskey.io/) or [Discord](https://discord.gg/Wp8gVStHW3). ## Before implementation When you want to add a feature or fix a bug, **first have the design and policy reviewed in an Issue** (if it is not there, please make one). Without this step, there is a high possibility that the PR will not be merged even if it is implemented. From a3a3822bbe44b9b9903eeffff6b86107127df456 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 17 Oct 2021 16:26:35 +0900 Subject: [PATCH 03/46] =?UTF-8?q?enhance:=20=E3=83=A6=E3=83=BC=E3=82=B6?= =?UTF-8?q?=E3=83=BC=E6=A4=9C=E7=B4=A2=E3=81=AE=E7=B2=BE=E5=BA=A6=E3=82=92?= =?UTF-8?q?=E5=BC=B7=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 2 + src/client/components/form/radios.vue | 12 -- src/client/pages/explore.vue | 19 ++- .../users/search-by-username-and-host.ts | 9 +- src/server/api/endpoints/users/search.ts | 125 +++++++++++------- 5 files changed, 103 insertions(+), 64 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1139707b5..ef9934f6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,9 @@ ### Improvements - クライアント: ユーザーのリアクション一覧を見れるように +- クライアント: ユーザー検索の精度を強化 - API: ユーザーのリアクション一覧を取得する users/reactions を追加 +- API: users/search および users/search-by-username-and-host を強化 ### Bugfixes diff --git a/src/client/components/form/radios.vue b/src/client/components/form/radios.vue index 1d3d80172..998a73820 100644 --- a/src/client/components/form/radios.vue +++ b/src/client/components/form/radios.vue @@ -22,7 +22,6 @@ export default defineComponent({ } }, render() { - const label = this.$slots.desc(); let options = this.$slots.default(); // なぜかFragmentになることがあるため @@ -31,7 +30,6 @@ export default defineComponent({ return h('div', { class: 'novjtcto' }, [ - h('div', { class: 'label' }, label), ...options.map(option => h(MkRadio, { key: option.key, value: option.props.value, @@ -45,16 +43,6 @@ export default defineComponent({ From ff25b6b65a742c393ba895b5a0eb2554be239ddd Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 17 Oct 2021 18:38:38 +0900 Subject: [PATCH 05/46] #7880 --- src/client/pages/explore.vue | 6 +- .../users/search-by-username-and-host.ts | 14 ++-- src/server/api/endpoints/users/search.ts | 72 +++++++------------ 3 files changed, 38 insertions(+), 54 deletions(-) diff --git a/src/client/pages/explore.vue b/src/client/pages/explore.vue index 596bc1f0e..0c29b11b3 100644 --- a/src/client/pages/explore.vue +++ b/src/client/pages/explore.vue @@ -69,7 +69,7 @@ - + @@ -167,14 +167,14 @@ export default defineComponent({ limit: 10, params: computed(() => (this.searchQuery && this.searchQuery !== '') ? { query: this.searchQuery, - scope: this.searchScope, + origin: this.searchOrigin, } : null) }, tagsLocal: [], tagsRemote: [], stats: null, searchQuery: null, - searchScope: 'both', + searchOrigin: 'both', num: number, }; }, diff --git a/src/server/api/endpoints/users/search-by-username-and-host.ts b/src/server/api/endpoints/users/search-by-username-and-host.ts index 8fdc71065..3b8d024af 100644 --- a/src/server/api/endpoints/users/search-by-username-and-host.ts +++ b/src/server/api/endpoints/users/search-by-username-and-host.ts @@ -46,13 +46,15 @@ export const meta = { }; export default define(meta, async (ps, me) => { + const activeThreshold = new Date(Date.now() - (1000 * 60 * 60 * 24 * 30)); // 30日 + if (ps.host) { const q = Users.createQueryBuilder('user') .where('user.isSuspended = FALSE') .andWhere('user.host LIKE :host', { host: ps.host.toLowerCase() + '%' }); if (ps.username) { - q.andWhere('user.usernameLower like :username', { username: ps.username.toLowerCase() + '%' }); + q.andWhere('user.usernameLower LIKE :username', { username: ps.username.toLowerCase() + '%' }); } q.andWhere('user.updatedAt IS NOT NULL'); @@ -65,12 +67,12 @@ export default define(meta, async (ps, me) => { let users = await Users.createQueryBuilder('user') .where('user.host IS NULL') .andWhere('user.isSuspended = FALSE') - .andWhere('user.usernameLower like :username', { username: ps.username.toLowerCase() + '%' }) + .andWhere('user.usernameLower LIKE :username', { username: ps.username.toLowerCase() + '%' }) .andWhere(new Brackets(qb => { qb - .where('user.lastActiveDate IS NULL') - .orWhere('user.lastActiveDate > :activeThreshold', { activeThreshold: new Date(Date.now() - USER_ACTIVE_THRESHOLD) }); + .where('user.updatedAt IS NULL') + .orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold }); })) - .orderBy('user.lastActiveDate', 'DESC', 'NULLS LAST') + .orderBy('user.updatedAt', 'DESC', 'NULLS LAST') .take(ps.limit!) .skip(ps.offset) .getMany(); @@ -79,7 +81,7 @@ export default define(meta, async (ps, me) => { const otherUsers = await Users.createQueryBuilder('user') .where('user.host IS NOT NULL') .andWhere('user.isSuspended = FALSE') - .andWhere('user.usernameLower like :username', { username: ps.username.toLowerCase() + '%' }) + .andWhere('user.usernameLower LIKE :username', { username: ps.username.toLowerCase() + '%' }) .andWhere('user.updatedAt IS NOT NULL') .orderBy('user.updatedAt', 'DESC') .take(ps.limit! - users.length) diff --git a/src/server/api/endpoints/users/search.ts b/src/server/api/endpoints/users/search.ts index e4fbfedd1..9aa988d9e 100644 --- a/src/server/api/endpoints/users/search.ts +++ b/src/server/api/endpoints/users/search.ts @@ -3,7 +3,6 @@ import define from '../../define'; import { UserProfiles, Users } from '@/models/index'; import { User } from '@/models/entities/user'; import { Brackets } from 'typeorm'; -import { USER_ACTIVE_THRESHOLD } from '@/const'; export const meta = { tags: ['users'], @@ -25,9 +24,9 @@ export const meta = { default: 10, }, - scope: { - validator: $.optional.str.or(['local', 'remote', 'both']), - default: 'both', + origin: { + validator: $.optional.str.or(['local', 'remote', 'combined']), + default: 'combined', }, detail: { @@ -48,59 +47,49 @@ export const meta = { }; export default define(meta, async (ps, me) => { + const activeThreshold = new Date(Date.now() - (1000 * 60 * 60 * 24 * 30)); // 30日 + const isUsername = ps.query.startsWith('@'); let users: User[] = []; if (isUsername) { const usernameQuery = Users.createQueryBuilder('user') - .where('user.usernameLower like :username', { username: ps.query.replace('@', '').toLowerCase() + '%' }) + .where('user.usernameLower LIKE :username', { username: ps.query.replace('@', '').toLowerCase() + '%' }) .andWhere(new Brackets(qb => { qb - .where('user.lastActiveDate IS NULL') - .orWhere('user.lastActiveDate > :activeThreshold', { activeThreshold: new Date(Date.now() - USER_ACTIVE_THRESHOLD) }); + .where('user.updatedAt IS NULL') + .orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold }); })) .andWhere('user.isSuspended = FALSE'); - if (ps.scope === 'local') { - usernameQuery - .andWhere('user.host IS NULL') - .orderBy('user.lastActiveDate', 'DESC', 'NULLS LAST'); - } else if (ps.scope === 'remote') { - usernameQuery - .andWhere('user.host IS NOT NULL') - .orderBy('user.updatedAt', 'DESC', 'NULLS LAST'); - } else { // both - usernameQuery - .orderBy('user.updatedAt', 'DESC', 'NULLS LAST'); + if (ps.origin === 'local') { + usernameQuery.andWhere('user.host IS NULL'); + } else if (ps.origin === 'remote') { + usernameQuery.andWhere('user.host IS NOT NULL'); } users = await usernameQuery + .orderBy('user.updatedAt', 'DESC', 'NULLS LAST') .take(ps.limit!) .skip(ps.offset) .getMany(); } else { const nameQuery = Users.createQueryBuilder('user') - .where('user.name ilike :query', { query: '%' + ps.query + '%' }) + .where('user.name ILIKE :query', { query: '%' + ps.query + '%' }) .andWhere(new Brackets(qb => { qb - .where('user.lastActiveDate IS NULL') - .orWhere('user.lastActiveDate > :activeThreshold', { activeThreshold: new Date(Date.now() - USER_ACTIVE_THRESHOLD) }); + .where('user.updatedAt IS NULL') + .orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold }); })) .andWhere('user.isSuspended = FALSE'); - if (ps.scope === 'local') { - nameQuery - .andWhere('user.host IS NULL') - .orderBy('user.lastActiveDate', 'DESC', 'NULLS LAST'); - } else if (ps.scope === 'remote') { - nameQuery - .andWhere('user.host IS NOT NULL') - .orderBy('user.updatedAt', 'DESC', 'NULLS LAST'); - } else { // both - nameQuery - .orderBy('user.updatedAt', 'DESC', 'NULLS LAST'); + if (ps.origin === 'local') { + nameQuery.andWhere('user.host IS NULL'); + } else if (ps.origin === 'remote') { + nameQuery.andWhere('user.host IS NOT NULL'); } users = await nameQuery + .orderBy('user.updatedAt', 'DESC', 'NULLS LAST') .take(ps.limit!) .skip(ps.offset) .getMany(); @@ -108,32 +97,25 @@ export default define(meta, async (ps, me) => { if (users.length < ps.limit!) { const profQuery = UserProfiles.createQueryBuilder('prof') .select('prof.userId') - .where('prof.description ilike :query', { query: '%' + ps.query + '%' }); + .where('prof.description ILIKE :query', { query: '%' + ps.query + '%' }); - if (ps.scope === 'local') { + if (ps.origin === 'local') { profQuery.andWhere('prof.userHost IS NULL'); - } else if (ps.scope === 'remote') { + } else if (ps.origin === 'remote') { profQuery.andWhere('prof.userHost IS NOT NULL'); } const query = Users.createQueryBuilder('user') .where(`user.id IN (${ profQuery.getQuery() })`) .andWhere(new Brackets(qb => { qb - .where('user.lastActiveDate IS NULL') - .orWhere('user.lastActiveDate > :activeThreshold', { activeThreshold: new Date(Date.now() - USER_ACTIVE_THRESHOLD) }); + .where('user.updatedAt IS NULL') + .orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold }); })) .andWhere('user.isSuspended = FALSE') .setParameters(profQuery.getParameters()); - if (ps.scope === 'local') { - query.orderBy('user.lastActiveDate', 'DESC', 'NULLS LAST'); - } else if (ps.scope === 'remote') { - query.orderBy('user.updatedAt', 'DESC', 'NULLS LAST'); - } else { // both - query.orderBy('user.updatedAt', 'DESC', 'NULLS LAST'); - } - users = users.concat(await query + .orderBy('user.updatedAt', 'DESC', 'NULLS LAST') .take(ps.limit!) .skip(ps.offset) .getMany() From d0736a36c7aa202b797a7493cec070c811f1d09f Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 17 Oct 2021 18:39:58 +0900 Subject: [PATCH 06/46] Update explore.vue --- src/client/pages/explore.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/pages/explore.vue b/src/client/pages/explore.vue index 0c29b11b3..6f304877b 100644 --- a/src/client/pages/explore.vue +++ b/src/client/pages/explore.vue @@ -174,7 +174,7 @@ export default defineComponent({ tagsRemote: [], stats: null, searchQuery: null, - searchOrigin: 'both', + searchOrigin: 'combined', num: number, }; }, From 22c8598043ce6da8e72e62a92668beca73e7b3f3 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 17 Oct 2021 18:47:33 +0900 Subject: [PATCH 07/46] :art: --- src/client/components/tab.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/components/tab.vue b/src/client/components/tab.vue index ce86af8f9..c62972735 100644 --- a/src/client/components/tab.vue +++ b/src/client/components/tab.vue @@ -36,7 +36,7 @@ export default defineComponent({ > button { flex: 1; padding: 10px 8px; - border-radius: 6px; + border-radius: var(--radius); &:disabled { opacity: 1 !important; From 41e6dfb87a7a64549edb26e41ad7e1d1232a209f Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 17 Oct 2021 21:04:34 +0900 Subject: [PATCH 08/46] :art: --- CHANGELOG.md | 1 + src/client/scripts/theme.ts | 1 + src/client/themes/l-sushi.json5 | 18 ++++++++++++++++++ 3 files changed, 20 insertions(+) create mode 100644 src/client/themes/l-sushi.json5 diff --git a/CHANGELOG.md b/CHANGELOG.md index ef9934f6d..d2889b07b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ ### Improvements - クライアント: ユーザーのリアクション一覧を見れるように - クライアント: ユーザー検索の精度を強化 +- クライアント: 新しいライトテーマを追加 - API: ユーザーのリアクション一覧を取得する users/reactions を追加 - API: users/search および users/search-by-username-and-host を強化 diff --git a/src/client/scripts/theme.ts b/src/client/scripts/theme.ts index e79d54fa6..ad1b033ed 100644 --- a/src/client/scripts/theme.ts +++ b/src/client/scripts/theme.ts @@ -20,6 +20,7 @@ export const builtinThemes = [ require('@client/themes/l-apricot.json5'), require('@client/themes/l-rainy.json5'), require('@client/themes/l-vivid.json5'), + require('@client/themes/l-sushi.json5'), require('@client/themes/d-dark.json5'), require('@client/themes/d-persimmon.json5'), diff --git a/src/client/themes/l-sushi.json5 b/src/client/themes/l-sushi.json5 new file mode 100644 index 000000000..5846927d6 --- /dev/null +++ b/src/client/themes/l-sushi.json5 @@ -0,0 +1,18 @@ +{ + id: '213273e5-7d20-d5f0-6e36-1b6a4f67115c', + + name: 'Mi Sushi Light', + author: 'syuilo', + + base: 'light', + + props: { + accent: '#e36749', + bg: '#f0eee9', + fg: '#5f5f5f', + renote: '@accent', + link: '@accent', + mention: '@accent', + hashtag: '#229e82', + }, +} From 04229229477f9d53bd0feb2df66cc686a39e3a7b Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 17 Oct 2021 21:23:15 +0900 Subject: [PATCH 09/46] =?UTF-8?q?fix(client):=20=E3=83=86=E3=83=BC?= =?UTF-8?q?=E3=83=9E=E3=81=AE=E7=AE=A1=E7=90=86=E3=81=8C=E8=A1=8C=E3=81=88?= =?UTF-8?q?=E3=81=AA=E3=81=84=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 1 + src/client/pages/settings/theme.manage.vue | 14 +++++++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d2889b07b..c58886e0b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ - API: users/search および users/search-by-username-and-host を強化 ### Bugfixes +- クライアント: テーマの管理が行えない問題を修正 ## 12.92.0 (2021/10/16) diff --git a/src/client/pages/settings/theme.manage.vue b/src/client/pages/settings/theme.manage.vue index da21a47a5..1a11a664f 100644 --- a/src/client/pages/settings/theme.manage.vue +++ b/src/client/pages/settings/theme.manage.vue @@ -10,13 +10,13 @@ diff --git a/src/client/components/number-diff.vue b/src/client/components/number-diff.vue new file mode 100644 index 000000000..ba7e6964d --- /dev/null +++ b/src/client/components/number-diff.vue @@ -0,0 +1,47 @@ + + + + + diff --git a/src/client/pages/instance-info.vue b/src/client/pages/instance-info.vue index 4fbf104f0..7a4cd5f01 100644 --- a/src/client/pages/instance-info.vue +++ b/src/client/pages/instance-info.vue @@ -65,17 +65,17 @@
- - - - - - - - - - - + + + + + + + + + + + @@ -83,7 +83,7 @@
- +
@@ -135,7 +135,7 @@ + + diff --git a/src/client/pages/instance/queue.chart.vue b/src/client/pages/instance/queue.chart.vue index 887fe9a57..4f8fd762b 100644 --- a/src/client/pages/instance/queue.chart.vue +++ b/src/client/pages/instance/queue.chart.vue @@ -67,7 +67,7 @@ export default defineComponent({ // TODO: var(--panel)の色が暗いか明るいかで判定する const gridColor = this.$store.state.darkMode ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)'; - Chart.defaults.global.defaultFontColor = getComputedStyle(document.documentElement).getPropertyValue('--fg'); + Chart.defaults.color = getComputedStyle(document.documentElement).getPropertyValue('--fg'); this.chart = markRaw(new Chart(this.$refs.chart, { type: 'line', diff --git a/src/client/scripts/hpml/lib.ts b/src/client/scripts/hpml/lib.ts index 150a04732..200faf820 100644 --- a/src/client/scripts/hpml/lib.ts +++ b/src/client/scripts/hpml/lib.ts @@ -1,11 +1,11 @@ import * as tinycolor from 'tinycolor2'; -import Chart from 'chart.js'; import { Hpml } from './evaluator'; import { values, utils } from '@syuilo/aiscript'; import { Fn, HpmlScope } from '.'; import { Expr } from './expr'; import * as seedrandom from 'seedrandom'; +/* // https://stackoverflow.com/questions/38493564/chart-area-background-color-chartjs Chart.pluginService.register({ beforeDraw: (chart, easing) => { @@ -18,6 +18,7 @@ Chart.pluginService.register({ } } }); +*/ export function initAiLib(hpml: Hpml) { return { @@ -49,11 +50,12 @@ export function initAiLib(hpml: Hpml) { ])); }), 'MkPages:chart': values.FN_NATIVE(([id, opts]) => { + /* TODO utils.assertString(id); utils.assertObject(opts); const canvas = hpml.canvases[id.value]; const color = getComputedStyle(document.documentElement).getPropertyValue('--accent'); - Chart.defaults.global.defaultFontColor = '#555'; + Chart.defaults.color = '#555'; const chart = new Chart(canvas, { type: opts.value.get('type').value, data: { @@ -122,6 +124,7 @@ export function initAiLib(hpml: Hpml) { }) } }); + */ }) }; } diff --git a/src/queue/index.ts b/src/queue/index.ts index 43c062bae..37eb80960 100644 --- a/src/queue/index.ts +++ b/src/queue/index.ts @@ -10,7 +10,7 @@ import procesObjectStorage from './processors/object-storage/index'; import { queueLogger } from './logger'; import { DriveFile } from '@/models/entities/drive-file'; import { getJobInfo } from './get-job-info'; -import { dbQueue, deliverQueue, inboxQueue, objectStorageQueue } from './queues'; +import { systemQueue, dbQueue, deliverQueue, inboxQueue, objectStorageQueue } from './queues'; import { ThinUser } from './types'; import { IActivity } from '@/remote/activitypub/type'; @@ -22,11 +22,20 @@ function renderError(e: Error): any { }; } +const systemLogger = queueLogger.createSubLogger('system'); const deliverLogger = queueLogger.createSubLogger('deliver'); const inboxLogger = queueLogger.createSubLogger('inbox'); const dbLogger = queueLogger.createSubLogger('db'); const objectStorageLogger = queueLogger.createSubLogger('objectStorage'); +systemQueue + .on('waiting', (jobId) => systemLogger.debug(`waiting id=${jobId}`)) + .on('active', (job) => systemLogger.debug(`active id=${job.id}`)) + .on('completed', (job, result) => systemLogger.debug(`completed(${result}) id=${job.id}`)) + .on('failed', (job, err) => systemLogger.warn(`failed(${err}) id=${job.id}`, { job, e: renderError(err) })) + .on('error', (job: any, err: Error) => systemLogger.error(`error ${err}`, { job, e: renderError(err) })) + .on('stalled', (job) => systemLogger.warn(`stalled id=${job.id}`)); + deliverQueue .on('waiting', (jobId) => deliverLogger.debug(`waiting id=${jobId}`)) .on('active', (job) => deliverLogger.debug(`active ${getJobInfo(job, true)} to=${job.data.to}`)) @@ -220,12 +229,17 @@ export function createCleanRemoteFilesJob() { } export default function() { - if (!envOption.onlyServer) { - deliverQueue.process(config.deliverJobConcurrency || 128, processDeliver); - inboxQueue.process(config.inboxJobConcurrency || 16, processInbox); - processDb(dbQueue); - procesObjectStorage(objectStorageQueue); - } + if (envOption.onlyServer) return; + + deliverQueue.process(config.deliverJobConcurrency || 128, processDeliver); + inboxQueue.process(config.inboxJobConcurrency || 16, processInbox); + processDb(dbQueue); + procesObjectStorage(objectStorageQueue); + + systemQueue.add('resyncCharts', { + }, { + repeat: { cron: '0 0 * * *' } + }); } export function destroy() { diff --git a/src/queue/processors/system/index.ts b/src/queue/processors/system/index.ts new file mode 100644 index 000000000..52b786810 --- /dev/null +++ b/src/queue/processors/system/index.ts @@ -0,0 +1,12 @@ +import * as Bull from 'bull'; +import { resyncCharts } from './resync-charts'; + +const jobs = { + resyncCharts, +} as Record | Bull.ProcessPromiseFunction<{}>>; + +export default function(dbQueue: Bull.Queue<{}>) { + for (const [k, v] of Object.entries(jobs)) { + dbQueue.process(k, v); + } +} diff --git a/src/queue/processors/system/resync-charts.ts b/src/queue/processors/system/resync-charts.ts new file mode 100644 index 000000000..b36b024cf --- /dev/null +++ b/src/queue/processors/system/resync-charts.ts @@ -0,0 +1,21 @@ +import * as Bull from 'bull'; + +import { queueLogger } from '../../logger'; +import { driveChart, notesChart, usersChart } from '@/services/chart/index'; + +const logger = queueLogger.createSubLogger('resync-charts'); + +export default async function resyncCharts(job: Bull.Job<{}>, done: any): Promise { + logger.info(`Resync charts...`); + + // TODO: ユーザーごとのチャートも更新する + // TODO: インスタンスごとのチャートも更新する + await Promise.all([ + driveChart.resync(), + notesChart.resync(), + usersChart.resync(), + ]); + + logger.succ(`All charts successfully resynced.`); + done(); +} diff --git a/src/queue/queues.ts b/src/queue/queues.ts index d8c09ef86..a66a7ca45 100644 --- a/src/queue/queues.ts +++ b/src/queue/queues.ts @@ -2,6 +2,7 @@ import config from '@/config/index'; import { initialize as initializeQueue } from './initialize'; import { DeliverJobData, InboxJobData, DbJobData, ObjectStorageJobData } from './types'; +export const systemQueue = initializeQueue<{}>('system'); export const deliverQueue = initializeQueue('deliver', config.deliverJobPerSec || 128); export const inboxQueue = initializeQueue('inbox', config.inboxJobPerSec || 16); export const dbQueue = initializeQueue('db'); diff --git a/src/server/api/endpoints/admin/resync-chart.ts b/src/server/api/endpoints/admin/resync-chart.ts index b0e687333..e01dfce1b 100644 --- a/src/server/api/endpoints/admin/resync-chart.ts +++ b/src/server/api/endpoints/admin/resync-chart.ts @@ -1,5 +1,5 @@ import define from '../../define'; -import { driveChart, notesChart, usersChart, instanceChart } from '@/services/chart/index'; +import { driveChart, notesChart, usersChart } from '@/services/chart/index'; import { insertModerationLog } from '@/services/insert-moderation-log'; export const meta = { @@ -15,7 +15,7 @@ export default define(meta, async (ps, me) => { driveChart.resync(); notesChart.resync(); usersChart.resync(); - instanceChart.resync(); // TODO: ユーザーごとのチャートもキューに入れて更新する + // TODO: インスタンスごとのチャートもキューに入れて更新する }); diff --git a/yarn.lock b/yarn.lock index e2140e185..449390a6a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2664,28 +2664,22 @@ character-parser@^2.2.0: dependencies: is-regex "^1.0.3" -chart.js@2.9.4: - version "2.9.4" - resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-2.9.4.tgz#0827f9563faffb2dc5c06562f8eb10337d5b9684" - integrity sha512-B07aAzxcrikjAPyV+01j7BmOpxtQETxTSlQ26BEYJ+3iUkbNKaOJ/nDbT6JjyqYxseM0ON12COHYdU2cTIjC7A== - dependencies: - chartjs-color "^2.1.0" - moment "^2.10.2" +chart.js@3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-3.5.1.tgz#73e24d23a4134a70ccdb5e79a917f156b6f3644a" + integrity sha512-m5kzt72I1WQ9LILwQC4syla/LD/N413RYv2Dx2nnTkRS9iv/ey1xLTt0DnPc/eWV4zI+BgEgDYBIzbQhZHc/PQ== -chartjs-color-string@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/chartjs-color-string/-/chartjs-color-string-0.6.0.tgz#1df096621c0e70720a64f4135ea171d051402f71" - integrity sha512-TIB5OKn1hPJvO7JcteW4WY/63v6KwEdt6udfnDE9iCAZgy+V4SrbSxoIbTw/xkUIapjEI4ExGtD0+6D3KyFd7A== - dependencies: - color-name "^1.0.0" +chartjs-adapter-date-fns@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/chartjs-adapter-date-fns/-/chartjs-adapter-date-fns-2.0.0.tgz#5e53b2f660b993698f936f509c86dddf9ed44c6b" + integrity sha512-rmZINGLe+9IiiEB0kb57vH3UugAtYw33anRiw5kS2Tu87agpetDDoouquycWc9pRsKtQo5j+vLsYHyr8etAvFw== -chartjs-color@^2.1.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/chartjs-color/-/chartjs-color-2.4.1.tgz#6118bba202fe1ea79dd7f7c0f9da93467296c3b0" - integrity sha512-haqOg1+Yebys/Ts/9bLo/BqUcONQOdr/hoEr2LLTRl6C5LXctUdHxsCYfvQVg5JIxITrfCNUDr4ntqmQk9+/0w== +chartjs-plugin-zoom@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/chartjs-plugin-zoom/-/chartjs-plugin-zoom-1.1.1.tgz#8a28923a17fcb5eb57a0dc94c5113bf402677647" + integrity sha512-1q54WOzK7FtAjkbemQeqvmFUV0btNYIQny2HbQ6Awq9wUtCz7Zmj6vIgp3C1DYMQwN0nqgpC3vnApqiwI7cSdQ== dependencies: - chartjs-color-string "^0.6.0" - color-convert "^1.9.3" + hammerjs "^2.0.8" check-more-types@2.24.0, check-more-types@^2.24.0: version "2.24.0" @@ -2974,7 +2968,7 @@ collection-visit@^1.0.0: map-visit "^1.0.0" object-visit "^1.0.0" -color-convert@^1.3.0, color-convert@^1.9.0, color-convert@^1.9.3: +color-convert@^1.3.0, color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== @@ -3616,6 +3610,11 @@ data-urls@^2.0.0: whatwg-mimetype "^2.3.0" whatwg-url "^8.0.0" +date-fns@2.25.0: + version "2.25.0" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.25.0.tgz#8c5c8f1d958be3809a9a03f4b742eba894fc5680" + integrity sha512-ovYRFnTrbGPD4nqaEqescPEv1mNwvt+UTqI3Ay9SzNtey9NZnYu6E2qCcBBgJ6/2VF1zGGygpyTDITqpQQ5e+w== + date-fns@^2.16.1: version "2.19.0" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.19.0.tgz#65193348635a28d5d916c43ec7ce6fbd145059e1" @@ -5300,6 +5299,11 @@ gulplog@^1.0.0: dependencies: glogg "^1.0.0" +hammerjs@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/hammerjs/-/hammerjs-2.0.8.tgz#04ef77862cff2bb79d30f7692095930222bf60f1" + integrity sha1-BO93hiz/K7edMPdpIJWTAiK/YPE= + har-schema@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" @@ -7383,7 +7387,7 @@ moment-timezone@^0.5.25: dependencies: moment ">= 2.9.0" -"moment@>= 2.9.0", moment@^2.10.2, moment@^2.22.2: +"moment@>= 2.9.0", moment@^2.22.2: version "2.24.0" resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b" integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg== From 79f7650c5a3ae49746cd5e6177264b9fa199eb04 Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 22 Oct 2021 06:17:29 +0900 Subject: [PATCH 30/46] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 96266e56d..3b59251f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ ## 12.x.x (unreleased) ### Improvements +- クライアント: コントロールパネルのパフォーマンスを改善 - クライアント: 自分のリアクション一覧を見れるように - 設定により、リアクション一覧を全員に公開することも可能 - クライアント: ユーザー検索の精度を強化 From ac1859216714e427892cf387cba17f7a4aaeeac6 Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 22 Oct 2021 06:23:23 +0900 Subject: [PATCH 31/46] :art: --- src/client/components/form/input.vue | 2 +- src/client/components/form/select.vue | 65 ++++++++++++++++++++++--- src/client/components/form/textarea.vue | 2 +- src/client/components/ui/menu.vue | 5 ++ src/client/components/ui/popup-menu.vue | 6 ++- src/client/os.ts | 7 ++- 6 files changed, 75 insertions(+), 12 deletions(-) diff --git a/src/client/components/form/input.vue b/src/client/components/form/input.vue index d7b6f7751..591eda9ed 100644 --- a/src/client/components/form/input.vue +++ b/src/client/components/form/input.vue @@ -33,7 +33,7 @@ diff --git a/src/db/postgre.ts b/src/db/postgre.ts index 0b635ea18..4f4047b61 100644 --- a/src/db/postgre.ts +++ b/src/db/postgre.ts @@ -8,7 +8,6 @@ import { entities as charts } from '@/services/chart/entities'; import { dbLogger } from './logger'; import * as highlight from 'cli-highlight'; -import { Log } from '@/models/entities/log'; import { User } from '@/models/entities/user'; import { DriveFile } from '@/models/entities/drive-file'; import { DriveFolder } from '@/models/entities/drive-folder'; @@ -144,7 +143,6 @@ export const entities = [ PageLike, GalleryPost, GalleryLike, - Log, DriveFile, DriveFolder, Poll, diff --git a/src/models/entities/log.ts b/src/models/entities/log.ts deleted file mode 100644 index 182a9fbed..000000000 --- a/src/models/entities/log.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { Entity, PrimaryColumn, Index, Column } from 'typeorm'; -import { id } from '../id'; - -@Entity() -export class Log { - @PrimaryColumn(id()) - public id: string; - - @Index() - @Column('timestamp with time zone', { - comment: 'The created date of the Log.' - }) - public createdAt: Date; - - @Index() - @Column('varchar', { - length: 64, array: true, default: '{}' - }) - public domain: string[]; - - @Index() - @Column('enum', { - enum: ['error', 'warning', 'info', 'success', 'debug'] - }) - public level: string; - - @Column('varchar', { - length: 8 - }) - public worker: string; - - @Column('varchar', { - length: 128 - }) - public machine: string; - - @Column('varchar', { - length: 2048 - }) - public message: string; - - @Column('jsonb', { - default: {} - }) - public data: Record; -} diff --git a/src/models/index.ts b/src/models/index.ts index 059a3d7b8..4c6f19eaf 100644 --- a/src/models/index.ts +++ b/src/models/index.ts @@ -13,7 +13,6 @@ import { UserRepository } from './repositories/user'; import { NoteRepository } from './repositories/note'; import { DriveFileRepository } from './repositories/drive-file'; import { DriveFolderRepository } from './repositories/drive-folder'; -import { Log } from './entities/log'; import { AccessToken } from './entities/access-token'; import { UserNotePining } from './entities/user-note-pining'; import { SigninRepository } from './repositories/signin'; @@ -108,7 +107,6 @@ export const Signins = getCustomRepository(SigninRepository); export const MessagingMessages = getCustomRepository(MessagingMessageRepository); export const ReversiGames = getCustomRepository(ReversiGameRepository); export const ReversiMatchings = getCustomRepository(ReversiMatchingRepository); -export const Logs = getRepository(Log); export const Pages = getCustomRepository(PageRepository); export const PageLikes = getCustomRepository(PageLikeRepository); export const GalleryPosts = getCustomRepository(GalleryPostRepository); diff --git a/src/server/api/endpoints/admin/logs.ts b/src/server/api/endpoints/admin/logs.ts deleted file mode 100644 index 776403a62..000000000 --- a/src/server/api/endpoints/admin/logs.ts +++ /dev/null @@ -1,126 +0,0 @@ -import $ from 'cafy'; -import define from '../../define'; -import { Logs } from '@/models/index'; -import { Brackets } from 'typeorm'; - -export const meta = { - tags: ['admin'], - - requireCredential: true as const, - requireModerator: true, - - params: { - limit: { - validator: $.optional.num.range(1, 100), - default: 30 - }, - - level: { - validator: $.optional.nullable.str, - default: null - }, - - domain: { - validator: $.optional.nullable.str, - default: null - } - }, - - res: { - type: 'array' as const, - optional: false as const, nullable: false as const, - items: { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: { - id: { - type: 'string' as const, - optional: false as const, nullable: false as const, - format: 'id', - example: 'xxxxxxxxxx', - }, - createdAt: { - type: 'string' as const, - optional: false as const, nullable: false as const, - format: 'date-time', - }, - domain: { - type: 'array' as const, - optional: false as const, nullable: false as const, - items: { - type: 'string' as const, - optional: true as const, nullable: false as const - } - }, - level: { - type: 'string' as const, - optional: false as const, nullable: false as const - }, - worker: { - type: 'string' as const, - optional: false as const, nullable: false as const - }, - machine: { - type: 'string' as const, - optional: false as const, nullable: false as const, - }, - message: { - type: 'string' as const, - optional: false as const, nullable: false as const, - }, - data: { - type: 'object' as const, - optional: false as const, nullable: false as const - } - } - } - } -}; - -export default define(meta, async (ps) => { - const query = Logs.createQueryBuilder('log'); - - if (ps.level) query.andWhere('log.level = :level', { level: ps.level }); - - if (ps.domain) { - const whiteDomains = ps.domain.split(' ').filter(x => !x.startsWith('-')); - const blackDomains = ps.domain.split(' ').filter(x => x.startsWith('-')).map(x => x.substr(1)); - - if (whiteDomains.length > 0) { - query.andWhere(new Brackets(qb => { - for (const whiteDomain of whiteDomains) { - let i = 0; - for (const subDomain of whiteDomain.split('.')) { - const p = `whiteSubDomain_${subDomain}_${i}`; - // SQL is 1 based, so we need '+ 1' - qb.orWhere(`log.domain[${i + 1}] = :${p}`, { [p]: subDomain }); - i++; - } - } - })); - } - - if (blackDomains.length > 0) { - query.andWhere(new Brackets(qb => { - for (const blackDomain of blackDomains) { - qb.andWhere(new Brackets(qb => { - const subDomains = blackDomain.split('.'); - let i = 0; - for (const subDomain of subDomains) { - const p = `blackSubDomain_${subDomain}_${i}`; - // 全体で否定できないのでド・モルガンの法則で - // !(P && Q) を !P || !Q で表す - // SQL is 1 based, so we need '+ 1' - qb.orWhere(`log.domain[${i + 1}] != :${p}`, { [p]: subDomain }); - i++; - } - })); - } - })); - } - } - - const logs = await query.orderBy('log.createdAt', 'DESC').take(ps.limit!).getMany(); - - return logs; -}); diff --git a/src/services/logger.ts b/src/services/logger.ts index 8e783e67f..67ee44125 100644 --- a/src/services/logger.ts +++ b/src/services/logger.ts @@ -1,11 +1,7 @@ import * as cluster from 'cluster'; -import * as os from 'os'; import * as chalk from 'chalk'; import * as dateformat from 'dateformat'; import { envOption } from '../env'; -import { getRepository } from 'typeorm'; -import { Log } from '@/models/entities/log'; -import { genId } from '@/misc/gen-id'; import config from '@/config/index'; import * as SyslogPro from 'syslog-pro'; @@ -95,18 +91,6 @@ export default class Logger { null as never; send.bind(this.syslogClient)(message).catch(() => {}); - } else { - const Logs = getRepository(Log); - Logs.insert({ - id: genId(), - createdAt: new Date(), - machine: os.hostname(), - worker: worker.toString(), - domain: [this.domain].concat(subDomains).map(d => d.name), - level: level, - message: message.substr(0, 1000), // 1024を超えるとログが挿入できずエラーになり無限ループする - data: data, - } as Log).catch(() => {}); } } } From 1b33d50279d514520d07bbfb38e1ef221c6906dd Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 22 Oct 2021 21:01:36 +0900 Subject: [PATCH 39/46] =?UTF-8?q?=E3=83=A2=E3=83=87=E3=83=AC=E3=83=BC?= =?UTF-8?q?=E3=82=BF=E3=83=BC=E3=82=92=E3=83=96=E3=83=AD=E3=83=83=E3=82=AF?= =?UTF-8?q?=E3=81=A7=E3=81=8D=E3=81=AA=E3=81=84=E4=BB=95=E6=A7=98=E3=82=92?= =?UTF-8?q?=E5=BB=83=E6=AD=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolve #7898 --- CHANGELOG.md | 1 + src/server/api/endpoints/blocking/create.ts | 13 +------------ src/services/blocking/create.ts | 4 ---- 3 files changed, 2 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a6741184..244ceb382 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ - ActivityPub: not reacted な Undo.Like がinboxに滞留するのを修正 ### Changes +- 連合の考慮に問題があることなどが分かったため、モデレーターをブロックできない仕様を廃止しました - データベースにログを保存しないようになりました - ログを永続化したい場合はsyslogを利用してください diff --git a/src/server/api/endpoints/blocking/create.ts b/src/server/api/endpoints/blocking/create.ts index 4deaa3997..295325239 100644 --- a/src/server/api/endpoints/blocking/create.ts +++ b/src/server/api/endpoints/blocking/create.ts @@ -43,12 +43,6 @@ export const meta = { code: 'ALREADY_BLOCKING', id: '787fed64-acb9-464a-82eb-afbd745b9614' }, - - cannotBlockModerator: { - message: 'Cannot block a moderator or an admin.', - code: 'CANNOT_BLOCK_MODERATOR', - id: '8544aaef-89fb-e470-9f6c-385d38b474f5' - } }, res: { @@ -82,12 +76,7 @@ export default define(meta, async (ps, user) => { throw new ApiError(meta.errors.alreadyBlocking); } - try { - await create(blocker, blockee); - } catch (e) { - if (e.id === 'e42b7890-5e4d-9d9c-d54b-cf4dd30adfb5') throw new ApiError(meta.errors.cannotBlockModerator); - throw e; - } + await create(blocker, blockee); NoteWatchings.delete({ userId: blocker.id, diff --git a/src/services/blocking/create.ts b/src/services/blocking/create.ts index defe37751..6aadc847a 100644 --- a/src/services/blocking/create.ts +++ b/src/services/blocking/create.ts @@ -12,10 +12,6 @@ import { genId } from '@/misc/gen-id'; import { IdentifiableError } from '@/misc/identifiable-error'; export default async function(blocker: User, blockee: User) { - if (blockee.isAdmin || blockee.isModerator) { - throw new IdentifiableError('e42b7890-5e4d-9d9c-d54b-cf4dd30adfb5'); - } - await Promise.all([ cancelRequest(blocker, blockee), cancelRequest(blockee, blocker), From 9f7ffa0d7b9b4bed28e0324f911e2d5be77c541e Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 22 Oct 2021 21:51:48 +0900 Subject: [PATCH 40/46] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 244ceb382..0357b531c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ - API: users/search および users/search-by-username-and-host を強化 - ミュート及びブロックのインポートを行えるように - クライアント: /share のクエリでリプライやファイル等の情報を渡せるように +- チャートのsyncを毎日0時に自動で行うように ### Bugfixes - クライアント: テーマの管理が行えない問題を修正 From 57f164cf8e9d0331827cd4eba6b886e56f44da8a Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 22 Oct 2021 23:46:47 +0900 Subject: [PATCH 41/46] fix chart rendering --- src/client/components/queue-chart.vue | 202 +++++++++++++++++++++++++ src/client/pages/admin/queue.chart.vue | 200 +++++------------------- 2 files changed, 244 insertions(+), 158 deletions(-) create mode 100644 src/client/components/queue-chart.vue diff --git a/src/client/components/queue-chart.vue b/src/client/components/queue-chart.vue new file mode 100644 index 000000000..596270880 --- /dev/null +++ b/src/client/components/queue-chart.vue @@ -0,0 +1,202 @@ + + + + + diff --git a/src/client/pages/admin/queue.chart.vue b/src/client/pages/admin/queue.chart.vue index 4f8fd762b..084181a60 100644 --- a/src/client/pages/admin/queue.chart.vue +++ b/src/client/pages/admin/queue.chart.vue @@ -11,7 +11,7 @@
- +
@@ -27,177 +27,61 @@ From b894d585f3509696037d402335f6f4a4af2fa01b Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 23 Oct 2021 00:04:19 +0900 Subject: [PATCH 42/46] improve dashboard --- src/client/components/ui/container.vue | 9 +++- src/client/pages/admin/overview.vue | 60 ++++++++++++++++++++++++-- 2 files changed, 64 insertions(+), 5 deletions(-) diff --git a/src/client/components/ui/container.vue b/src/client/components/ui/container.vue index 194009909..14673dfcd 100644 --- a/src/client/components/ui/container.vue +++ b/src/client/components/ui/container.vue @@ -1,5 +1,5 @@