From 87d3a06dcd6a76120789c050dd6a0c7111bf7224 Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 8 Apr 2019 23:05:41 +0900 Subject: revert rename --- src/server/api/endpoints/notes/hybrid-timeline.ts | 195 ++++++++++++++++++++++ src/server/api/endpoints/notes/social-timeline.ts | 195 ---------------------- src/server/api/stream/channels/hybrid-timeline.ts | 64 +++++++ src/server/api/stream/channels/index.ts | 4 +- src/server/api/stream/channels/social-timeline.ts | 64 ------- 5 files changed, 261 insertions(+), 261 deletions(-) create mode 100644 src/server/api/endpoints/notes/hybrid-timeline.ts delete mode 100644 src/server/api/endpoints/notes/social-timeline.ts create mode 100644 src/server/api/stream/channels/hybrid-timeline.ts delete mode 100644 src/server/api/stream/channels/social-timeline.ts (limited to 'src/server/api') diff --git a/src/server/api/endpoints/notes/hybrid-timeline.ts b/src/server/api/endpoints/notes/hybrid-timeline.ts new file mode 100644 index 0000000000..76f1682a95 --- /dev/null +++ b/src/server/api/endpoints/notes/hybrid-timeline.ts @@ -0,0 +1,195 @@ +import $ from 'cafy'; +import { ID } from '../../../../misc/cafy-id'; +import define from '../../define'; +import fetchMeta from '../../../../misc/fetch-meta'; +import { ApiError } from '../../error'; +import { makePaginationQuery } from '../../common/make-pagination-query'; +import { Followings, Notes } from '../../../../models'; +import { Brackets } from 'typeorm'; +import { generateVisibilityQuery } from '../../common/generate-visibility-query'; +import { generateMuteQuery } from '../../common/generate-mute-query'; +import { activeUsersChart } from '../../../../services/chart'; + +export const meta = { + desc: { + 'ja-JP': 'ソーシャルタイムラインを取得します。' + }, + + tags: ['notes'], + + params: { + limit: { + validator: $.optional.num.range(1, 100), + default: 10, + desc: { + 'ja-JP': '最大数' + } + }, + + sinceId: { + validator: $.optional.type(ID), + desc: { + 'ja-JP': '指定すると、その投稿を基点としてより新しい投稿を取得します' + } + }, + + untilId: { + validator: $.optional.type(ID), + desc: { + 'ja-JP': '指定すると、その投稿を基点としてより古い投稿を取得します' + } + }, + + sinceDate: { + validator: $.optional.num, + desc: { + 'ja-JP': '指定した時間を基点としてより新しい投稿を取得します。数値は、1970年1月1日 00:00:00 UTC から指定した日時までの経過時間をミリ秒単位で表します。' + } + }, + + untilDate: { + validator: $.optional.num, + desc: { + 'ja-JP': '指定した時間を基点としてより古い投稿を取得します。数値は、1970年1月1日 00:00:00 UTC から指定した日時までの経過時間をミリ秒単位で表します。' + } + }, + + includeMyRenotes: { + validator: $.optional.bool, + default: true, + desc: { + 'ja-JP': '自分の行ったRenoteを含めるかどうか' + } + }, + + includeRenotedMyNotes: { + validator: $.optional.bool, + default: true, + desc: { + 'ja-JP': 'Renoteされた自分の投稿を含めるかどうか' + } + }, + + includeLocalRenotes: { + validator: $.optional.bool, + default: true, + desc: { + 'ja-JP': 'Renoteされたローカルの投稿を含めるかどうか' + } + }, + + withFiles: { + validator: $.optional.bool, + desc: { + 'ja-JP': 'true にすると、ファイルが添付された投稿だけ取得します' + } + }, + }, + + res: { + type: 'array', + items: { + type: 'Note', + }, + }, + + errors: { + stlDisabled: { + message: 'Hybrid timeline has been disabled.', + code: 'STL_DISABLED', + id: '620763f4-f621-4533-ab33-0577a1a3c342' + }, + } +}; + +export default define(meta, async (ps, user) => { + // TODO どっかにキャッシュ + const m = await fetchMeta(); + if (m.disableLocalTimeline && !user.isAdmin && !user.isModerator) { + throw new ApiError(meta.errors.stlDisabled); + } + + //#region Construct query + const followingQuery = Followings.createQueryBuilder('following') + .select('following.followeeId') + .where('following.followerId = :followerId', { followerId: user.id }); + + const query = makePaginationQuery(Notes.createQueryBuilder('note'), + ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) + .andWhere(new Brackets(qb => { + qb.where(`((note.userId IN (${ followingQuery.getQuery() })) OR (note.userId = :meId))`, { meId: user.id }) + .orWhere('(note.visibility = \'public\') AND (note.userHost IS NULL)'); + })) + .leftJoinAndSelect('note.user', 'user') + .setParameters(followingQuery.getParameters()); + + generateVisibilityQuery(query, user); + generateMuteQuery(query, user); + + /* TODO + // MongoDBではトップレベルで否定ができないため、De Morganの法則を利用してクエリします。 + // つまり、「『自分の投稿かつRenote』ではない」を「『自分の投稿ではない』または『Renoteではない』」と表現します。 + // for details: https://en.wikipedia.org/wiki/De_Morgan%27s_laws + + if (ps.includeMyRenotes === false) { + query.$and.push({ + $or: [{ + userId: { $ne: user.id } + }, { + renoteId: null + }, { + text: { $ne: null } + }, { + fileIds: { $ne: [] } + }, { + poll: { $ne: null } + }] + }); + } + + if (ps.includeRenotedMyNotes === false) { + query.$and.push({ + $or: [{ + '_renote.userId': { $ne: user.id } + }, { + renoteId: null + }, { + text: { $ne: null } + }, { + fileIds: { $ne: [] } + }, { + poll: { $ne: null } + }] + }); + } + + if (ps.includeLocalRenotes === false) { + query.$and.push({ + $or: [{ + '_renote.user.host': { $ne: null } + }, { + renoteId: null + }, { + text: { $ne: null } + }, { + fileIds: { $ne: [] } + }, { + poll: { $ne: null } + }] + }); + } + */ + + if (ps.withFiles) { + query.andWhere('note.fileIds != \'{}\''); + } + //#endregion + + const timeline = await query.take(ps.limit).getMany(); + + if (user) { + activeUsersChart.update(user); + } + + return await Notes.packMany(timeline, user); +}); diff --git a/src/server/api/endpoints/notes/social-timeline.ts b/src/server/api/endpoints/notes/social-timeline.ts deleted file mode 100644 index 10e215d6c4..0000000000 --- a/src/server/api/endpoints/notes/social-timeline.ts +++ /dev/null @@ -1,195 +0,0 @@ -import $ from 'cafy'; -import { ID } from '../../../../misc/cafy-id'; -import define from '../../define'; -import fetchMeta from '../../../../misc/fetch-meta'; -import { ApiError } from '../../error'; -import { makePaginationQuery } from '../../common/make-pagination-query'; -import { Followings, Notes } from '../../../../models'; -import { Brackets } from 'typeorm'; -import { generateVisibilityQuery } from '../../common/generate-visibility-query'; -import { generateMuteQuery } from '../../common/generate-mute-query'; -import { activeUsersChart } from '../../../../services/chart'; - -export const meta = { - desc: { - 'ja-JP': 'ソーシャルタイムラインを取得します。' - }, - - tags: ['notes'], - - params: { - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - desc: { - 'ja-JP': '最大数' - } - }, - - sinceId: { - validator: $.optional.type(ID), - desc: { - 'ja-JP': '指定すると、その投稿を基点としてより新しい投稿を取得します' - } - }, - - untilId: { - validator: $.optional.type(ID), - desc: { - 'ja-JP': '指定すると、その投稿を基点としてより古い投稿を取得します' - } - }, - - sinceDate: { - validator: $.optional.num, - desc: { - 'ja-JP': '指定した時間を基点としてより新しい投稿を取得します。数値は、1970年1月1日 00:00:00 UTC から指定した日時までの経過時間をミリ秒単位で表します。' - } - }, - - untilDate: { - validator: $.optional.num, - desc: { - 'ja-JP': '指定した時間を基点としてより古い投稿を取得します。数値は、1970年1月1日 00:00:00 UTC から指定した日時までの経過時間をミリ秒単位で表します。' - } - }, - - includeMyRenotes: { - validator: $.optional.bool, - default: true, - desc: { - 'ja-JP': '自分の行ったRenoteを含めるかどうか' - } - }, - - includeRenotedMyNotes: { - validator: $.optional.bool, - default: true, - desc: { - 'ja-JP': 'Renoteされた自分の投稿を含めるかどうか' - } - }, - - includeLocalRenotes: { - validator: $.optional.bool, - default: true, - desc: { - 'ja-JP': 'Renoteされたローカルの投稿を含めるかどうか' - } - }, - - withFiles: { - validator: $.optional.bool, - desc: { - 'ja-JP': 'true にすると、ファイルが添付された投稿だけ取得します' - } - }, - }, - - res: { - type: 'array', - items: { - type: 'Note', - }, - }, - - errors: { - stlDisabled: { - message: 'Social timeline has been disabled.', - code: 'STL_DISABLED', - id: '620763f4-f621-4533-ab33-0577a1a3c342' - }, - } -}; - -export default define(meta, async (ps, user) => { - // TODO どっかにキャッシュ - const m = await fetchMeta(); - if (m.disableLocalTimeline && !user.isAdmin && !user.isModerator) { - throw new ApiError(meta.errors.stlDisabled); - } - - //#region Construct query - const followingQuery = Followings.createQueryBuilder('following') - .select('following.followeeId') - .where('following.followerId = :followerId', { followerId: user.id }); - - const query = makePaginationQuery(Notes.createQueryBuilder('note'), - ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) - .andWhere(new Brackets(qb => { - qb.where(`((note.userId IN (${ followingQuery.getQuery() })) OR (note.userId = :meId))`, { meId: user.id }) - .orWhere('(note.visibility = \'public\') AND (note.userHost IS NULL)'); - })) - .leftJoinAndSelect('note.user', 'user') - .setParameters(followingQuery.getParameters()); - - generateVisibilityQuery(query, user); - generateMuteQuery(query, user); - - /* TODO - // MongoDBではトップレベルで否定ができないため、De Morganの法則を利用してクエリします。 - // つまり、「『自分の投稿かつRenote』ではない」を「『自分の投稿ではない』または『Renoteではない』」と表現します。 - // for details: https://en.wikipedia.org/wiki/De_Morgan%27s_laws - - if (ps.includeMyRenotes === false) { - query.$and.push({ - $or: [{ - userId: { $ne: user.id } - }, { - renoteId: null - }, { - text: { $ne: null } - }, { - fileIds: { $ne: [] } - }, { - poll: { $ne: null } - }] - }); - } - - if (ps.includeRenotedMyNotes === false) { - query.$and.push({ - $or: [{ - '_renote.userId': { $ne: user.id } - }, { - renoteId: null - }, { - text: { $ne: null } - }, { - fileIds: { $ne: [] } - }, { - poll: { $ne: null } - }] - }); - } - - if (ps.includeLocalRenotes === false) { - query.$and.push({ - $or: [{ - '_renote.user.host': { $ne: null } - }, { - renoteId: null - }, { - text: { $ne: null } - }, { - fileIds: { $ne: [] } - }, { - poll: { $ne: null } - }] - }); - } - */ - - if (ps.withFiles) { - query.andWhere('note.fileIds != \'{}\''); - } - //#endregion - - const timeline = await query.take(ps.limit).getMany(); - - if (user) { - activeUsersChart.update(user); - } - - return await Notes.packMany(timeline, user); -}); diff --git a/src/server/api/stream/channels/hybrid-timeline.ts b/src/server/api/stream/channels/hybrid-timeline.ts new file mode 100644 index 0000000000..3f09dd8398 --- /dev/null +++ b/src/server/api/stream/channels/hybrid-timeline.ts @@ -0,0 +1,64 @@ +import autobind from 'autobind-decorator'; +import shouldMuteThisNote from '../../../../misc/should-mute-this-note'; +import Channel from '../channel'; +import fetchMeta from '../../../../misc/fetch-meta'; +import { Notes } from '../../../../models'; + +export default class extends Channel { + public readonly chName = 'hybridTimeline'; + public static shouldShare = true; + public static requireCredential = true; + + @autobind + public async init(params: any) { + const meta = await fetchMeta(); + if (meta.disableLocalTimeline && !this.user.isAdmin && !this.user.isModerator) return; + + // Subscribe events + this.subscriber.on('notesStream', this.onNote); + } + + @autobind + private async onNote(note: any) { + // 自分自身の投稿 または その投稿のユーザーをフォローしている または ローカルの投稿 の場合だけ + if (!( + this.user.id === note.userId || + this.following.includes(note.userId) || + note.user.host === null + )) return; + + if (['followers', 'specified'].includes(note.visibility)) { + note = await Notes.pack(note.id, this.user, { + detail: true + }); + + if (note.isHidden) { + return; + } + } else { + // リプライなら再pack + if (note.replyId != null) { + note.reply = await Notes.pack(note.replyId, this.user, { + detail: true + }); + } + // Renoteなら再pack + if (note.renoteId != null) { + note.renote = await Notes.pack(note.renoteId, this.user, { + detail: true + }); + } + } + + // 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する + if (shouldMuteThisNote(note, this.muting)) return; + + this.send('note', note); + } + + @autobind + public dispose() { + // Unsubscribe events + this.subscriber.off('notesStream', this.onNote); + } +} diff --git a/src/server/api/stream/channels/index.ts b/src/server/api/stream/channels/index.ts index 199ab0a809..4527fb1e46 100644 --- a/src/server/api/stream/channels/index.ts +++ b/src/server/api/stream/channels/index.ts @@ -1,7 +1,7 @@ import main from './main'; import homeTimeline from './home-timeline'; import localTimeline from './local-timeline'; -import socialTimeline from './social-timeline'; +import hybridTimeline from './hybrid-timeline'; import globalTimeline from './global-timeline'; import notesStats from './notes-stats'; import serverStats from './server-stats'; @@ -20,7 +20,7 @@ export default { main, homeTimeline, localTimeline, - socialTimeline, + hybridTimeline, globalTimeline, notesStats, serverStats, diff --git a/src/server/api/stream/channels/social-timeline.ts b/src/server/api/stream/channels/social-timeline.ts deleted file mode 100644 index 1d76eed297..0000000000 --- a/src/server/api/stream/channels/social-timeline.ts +++ /dev/null @@ -1,64 +0,0 @@ -import autobind from 'autobind-decorator'; -import shouldMuteThisNote from '../../../../misc/should-mute-this-note'; -import Channel from '../channel'; -import fetchMeta from '../../../../misc/fetch-meta'; -import { Notes } from '../../../../models'; - -export default class extends Channel { - public readonly chName = 'socialTimeline'; - public static shouldShare = true; - public static requireCredential = true; - - @autobind - public async init(params: any) { - const meta = await fetchMeta(); - if (meta.disableLocalTimeline && !this.user.isAdmin && !this.user.isModerator) return; - - // Subscribe events - this.subscriber.on('notesStream', this.onNote); - } - - @autobind - private async onNote(note: any) { - // 自分自身の投稿 または その投稿のユーザーをフォローしている または ローカルの投稿 の場合だけ - if (!( - this.user.id === note.userId || - this.following.includes(note.userId) || - note.user.host === null - )) return; - - if (['followers', 'specified'].includes(note.visibility)) { - note = await Notes.pack(note.id, this.user, { - detail: true - }); - - if (note.isHidden) { - return; - } - } else { - // リプライなら再pack - if (note.replyId != null) { - note.reply = await Notes.pack(note.replyId, this.user, { - detail: true - }); - } - // Renoteなら再pack - if (note.renoteId != null) { - note.renote = await Notes.pack(note.renoteId, this.user, { - detail: true - }); - } - } - - // 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する - if (shouldMuteThisNote(note, this.muting)) return; - - this.send('note', note); - } - - @autobind - public dispose() { - // Unsubscribe events - this.subscriber.off('notesStream', this.onNote); - } -} -- cgit v1.2.3-freya