diff options
Diffstat (limited to 'src/server/api/common')
| -rw-r--r-- | src/server/api/common/generate-mute-query.ts | 36 | ||||
| -rw-r--r-- | src/server/api/common/generate-native-user-token.ts | 2 | ||||
| -rw-r--r-- | src/server/api/common/generate-visibility-query.ts | 40 | ||||
| -rw-r--r-- | src/server/api/common/get-friends.ts | 49 | ||||
| -rw-r--r-- | src/server/api/common/get-hide-users.ts | 25 | ||||
| -rw-r--r-- | src/server/api/common/getters.ts | 42 | ||||
| -rw-r--r-- | src/server/api/common/make-pagination-query.ts | 28 | ||||
| -rw-r--r-- | src/server/api/common/read-messaging-message.ts | 76 | ||||
| -rw-r--r-- | src/server/api/common/read-notification.ts | 74 | ||||
| -rw-r--r-- | src/server/api/common/signin.ts | 2 |
10 files changed, 160 insertions, 214 deletions
diff --git a/src/server/api/common/generate-mute-query.ts b/src/server/api/common/generate-mute-query.ts new file mode 100644 index 0000000000..090c14eb83 --- /dev/null +++ b/src/server/api/common/generate-mute-query.ts @@ -0,0 +1,36 @@ +import { User } from '../../../models/entities/user'; +import { Mutings } from '../../../models'; +import { SelectQueryBuilder, Brackets } from 'typeorm'; + +export function generateMuteQuery(q: SelectQueryBuilder<any>, me: User) { + const mutingQuery = Mutings.createQueryBuilder('muting') + .select('muting.muteeId') + .where('muting.muterId = :muterId', { muterId: me.id }); + + // 投稿の作者をミュートしていない かつ + // 投稿の返信先の作者をミュートしていない かつ + // 投稿の引用元の作者をミュートしていない + q + .andWhere(`note.userId NOT IN (${ mutingQuery.getQuery() })`) + .andWhere(new Brackets(qb => { qb + .where(`note.replyUserId IS NULL`) + .orWhere(`note.replyUserId NOT IN (${ mutingQuery.getQuery() })`); + })) + .andWhere(new Brackets(qb => { qb + .where(`note.renoteUserId IS NULL`) + .orWhere(`note.renoteUserId NOT IN (${ mutingQuery.getQuery() })`); + })); + + q.setParameters(mutingQuery.getParameters()); +} + +export function generateMuteQueryForUsers(q: SelectQueryBuilder<any>, me: User) { + const mutingQuery = Mutings.createQueryBuilder('muting') + .select('muting.muteeId') + .where('muting.muterId = :muterId', { muterId: me.id }); + + q + .andWhere(`user.id NOT IN (${ mutingQuery.getQuery() })`); + + q.setParameters(mutingQuery.getParameters()); +} diff --git a/src/server/api/common/generate-native-user-token.ts b/src/server/api/common/generate-native-user-token.ts index 2082b89a5a..92f8a3a0e8 100644 --- a/src/server/api/common/generate-native-user-token.ts +++ b/src/server/api/common/generate-native-user-token.ts @@ -1,3 +1,3 @@ import rndstr from 'rndstr'; -export default () => `!${rndstr('a-zA-Z0-9', 32)}`; +export default () => `!${rndstr('a-zA-Z0-9', 31)}`; diff --git a/src/server/api/common/generate-visibility-query.ts b/src/server/api/common/generate-visibility-query.ts new file mode 100644 index 0000000000..2807dc99dc --- /dev/null +++ b/src/server/api/common/generate-visibility-query.ts @@ -0,0 +1,40 @@ +import { User } from '../../../models/entities/user'; +import { Followings } from '../../../models'; +import { Brackets, SelectQueryBuilder } from 'typeorm'; + +export function generateVisibilityQuery(q: SelectQueryBuilder<any>, me?: User) { + if (me == null) { + q.andWhere(new Brackets(qb => { qb + .where(`note.visibility = 'public'`) + .orWhere(`note.visibility = 'home'`); + })); + } else { + const followingQuery = Followings.createQueryBuilder('following') + .select('following.followeeId') + .where('following.followerId = :followerId', { followerId: me.id }); + + q.andWhere(new Brackets(qb => { qb + // 公開投稿である + .where(new Brackets(qb => { qb + .where(`note.visibility = 'public'`) + .orWhere(`note.visibility = 'home'`); + })) + // または 自分自身 + .orWhere('note.userId = :userId1', { userId1: me.id }) + // または 自分宛て + .orWhere(':userId2 = ANY(note.visibleUserIds)', { userId2: me.id }) + .orWhere(new Brackets(qb => { qb + // または フォロワー宛ての投稿であり、 + .where('note.visibility = \'followers\'') + .andWhere(new Brackets(qb => { qb + // 自分がフォロワーである + .where(`note.userId IN (${ followingQuery.getQuery() })`) + // または 自分の投稿へのリプライ + .orWhere('note.replyUserId = :userId3', { userId3: me.id }); + })); + })); + })); + + q.setParameters(followingQuery.getParameters()); + } +} diff --git a/src/server/api/common/get-friends.ts b/src/server/api/common/get-friends.ts deleted file mode 100644 index 876aa399f7..0000000000 --- a/src/server/api/common/get-friends.ts +++ /dev/null @@ -1,49 +0,0 @@ -import * as mongodb from 'mongodb'; -import Following from '../../../models/following'; - -export const getFriendIds = async (me: mongodb.ObjectID, includeMe = true) => { - // Fetch relation to other users who the I follows - // SELECT followee - const followings = await Following - .find({ - followerId: me - }, { - fields: { - followeeId: true - } - }); - - // ID list of other users who the I follows - const myfollowingIds = followings.map(following => following.followeeId); - - if (includeMe) { - myfollowingIds.push(me); - } - - return myfollowingIds; -}; - -export const getFriends = async (me: mongodb.ObjectID, includeMe = true, remoteOnly = false) => { - const q: any = remoteOnly ? { - followerId: me, - '_followee.host': { $ne: null } - } : { - followerId: me - }; - // Fetch relation to other users who the I follows - const followings = await Following - .find(q); - - // ID list of other users who the I follows - const myfollowings = followings.map(following => ({ - id: following.followeeId - })); - - if (includeMe) { - myfollowings.push({ - id: me - }); - } - - return myfollowings; -}; diff --git a/src/server/api/common/get-hide-users.ts b/src/server/api/common/get-hide-users.ts deleted file mode 100644 index 3cdf806751..0000000000 --- a/src/server/api/common/get-hide-users.ts +++ /dev/null @@ -1,25 +0,0 @@ -import * as mongo from 'mongodb'; -import Mute from '../../../models/mute'; -import User, { IUser } from '../../../models/user'; -import { unique } from '../../../prelude/array'; - -export async function getHideUserIds(me: IUser) { - return await getHideUserIdsById(me ? me._id : null); -} - -export async function getHideUserIdsById(meId?: mongo.ObjectID) { - const [suspended, muted] = await Promise.all([ - User.find({ - isSuspended: true - }, { - fields: { - _id: true - } - }), - meId ? Mute.find({ - muterId: meId - }) : Promise.resolve([]) - ]); - - return unique(suspended.map(user => user._id).concat(muted.map(mute => mute.muteeId))); -} diff --git a/src/server/api/common/getters.ts b/src/server/api/common/getters.ts index 7a72e6489a..b720840ebb 100644 --- a/src/server/api/common/getters.ts +++ b/src/server/api/common/getters.ts @@ -1,18 +1,15 @@ -import * as mongo from 'mongodb'; -import Note from '../../../models/note'; -import User, { isRemoteUser, isLocalUser } from '../../../models/user'; import { IdentifiableError } from '../../../misc/identifiable-error'; +import { User } from '../../../models/entities/user'; +import { Note } from '../../../models/entities/note'; +import { Notes, Users } from '../../../models'; /** * Get note for API processing */ -export async function getNote(noteId: mongo.ObjectID) { - const note = await Note.findOne({ - _id: noteId, - deletedAt: { $exists: false } - }); +export async function getNote(noteId: Note['id']) { + const note = await Notes.findOne(noteId); - if (note === null) { + if (note == null) { throw new IdentifiableError('9725d0ce-ba28-4dde-95a7-2cbb2c15de24', 'No such note.'); } @@ -22,23 +19,10 @@ export async function getNote(noteId: mongo.ObjectID) { /** * Get user for API processing */ -export async function getUser(userId: mongo.ObjectID) { - const user = await User.findOne({ - _id: userId, - $or: [{ - isDeleted: { $exists: false } - }, { - isDeleted: false - }] - }, { - fields: { - data: false, - profile: false, - clientSettings: false - } - }); +export async function getUser(userId: User['id']) { + const user = await Users.findOne(userId); - if (user === null) { + if (user == null) { throw new IdentifiableError('15348ddd-432d-49c2-8a5a-8069753becff', 'No such user.'); } @@ -48,10 +32,10 @@ export async function getUser(userId: mongo.ObjectID) { /** * Get remote user for API processing */ -export async function getRemoteUser(userId: mongo.ObjectID) { +export async function getRemoteUser(userId: User['id']) { const user = await getUser(userId); - if (!isRemoteUser(user)) { + if (!Users.isRemoteUser(user)) { throw 'user is not a remote user'; } @@ -61,10 +45,10 @@ export async function getRemoteUser(userId: mongo.ObjectID) { /** * Get local user for API processing */ -export async function getLocalUser(userId: mongo.ObjectID) { +export async function getLocalUser(userId: User['id']) { const user = await getUser(userId); - if (!isLocalUser(user)) { + if (!Users.isLocalUser(user)) { throw 'user is not a local user'; } diff --git a/src/server/api/common/make-pagination-query.ts b/src/server/api/common/make-pagination-query.ts new file mode 100644 index 0000000000..0c859a4f8d --- /dev/null +++ b/src/server/api/common/make-pagination-query.ts @@ -0,0 +1,28 @@ +import { SelectQueryBuilder } from 'typeorm'; + +export function makePaginationQuery<T>(q: SelectQueryBuilder<T>, sinceId: string, untilId: string, sinceDate?: number, untilDate?: number) { + if (sinceId && untilId) { + q.andWhere(`${q.alias}.id > :sinceId`, { sinceId: sinceId }); + q.andWhere(`${q.alias}.id < :untilId`, { untilId: untilId }); + q.orderBy(`${q.alias}.id`, 'DESC'); + } else if (sinceId) { + q.andWhere(`${q.alias}.id > :sinceId`, { sinceId: sinceId }); + q.orderBy(`${q.alias}.id`, 'ASC'); + } else if (untilId) { + q.andWhere(`${q.alias}.id < :untilId`, { untilId: untilId }); + q.orderBy(`${q.alias}.id`, 'DESC'); + } else if (sinceDate && untilDate) { + q.andWhere(`${q.alias}.createdAt > :sinceDate`, { sinceDate: new Date(sinceDate) }); + q.andWhere(`${q.alias}.createdAt < :untilDate`, { untilDate: new Date(untilDate) }); + q.orderBy(`${q.alias}.createdAt`, 'DESC'); + } else if (sinceDate) { + q.andWhere(`${q.alias}.createdAt > :sinceDate`, { sinceDate: new Date(sinceDate) }); + q.orderBy(`${q.alias}.createdAt`, 'ASC'); + } else if (untilDate) { + q.andWhere(`${q.alias}.createdAt < :untilDate`, { untilDate: new Date(untilDate) }); + q.orderBy(`${q.alias}.createdAt`, 'DESC'); + } else { + q.orderBy(`${q.alias}.id`, 'DESC'); + } + return q; +} diff --git a/src/server/api/common/read-messaging-message.ts b/src/server/api/common/read-messaging-message.ts index 9f1e7e6ab4..2cb5a1f87f 100644 --- a/src/server/api/common/read-messaging-message.ts +++ b/src/server/api/common/read-messaging-message.ts @@ -1,77 +1,43 @@ -import * as mongo from 'mongodb'; -import isObjectId from '../../../misc/is-objectid'; -import Message from '../../../models/messaging-message'; -import { IMessagingMessage as IMessage } from '../../../models/messaging-message'; import { publishMainStream } from '../../../services/stream'; import { publishMessagingStream } from '../../../services/stream'; import { publishMessagingIndexStream } from '../../../services/stream'; -import User from '../../../models/user'; +import { User } from '../../../models/entities/user'; +import { MessagingMessage } from '../../../models/entities/messaging-message'; +import { MessagingMessages } from '../../../models'; +import { In } from 'typeorm'; /** * Mark messages as read */ -export default ( - user: string | mongo.ObjectID, - otherparty: string | mongo.ObjectID, - message: string | string[] | IMessage | IMessage[] | mongo.ObjectID | mongo.ObjectID[] -) => new Promise<any>(async (resolve, reject) => { - - const userId = isObjectId(user) - ? user - : new mongo.ObjectID(user); - - const otherpartyId = isObjectId(otherparty) - ? otherparty - : new mongo.ObjectID(otherparty); - - const ids: mongo.ObjectID[] = Array.isArray(message) - ? isObjectId(message[0]) - ? (message as mongo.ObjectID[]) - : typeof message[0] === 'string' - ? (message as string[]).map(m => new mongo.ObjectID(m)) - : (message as IMessage[]).map(m => m._id) - : isObjectId(message) - ? [(message as mongo.ObjectID)] - : typeof message === 'string' - ? [new mongo.ObjectID(message)] - : [(message as IMessage)._id]; +export default async ( + userId: User['id'], + otherpartyId: User['id'], + messageIds: MessagingMessage['id'][] +) => { + if (messageIds.length === 0) return; // Update documents - await Message.update({ - _id: { $in: ids }, + await MessagingMessages.update({ + id: In(messageIds), userId: otherpartyId, recipientId: userId, isRead: false }, { - $set: { - isRead: true - } - }, { - multi: true - }); + isRead: true + }); // Publish event - publishMessagingStream(otherpartyId, userId, 'read', ids.map(id => id.toString())); - publishMessagingIndexStream(userId, 'read', ids.map(id => id.toString())); + publishMessagingStream(otherpartyId, userId, 'read', messageIds); + publishMessagingIndexStream(userId, 'read', messageIds); // Calc count of my unread messages - const count = await Message - .count({ - recipientId: userId, - isRead: false - }, { - limit: 1 - }); + const count = await MessagingMessages.count({ + recipientId: userId, + isRead: false + }); if (count == 0) { - // Update flag - User.update({ _id: userId }, { - $set: { - hasUnreadMessagingMessage: false - } - }); - // 全ての(いままで未読だった)自分宛てのメッセージを(これで)読みましたよというイベントを発行 publishMainStream(userId, 'readAllMessagingMessages'); } -}); +}; diff --git a/src/server/api/common/read-notification.ts b/src/server/api/common/read-notification.ts index 4361305119..c8d43ba286 100644 --- a/src/server/api/common/read-notification.ts +++ b/src/server/api/common/read-notification.ts @@ -1,72 +1,38 @@ -import * as mongo from 'mongodb'; -import isObjectId from '../../../misc/is-objectid'; -import { default as Notification, INotification } from '../../../models/notification'; import { publishMainStream } from '../../../services/stream'; -import Mute from '../../../models/mute'; -import User from '../../../models/user'; +import { User } from '../../../models/entities/user'; +import { Notification } from '../../../models/entities/notification'; +import { Mutings, Notifications } from '../../../models'; +import { In, Not } from 'typeorm'; /** * Mark notifications as read */ -export default ( - user: string | mongo.ObjectID, - message: string | string[] | INotification | INotification[] | mongo.ObjectID | mongo.ObjectID[] -) => new Promise<any>(async (resolve, reject) => { - - const userId = isObjectId(user) - ? user - : new mongo.ObjectID(user); - - const ids: mongo.ObjectID[] = Array.isArray(message) - ? isObjectId(message[0]) - ? (message as mongo.ObjectID[]) - : typeof message[0] === 'string' - ? (message as string[]).map(m => new mongo.ObjectID(m)) - : (message as INotification[]).map(m => m._id) - : isObjectId(message) - ? [(message as mongo.ObjectID)] - : typeof message === 'string' - ? [new mongo.ObjectID(message)] - : [(message as INotification)._id]; - - const mute = await Mute.find({ +export async function readNotification( + userId: User['id'], + notificationIds: Notification['id'][] +) { + const mute = await Mutings.find({ muterId: userId }); const mutedUserIds = mute.map(m => m.muteeId); // Update documents - await Notification.update({ - _id: { $in: ids }, + await Notifications.update({ + id: In(notificationIds), isRead: false }, { - $set: { - isRead: true - } - }, { - multi: true - }); + isRead: true + }); // Calc count of my unread notifications - const count = await Notification - .count({ - notifieeId: userId, - notifierId: { - $nin: mutedUserIds - }, - isRead: false - }, { - limit: 1 - }); - - if (count == 0) { - // Update flag - User.update({ _id: userId }, { - $set: { - hasUnreadNotification: false - } - }); + const count = await Notifications.count({ + notifieeId: userId, + ...(mutedUserIds.length > 0 ? { notifierId: Not(In(mutedUserIds)) } : {}), + isRead: false + }); + if (count === 0) { // 全ての(いままで未読だった)通知を(これで)読みましたよというイベントを発行 publishMainStream(userId, 'readAllNotifications'); } -}); +} diff --git a/src/server/api/common/signin.ts b/src/server/api/common/signin.ts index 84cad3a935..0f4ee4ca11 100644 --- a/src/server/api/common/signin.ts +++ b/src/server/api/common/signin.ts @@ -1,7 +1,7 @@ import * as Koa from 'koa'; import config from '../../../config'; -import { ILocalUser } from '../../../models/user'; +import { ILocalUser } from '../../../models/entities/user'; export default function(ctx: Koa.BaseContext, user: ILocalUser, redirect = false) { if (redirect) { |