summaryrefslogtreecommitdiff
path: root/src/server/api
diff options
context:
space:
mode:
authorsyuilo <Syuilotan@yahoo.co.jp>2021-08-17 21:48:59 +0900
committerGitHub <noreply@github.com>2021-08-17 21:48:59 +0900
commit7015df37e3545d835ecd71cdcd1910fbb16e80da (patch)
tree58fe6dd4352444302dbdadb8a31d540604437495 /src/server/api
parentFix truncate (#7642) (diff)
downloadsharkey-7015df37e3545d835ecd71cdcd1910fbb16e80da.tar.gz
sharkey-7015df37e3545d835ecd71cdcd1910fbb16e80da.tar.bz2
sharkey-7015df37e3545d835ecd71cdcd1910fbb16e80da.zip
enhance(server): Improve user block (#7640)
* enhance(server): Improve user block * Update CHANGELOG.md * ユーザーリスト対応 * 相手から見れなくなるように * Update 1629004542760-chart-reindex.ts https://github.com/misskey-dev/misskey/commit/2365761ba5445f26c8b66b3b20ef4be44e70d549#commitcomment-54919821 * update test * add test * add todos * Update 1629004542760-chart-reindex.ts
Diffstat (limited to 'src/server/api')
-rw-r--r--src/server/api/common/generate-block-query.ts25
-rw-r--r--src/server/api/common/inject-featured.ts2
-rw-r--r--src/server/api/endpoints/antennas/notes.ts2
-rw-r--r--src/server/api/endpoints/clips/notes.ts2
-rw-r--r--src/server/api/endpoints/messaging/messages/create.ts19
-rw-r--r--src/server/api/endpoints/notes/children.ts2
-rw-r--r--src/server/api/endpoints/notes/create.ts30
-rw-r--r--src/server/api/endpoints/notes/featured.ts2
-rw-r--r--src/server/api/endpoints/notes/global-timeline.ts2
-rw-r--r--src/server/api/endpoints/notes/hybrid-timeline.ts2
-rw-r--r--src/server/api/endpoints/notes/local-timeline.ts2
-rw-r--r--src/server/api/endpoints/notes/mentions.ts2
-rw-r--r--src/server/api/endpoints/notes/polls/vote.ts23
-rw-r--r--src/server/api/endpoints/notes/reactions/create.ts9
-rw-r--r--src/server/api/endpoints/notes/renotes.ts2
-rw-r--r--src/server/api/endpoints/notes/replies.ts2
-rw-r--r--src/server/api/endpoints/notes/search-by-tag.ts2
-rw-r--r--src/server/api/endpoints/notes/search.ts2
-rw-r--r--src/server/api/endpoints/notes/timeline.ts2
-rw-r--r--src/server/api/endpoints/users.ts2
-rw-r--r--src/server/api/endpoints/users/lists/push.ts21
-rw-r--r--src/server/api/endpoints/users/notes.ts2
-rw-r--r--src/server/api/endpoints/users/recommendation.ts3
-rw-r--r--src/server/api/stream/channel.ts4
-rw-r--r--src/server/api/stream/channels/antenna.ts3
-rw-r--r--src/server/api/stream/channels/channel.ts3
-rw-r--r--src/server/api/stream/channels/global-timeline.ts3
-rw-r--r--src/server/api/stream/channels/hashtag.ts3
-rw-r--r--src/server/api/stream/channels/home-timeline.ts3
-rw-r--r--src/server/api/stream/channels/hybrid-timeline.ts3
-rw-r--r--src/server/api/stream/channels/local-timeline.ts3
-rw-r--r--src/server/api/stream/channels/user-list.ts3
-rw-r--r--src/server/api/stream/index.ts18
33 files changed, 196 insertions, 12 deletions
diff --git a/src/server/api/common/generate-block-query.ts b/src/server/api/common/generate-block-query.ts
index fa2179ae64..016da57aac 100644
--- a/src/server/api/common/generate-block-query.ts
+++ b/src/server/api/common/generate-block-query.ts
@@ -1,6 +1,29 @@
import { User } from '../../../models/entities/user';
import { Blockings } from '../../../models';
-import { SelectQueryBuilder } from 'typeorm';
+import { Brackets, SelectQueryBuilder } from 'typeorm';
+
+// ここでいうBlockedは被Blockedの意
+export function generateBlockedUserQuery(q: SelectQueryBuilder<any>, me: { id: User['id'] }) {
+ const blockingQuery = Blockings.createQueryBuilder('blocking')
+ .select('blocking.blockerId')
+ .where('blocking.blockeeId = :blockeeId', { blockeeId: me.id });
+
+ // 投稿の作者にブロックされていない かつ
+ // 投稿の返信先の作者にブロックされていない かつ
+ // 投稿の引用元の作者にブロックされていない
+ q
+ .andWhere(`note.userId NOT IN (${ blockingQuery.getQuery() })`)
+ .andWhere(new Brackets(qb => { qb
+ .where(`note.replyUserId IS NULL`)
+ .orWhere(`note.replyUserId NOT IN (${ blockingQuery.getQuery() })`);
+ }))
+ .andWhere(new Brackets(qb => { qb
+ .where(`note.renoteUserId IS NULL`)
+ .orWhere(`note.renoteUserId NOT IN (${ blockingQuery.getQuery() })`);
+ }));
+
+ q.setParameters(blockingQuery.getParameters());
+}
export function generateBlockQueryForUsers(q: SelectQueryBuilder<any>, me: { id: User['id'] }) {
const blockingQuery = Blockings.createQueryBuilder('blocking')
diff --git a/src/server/api/common/inject-featured.ts b/src/server/api/common/inject-featured.ts
index bbed7f69cb..3659b7f2b2 100644
--- a/src/server/api/common/inject-featured.ts
+++ b/src/server/api/common/inject-featured.ts
@@ -3,6 +3,7 @@ import { Note } from '../../../models/entities/note';
import { User } from '../../../models/entities/user';
import { Notes, UserProfiles, NoteReactions } from '../../../models';
import { generateMutedUserQuery } from './generate-muted-user-query';
+import { generateBlockedUserQuery } from './generate-block-query';
// TODO: リアクション、Renote、返信などをしたノートは除外する
@@ -29,6 +30,7 @@ export async function injectFeatured(timeline: Note[], user?: User | null) {
query.andWhere('note.userId != :userId', { userId: user.id });
generateMutedUserQuery(query, user);
+ generateBlockedUserQuery(query, user);
const reactionQuery = NoteReactions.createQueryBuilder('reaction')
.select('reaction.noteId')
diff --git a/src/server/api/endpoints/antennas/notes.ts b/src/server/api/endpoints/antennas/notes.ts
index a244f7f9b4..aadb4261e3 100644
--- a/src/server/api/endpoints/antennas/notes.ts
+++ b/src/server/api/endpoints/antennas/notes.ts
@@ -6,6 +6,7 @@ import { makePaginationQuery } from '../../common/make-pagination-query';
import { generateVisibilityQuery } from '../../common/generate-visibility-query';
import { generateMutedUserQuery } from '../../common/generate-muted-user-query';
import { ApiError } from '../../error';
+import { generateBlockedUserQuery } from '../../common/generate-block-query';
export const meta = {
tags: ['antennas', 'account', 'notes'],
@@ -77,6 +78,7 @@ export default define(meta, async (ps, user) => {
generateVisibilityQuery(query, user);
generateMutedUserQuery(query, user);
+ generateBlockedUserQuery(query, user);
const notes = await query
.take(ps.limit!)
diff --git a/src/server/api/endpoints/clips/notes.ts b/src/server/api/endpoints/clips/notes.ts
index 5fd17584d3..4bece5a2c8 100644
--- a/src/server/api/endpoints/clips/notes.ts
+++ b/src/server/api/endpoints/clips/notes.ts
@@ -6,6 +6,7 @@ import { makePaginationQuery } from '../../common/make-pagination-query';
import { generateVisibilityQuery } from '../../common/generate-visibility-query';
import { generateMutedUserQuery } from '../../common/generate-muted-user-query';
import { ApiError } from '../../error';
+import { generateBlockedUserQuery } from '../../common/generate-block-query';
export const meta = {
tags: ['account', 'notes', 'clips'],
@@ -81,6 +82,7 @@ export default define(meta, async (ps, user) => {
if (user) {
generateVisibilityQuery(query, user);
generateMutedUserQuery(query, user);
+ generateBlockedUserQuery(query, user);
}
const notes = await query
diff --git a/src/server/api/endpoints/messaging/messages/create.ts b/src/server/api/endpoints/messaging/messages/create.ts
index 1cd50145b3..a00513a24d 100644
--- a/src/server/api/endpoints/messaging/messages/create.ts
+++ b/src/server/api/endpoints/messaging/messages/create.ts
@@ -3,7 +3,7 @@ import { ID } from '@/misc/cafy-id';
import define from '../../../define';
import { ApiError } from '../../../error';
import { getUser } from '../../../common/getters';
-import { MessagingMessages, DriveFiles, UserGroups, UserGroupJoinings } from '../../../../../models';
+import { MessagingMessages, DriveFiles, UserGroups, UserGroupJoinings, Blockings } from '../../../../../models';
import { User } from '../../../../../models/entities/user';
import { UserGroup } from '../../../../../models/entities/user-group';
import { createMessage } from '../../../../../services/messages/create';
@@ -74,7 +74,13 @@ export const meta = {
message: 'Content required. You need to set text or fileId.',
code: 'CONTENT_REQUIRED',
id: '25587321-b0e6-449c-9239-f8925092942c'
- }
+ },
+
+ youHaveBeenBlocked: {
+ message: 'You cannot send a message because you have been blocked by this user.',
+ code: 'YOU_HAVE_BEEN_BLOCKED',
+ id: 'c15a5199-7422-4968-941a-2a462c478f7d'
+ },
}
};
@@ -93,6 +99,15 @@ export default define(meta, async (ps, user) => {
if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser);
throw e;
});
+
+ // Check blocking
+ const block = await Blockings.findOne({
+ blockerId: recipientUser.id,
+ blockeeId: user.id,
+ });
+ if (block) {
+ throw new ApiError(meta.errors.youHaveBeenBlocked);
+ }
} else if (ps.groupId != null) {
// Fetch recipient (group)
recipientGroup = await UserGroups.findOne(ps.groupId);
diff --git a/src/server/api/endpoints/notes/children.ts b/src/server/api/endpoints/notes/children.ts
index adbe714bf4..f4d2958810 100644
--- a/src/server/api/endpoints/notes/children.ts
+++ b/src/server/api/endpoints/notes/children.ts
@@ -6,6 +6,7 @@ import { generateVisibilityQuery } from '../../common/generate-visibility-query'
import { generateMutedUserQuery } from '../../common/generate-muted-user-query';
import { Brackets } from 'typeorm';
import { Notes } from '../../../../models';
+import { generateBlockedUserQuery } from '../../common/generate-block-query';
export const meta = {
tags: ['notes'],
@@ -63,6 +64,7 @@ export default define(meta, async (ps, user) => {
generateVisibilityQuery(query, user);
if (user) generateMutedUserQuery(query, user);
+ if (user) generateBlockedUserQuery(query, user);
const notes = await query.take(ps.limit!).getMany();
diff --git a/src/server/api/endpoints/notes/create.ts b/src/server/api/endpoints/notes/create.ts
index ddb5c953ec..9c055683f7 100644
--- a/src/server/api/endpoints/notes/create.ts
+++ b/src/server/api/endpoints/notes/create.ts
@@ -7,7 +7,7 @@ import { fetchMeta } from '@/misc/fetch-meta';
import { ApiError } from '../../error';
import { ID } from '@/misc/cafy-id';
import { User } from '../../../../models/entities/user';
-import { Users, DriveFiles, Notes, Channels } from '../../../../models';
+import { Users, DriveFiles, Notes, Channels, Blockings } from '../../../../models';
import { DriveFile } from '../../../../models/entities/drive-file';
import { Note } from '../../../../models/entities/note';
import { DB_MAX_NOTE_TEXT_LENGTH } from '@/misc/hard-limits';
@@ -171,6 +171,12 @@ export const meta = {
code: 'NO_SUCH_CHANNEL',
id: 'b1653923-5453-4edc-b786-7c4f39bb0bbb'
},
+
+ youHaveBeenBlocked: {
+ message: 'You have been blocked by this user.',
+ code: 'YOU_HAVE_BEEN_BLOCKED',
+ id: 'b390d7e1-8a5e-46ed-b625-06271cafd3d3'
+ },
}
};
@@ -202,6 +208,17 @@ export default define(meta, async (ps, user) => {
} else if (renote.renoteId && !renote.text && !renote.fileIds) {
throw new ApiError(meta.errors.cannotReRenote);
}
+
+ // Check blocking
+ if (renote.userId !== user.id) {
+ const block = await Blockings.findOne({
+ blockerId: renote.userId,
+ blockeeId: user.id,
+ });
+ if (block) {
+ throw new ApiError(meta.errors.youHaveBeenBlocked);
+ }
+ }
}
let reply: Note | undefined;
@@ -217,6 +234,17 @@ export default define(meta, async (ps, user) => {
if (reply.renoteId && !reply.text && !reply.fileIds) {
throw new ApiError(meta.errors.cannotReplyToPureRenote);
}
+
+ // Check blocking
+ if (reply.userId !== user.id) {
+ const block = await Blockings.findOne({
+ blockerId: reply.userId,
+ blockeeId: user.id,
+ });
+ if (block) {
+ throw new ApiError(meta.errors.youHaveBeenBlocked);
+ }
+ }
}
if (ps.poll) {
diff --git a/src/server/api/endpoints/notes/featured.ts b/src/server/api/endpoints/notes/featured.ts
index 5b4367f7a3..44c0fb23ab 100644
--- a/src/server/api/endpoints/notes/featured.ts
+++ b/src/server/api/endpoints/notes/featured.ts
@@ -2,6 +2,7 @@ import $ from 'cafy';
import define from '../../define';
import { generateMutedUserQuery } from '../../common/generate-muted-user-query';
import { Notes } from '../../../../models';
+import { generateBlockedUserQuery } from '../../common/generate-block-query';
export const meta = {
tags: ['notes'],
@@ -48,6 +49,7 @@ export default define(meta, async (ps, user) => {
.leftJoinAndSelect('renote.user', 'renoteUser');
if (user) generateMutedUserQuery(query, user);
+ if (user) generateBlockedUserQuery(query, user);
let notes = await query
.orderBy('note.score', 'DESC')
diff --git a/src/server/api/endpoints/notes/global-timeline.ts b/src/server/api/endpoints/notes/global-timeline.ts
index 741c5985a3..96bfde5aa2 100644
--- a/src/server/api/endpoints/notes/global-timeline.ts
+++ b/src/server/api/endpoints/notes/global-timeline.ts
@@ -9,6 +9,7 @@ import { generateMutedUserQuery } from '../../common/generate-muted-user-query';
import { activeUsersChart } from '../../../../services/chart';
import { generateRepliesQuery } from '../../common/generate-replies-query';
import { generateMutedNoteQuery } from '../../common/generate-muted-note-query';
+import { generateBlockedUserQuery } from '../../common/generate-block-query';
export const meta = {
tags: ['notes'],
@@ -81,6 +82,7 @@ export default define(meta, async (ps, user) => {
generateRepliesQuery(query, user);
if (user) generateMutedUserQuery(query, user);
if (user) generateMutedNoteQuery(query, user);
+ if (user) generateBlockedUserQuery(query, user);
if (ps.withFiles) {
query.andWhere('note.fileIds != \'{}\'');
diff --git a/src/server/api/endpoints/notes/hybrid-timeline.ts b/src/server/api/endpoints/notes/hybrid-timeline.ts
index 23fc5a6068..91a36fd0cc 100644
--- a/src/server/api/endpoints/notes/hybrid-timeline.ts
+++ b/src/server/api/endpoints/notes/hybrid-timeline.ts
@@ -12,6 +12,7 @@ import { activeUsersChart } from '../../../../services/chart';
import { generateRepliesQuery } from '../../common/generate-replies-query';
import { generateMutedNoteQuery } from '../../common/generate-muted-note-query';
import { generateChannelQuery } from '../../common/generate-channel-query';
+import { generateBlockedUserQuery } from '../../common/generate-block-query';
export const meta = {
tags: ['notes'],
@@ -108,6 +109,7 @@ export default define(meta, async (ps, user) => {
generateVisibilityQuery(query, user);
generateMutedUserQuery(query, user);
generateMutedNoteQuery(query, user);
+ generateBlockedUserQuery(query, user);
if (ps.includeMyRenotes === false) {
query.andWhere(new Brackets(qb => {
diff --git a/src/server/api/endpoints/notes/local-timeline.ts b/src/server/api/endpoints/notes/local-timeline.ts
index 523fbee9a8..4f481b599d 100644
--- a/src/server/api/endpoints/notes/local-timeline.ts
+++ b/src/server/api/endpoints/notes/local-timeline.ts
@@ -12,6 +12,7 @@ import { Brackets } from 'typeorm';
import { generateRepliesQuery } from '../../common/generate-replies-query';
import { generateMutedNoteQuery } from '../../common/generate-muted-note-query';
import { generateChannelQuery } from '../../common/generate-channel-query';
+import { generateBlockedUserQuery } from '../../common/generate-block-query';
export const meta = {
tags: ['notes'],
@@ -94,6 +95,7 @@ export default define(meta, async (ps, user) => {
generateVisibilityQuery(query, user);
if (user) generateMutedUserQuery(query, user);
if (user) generateMutedNoteQuery(query, user);
+ if (user) generateBlockedUserQuery(query, user);
if (ps.withFiles) {
query.andWhere('note.fileIds != \'{}\'');
diff --git a/src/server/api/endpoints/notes/mentions.ts b/src/server/api/endpoints/notes/mentions.ts
index e1e916c586..6a2358228b 100644
--- a/src/server/api/endpoints/notes/mentions.ts
+++ b/src/server/api/endpoints/notes/mentions.ts
@@ -7,6 +7,7 @@ import { generateVisibilityQuery } from '../../common/generate-visibility-query'
import { generateMutedUserQuery } from '../../common/generate-muted-user-query';
import { makePaginationQuery } from '../../common/make-pagination-query';
import { Brackets } from 'typeorm';
+import { generateBlockedUserQuery } from '../../common/generate-block-query';
export const meta = {
tags: ['notes'],
@@ -66,6 +67,7 @@ export default define(meta, async (ps, user) => {
generateVisibilityQuery(query, user);
generateMutedUserQuery(query, user);
+ generateBlockedUserQuery(query, user);
if (ps.visibility) {
query.andWhere('note.visibility = :visibility', { visibility: ps.visibility });
diff --git a/src/server/api/endpoints/notes/polls/vote.ts b/src/server/api/endpoints/notes/polls/vote.ts
index b40e187fd8..6f2892960f 100644
--- a/src/server/api/endpoints/notes/polls/vote.ts
+++ b/src/server/api/endpoints/notes/polls/vote.ts
@@ -9,7 +9,7 @@ import { deliver } from '../../../../../queue';
import { renderActivity } from '../../../../../remote/activitypub/renderer';
import renderVote from '../../../../../remote/activitypub/renderer/vote';
import { deliverQuestionUpdate } from '../../../../../services/note/polls/update';
-import { PollVotes, NoteWatchings, Users, Polls } from '../../../../../models';
+import { PollVotes, NoteWatchings, Users, Polls, Blockings } from '../../../../../models';
import { Not } from 'typeorm';
import { IRemoteUser } from '../../../../../models/entities/user';
import { genId } from '@/misc/gen-id';
@@ -61,6 +61,12 @@ export const meta = {
code: 'ALREADY_EXPIRED',
id: '1022a357-b085-4054-9083-8f8de358337e'
},
+
+ youHaveBeenBlocked: {
+ message: 'You cannot vote this poll because you have been blocked by this user.',
+ code: 'YOU_HAVE_BEEN_BLOCKED',
+ id: '85a5377e-b1e9-4617-b0b9-5bea73331e49'
+ },
}
};
@@ -77,6 +83,17 @@ export default define(meta, async (ps, user) => {
throw new ApiError(meta.errors.noPoll);
}
+ // Check blocking
+ if (note.userId !== user.id) {
+ const block = await Blockings.findOne({
+ blockerId: note.userId,
+ blockeeId: user.id,
+ });
+ if (block) {
+ throw new ApiError(meta.errors.youHaveBeenBlocked);
+ }
+ }
+
const poll = await Polls.findOneOrFail({ noteId: note.id });
if (poll.expiresAt && poll.expiresAt < createdAt) {
@@ -103,13 +120,13 @@ export default define(meta, async (ps, user) => {
}
// Create vote
- const vote = await PollVotes.save({
+ const vote = await PollVotes.insert({
id: genId(),
createdAt,
noteId: note.id,
userId: user.id,
choice: ps.choice
- });
+ }).then(x => PollVotes.findOneOrFail(x.identifiers[0]));
// Increment votes count
const index = ps.choice + 1; // In SQL, array index is 1 based
diff --git a/src/server/api/endpoints/notes/reactions/create.ts b/src/server/api/endpoints/notes/reactions/create.ts
index e8533fee56..3243332c50 100644
--- a/src/server/api/endpoints/notes/reactions/create.ts
+++ b/src/server/api/endpoints/notes/reactions/create.ts
@@ -33,7 +33,13 @@ export const meta = {
message: 'You are already reacting to that note.',
code: 'ALREADY_REACTED',
id: '71efcf98-86d6-4e2b-b2ad-9d032369366b'
- }
+ },
+
+ youHaveBeenBlocked: {
+ message: 'You cannot react this note because you have been blocked by this user.',
+ code: 'YOU_HAVE_BEEN_BLOCKED',
+ id: '20ef5475-9f38-4e4c-bd33-de6d979498ec'
+ },
}
};
@@ -44,6 +50,7 @@ export default define(meta, async (ps, user) => {
});
await createReaction(user, note, ps.reaction).catch(e => {
if (e.id === '51c42bb4-931a-456b-bff7-e5a8a70dd298') throw new ApiError(meta.errors.alreadyReacted);
+ if (e.id === 'e70412a4-7197-4726-8e74-f3e0deb92aa7') throw new ApiError(meta.errors.youHaveBeenBlocked);
throw e;
});
return;
diff --git a/src/server/api/endpoints/notes/renotes.ts b/src/server/api/endpoints/notes/renotes.ts
index d384b7962f..5e3b3ccbc6 100644
--- a/src/server/api/endpoints/notes/renotes.ts
+++ b/src/server/api/endpoints/notes/renotes.ts
@@ -7,6 +7,7 @@ import { generateVisibilityQuery } from '../../common/generate-visibility-query'
import { generateMutedUserQuery } from '../../common/generate-muted-user-query';
import { makePaginationQuery } from '../../common/make-pagination-query';
import { Notes } from '../../../../models';
+import { generateBlockedUserQuery } from '../../common/generate-block-query';
export const meta = {
tags: ['notes'],
@@ -67,6 +68,7 @@ export default define(meta, async (ps, user) => {
generateVisibilityQuery(query, user);
if (user) generateMutedUserQuery(query, user);
+ if (user) generateBlockedUserQuery(query, user);
const renotes = await query.take(ps.limit!).getMany();
diff --git a/src/server/api/endpoints/notes/replies.ts b/src/server/api/endpoints/notes/replies.ts
index 79a983e75f..7960078c8e 100644
--- a/src/server/api/endpoints/notes/replies.ts
+++ b/src/server/api/endpoints/notes/replies.ts
@@ -5,6 +5,7 @@ import { Notes } from '../../../../models';
import { makePaginationQuery } from '../../common/make-pagination-query';
import { generateVisibilityQuery } from '../../common/generate-visibility-query';
import { generateMutedUserQuery } from '../../common/generate-muted-user-query';
+import { generateBlockedUserQuery } from '../../common/generate-block-query';
export const meta = {
tags: ['notes'],
@@ -52,6 +53,7 @@ export default define(meta, async (ps, user) => {
generateVisibilityQuery(query, user);
if (user) generateMutedUserQuery(query, user);
+ if (user) generateBlockedUserQuery(query, user);
const timeline = await query.take(ps.limit!).getMany();
diff --git a/src/server/api/endpoints/notes/search-by-tag.ts b/src/server/api/endpoints/notes/search-by-tag.ts
index bbada17613..39d99babac 100644
--- a/src/server/api/endpoints/notes/search-by-tag.ts
+++ b/src/server/api/endpoints/notes/search-by-tag.ts
@@ -8,6 +8,7 @@ import { generateVisibilityQuery } from '../../common/generate-visibility-query'
import { Brackets } from 'typeorm';
import { safeForSql } from '@/misc/safe-for-sql';
import { normalizeForSearch } from '@/misc/normalize-for-search';
+import { generateBlockedUserQuery } from '../../common/generate-block-query';
export const meta = {
tags: ['notes', 'hashtags'],
@@ -75,6 +76,7 @@ export default define(meta, async (ps, me) => {
generateVisibilityQuery(query, me);
if (me) generateMutedUserQuery(query, me);
+ if (me) generateBlockedUserQuery(query, me);
try {
if (ps.tag) {
diff --git a/src/server/api/endpoints/notes/search.ts b/src/server/api/endpoints/notes/search.ts
index dc411283a2..0e0eaa06a8 100644
--- a/src/server/api/endpoints/notes/search.ts
+++ b/src/server/api/endpoints/notes/search.ts
@@ -8,6 +8,7 @@ import config from '@/config';
import { makePaginationQuery } from '../../common/make-pagination-query';
import { generateVisibilityQuery } from '../../common/generate-visibility-query';
import { generateMutedUserQuery } from '../../common/generate-muted-user-query';
+import { generateBlockedUserQuery } from '../../common/generate-block-query';
export const meta = {
tags: ['notes'],
@@ -82,6 +83,7 @@ export default define(meta, async (ps, me) => {
generateVisibilityQuery(query, me);
if (me) generateMutedUserQuery(query, me);
+ if (me) generateBlockedUserQuery(query, me);
const notes = await query.take(ps.limit!).getMany();
diff --git a/src/server/api/endpoints/notes/timeline.ts b/src/server/api/endpoints/notes/timeline.ts
index 687869a63d..5f03400919 100644
--- a/src/server/api/endpoints/notes/timeline.ts
+++ b/src/server/api/endpoints/notes/timeline.ts
@@ -10,6 +10,7 @@ import { Brackets } from 'typeorm';
import { generateRepliesQuery } from '../../common/generate-replies-query';
import { generateMutedNoteQuery } from '../../common/generate-muted-note-query';
import { generateChannelQuery } from '../../common/generate-channel-query';
+import { generateBlockedUserQuery } from '../../common/generate-block-query';
export const meta = {
tags: ['notes'],
@@ -100,6 +101,7 @@ export default define(meta, async (ps, user) => {
generateVisibilityQuery(query, user);
generateMutedUserQuery(query, user);
generateMutedNoteQuery(query, user);
+ generateBlockedUserQuery(query, user);
if (ps.includeMyRenotes === false) {
query.andWhere(new Brackets(qb => {
diff --git a/src/server/api/endpoints/users.ts b/src/server/api/endpoints/users.ts
index 933eb70b6f..3c30f459da 100644
--- a/src/server/api/endpoints/users.ts
+++ b/src/server/api/endpoints/users.ts
@@ -2,6 +2,7 @@ import $ from 'cafy';
import define from '../define';
import { Users } from '../../../models';
import { generateMutedUserQueryForUsers } from '../common/generate-muted-user-query';
+import { generateBlockedUserQuery } from '../common/generate-block-query';
export const meta = {
tags: ['users'],
@@ -89,6 +90,7 @@ export default define(meta, async (ps, me) => {
}
if (me) generateMutedUserQueryForUsers(query, me);
+ if (me) generateBlockedUserQuery(query, me);
query.take(ps.limit!);
query.skip(ps.offset);
diff --git a/src/server/api/endpoints/users/lists/push.ts b/src/server/api/endpoints/users/lists/push.ts
index b81d5b8c76..7bb6fc7f79 100644
--- a/src/server/api/endpoints/users/lists/push.ts
+++ b/src/server/api/endpoints/users/lists/push.ts
@@ -4,7 +4,7 @@ import define from '../../../define';
import { ApiError } from '../../../error';
import { getUser } from '../../../common/getters';
import { pushUserToUserList } from '../../../../../services/user-list/push';
-import { UserLists, UserListJoinings } from '../../../../../models';
+import { UserLists, UserListJoinings, Blockings } from '../../../../../models';
export const meta = {
tags: ['lists', 'users'],
@@ -40,7 +40,13 @@ export const meta = {
message: 'That user has already been added to that list.',
code: 'ALREADY_ADDED',
id: '1de7c884-1595-49e9-857e-61f12f4d4fc5'
- }
+ },
+
+ youHaveBeenBlocked: {
+ message: 'You cannot push this user because you have been blocked by this user.',
+ code: 'YOU_HAVE_BEEN_BLOCKED',
+ id: '990232c5-3f9d-4d83-9f3f-ef27b6332a4b'
+ },
}
};
@@ -61,6 +67,17 @@ export default define(meta, async (ps, me) => {
throw e;
});
+ // Check blocking
+ if (user.id !== me.id) {
+ const block = await Blockings.findOne({
+ blockerId: user.id,
+ blockeeId: me.id,
+ });
+ if (block) {
+ throw new ApiError(meta.errors.youHaveBeenBlocked);
+ }
+ }
+
const exist = await UserListJoinings.findOne({
userListId: userList.id,
userId: user.id
diff --git a/src/server/api/endpoints/users/notes.ts b/src/server/api/endpoints/users/notes.ts
index 55f07e390b..836c3c97b7 100644
--- a/src/server/api/endpoints/users/notes.ts
+++ b/src/server/api/endpoints/users/notes.ts
@@ -8,6 +8,7 @@ import { generateVisibilityQuery } from '../../common/generate-visibility-query'
import { Notes } from '../../../../models';
import { generateMutedUserQuery } from '../../common/generate-muted-user-query';
import { Brackets } from 'typeorm';
+import { generateBlockedUserQuery } from '../../common/generate-block-query';
export const meta = {
tags: ['users', 'notes'],
@@ -100,6 +101,7 @@ export default define(meta, async (ps, me) => {
generateVisibilityQuery(query, me);
if (me) generateMutedUserQuery(query, me, user);
+ if (me) generateBlockedUserQuery(query, me);
if (ps.withFiles) {
query.andWhere('note.fileIds != \'{}\'');
diff --git a/src/server/api/endpoints/users/recommendation.ts b/src/server/api/endpoints/users/recommendation.ts
index 7c269268bf..fba4f4f682 100644
--- a/src/server/api/endpoints/users/recommendation.ts
+++ b/src/server/api/endpoints/users/recommendation.ts
@@ -3,7 +3,7 @@ import $ from 'cafy';
import define from '../../define';
import { Users, Followings } from '../../../../models';
import { generateMutedUserQueryForUsers } from '../../common/generate-muted-user-query';
-import { generateBlockQueryForUsers } from '../../common/generate-block-query';
+import { generateBlockedUserQuery, generateBlockQueryForUsers } from '../../common/generate-block-query';
export const meta = {
tags: ['users'],
@@ -46,6 +46,7 @@ export default define(meta, async (ps, me) => {
generateMutedUserQueryForUsers(query, me);
generateBlockQueryForUsers(query, me);
+ generateBlockedUserQuery(query, me);
const followingQuery = Followings.createQueryBuilder('following')
.select('following.followeeId')
diff --git a/src/server/api/stream/channel.ts b/src/server/api/stream/channel.ts
index 9b7c31e7bb..2824d7d1b8 100644
--- a/src/server/api/stream/channel.ts
+++ b/src/server/api/stream/channel.ts
@@ -27,6 +27,10 @@ export default abstract class Channel {
return this.connection.muting;
}
+ protected get blocking() {
+ return this.connection.blocking;
+ }
+
protected get followingChannels() {
return this.connection.followingChannels;
}
diff --git a/src/server/api/stream/channels/antenna.ts b/src/server/api/stream/channels/antenna.ts
index d93143f4d8..db4fab8412 100644
--- a/src/server/api/stream/channels/antenna.ts
+++ b/src/server/api/stream/channels/antenna.ts
@@ -2,6 +2,7 @@ import autobind from 'autobind-decorator';
import Channel from '../channel';
import { Notes } from '../../../../models';
import { isMutedUserRelated } from '@/misc/is-muted-user-related';
+import { isBlockerUserRelated } from '@/misc/is-blocker-user-related';
export default class extends Channel {
public readonly chName = 'antenna';
@@ -26,6 +27,8 @@ export default class extends Channel {
// 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
if (isMutedUserRelated(note, this.muting)) return;
+ // 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
+ if (isBlockerUserRelated(note, this.blocking)) return;
this.connection.cacheNote(note);
diff --git a/src/server/api/stream/channels/channel.ts b/src/server/api/stream/channels/channel.ts
index 6af2d80e0c..7910f0f2f8 100644
--- a/src/server/api/stream/channels/channel.ts
+++ b/src/server/api/stream/channels/channel.ts
@@ -2,6 +2,7 @@ import autobind from 'autobind-decorator';
import Channel from '../channel';
import { Notes, Users } from '../../../../models';
import { isMutedUserRelated } from '@/misc/is-muted-user-related';
+import { isBlockerUserRelated } from '@/misc/is-blocker-user-related';
import { PackedNote } from '../../../../models/repositories/note';
import { User } from '../../../../models/entities/user';
@@ -42,6 +43,8 @@ export default class extends Channel {
// 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
if (isMutedUserRelated(note, this.muting)) return;
+ // 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
+ if (isBlockerUserRelated(note, this.blocking)) return;
this.connection.cacheNote(note);
diff --git a/src/server/api/stream/channels/global-timeline.ts b/src/server/api/stream/channels/global-timeline.ts
index c59eb37779..02792bffa4 100644
--- a/src/server/api/stream/channels/global-timeline.ts
+++ b/src/server/api/stream/channels/global-timeline.ts
@@ -5,6 +5,7 @@ import { fetchMeta } from '@/misc/fetch-meta';
import { Notes } from '../../../../models';
import { PackedNote } from '../../../../models/repositories/note';
import { checkWordMute } from '@/misc/check-word-mute';
+import { isBlockerUserRelated } from '@/misc/is-blocker-user-related';
export default class extends Channel {
public readonly chName = 'globalTimeline';
@@ -49,6 +50,8 @@ export default class extends Channel {
// 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
if (isMutedUserRelated(note, this.muting)) return;
+ // 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
+ if (isBlockerUserRelated(note, this.blocking)) return;
// 流れてきたNoteがミュートすべきNoteだったら無視する
// TODO: 将来的には、単にMutedNoteテーブルにレコードがあるかどうかで判定したい(以下の理由により難しそうではある)
diff --git a/src/server/api/stream/channels/hashtag.ts b/src/server/api/stream/channels/hashtag.ts
index b662af0723..4cabd4db62 100644
--- a/src/server/api/stream/channels/hashtag.ts
+++ b/src/server/api/stream/channels/hashtag.ts
@@ -4,6 +4,7 @@ import Channel from '../channel';
import { Notes } from '../../../../models';
import { PackedNote } from '../../../../models/repositories/note';
import { normalizeForSearch } from '@/misc/normalize-for-search';
+import { isBlockerUserRelated } from '@/misc/is-blocker-user-related';
export default class extends Channel {
public readonly chName = 'hashtag';
@@ -36,6 +37,8 @@ export default class extends Channel {
// 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
if (isMutedUserRelated(note, this.muting)) return;
+ // 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
+ if (isBlockerUserRelated(note, this.blocking)) return;
this.connection.cacheNote(note);
diff --git a/src/server/api/stream/channels/home-timeline.ts b/src/server/api/stream/channels/home-timeline.ts
index b1091a46e1..7659b5ffa3 100644
--- a/src/server/api/stream/channels/home-timeline.ts
+++ b/src/server/api/stream/channels/home-timeline.ts
@@ -4,6 +4,7 @@ import Channel from '../channel';
import { Notes } from '../../../../models';
import { PackedNote } from '../../../../models/repositories/note';
import { checkWordMute } from '@/misc/check-word-mute';
+import { isBlockerUserRelated } from '@/misc/is-blocker-user-related';
export default class extends Channel {
public readonly chName = 'homeTimeline';
@@ -57,6 +58,8 @@ export default class extends Channel {
// 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
if (isMutedUserRelated(note, this.muting)) return;
+ // 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
+ if (isBlockerUserRelated(note, this.blocking)) return;
// 流れてきたNoteがミュートすべきNoteだったら無視する
// TODO: 将来的には、単にMutedNoteテーブルにレコードがあるかどうかで判定したい(以下の理由により難しそうではある)
diff --git a/src/server/api/stream/channels/hybrid-timeline.ts b/src/server/api/stream/channels/hybrid-timeline.ts
index d769a24373..664435f674 100644
--- a/src/server/api/stream/channels/hybrid-timeline.ts
+++ b/src/server/api/stream/channels/hybrid-timeline.ts
@@ -6,6 +6,7 @@ import { Notes } from '../../../../models';
import { PackedNote } from '../../../../models/repositories/note';
import { PackedUser } from '../../../../models/repositories/user';
import { checkWordMute } from '@/misc/check-word-mute';
+import { isBlockerUserRelated } from '@/misc/is-blocker-user-related';
export default class extends Channel {
public readonly chName = 'hybridTimeline';
@@ -66,6 +67,8 @@ export default class extends Channel {
// 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
if (isMutedUserRelated(note, this.muting)) return;
+ // 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
+ if (isBlockerUserRelated(note, this.blocking)) return;
// 流れてきたNoteがミュートすべきNoteだったら無視する
// TODO: 将来的には、単にMutedNoteテーブルにレコードがあるかどうかで判定したい(以下の理由により難しそうではある)
diff --git a/src/server/api/stream/channels/local-timeline.ts b/src/server/api/stream/channels/local-timeline.ts
index aa0b6c4026..528059daba 100644
--- a/src/server/api/stream/channels/local-timeline.ts
+++ b/src/server/api/stream/channels/local-timeline.ts
@@ -6,6 +6,7 @@ import { Notes } from '../../../../models';
import { PackedNote } from '../../../../models/repositories/note';
import { PackedUser } from '../../../../models/repositories/user';
import { checkWordMute } from '@/misc/check-word-mute';
+import { isBlockerUserRelated } from '@/misc/is-blocker-user-related';
export default class extends Channel {
public readonly chName = 'localTimeline';
@@ -51,6 +52,8 @@ export default class extends Channel {
// 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
if (isMutedUserRelated(note, this.muting)) return;
+ // 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
+ if (isBlockerUserRelated(note, this.blocking)) return;
// 流れてきたNoteがミュートすべきNoteだったら無視する
// TODO: 将来的には、単にMutedNoteテーブルにレコードがあるかどうかで判定したい(以下の理由により難しそうではある)
diff --git a/src/server/api/stream/channels/user-list.ts b/src/server/api/stream/channels/user-list.ts
index da227f24ec..1f42fbe49e 100644
--- a/src/server/api/stream/channels/user-list.ts
+++ b/src/server/api/stream/channels/user-list.ts
@@ -4,6 +4,7 @@ import { Notes, UserListJoinings, UserLists } from '../../../../models';
import { isMutedUserRelated } from '@/misc/is-muted-user-related';
import { User } from '../../../../models/entities/user';
import { PackedNote } from '../../../../models/repositories/note';
+import { isBlockerUserRelated } from '@/misc/is-blocker-user-related';
export default class extends Channel {
public readonly chName = 'userList';
@@ -74,6 +75,8 @@ export default class extends Channel {
// 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
if (isMutedUserRelated(note, this.muting)) return;
+ // 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
+ if (isBlockerUserRelated(note, this.blocking)) return;
this.send('note', note);
}
diff --git a/src/server/api/stream/index.ts b/src/server/api/stream/index.ts
index 75d82cfe66..96d4194a7d 100644
--- a/src/server/api/stream/index.ts
+++ b/src/server/api/stream/index.ts
@@ -8,7 +8,7 @@ import channels from './channels';
import { EventEmitter } from 'events';
import { User } from '../../../models/entities/user';
import { Channel as ChannelModel } from '../../../models/entities/channel';
-import { Users, Followings, Mutings, UserProfiles, ChannelFollowings } from '../../../models';
+import { Users, Followings, Mutings, UserProfiles, ChannelFollowings, Blockings } from '../../../models';
import { ApiError } from '../error';
import { AccessToken } from '../../../models/entities/access-token';
import { UserProfile } from '../../../models/entities/user-profile';
@@ -24,6 +24,7 @@ export default class Connection {
public userProfile?: UserProfile;
public following: Set<User['id']> = new Set();
public muting: Set<User['id']> = new Set();
+ public blocking: Set<User['id']> = new Set(); // "被"blocking
public followingChannels: Set<ChannelModel['id']> = new Set();
public token?: AccessToken;
private wsConnection: websocket.connection;
@@ -52,6 +53,7 @@ export default class Connection {
if (this.user) {
this.updateFollowing();
this.updateMuting();
+ this.updateBlocking();
this.updateFollowingChannels();
this.updateUserProfile();
@@ -80,6 +82,8 @@ export default class Connection {
this.muting.delete(body.id);
break;
+ // TODO: block events
+
case 'followChannel':
this.followingChannels.add(body.id);
break;
@@ -376,6 +380,18 @@ export default class Connection {
}
@autobind
+ private async updateBlocking() { // ここでいうBlockingは被Blockingの意
+ const blockings = await Blockings.find({
+ where: {
+ blockeeId: this.user!.id
+ },
+ select: ['blockerId']
+ });
+
+ this.blocking = new Set<string>(blockings.map(x => x.blockerId));
+ }
+
+ @autobind
private async updateFollowingChannels() {
const followings = await ChannelFollowings.find({
where: {