summaryrefslogtreecommitdiff
path: root/src/models/repositories/user.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/models/repositories/user.ts')
-rw-r--r--src/models/repositories/user.ts659
1 files changed, 0 insertions, 659 deletions
diff --git a/src/models/repositories/user.ts b/src/models/repositories/user.ts
deleted file mode 100644
index fc0860970c..0000000000
--- a/src/models/repositories/user.ts
+++ /dev/null
@@ -1,659 +0,0 @@
-import $ from 'cafy';
-import { EntityRepository, Repository, In, Not } from 'typeorm';
-import { User, ILocalUser, IRemoteUser } from '@/models/entities/user';
-import { Notes, NoteUnreads, FollowRequests, Notifications, MessagingMessages, UserNotePinings, Followings, Blockings, Mutings, UserProfiles, UserSecurityKeys, UserGroupJoinings, Pages, Announcements, AnnouncementReads, Antennas, AntennaNotes, ChannelFollowings, Instances } from '../index';
-import config from '@/config/index';
-import { Packed } from '@/misc/schema';
-import { awaitAll } from '@/prelude/await-all';
-import { populateEmojis } from '@/misc/populate-emojis';
-import { getAntennas } from '@/misc/antenna-cache';
-import { USER_ACTIVE_THRESHOLD, USER_ONLINE_THRESHOLD } from '@/const';
-
-@EntityRepository(User)
-export class UserRepository extends Repository<User> {
- public async getRelation(me: User['id'], target: User['id']) {
- const [following1, following2, followReq1, followReq2, toBlocking, fromBlocked, mute] = await Promise.all([
- Followings.findOne({
- followerId: me,
- followeeId: target
- }),
- Followings.findOne({
- followerId: target,
- followeeId: me
- }),
- FollowRequests.findOne({
- followerId: me,
- followeeId: target
- }),
- FollowRequests.findOne({
- followerId: target,
- followeeId: me
- }),
- Blockings.findOne({
- blockerId: me,
- blockeeId: target
- }),
- Blockings.findOne({
- blockerId: target,
- blockeeId: me
- }),
- Mutings.findOne({
- muterId: me,
- muteeId: target
- })
- ]);
-
- return {
- id: target,
- isFollowing: following1 != null,
- hasPendingFollowRequestFromYou: followReq1 != null,
- hasPendingFollowRequestToYou: followReq2 != null,
- isFollowed: following2 != null,
- isBlocking: toBlocking != null,
- isBlocked: fromBlocked != null,
- isMuted: mute != null
- };
- }
-
- public async getHasUnreadMessagingMessage(userId: User['id']): Promise<boolean> {
- const mute = await Mutings.find({
- muterId: userId
- });
-
- const joinings = await UserGroupJoinings.find({ userId: userId });
-
- const groupQs = Promise.all(joinings.map(j => MessagingMessages.createQueryBuilder('message')
- .where(`message.groupId = :groupId`, { groupId: j.userGroupId })
- .andWhere('message.userId != :userId', { userId: userId })
- .andWhere('NOT (:userId = ANY(message.reads))', { userId: userId })
- .andWhere('message.createdAt > :joinedAt', { joinedAt: j.createdAt }) // 自分が加入する前の会話については、未読扱いしない
- .getOne().then(x => x != null)));
-
- const [withUser, withGroups] = await Promise.all([
- MessagingMessages.count({
- where: {
- recipientId: userId,
- isRead: false,
- ...(mute.length > 0 ? { userId: Not(In(mute.map(x => x.muteeId))) } : {}),
- },
- take: 1
- }).then(count => count > 0),
- groupQs
- ]);
-
- return withUser || withGroups.some(x => x);
- }
-
- public async getHasUnreadAnnouncement(userId: User['id']): Promise<boolean> {
- const reads = await AnnouncementReads.find({
- userId: userId
- });
-
- const count = await Announcements.count(reads.length > 0 ? {
- id: Not(In(reads.map(read => read.announcementId)))
- } : {});
-
- return count > 0;
- }
-
- public async getHasUnreadAntenna(userId: User['id']): Promise<boolean> {
- const myAntennas = (await getAntennas()).filter(a => a.userId === userId);
-
- const unread = myAntennas.length > 0 ? await AntennaNotes.findOne({
- antennaId: In(myAntennas.map(x => x.id)),
- read: false
- }) : null;
-
- return unread != null;
- }
-
- public async getHasUnreadChannel(userId: User['id']): Promise<boolean> {
- const channels = await ChannelFollowings.find({ followerId: userId });
-
- const unread = channels.length > 0 ? await NoteUnreads.findOne({
- userId: userId,
- noteChannelId: In(channels.map(x => x.followeeId)),
- }) : null;
-
- return unread != null;
- }
-
- public async getHasUnreadNotification(userId: User['id']): Promise<boolean> {
- const mute = await Mutings.find({
- muterId: userId
- });
- const mutedUserIds = mute.map(m => m.muteeId);
-
- const count = await Notifications.count({
- where: {
- notifieeId: userId,
- ...(mutedUserIds.length > 0 ? { notifierId: Not(In(mutedUserIds)) } : {}),
- isRead: false
- },
- take: 1
- });
-
- return count > 0;
- }
-
- public async getHasPendingReceivedFollowRequest(userId: User['id']): Promise<boolean> {
- const count = await FollowRequests.count({
- followeeId: userId
- });
-
- return count > 0;
- }
-
- public getOnlineStatus(user: User): string {
- if (user.hideOnlineStatus) return 'unknown';
- if (user.lastActiveDate == null) return 'unknown';
- const elapsed = Date.now() - user.lastActiveDate.getTime();
- return (
- elapsed < USER_ONLINE_THRESHOLD ? 'online' :
- elapsed < USER_ACTIVE_THRESHOLD ? 'active' :
- 'offline'
- );
- }
-
- public getAvatarUrl(user: User): string {
- if (user.avatarUrl) {
- return user.avatarUrl;
- } else {
- return `${config.url}/random-avatar/${user.id}`;
- }
- }
-
- public async pack(
- src: User['id'] | User,
- me?: { id: User['id'] } | null | undefined,
- options?: {
- detail?: boolean,
- includeSecrets?: boolean,
- }
- ): Promise<Packed<'User'>> {
- const opts = Object.assign({
- detail: false,
- includeSecrets: false
- }, options);
-
- const user = typeof src === 'object' ? src : await this.findOneOrFail(src);
- const meId = me ? me.id : null;
-
- const relation = meId && (meId !== user.id) && opts.detail ? await this.getRelation(meId, user.id) : null;
- const pins = opts.detail ? await UserNotePinings.createQueryBuilder('pin')
- .where('pin.userId = :userId', { userId: user.id })
- .innerJoinAndSelect('pin.note', 'note')
- .orderBy('pin.id', 'DESC')
- .getMany() : [];
- const profile = opts.detail ? await UserProfiles.findOneOrFail(user.id) : null;
-
- const followingCount = profile == null ? null :
- (profile.ffVisibility === 'public') || (meId === user.id) ? user.followingCount :
- (profile.ffVisibility === 'followers') && (relation!.isFollowing) ? user.followingCount :
- null;
-
- const followersCount = profile == null ? null :
- (profile.ffVisibility === 'public') || (meId === user.id) ? user.followersCount :
- (profile.ffVisibility === 'followers') && (relation!.isFollowing) ? user.followersCount :
- null;
-
- const falsy = opts.detail ? false : undefined;
-
- const packed = {
- id: user.id,
- name: user.name,
- username: user.username,
- host: user.host,
- avatarUrl: this.getAvatarUrl(user),
- avatarBlurhash: user.avatarBlurhash,
- avatarColor: null, // 後方互換性のため
- isAdmin: user.isAdmin || falsy,
- isModerator: user.isModerator || falsy,
- isBot: user.isBot || falsy,
- isCat: user.isCat || falsy,
- instance: user.host ? Instances.findOne({ host: user.host }).then(instance => instance ? {
- name: instance.name,
- softwareName: instance.softwareName,
- softwareVersion: instance.softwareVersion,
- iconUrl: instance.iconUrl,
- faviconUrl: instance.faviconUrl,
- themeColor: instance.themeColor,
- } : undefined) : undefined,
- emojis: populateEmojis(user.emojis, user.host),
- onlineStatus: this.getOnlineStatus(user),
-
- ...(opts.detail ? {
- url: profile!.url,
- uri: user.uri,
- createdAt: user.createdAt.toISOString(),
- updatedAt: user.updatedAt ? user.updatedAt.toISOString() : null,
- lastFetchedAt: user.lastFetchedAt?.toISOString(),
- bannerUrl: user.bannerUrl,
- bannerBlurhash: user.bannerBlurhash,
- bannerColor: null, // 後方互換性のため
- isLocked: user.isLocked,
- isModerator: user.isModerator || falsy,
- isSilenced: user.isSilenced || falsy,
- isSuspended: user.isSuspended || falsy,
- description: profile!.description,
- location: profile!.location,
- birthday: profile!.birthday,
- lang: profile!.lang,
- fields: profile!.fields,
- followersCount: followersCount || 0,
- followingCount: followingCount || 0,
- notesCount: user.notesCount,
- pinnedNoteIds: pins.map(pin => pin.noteId),
- pinnedNotes: Notes.packMany(pins.map(pin => pin.note!), me, {
- detail: true
- }),
- pinnedPageId: profile!.pinnedPageId,
- pinnedPage: profile!.pinnedPageId ? Pages.pack(profile!.pinnedPageId, me) : null,
- publicReactions: profile!.publicReactions,
- ffVisibility: profile!.ffVisibility,
- twoFactorEnabled: profile!.twoFactorEnabled,
- usePasswordLessLogin: profile!.usePasswordLessLogin,
- securityKeys: profile!.twoFactorEnabled
- ? UserSecurityKeys.count({
- userId: user.id
- }).then(result => result >= 1)
- : false,
- } : {}),
-
- ...(opts.detail && meId === user.id ? {
- avatarId: user.avatarId,
- bannerId: user.bannerId,
- injectFeaturedNote: profile!.injectFeaturedNote,
- receiveAnnouncementEmail: profile!.receiveAnnouncementEmail,
- alwaysMarkNsfw: profile!.alwaysMarkNsfw,
- carefulBot: profile!.carefulBot,
- autoAcceptFollowed: profile!.autoAcceptFollowed,
- noCrawle: profile!.noCrawle,
- isExplorable: user.isExplorable,
- isDeleted: user.isDeleted,
- hideOnlineStatus: user.hideOnlineStatus,
- hasUnreadSpecifiedNotes: NoteUnreads.count({
- where: { userId: user.id, isSpecified: true },
- take: 1
- }).then(count => count > 0),
- hasUnreadMentions: NoteUnreads.count({
- where: { userId: user.id, isMentioned: true },
- take: 1
- }).then(count => count > 0),
- hasUnreadAnnouncement: this.getHasUnreadAnnouncement(user.id),
- hasUnreadAntenna: this.getHasUnreadAntenna(user.id),
- hasUnreadChannel: this.getHasUnreadChannel(user.id),
- hasUnreadMessagingMessage: this.getHasUnreadMessagingMessage(user.id),
- hasUnreadNotification: this.getHasUnreadNotification(user.id),
- hasPendingReceivedFollowRequest: this.getHasPendingReceivedFollowRequest(user.id),
- integrations: profile!.integrations,
- mutedWords: profile!.mutedWords,
- mutingNotificationTypes: profile!.mutingNotificationTypes,
- emailNotificationTypes: profile!.emailNotificationTypes,
- } : {}),
-
- ...(opts.includeSecrets ? {
- email: profile!.email,
- emailVerified: profile!.emailVerified,
- securityKeysList: profile!.twoFactorEnabled
- ? UserSecurityKeys.find({
- where: {
- userId: user.id
- },
- select: ['id', 'name', 'lastUsed']
- })
- : []
- } : {}),
-
- ...(relation ? {
- isFollowing: relation.isFollowing,
- isFollowed: relation.isFollowed,
- hasPendingFollowRequestFromYou: relation.hasPendingFollowRequestFromYou,
- hasPendingFollowRequestToYou: relation.hasPendingFollowRequestToYou,
- isBlocking: relation.isBlocking,
- isBlocked: relation.isBlocked,
- isMuted: relation.isMuted,
- } : {})
- };
-
- return await awaitAll(packed);
- }
-
- public packMany(
- users: (User['id'] | User)[],
- me?: { id: User['id'] } | null | undefined,
- options?: {
- detail?: boolean,
- includeSecrets?: boolean,
- }
- ) {
- return Promise.all(users.map(u => this.pack(u, me, options)));
- }
-
- public isLocalUser(user: User): user is ILocalUser;
- public isLocalUser<T extends { host: User['host'] }>(user: T): user is T & { host: null; };
- public isLocalUser(user: User | { host: User['host'] }): boolean {
- return user.host == null;
- }
-
- public isRemoteUser(user: User): user is IRemoteUser;
- public isRemoteUser<T extends { host: User['host'] }>(user: T): user is T & { host: string; };
- public isRemoteUser(user: User | { host: User['host'] }): boolean {
- return !this.isLocalUser(user);
- }
-
- //#region Validators
- public validateLocalUsername = $.str.match(/^\w{1,20}$/);
- public validatePassword = $.str.min(1);
- public validateName = $.str.min(1).max(50);
- public validateDescription = $.str.min(1).max(500);
- public validateLocation = $.str.min(1).max(50);
- public validateBirthday = $.str.match(/^([0-9]{4})-([0-9]{2})-([0-9]{2})$/);
- //#endregion
-}
-
-export const packedUserSchema = {
- type: 'object' as const,
- nullable: false as const, optional: false as const,
- properties: {
- id: {
- type: 'string' as const,
- nullable: false as const, optional: false as const,
- format: 'id',
- example: 'xxxxxxxxxx',
- },
- name: {
- type: 'string' as const,
- nullable: true as const, optional: false as const,
- example: '藍'
- },
- username: {
- type: 'string' as const,
- nullable: false as const, optional: false as const,
- example: 'ai'
- },
- host: {
- type: 'string' as const,
- nullable: true as const, optional: false as const,
- example: 'misskey.example.com'
- },
- avatarUrl: {
- type: 'string' as const,
- format: 'url',
- nullable: true as const, optional: false as const,
- },
- avatarBlurhash: {
- type: 'any' as const,
- nullable: true as const, optional: false as const,
- },
- avatarColor: {
- type: 'any' as const,
- nullable: true as const, optional: false as const,
- default: null
- },
- isAdmin: {
- type: 'boolean' as const,
- nullable: false as const, optional: true as const,
- default: false
- },
- isModerator: {
- type: 'boolean' as const,
- nullable: false as const, optional: true as const,
- default: false
- },
- isBot: {
- type: 'boolean' as const,
- nullable: false as const, optional: true as const,
- },
- isCat: {
- type: 'boolean' as const,
- nullable: false as const, optional: true as const,
- },
- emojis: {
- type: 'array' as const,
- nullable: false as const, optional: false as const,
- items: {
- type: 'object' as const,
- nullable: false as const, optional: false as const,
- properties: {
- name: {
- type: 'string' as const,
- nullable: false as const, optional: false as const
- },
- url: {
- type: 'string' as const,
- nullable: false as const, optional: false as const,
- format: 'url'
- },
- }
- }
- },
- url: {
- type: 'string' as const,
- format: 'url',
- nullable: true as const, optional: true as const,
- },
- createdAt: {
- type: 'string' as const,
- nullable: false as const, optional: true as const,
- format: 'date-time',
- },
- updatedAt: {
- type: 'string' as const,
- nullable: true as const, optional: true as const,
- format: 'date-time',
- },
- bannerUrl: {
- type: 'string' as const,
- format: 'url',
- nullable: true as const, optional: true as const,
- },
- bannerBlurhash: {
- type: 'any' as const,
- nullable: true as const, optional: true as const,
- },
- bannerColor: {
- type: 'any' as const,
- nullable: true as const, optional: true as const,
- default: null
- },
- isLocked: {
- type: 'boolean' as const,
- nullable: false as const, optional: true as const,
- },
- isSuspended: {
- type: 'boolean' as const,
- nullable: false as const, optional: true as const,
- example: false
- },
- description: {
- type: 'string' as const,
- nullable: true as const, optional: true as const,
- example: 'Hi masters, I am Ai!'
- },
- location: {
- type: 'string' as const,
- nullable: true as const, optional: true as const,
- },
- birthday: {
- type: 'string' as const,
- nullable: true as const, optional: true as const,
- example: '2018-03-12'
- },
- fields: {
- type: 'array' as const,
- nullable: false as const, optional: true as const,
- items: {
- type: 'object' as const,
- nullable: false as const, optional: false as const,
- properties: {
- name: {
- type: 'string' as const,
- nullable: false as const, optional: false as const
- },
- value: {
- type: 'string' as const,
- nullable: false as const, optional: false as const
- }
- },
- maxLength: 4
- }
- },
- followersCount: {
- type: 'number' as const,
- nullable: false as const, optional: true as const,
- },
- followingCount: {
- type: 'number' as const,
- nullable: false as const, optional: true as const,
- },
- notesCount: {
- type: 'number' as const,
- nullable: false as const, optional: true as const,
- },
- pinnedNoteIds: {
- type: 'array' as const,
- nullable: false as const, optional: true as const,
- items: {
- type: 'string' as const,
- nullable: false as const, optional: false as const,
- format: 'id',
- }
- },
- pinnedNotes: {
- type: 'array' as const,
- nullable: false as const, optional: true as const,
- items: {
- type: 'object' as const,
- nullable: false as const, optional: false as const,
- ref: 'Note' as const,
- }
- },
- pinnedPageId: {
- type: 'string' as const,
- nullable: true as const, optional: true as const
- },
- pinnedPage: {
- type: 'object' as const,
- nullable: true as const, optional: true as const,
- ref: 'Page' as const,
- },
- twoFactorEnabled: {
- type: 'boolean' as const,
- nullable: false as const, optional: true as const,
- default: false
- },
- usePasswordLessLogin: {
- type: 'boolean' as const,
- nullable: false as const, optional: true as const,
- default: false
- },
- securityKeys: {
- type: 'boolean' as const,
- nullable: false as const, optional: true as const,
- default: false
- },
- avatarId: {
- type: 'string' as const,
- nullable: true as const, optional: true as const,
- format: 'id'
- },
- bannerId: {
- type: 'string' as const,
- nullable: true as const, optional: true as const,
- format: 'id'
- },
- autoWatch: {
- type: 'boolean' as const,
- nullable: false as const, optional: true as const
- },
- injectFeaturedNote: {
- type: 'boolean' as const,
- nullable: false as const, optional: true as const
- },
- alwaysMarkNsfw: {
- type: 'boolean' as const,
- nullable: false as const, optional: true as const
- },
- carefulBot: {
- type: 'boolean' as const,
- nullable: false as const, optional: true as const
- },
- autoAcceptFollowed: {
- type: 'boolean' as const,
- nullable: false as const, optional: true as const
- },
- hasUnreadSpecifiedNotes: {
- type: 'boolean' as const,
- nullable: false as const, optional: true as const,
- },
- hasUnreadMentions: {
- type: 'boolean' as const,
- nullable: false as const, optional: true as const,
- },
- hasUnreadAnnouncement: {
- type: 'boolean' as const,
- nullable: false as const, optional: true as const,
- },
- hasUnreadAntenna: {
- type: 'boolean' as const,
- nullable: false as const, optional: true as const,
- },
- hasUnreadChannel: {
- type: 'boolean' as const,
- nullable: false as const, optional: true as const,
- },
- hasUnreadMessagingMessage: {
- type: 'boolean' as const,
- nullable: false as const, optional: true as const,
- },
- hasUnreadNotification: {
- type: 'boolean' as const,
- nullable: false as const, optional: true as const,
- },
- hasPendingReceivedFollowRequest: {
- type: 'boolean' as const,
- nullable: false as const, optional: true as const,
- },
- integrations: {
- type: 'object' as const,
- nullable: false as const, optional: true as const
- },
- mutedWords: {
- type: 'array' as const,
- nullable: false as const, optional: true as const
- },
- mutingNotificationTypes: {
- type: 'array' as const,
- nullable: false as const, optional: true as const
- },
- isFollowing: {
- type: 'boolean' as const,
- optional: true as const, nullable: false as const
- },
- hasPendingFollowRequestFromYou: {
- type: 'boolean' as const,
- optional: true as const, nullable: false as const
- },
- hasPendingFollowRequestToYou: {
- type: 'boolean' as const,
- optional: true as const, nullable: false as const
- },
- isFollowed: {
- type: 'boolean' as const,
- optional: true as const, nullable: false as const
- },
- isBlocking: {
- type: 'boolean' as const,
- optional: true as const, nullable: false as const
- },
- isBlocked: {
- type: 'boolean' as const,
- optional: true as const, nullable: false as const
- },
- isMuted: {
- type: 'boolean' as const,
- optional: true as const, nullable: false as const
- }
- },
-};