From 0e4a111f81cceed275d9bec2695f6e401fb654d8 Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 12 Nov 2021 02:02:25 +0900 Subject: refactoring Resolve #7779 --- src/server/api/common/generate-block-query.ts | 42 ------- src/server/api/common/generate-channel-query.ts | 24 ---- src/server/api/common/generate-muted-note-query.ts | 13 --- .../api/common/generate-muted-note-thread-query.ts | 17 --- src/server/api/common/generate-muted-user-query.ts | 40 ------- .../api/common/generate-native-user-token.ts | 3 - src/server/api/common/generate-replies-query.ts | 27 ----- src/server/api/common/generate-visibility-query.ts | 40 ------- src/server/api/common/getters.ts | 56 ---------- src/server/api/common/inject-featured.ts | 56 ---------- src/server/api/common/inject-promo.ts | 34 ------ src/server/api/common/is-native-token.ts | 1 - src/server/api/common/make-pagination-query.ts | 28 ----- src/server/api/common/read-messaging-message.ts | 122 --------------------- src/server/api/common/read-notification.ts | 43 -------- src/server/api/common/signin.ts | 44 -------- src/server/api/common/signup.ts | 113 ------------------- 17 files changed, 703 deletions(-) delete mode 100644 src/server/api/common/generate-block-query.ts delete mode 100644 src/server/api/common/generate-channel-query.ts delete mode 100644 src/server/api/common/generate-muted-note-query.ts delete mode 100644 src/server/api/common/generate-muted-note-thread-query.ts delete mode 100644 src/server/api/common/generate-muted-user-query.ts delete mode 100644 src/server/api/common/generate-native-user-token.ts delete mode 100644 src/server/api/common/generate-replies-query.ts delete mode 100644 src/server/api/common/generate-visibility-query.ts delete mode 100644 src/server/api/common/getters.ts delete mode 100644 src/server/api/common/inject-featured.ts delete mode 100644 src/server/api/common/inject-promo.ts delete mode 100644 src/server/api/common/is-native-token.ts delete mode 100644 src/server/api/common/make-pagination-query.ts delete mode 100644 src/server/api/common/read-messaging-message.ts delete mode 100644 src/server/api/common/read-notification.ts delete mode 100644 src/server/api/common/signin.ts delete mode 100644 src/server/api/common/signup.ts (limited to 'src/server/api/common') diff --git a/src/server/api/common/generate-block-query.ts b/src/server/api/common/generate-block-query.ts deleted file mode 100644 index 4fd6184738..0000000000 --- a/src/server/api/common/generate-block-query.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { User } from '@/models/entities/user'; -import { Blockings } from '@/models/index'; -import { Brackets, SelectQueryBuilder } from 'typeorm'; - -// ここでいうBlockedは被Blockedの意 -export function generateBlockedUserQuery(q: SelectQueryBuilder, 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, me: { id: User['id'] }) { - const blockingQuery = Blockings.createQueryBuilder('blocking') - .select('blocking.blockeeId') - .where('blocking.blockerId = :blockerId', { blockerId: me.id }); - - const blockedQuery = Blockings.createQueryBuilder('blocking') - .select('blocking.blockerId') - .where('blocking.blockeeId = :blockeeId', { blockeeId: me.id }); - - q.andWhere(`user.id NOT IN (${ blockingQuery.getQuery() })`); - q.setParameters(blockingQuery.getParameters()); - - q.andWhere(`user.id NOT IN (${ blockedQuery.getQuery() })`); - q.setParameters(blockedQuery.getParameters()); -} diff --git a/src/server/api/common/generate-channel-query.ts b/src/server/api/common/generate-channel-query.ts deleted file mode 100644 index 80a0acf7f9..0000000000 --- a/src/server/api/common/generate-channel-query.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { User } from '@/models/entities/user'; -import { ChannelFollowings } from '@/models/index'; -import { Brackets, SelectQueryBuilder } from 'typeorm'; - -export function generateChannelQuery(q: SelectQueryBuilder, me?: { id: User['id'] } | null) { - if (me == null) { - q.andWhere('note.channelId IS NULL'); - } else { - q.leftJoinAndSelect('note.channel', 'channel'); - - const channelFollowingQuery = ChannelFollowings.createQueryBuilder('channelFollowing') - .select('channelFollowing.followeeId') - .where('channelFollowing.followerId = :followerId', { followerId: me.id }); - - q.andWhere(new Brackets(qb => { qb - // チャンネルのノートではない - .where('note.channelId IS NULL') - // または自分がフォローしているチャンネルのノート - .orWhere(`note.channelId IN (${ channelFollowingQuery.getQuery() })`); - })); - - q.setParameters(channelFollowingQuery.getParameters()); - } -} diff --git a/src/server/api/common/generate-muted-note-query.ts b/src/server/api/common/generate-muted-note-query.ts deleted file mode 100644 index 0737842613..0000000000 --- a/src/server/api/common/generate-muted-note-query.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { User } from '@/models/entities/user'; -import { MutedNotes } from '@/models/index'; -import { SelectQueryBuilder } from 'typeorm'; - -export function generateMutedNoteQuery(q: SelectQueryBuilder, me: { id: User['id'] }) { - 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()); -} diff --git a/src/server/api/common/generate-muted-note-thread-query.ts b/src/server/api/common/generate-muted-note-thread-query.ts deleted file mode 100644 index 7e2cbd498b..0000000000 --- a/src/server/api/common/generate-muted-note-thread-query.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { User } from '@/models/entities/user'; -import { NoteThreadMutings } from '@/models/index'; -import { Brackets, SelectQueryBuilder } from 'typeorm'; - -export function generateMutedNoteThreadQuery(q: SelectQueryBuilder, me: { id: User['id'] }) { - const mutedQuery = NoteThreadMutings.createQueryBuilder('threadMuted') - .select('threadMuted.threadId') - .where('threadMuted.userId = :userId', { userId: me.id }); - - q.andWhere(`note.id NOT IN (${ mutedQuery.getQuery() })`); - q.andWhere(new Brackets(qb => { qb - .where(`note.threadId IS NULL`) - .orWhere(`note.threadId NOT IN (${ mutedQuery.getQuery() })`); - })); - - q.setParameters(mutedQuery.getParameters()); -} diff --git a/src/server/api/common/generate-muted-user-query.ts b/src/server/api/common/generate-muted-user-query.ts deleted file mode 100644 index 7e200b87ef..0000000000 --- a/src/server/api/common/generate-muted-user-query.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { User } from '@/models/entities/user'; -import { Mutings } from '@/models/index'; -import { SelectQueryBuilder, Brackets } from 'typeorm'; - -export function generateMutedUserQuery(q: SelectQueryBuilder, me: { id: User['id'] }, exclude?: User) { - const mutingQuery = Mutings.createQueryBuilder('muting') - .select('muting.muteeId') - .where('muting.muterId = :muterId', { muterId: me.id }); - - if (exclude) { - mutingQuery.andWhere('muting.muteeId != :excludeId', { excludeId: exclude.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 generateMutedUserQueryForUsers(q: SelectQueryBuilder, me: { id: User['id'] }) { - 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 deleted file mode 100644 index 1f791c57ce..0000000000 --- a/src/server/api/common/generate-native-user-token.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { secureRndstr } from '@/misc/secure-rndstr'; - -export default () => secureRndstr(16, true); diff --git a/src/server/api/common/generate-replies-query.ts b/src/server/api/common/generate-replies-query.ts deleted file mode 100644 index fbc41b2c25..0000000000 --- a/src/server/api/common/generate-replies-query.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { User } from '@/models/entities/user'; -import { Brackets, SelectQueryBuilder } from 'typeorm'; - -export function generateRepliesQuery(q: SelectQueryBuilder, me?: { id: User['id'] } | null) { - if (me == null) { - q.andWhere(new Brackets(qb => { qb - .where(`note.replyId IS NULL`) // 返信ではない - .orWhere(new Brackets(qb => { qb // 返信だけど投稿者自身への返信 - .where(`note.replyId IS NOT NULL`) - .andWhere('note.replyUserId = note.userId'); - })); - })); - } else { - q.andWhere(new Brackets(qb => { qb - .where(`note.replyId IS NULL`) // 返信ではない - .orWhere('note.replyUserId = :meId', { meId: me.id }) // 返信だけど自分のノートへの返信 - .orWhere(new Brackets(qb => { qb // 返信だけど自分の行った返信 - .where(`note.replyId IS NOT NULL`) - .andWhere('note.userId = :meId', { meId: me.id }); - })) - .orWhere(new Brackets(qb => { qb // 返信だけど投稿者自身への返信 - .where(`note.replyId IS NOT NULL`) - .andWhere('note.replyUserId = note.userId'); - })); - })); - } -} diff --git a/src/server/api/common/generate-visibility-query.ts b/src/server/api/common/generate-visibility-query.ts deleted file mode 100644 index 813e8b6c09..0000000000 --- a/src/server/api/common/generate-visibility-query.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { User } from '@/models/entities/user'; -import { Followings } from '@/models/index'; -import { Brackets, SelectQueryBuilder } from 'typeorm'; - -export function generateVisibilityQuery(q: SelectQueryBuilder, me?: { id: User['id'] } | null) { - 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(`'{"${me.id}"}' <@ note.visibleUserIds`) - .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/getters.ts b/src/server/api/common/getters.ts deleted file mode 100644 index 4b2ee8f1da..0000000000 --- a/src/server/api/common/getters.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { IdentifiableError } from '@/misc/identifiable-error'; -import { User } from '@/models/entities/user'; -import { Note } from '@/models/entities/note'; -import { Notes, Users } from '@/models/index'; - -/** - * Get note for API processing - */ -export async function getNote(noteId: Note['id']) { - const note = await Notes.findOne(noteId); - - if (note == null) { - throw new IdentifiableError('9725d0ce-ba28-4dde-95a7-2cbb2c15de24', 'No such note.'); - } - - return note; -} - -/** - * Get user for API processing - */ -export async function getUser(userId: User['id']) { - const user = await Users.findOne(userId); - - if (user == null) { - throw new IdentifiableError('15348ddd-432d-49c2-8a5a-8069753becff', 'No such user.'); - } - - return user; -} - -/** - * Get remote user for API processing - */ -export async function getRemoteUser(userId: User['id']) { - const user = await getUser(userId); - - if (!Users.isRemoteUser(user)) { - throw new Error('user is not a remote user'); - } - - return user; -} - -/** - * Get local user for API processing - */ -export async function getLocalUser(userId: User['id']) { - const user = await getUser(userId); - - if (!Users.isLocalUser(user)) { - throw new Error('user is not a local user'); - } - - return user; -} diff --git a/src/server/api/common/inject-featured.ts b/src/server/api/common/inject-featured.ts deleted file mode 100644 index 1dc13c83ef..0000000000 --- a/src/server/api/common/inject-featured.ts +++ /dev/null @@ -1,56 +0,0 @@ -import rndstr from 'rndstr'; -import { Note } from '@/models/entities/note'; -import { User } from '@/models/entities/user'; -import { Notes, UserProfiles, NoteReactions } from '@/models/index'; -import { generateMutedUserQuery } from './generate-muted-user-query'; -import { generateBlockedUserQuery } from './generate-block-query'; - -// TODO: リアクション、Renote、返信などをしたノートは除外する - -export async function injectFeatured(timeline: Note[], user?: User | null) { - if (timeline.length < 5) return; - - if (user) { - const profile = await UserProfiles.findOneOrFail(user.id); - if (!profile.injectFeaturedNote) return; - } - - const max = 30; - const day = 1000 * 60 * 60 * 24 * 3; // 3日前まで - - const query = Notes.createQueryBuilder('note') - .addSelect('note.score') - .where('note.userHost IS NULL') - .andWhere(`note.score > 0`) - .andWhere(`note.createdAt > :date`, { date: new Date(Date.now() - day) }) - .andWhere(`note.visibility = 'public'`) - .innerJoinAndSelect('note.user', 'user'); - - if (user) { - query.andWhere('note.userId != :userId', { userId: user.id }); - - generateMutedUserQuery(query, user); - generateBlockedUserQuery(query, user); - - const reactionQuery = NoteReactions.createQueryBuilder('reaction') - .select('reaction.noteId') - .where('reaction.userId = :userId', { userId: user.id }); - - query.andWhere(`note.id NOT IN (${ reactionQuery.getQuery() })`); - } - - const notes = await query - .orderBy('note.score', 'DESC') - .take(max) - .getMany(); - - if (notes.length === 0) return; - - // Pick random one - const featured = notes[Math.floor(Math.random() * notes.length)]; - - (featured as any)._featuredId_ = rndstr('a-z0-9', 8); - - // Inject featured - timeline.splice(3, 0, featured); -} diff --git a/src/server/api/common/inject-promo.ts b/src/server/api/common/inject-promo.ts deleted file mode 100644 index 87767a65bf..0000000000 --- a/src/server/api/common/inject-promo.ts +++ /dev/null @@ -1,34 +0,0 @@ -import rndstr from 'rndstr'; -import { Note } from '@/models/entities/note'; -import { User } from '@/models/entities/user'; -import { PromoReads, PromoNotes, Notes, Users } from '@/models/index'; - -export async function injectPromo(timeline: Note[], user?: User | null) { - if (timeline.length < 5) return; - - // TODO: readやexpireフィルタはクエリ側でやる - - const reads = user ? await PromoReads.find({ - userId: user.id - }) : []; - - let promos = await PromoNotes.find(); - - promos = promos.filter(n => n.expiresAt.getTime() > Date.now()); - promos = promos.filter(n => !reads.map(r => r.noteId).includes(n.noteId)); - - if (promos.length === 0) return; - - // Pick random promo - const promo = promos[Math.floor(Math.random() * promos.length)]; - - const note = await Notes.findOneOrFail(promo.noteId); - - // Join - note.user = await Users.findOneOrFail(note.userId); - - (note as any)._prId_ = rndstr('a-z0-9', 8); - - // Inject promo - timeline.splice(3, 0, note); -} diff --git a/src/server/api/common/is-native-token.ts b/src/server/api/common/is-native-token.ts deleted file mode 100644 index 2833c570c8..0000000000 --- a/src/server/api/common/is-native-token.ts +++ /dev/null @@ -1 +0,0 @@ -export default (token: string) => token.length === 16; diff --git a/src/server/api/common/make-pagination-query.ts b/src/server/api/common/make-pagination-query.ts deleted file mode 100644 index 51c11e5dff..0000000000 --- a/src/server/api/common/make-pagination-query.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { SelectQueryBuilder } from 'typeorm'; - -export function makePaginationQuery(q: SelectQueryBuilder, 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 deleted file mode 100644 index 33f41b2770..0000000000 --- a/src/server/api/common/read-messaging-message.ts +++ /dev/null @@ -1,122 +0,0 @@ -import { publishMainStream, publishGroupMessagingStream } from '@/services/stream'; -import { publishMessagingStream } from '@/services/stream'; -import { publishMessagingIndexStream } from '@/services/stream'; -import { User, IRemoteUser } from '@/models/entities/user'; -import { MessagingMessage } from '@/models/entities/messaging-message'; -import { MessagingMessages, UserGroupJoinings, Users } from '@/models/index'; -import { In } from 'typeorm'; -import { IdentifiableError } from '@/misc/identifiable-error'; -import { UserGroup } from '@/models/entities/user-group'; -import { toArray } from '@/prelude/array'; -import { renderReadActivity } from '@/remote/activitypub/renderer/read'; -import { renderActivity } from '@/remote/activitypub/renderer/index'; -import { deliver } from '@/queue/index'; -import orderedCollection from '@/remote/activitypub/renderer/ordered-collection'; - -/** - * Mark messages as read - */ -export async function readUserMessagingMessage( - userId: User['id'], - otherpartyId: User['id'], - messageIds: MessagingMessage['id'][] -) { - if (messageIds.length === 0) return; - - const messages = await MessagingMessages.find({ - id: In(messageIds) - }); - - for (const message of messages) { - if (message.recipientId !== userId) { - throw new IdentifiableError('e140a4bf-49ce-4fb6-b67c-b78dadf6b52f', 'Access denied (user).'); - } - } - - // Update documents - await MessagingMessages.update({ - id: In(messageIds), - userId: otherpartyId, - recipientId: userId, - isRead: false - }, { - isRead: true - }); - - // Publish event - publishMessagingStream(otherpartyId, userId, 'read', messageIds); - publishMessagingIndexStream(userId, 'read', messageIds); - - if (!await Users.getHasUnreadMessagingMessage(userId)) { - // 全ての(いままで未読だった)自分宛てのメッセージを(これで)読みましたよというイベントを発行 - publishMainStream(userId, 'readAllMessagingMessages'); - } -} - -/** - * Mark messages as read - */ -export async function readGroupMessagingMessage( - userId: User['id'], - groupId: UserGroup['id'], - messageIds: MessagingMessage['id'][] -) { - if (messageIds.length === 0) return; - - // check joined - const joining = await UserGroupJoinings.findOne({ - userId: userId, - userGroupId: groupId - }); - - if (joining == null) { - throw new IdentifiableError('930a270c-714a-46b2-b776-ad27276dc569', 'Access denied (group).'); - } - - const messages = await MessagingMessages.find({ - id: In(messageIds) - }); - - const reads: MessagingMessage['id'][] = []; - - for (const message of messages) { - if (message.userId === userId) continue; - if (message.reads.includes(userId)) continue; - - // Update document - await MessagingMessages.createQueryBuilder().update() - .set({ - reads: (() => `array_append("reads", '${joining.userId}')`) as any - }) - .where('id = :id', { id: message.id }) - .execute(); - - reads.push(message.id); - } - - // Publish event - publishGroupMessagingStream(groupId, 'read', { - ids: reads, - userId: userId - }); - publishMessagingIndexStream(userId, 'read', reads); - - if (!await Users.getHasUnreadMessagingMessage(userId)) { - // 全ての(いままで未読だった)自分宛てのメッセージを(これで)読みましたよというイベントを発行 - publishMainStream(userId, 'readAllMessagingMessages'); - } -} - -export async function deliverReadActivity(user: { id: User['id']; host: null; }, recipient: IRemoteUser, messages: MessagingMessage | MessagingMessage[]) { - messages = toArray(messages).filter(x => x.uri); - const contents = messages.map(x => renderReadActivity(user, x)); - - if (contents.length > 1) { - const collection = orderedCollection(null, contents.length, undefined, undefined, contents); - deliver(user, renderActivity(collection), recipient.inbox); - } else { - for (const content of contents) { - deliver(user, renderActivity(content), recipient.inbox); - } - } -} diff --git a/src/server/api/common/read-notification.ts b/src/server/api/common/read-notification.ts deleted file mode 100644 index a4406c9eeb..0000000000 --- a/src/server/api/common/read-notification.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { publishMainStream } from '@/services/stream'; -import { User } from '@/models/entities/user'; -import { Notification } from '@/models/entities/notification'; -import { Notifications, Users } from '@/models/index'; -import { In } from 'typeorm'; - -export async function readNotification( - userId: User['id'], - notificationIds: Notification['id'][] -) { - // Update documents - await Notifications.update({ - id: In(notificationIds), - isRead: false - }, { - isRead: true - }); - - post(userId); -} - -export async function readNotificationByQuery( - userId: User['id'], - query: Record -) { - // Update documents - await Notifications.update({ - ...query, - notifieeId: userId, - isRead: false - }, { - isRead: true - }); - - post(userId); -} - -async function post(userId: User['id']) { - if (!await Users.getHasUnreadNotification(userId)) { - // 全ての(いままで未読だった)通知を(これで)読みましたよというイベントを発行 - publishMainStream(userId, 'readAllNotifications'); - } -} diff --git a/src/server/api/common/signin.ts b/src/server/api/common/signin.ts deleted file mode 100644 index 4c7aacf1cd..0000000000 --- a/src/server/api/common/signin.ts +++ /dev/null @@ -1,44 +0,0 @@ -import * as Koa from 'koa'; - -import config from '@/config/index'; -import { ILocalUser } from '@/models/entities/user'; -import { Signins } from '@/models/index'; -import { genId } from '@/misc/gen-id'; -import { publishMainStream } from '@/services/stream'; - -export default function(ctx: Koa.Context, user: ILocalUser, redirect = false) { - if (redirect) { - //#region Cookie - ctx.cookies.set('igi', user.token, { - path: '/', - // SEE: https://github.com/koajs/koa/issues/974 - // When using a SSL proxy it should be configured to add the "X-Forwarded-Proto: https" header - secure: config.url.startsWith('https'), - httpOnly: false - }); - //#endregion - - ctx.redirect(config.url); - } else { - ctx.body = { - id: user.id, - i: user.token - }; - ctx.status = 200; - } - - (async () => { - // Append signin history - const record = await Signins.save({ - id: genId(), - createdAt: new Date(), - userId: user.id, - ip: ctx.ip, - headers: ctx.headers, - success: true - }); - - // Publish signin event - publishMainStream(user.id, 'signin', await Signins.pack(record)); - })(); -} diff --git a/src/server/api/common/signup.ts b/src/server/api/common/signup.ts deleted file mode 100644 index 2ba0d8e479..0000000000 --- a/src/server/api/common/signup.ts +++ /dev/null @@ -1,113 +0,0 @@ -import * as bcrypt from 'bcryptjs'; -import { generateKeyPair } from 'crypto'; -import generateUserToken from './generate-native-user-token'; -import { User } from '@/models/entities/user'; -import { Users, UsedUsernames } from '@/models/index'; -import { UserProfile } from '@/models/entities/user-profile'; -import { getConnection } from 'typeorm'; -import { genId } from '@/misc/gen-id'; -import { toPunyNullable } from '@/misc/convert-host'; -import { UserKeypair } from '@/models/entities/user-keypair'; -import { usersChart } from '@/services/chart/index'; -import { UsedUsername } from '@/models/entities/used-username'; - -export async function signup(opts: { - username: User['username']; - password?: string | null; - passwordHash?: UserProfile['password'] | null; - host?: string | null; -}) { - const { username, password, passwordHash, host } = opts; - let hash = passwordHash; - - // Validate username - if (!Users.validateLocalUsername.ok(username)) { - throw new Error('INVALID_USERNAME'); - } - - if (password != null && passwordHash == null) { - // Validate password - if (!Users.validatePassword.ok(password)) { - throw new Error('INVALID_PASSWORD'); - } - - // Generate hash of password - const salt = await bcrypt.genSalt(8); - hash = await bcrypt.hash(password, salt); - } - - // Generate secret - const secret = generateUserToken(); - - // Check username duplication - if (await Users.findOne({ usernameLower: username.toLowerCase(), host: null })) { - throw new Error('DUPLICATED_USERNAME'); - } - - // Check deleted username duplication - if (await UsedUsernames.findOne({ username: username.toLowerCase() })) { - throw new Error('USED_USERNAME'); - } - - const keyPair = await new Promise((res, rej) => - generateKeyPair('rsa', { - modulusLength: 4096, - publicKeyEncoding: { - type: 'spki', - format: 'pem' - }, - privateKeyEncoding: { - type: 'pkcs8', - format: 'pem', - cipher: undefined, - passphrase: undefined - } - } as any, (err, publicKey, privateKey) => - err ? rej(err) : res([publicKey, privateKey]) - )); - - let account!: User; - - // Start transaction - await getConnection().transaction(async transactionalEntityManager => { - const exist = await transactionalEntityManager.findOne(User, { - usernameLower: username.toLowerCase(), - host: null - }); - - if (exist) throw new Error(' the username is already used'); - - account = await transactionalEntityManager.save(new User({ - id: genId(), - createdAt: new Date(), - username: username, - usernameLower: username.toLowerCase(), - host: toPunyNullable(host), - token: secret, - isAdmin: (await Users.count({ - host: null, - })) === 0, - })); - - await transactionalEntityManager.save(new UserKeypair({ - publicKey: keyPair[0], - privateKey: keyPair[1], - userId: account.id - })); - - await transactionalEntityManager.save(new UserProfile({ - userId: account.id, - autoAcceptFollowed: true, - password: hash, - })); - - await transactionalEntityManager.save(new UsedUsername({ - createdAt: new Date(), - username: username.toLowerCase(), - })); - }); - - usersChart.update(account, true); - - return { account, secret }; -} -- cgit v1.2.3-freya