summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornullobsi <me@nullob.si>2022-02-05 23:02:48 -0800
committerGitHub <noreply@github.com>2022-02-06 16:02:48 +0900
commit3ff89fa7ecb643abf944ce966ffbf7f49000ca3f (patch)
treed0cc19173831e4f09e085c8bd805eb70c0e2ce1e
parentFix cast (#8257) (diff)
downloadsharkey-3ff89fa7ecb643abf944ce966ffbf7f49000ca3f.tar.gz
sharkey-3ff89fa7ecb643abf944ce966ffbf7f49000ca3f.tar.bz2
sharkey-3ff89fa7ecb643abf944ce966ffbf7f49000ca3f.zip
feat: Option to show replies in timeline (rebase #7685) (#8202)
* Add an option for timeline replies. Credit to Emilis (puffaboo) * update db on request
-rw-r--r--locales/ja-JP.yml2
-rw-r--r--packages/backend/migration/1629833361000-AddShowTLReplies.js15
-rw-r--r--packages/backend/src/models/entities/user.ts6
-rw-r--r--packages/backend/src/models/repositories/user.ts1
-rw-r--r--packages/backend/src/remote/activitypub/models/person.ts1
-rw-r--r--packages/backend/src/server/api/common/generate-replies-query.ts4
-rw-r--r--packages/backend/src/server/api/endpoints/i/update.ts5
-rw-r--r--packages/backend/src/server/api/stream/channels/global-timeline.ts2
-rw-r--r--packages/backend/src/server/api/stream/channels/home-timeline.ts2
-rw-r--r--packages/backend/src/server/api/stream/channels/hybrid-timeline.ts2
-rw-r--r--packages/backend/src/server/api/stream/channels/local-timeline.ts2
-rw-r--r--packages/client/src/pages/settings/profile.vue4
12 files changed, 39 insertions, 7 deletions
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 1393384626..ee23f2c5cd 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -141,6 +141,8 @@ flagAsBot: "Botとして設定"
flagAsBotDescription: "このアカウントがプログラムによって運用される場合は、このフラグをオンにします。オンにすると、反応の連鎖を防ぐためのフラグとして他の開発者に役立ったり、Misskeyのシステム上での扱いがBotに合ったものになります。"
flagAsCat: "Catとして設定"
flagAsCatDescription: "このアカウントが猫であることを示す場合は、このフラグをオンにします。"
+flagShowTimelineReplies: "タイムラインにノートへの返信を表示する"
+flagShowTimelineRepliesDescription: "オンにすると、タイムラインにユーザーのノート以外にもそのユーザーの他のノートへの返信を表示します。"
autoAcceptFollowed: "フォロー中ユーザーからのフォロリクを自動承認"
addAccount: "アカウントを追加"
loginFailed: "ログインに失敗しました"
diff --git a/packages/backend/migration/1629833361000-AddShowTLReplies.js b/packages/backend/migration/1629833361000-AddShowTLReplies.js
new file mode 100644
index 0000000000..bfd4ab7ff7
--- /dev/null
+++ b/packages/backend/migration/1629833361000-AddShowTLReplies.js
@@ -0,0 +1,15 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+class addShowTLReplies1629833361000 {
+ constructor() {
+ this.name = 'addShowTLReplies1629833361000';
+ }
+ async up(queryRunner) {
+ await queryRunner.query(`ALTER TABLE "user" ADD "showTimelineReplies" boolean NOT NULL DEFAULT false`);
+ await queryRunner.query(`COMMENT ON COLUMN "user"."showTimelineReplies" IS 'Whether to show users replying to other users in the timeline.'`);
+ }
+ async down(queryRunner) {
+ await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "showTimelineReplies"`);
+ }
+}
+exports.addShowTLReplies1629833361000 = addShowTLReplies1629833361000;
diff --git a/packages/backend/src/models/entities/user.ts b/packages/backend/src/models/entities/user.ts
index 0aa01ba00a..e4d9a3ced9 100644
--- a/packages/backend/src/models/entities/user.ts
+++ b/packages/backend/src/models/entities/user.ts
@@ -225,6 +225,12 @@ export class User {
})
public followersUri: string | null;
+ @Column('boolean', {
+ default: false,
+ comment: 'Whether to show users replying to other users in the timeline'
+ })
+ public showTimelineReplies: boolean;
+
@Index({ unique: true })
@Column('char', {
length: 16, nullable: true, unique: true,
diff --git a/packages/backend/src/models/repositories/user.ts b/packages/backend/src/models/repositories/user.ts
index 2b8398832d..33b2b32fee 100644
--- a/packages/backend/src/models/repositories/user.ts
+++ b/packages/backend/src/models/repositories/user.ts
@@ -220,6 +220,7 @@ export class UserRepository extends Repository<User> {
isModerator: user.isModerator || falsy,
isBot: user.isBot || falsy,
isCat: user.isCat || falsy,
+ showTimelineReplies: user.showTimelineReplies || falsy,
instance: user.host ? Instances.findOne({ host: user.host }).then(instance => instance ? {
name: instance.name,
softwareName: instance.softwareName,
diff --git a/packages/backend/src/remote/activitypub/models/person.ts b/packages/backend/src/remote/activitypub/models/person.ts
index 19a7a70903..aaccf51fa9 100644
--- a/packages/backend/src/remote/activitypub/models/person.ts
+++ b/packages/backend/src/remote/activitypub/models/person.ts
@@ -164,6 +164,7 @@ export async function createPerson(uri: string, resolver?: Resolver): Promise<Us
tags,
isBot,
isCat: (person as any).isCat === true,
+ showTimelineReplies: false,
})) as IRemoteUser;
await transactionalEntityManager.save(new UserProfile({
diff --git a/packages/backend/src/server/api/common/generate-replies-query.ts b/packages/backend/src/server/api/common/generate-replies-query.ts
index fbc41b2c25..249064d589 100644
--- a/packages/backend/src/server/api/common/generate-replies-query.ts
+++ b/packages/backend/src/server/api/common/generate-replies-query.ts
@@ -1,7 +1,7 @@
import { User } from '@/models/entities/user';
import { Brackets, SelectQueryBuilder } from 'typeorm';
-export function generateRepliesQuery(q: SelectQueryBuilder<any>, me?: { id: User['id'] } | null) {
+export function generateRepliesQuery(q: SelectQueryBuilder<any>, me?: Pick<User, 'id' | 'showTimelineReplies'> | null) {
if (me == null) {
q.andWhere(new Brackets(qb => { qb
.where(`note.replyId IS NULL`) // 返信ではない
@@ -10,7 +10,7 @@ export function generateRepliesQuery(q: SelectQueryBuilder<any>, me?: { id: User
.andWhere('note.replyUserId = note.userId');
}));
}));
- } else {
+ } else if(!me.showTimelineReplies) {
q.andWhere(new Brackets(qb => { qb
.where(`note.replyId IS NULL`) // 返信ではない
.orWhere('note.replyUserId = :meId', { meId: me.id }) // 返信だけど自分のノートへの返信
diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts
index 6b7e53aa1f..eb57aa2bfc 100644
--- a/packages/backend/src/server/api/endpoints/i/update.ts
+++ b/packages/backend/src/server/api/endpoints/i/update.ts
@@ -96,6 +96,10 @@ export const meta = {
validator: $.optional.bool,
},
+ showTimelineReplies: {
+ validator: $.optional.bool,
+ },
+
injectFeaturedNote: {
validator: $.optional.bool,
},
@@ -197,6 +201,7 @@ export default define(meta, async (ps, _user, token) => {
if (typeof ps.hideOnlineStatus === 'boolean') updates.hideOnlineStatus = ps.hideOnlineStatus;
if (typeof ps.publicReactions === 'boolean') profileUpdates.publicReactions = ps.publicReactions;
if (typeof ps.isBot === 'boolean') updates.isBot = ps.isBot;
+ if (typeof ps.showTimelineReplies === 'boolean') updates.showTimelineReplies = ps.showTimelineReplies;
if (typeof ps.carefulBot === 'boolean') profileUpdates.carefulBot = ps.carefulBot;
if (typeof ps.autoAcceptFollowed === 'boolean') profileUpdates.autoAcceptFollowed = ps.autoAcceptFollowed;
if (typeof ps.noCrawle === 'boolean') profileUpdates.noCrawle = ps.noCrawle;
diff --git a/packages/backend/src/server/api/stream/channels/global-timeline.ts b/packages/backend/src/server/api/stream/channels/global-timeline.ts
index f14f597aac..ecd87d093d 100644
--- a/packages/backend/src/server/api/stream/channels/global-timeline.ts
+++ b/packages/backend/src/server/api/stream/channels/global-timeline.ts
@@ -43,7 +43,7 @@ export default class extends Channel {
}
// 関係ない返信は除外
- if (note.reply) {
+ if (note.reply && !this.user!.showTimelineReplies) {
const reply = note.reply;
// 「チャンネル接続主への返信」でもなければ、「チャンネル接続主が行った返信」でもなければ、「投稿者の投稿者自身への返信」でもない場合
if (reply.userId !== this.user!.id && note.userId !== this.user!.id && reply.userId !== note.userId) return;
diff --git a/packages/backend/src/server/api/stream/channels/home-timeline.ts b/packages/backend/src/server/api/stream/channels/home-timeline.ts
index 3bd491421d..445db5c382 100644
--- a/packages/backend/src/server/api/stream/channels/home-timeline.ts
+++ b/packages/backend/src/server/api/stream/channels/home-timeline.ts
@@ -54,7 +54,7 @@ export default class extends Channel {
}
// 関係ない返信は除外
- if (note.reply) {
+ if (note.reply && !this.user!.showTimelineReplies) {
const reply = note.reply;
// 「チャンネル接続主への返信」でもなければ、「チャンネル接続主が行った返信」でもなければ、「投稿者の投稿者自身への返信」でもない場合
if (reply.userId !== this.user!.id && note.userId !== this.user!.id && reply.userId !== note.userId) return;
diff --git a/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts b/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts
index 0ae19aa7ce..c0be71fe2d 100644
--- a/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts
+++ b/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts
@@ -62,7 +62,7 @@ export default class extends Channel {
if (isInstanceMuted(note, new Set<string>(this.userProfile?.mutedInstances ?? []))) return;
// 関係ない返信は除外
- if (note.reply) {
+ if (note.reply && !this.user!.showTimelineReplies) {
const reply = note.reply;
// 「チャンネル接続主への返信」でもなければ、「チャンネル接続主が行った返信」でもなければ、「投稿者の投稿者自身への返信」でもない場合
if (reply.userId !== this.user!.id && note.userId !== this.user!.id && reply.userId !== note.userId) return;
diff --git a/packages/backend/src/server/api/stream/channels/local-timeline.ts b/packages/backend/src/server/api/stream/channels/local-timeline.ts
index 3178b1d511..ae8f62ba61 100644
--- a/packages/backend/src/server/api/stream/channels/local-timeline.ts
+++ b/packages/backend/src/server/api/stream/channels/local-timeline.ts
@@ -43,7 +43,7 @@ export default class extends Channel {
}
// 関係ない返信は除外
- if (note.reply) {
+ if (note.reply && !this.user!.showTimelineReplies) {
const reply = note.reply;
// 「チャンネル接続主への返信」でもなければ、「チャンネル接続主が行った返信」でもなければ、「投稿者の投稿者自身への返信」でもない場合
if (reply.userId !== this.user!.id && note.userId !== this.user!.id && reply.userId !== note.userId) return;
diff --git a/packages/client/src/pages/settings/profile.vue b/packages/client/src/pages/settings/profile.vue
index 66b654d87f..9b30d1c8e0 100644
--- a/packages/client/src/pages/settings/profile.vue
+++ b/packages/client/src/pages/settings/profile.vue
@@ -38,7 +38,7 @@
</FormSlot>
<FormSwitch v-model="profile.isCat" class="_formBlock">{{ i18n.ts.flagAsCat }}<template #caption>{{ i18n.ts.flagAsCatDescription }}</template></FormSwitch>
-
+ <FormSwitch v-model="profile.showTimelineReplies" class="_formBlock">{{ i18n.ts.flagShowTimelineReplies }}<template #caption>{{ i18n.ts.flagShowTimelineRepliesDescription }}</template></FormSwitch>
<FormSwitch v-model="profile.isBot" class="_formBlock">{{ i18n.ts.flagAsBot }}<template #caption>{{ i18n.ts.flagAsBotDescription }}</template></FormSwitch>
<FormSwitch v-model="profile.alwaysMarkNsfw" class="_formBlock">{{ i18n.ts.alwaysMarkSensitive }}</FormSwitch>
@@ -68,6 +68,7 @@ const profile = reactive({
lang: $i.lang,
isBot: $i.isBot,
isCat: $i.isCat,
+ showTimelineReplies: $i.showTimelineReplies,
alwaysMarkNsfw: $i.alwaysMarkNsfw,
});
@@ -97,6 +98,7 @@ function save() {
lang: profile.lang || null,
isBot: !!profile.isBot,
isCat: !!profile.isCat,
+ showTimelineReplies: !!profile.showTimelineReplies,
alwaysMarkNsfw: !!profile.alwaysMarkNsfw,
});
}