parent
b5a1fdd4c7
commit
cf43dd6ec5
32 changed files with 485 additions and 12 deletions
13
src/server/api/common/generate-muted-note-query.ts
Normal file
13
src/server/api/common/generate-muted-note-query.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { User } from '../../../models/entities/user';
|
||||
import { MutedNotes } from '../../../models';
|
||||
import { SelectQueryBuilder } from 'typeorm';
|
||||
|
||||
export function generateMutedNoteQuery(q: SelectQueryBuilder<any>, me: User) {
|
||||
const mutedQuery = MutedNotes.createQueryBuilder('muted')
|
||||
.select('muted.noteId')
|
||||
.where('muted.userId = :userId', { userId: me.id });
|
||||
|
||||
q.andWhere(`note.id NOT IN (${ mutedQuery.getQuery() })`);
|
||||
|
||||
q.setParameters(mutedQuery.getParameters());
|
||||
}
|
|
@ -142,7 +142,11 @@ export const meta = {
|
|||
desc: {
|
||||
'ja-JP': 'ピン留めするページID'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
mutedWords: {
|
||||
validator: $.optional.arr($.arr($.str))
|
||||
},
|
||||
},
|
||||
|
||||
errors: {
|
||||
|
@ -193,6 +197,10 @@ export default define(meta, async (ps, user, token) => {
|
|||
if (ps.birthday !== undefined) profileUpdates.birthday = ps.birthday;
|
||||
if (ps.avatarId !== undefined) updates.avatarId = ps.avatarId;
|
||||
if (ps.bannerId !== undefined) updates.bannerId = ps.bannerId;
|
||||
if (ps.mutedWords !== undefined) {
|
||||
profileUpdates.mutedWords = ps.mutedWords;
|
||||
profileUpdates.enableWordMute = ps.mutedWords.length > 0;
|
||||
}
|
||||
if (typeof ps.isLocked === 'boolean') updates.isLocked = ps.isLocked;
|
||||
if (typeof ps.isBot === 'boolean') updates.isBot = ps.isBot;
|
||||
if (typeof ps.carefulBot === 'boolean') profileUpdates.carefulBot = ps.carefulBot;
|
||||
|
|
|
@ -10,6 +10,7 @@ import { activeUsersChart } from '../../../../services/chart';
|
|||
import { generateRepliesQuery } from '../../common/generate-replies-query';
|
||||
import { injectPromo } from '../../common/inject-promo';
|
||||
import { injectFeatured } from '../../common/inject-featured';
|
||||
import { generateMutedNoteQuery } from '../../common/generate-muted-note-query';
|
||||
|
||||
export const meta = {
|
||||
desc: {
|
||||
|
@ -83,6 +84,7 @@ export default define(meta, async (ps, user) => {
|
|||
|
||||
generateRepliesQuery(query, user);
|
||||
if (user) generateMuteQuery(query, user);
|
||||
if (user) generateMutedNoteQuery(query, user);
|
||||
|
||||
if (ps.withFiles) {
|
||||
query.andWhere('note.fileIds != \'{}\'');
|
||||
|
|
|
@ -12,6 +12,7 @@ import { activeUsersChart } from '../../../../services/chart';
|
|||
import { generateRepliesQuery } from '../../common/generate-replies-query';
|
||||
import { injectPromo } from '../../common/inject-promo';
|
||||
import { injectFeatured } from '../../common/inject-featured';
|
||||
import { generateMutedNoteQuery } from '../../common/generate-muted-note-query';
|
||||
|
||||
export const meta = {
|
||||
desc: {
|
||||
|
@ -133,6 +134,7 @@ export default define(meta, async (ps, user) => {
|
|||
generateRepliesQuery(query, user);
|
||||
generateVisibilityQuery(query, user);
|
||||
generateMuteQuery(query, user);
|
||||
generateMutedNoteQuery(query, user);
|
||||
|
||||
if (ps.includeMyRenotes === false) {
|
||||
query.andWhere(new Brackets(qb => {
|
||||
|
|
|
@ -12,6 +12,7 @@ import { Brackets } from 'typeorm';
|
|||
import { generateRepliesQuery } from '../../common/generate-replies-query';
|
||||
import { injectPromo } from '../../common/inject-promo';
|
||||
import { injectFeatured } from '../../common/inject-featured';
|
||||
import { generateMutedNoteQuery } from '../../common/generate-muted-note-query';
|
||||
|
||||
export const meta = {
|
||||
desc: {
|
||||
|
@ -101,6 +102,7 @@ export default define(meta, async (ps, user) => {
|
|||
generateRepliesQuery(query, user);
|
||||
generateVisibilityQuery(query, user);
|
||||
if (user) generateMuteQuery(query, user);
|
||||
if (user) generateMutedNoteQuery(query, user);
|
||||
|
||||
if (ps.withFiles) {
|
||||
query.andWhere('note.fileIds != \'{}\'');
|
||||
|
|
|
@ -10,6 +10,7 @@ import { Brackets } from 'typeorm';
|
|||
import { generateRepliesQuery } from '../../common/generate-replies-query';
|
||||
import { injectPromo } from '../../common/inject-promo';
|
||||
import { injectFeatured } from '../../common/inject-featured';
|
||||
import { generateMutedNoteQuery } from '../../common/generate-muted-note-query';
|
||||
|
||||
export const meta = {
|
||||
desc: {
|
||||
|
@ -126,6 +127,7 @@ export default define(meta, async (ps, user) => {
|
|||
generateRepliesQuery(query, user);
|
||||
generateVisibilityQuery(query, user);
|
||||
generateMuteQuery(query, user);
|
||||
generateMutedNoteQuery(query, user);
|
||||
|
||||
if (ps.includeMyRenotes === false) {
|
||||
query.andWhere(new Brackets(qb => {
|
||||
|
|
|
@ -15,6 +15,10 @@ export default abstract class Channel {
|
|||
return this.connection.user;
|
||||
}
|
||||
|
||||
protected get userProfile() {
|
||||
return this.connection.userProfile;
|
||||
}
|
||||
|
||||
protected get following() {
|
||||
return this.connection.following;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import Channel from '../channel';
|
|||
import { fetchMeta } from '../../../../misc/fetch-meta';
|
||||
import { Notes } from '../../../../models';
|
||||
import { PackedNote } from '../../../../models/repositories/note';
|
||||
import { checkWordMute } from '../../../../misc/check-word-mute';
|
||||
|
||||
export default class extends Channel {
|
||||
public readonly chName = 'globalTimeline';
|
||||
|
@ -47,6 +48,13 @@ export default class extends Channel {
|
|||
// 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
|
||||
if (shouldMuteThisNote(note, this.muting)) return;
|
||||
|
||||
// 流れてきたNoteがミュートすべきNoteだったら無視する
|
||||
// TODO: 将来的には、単にMutedNoteテーブルにレコードがあるかどうかで判定したい(以下の理由により難しそうではある)
|
||||
// 現状では、ワードミュートにおけるMutedNoteレコードの追加処理はストリーミングに流す処理と並列で行われるため、
|
||||
// レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。
|
||||
// そのためレコードが存在するかのチェックでは不十分なので、改めてcheckWordMuteを呼んでいる
|
||||
if (this.userProfile && await checkWordMute(note, this.user, this.userProfile.mutedWords)) return;
|
||||
|
||||
this.send('note', note);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ import shouldMuteThisNote from '../../../../misc/should-mute-this-note';
|
|||
import Channel from '../channel';
|
||||
import { Notes } from '../../../../models';
|
||||
import { PackedNote } from '../../../../models/repositories/note';
|
||||
import { checkWordMute } from '../../../../misc/check-word-mute';
|
||||
|
||||
export default class extends Channel {
|
||||
public readonly chName = 'homeTimeline';
|
||||
|
@ -52,6 +53,13 @@ export default class extends Channel {
|
|||
// 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
|
||||
if (shouldMuteThisNote(note, this.muting)) return;
|
||||
|
||||
// 流れてきたNoteがミュートすべきNoteだったら無視する
|
||||
// TODO: 将来的には、単にMutedNoteテーブルにレコードがあるかどうかで判定したい(以下の理由により難しそうではある)
|
||||
// 現状では、ワードミュートにおけるMutedNoteレコードの追加処理はストリーミングに流す処理と並列で行われるため、
|
||||
// レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。
|
||||
// そのためレコードが存在するかのチェックでは不十分なので、改めてcheckWordMuteを呼んでいる
|
||||
if (this.userProfile && await checkWordMute(note, this.user, this.userProfile.mutedWords)) return;
|
||||
|
||||
this.send('note', note);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import { fetchMeta } from '../../../../misc/fetch-meta';
|
|||
import { Notes } from '../../../../models';
|
||||
import { PackedNote } from '../../../../models/repositories/note';
|
||||
import { PackedUser } from '../../../../models/repositories/user';
|
||||
import { checkWordMute } from '../../../../misc/check-word-mute';
|
||||
|
||||
export default class extends Channel {
|
||||
public readonly chName = 'hybridTimeline';
|
||||
|
@ -61,6 +62,13 @@ export default class extends Channel {
|
|||
// 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
|
||||
if (shouldMuteThisNote(note, this.muting)) return;
|
||||
|
||||
// 流れてきたNoteがミュートすべきNoteだったら無視する
|
||||
// TODO: 将来的には、単にMutedNoteテーブルにレコードがあるかどうかで判定したい(以下の理由により難しそうではある)
|
||||
// 現状では、ワードミュートにおけるMutedNoteレコードの追加処理はストリーミングに流す処理と並列で行われるため、
|
||||
// レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。
|
||||
// そのためレコードが存在するかのチェックでは不十分なので、改めてcheckWordMuteを呼んでいる
|
||||
if (this.userProfile && await checkWordMute(note, this.user, this.userProfile.mutedWords)) return;
|
||||
|
||||
this.send('note', note);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import { fetchMeta } from '../../../../misc/fetch-meta';
|
|||
import { Notes } from '../../../../models';
|
||||
import { PackedNote } from '../../../../models/repositories/note';
|
||||
import { PackedUser } from '../../../../models/repositories/user';
|
||||
import { checkWordMute } from '../../../../misc/check-word-mute';
|
||||
|
||||
export default class extends Channel {
|
||||
public readonly chName = 'localTimeline';
|
||||
|
@ -49,6 +50,13 @@ export default class extends Channel {
|
|||
// 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
|
||||
if (shouldMuteThisNote(note, this.muting)) return;
|
||||
|
||||
// 流れてきたNoteがミュートすべきNoteだったら無視する
|
||||
// TODO: 将来的には、単にMutedNoteテーブルにレコードがあるかどうかで判定したい(以下の理由により難しそうではある)
|
||||
// 現状では、ワードミュートにおけるMutedNoteレコードの追加処理はストリーミングに流す処理と並列で行われるため、
|
||||
// レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。
|
||||
// そのためレコードが存在するかのチェックでは不十分なので、改めてcheckWordMuteを呼んでいる
|
||||
if (this.userProfile && await checkWordMute(note, this.user, this.userProfile.mutedWords)) return;
|
||||
|
||||
this.send('note', note);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,15 +7,17 @@ import Channel from './channel';
|
|||
import channels from './channels';
|
||||
import { EventEmitter } from 'events';
|
||||
import { User } from '../../../models/entities/user';
|
||||
import { Users, Followings, Mutings } from '../../../models';
|
||||
import { Users, Followings, Mutings, UserProfiles } from '../../../models';
|
||||
import { ApiError } from '../error';
|
||||
import { AccessToken } from '../../../models/entities/access-token';
|
||||
import { UserProfile } from '../../../models/entities/user-profile';
|
||||
|
||||
/**
|
||||
* Main stream connection
|
||||
*/
|
||||
export default class Connection {
|
||||
public user?: User;
|
||||
public userProfile?: UserProfile;
|
||||
public following: User['id'][] = [];
|
||||
public muting: User['id'][] = [];
|
||||
public token?: AccessToken;
|
||||
|
@ -25,6 +27,7 @@ export default class Connection {
|
|||
private subscribingNotes: any = {};
|
||||
private followingClock: NodeJS.Timer;
|
||||
private mutingClock: NodeJS.Timer;
|
||||
private userProfileClock: NodeJS.Timer;
|
||||
|
||||
constructor(
|
||||
wsConnection: websocket.connection,
|
||||
|
@ -49,6 +52,9 @@ export default class Connection {
|
|||
|
||||
this.updateMuting();
|
||||
this.mutingClock = setInterval(this.updateMuting, 5000);
|
||||
|
||||
this.updateUserProfile();
|
||||
this.userProfileClock = setInterval(this.updateUserProfile, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -262,6 +268,13 @@ export default class Connection {
|
|||
this.muting = mutings.map(x => x.muteeId);
|
||||
}
|
||||
|
||||
@autobind
|
||||
private async updateUserProfile() {
|
||||
this.userProfile = await UserProfiles.findOne({
|
||||
userId: this.user!.id
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* ストリームが切れたとき
|
||||
*/
|
||||
|
@ -273,5 +286,6 @@ export default class Connection {
|
|||
|
||||
if (this.followingClock) clearInterval(this.followingClock);
|
||||
if (this.mutingClock) clearInterval(this.mutingClock);
|
||||
if (this.userProfileClock) clearInterval(this.userProfileClock);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue