2022-07-11 13:31:09 +00:00
import { In , Not } from 'typeorm' ;
2022-02-27 02:07:39 +00:00
import Ajv from 'ajv' ;
import { User , ILocalUser , IRemoteUser } from '@/models/entities/user.js' ;
import config from '@/config/index.js' ;
import { Packed } from '@/misc/schema.js' ;
import { awaitAll , Promiseable } from '@/prelude/await-all.js' ;
import { populateEmojis } from '@/misc/populate-emojis.js' ;
2022-11-13 17:45:31 +00:00
import { USER_ACTIVE_THRESHOLD , USER_ONLINE_THRESHOLD , HOUR } from '@/const.js' ;
2022-03-20 16:22:00 +00:00
import { Cache } from '@/misc/cache.js' ;
2022-03-26 06:34:00 +00:00
import { db } from '@/db/postgre.js' ;
2022-04-17 12:18:18 +00:00
import { Instance } from '../entities/instance.js' ;
2022-10-06 23:20:38 +00:00
import { Notes , NoteUnreads , FollowRequests , Notifications , MessagingMessages , UserNotePinings , Followings , Blockings , Mutings , RenoteMutings , UserProfiles , UserSecurityKeys , UserGroupJoinings , Pages , Announcements , AnnouncementReads , AntennaNotes , ChannelFollowings , Instances , DriveFiles } from '../index.js' ;
2022-03-20 16:22:00 +00:00
2022-11-13 17:45:31 +00:00
const userInstanceCache = new Cache < Instance | null > (
3 * HOUR ,
( host ) = > Instances . findOneBy ( { host } ) . then ( x = > x ? ? undefined ) ,
) ;
2019-04-23 13:35:26 +00:00
2022-01-18 13:27:10 +00:00
type IsUserDetailed < Detailed extends boolean > = Detailed extends true ? Packed < 'UserDetailed' > : Packed < 'UserLite' > ;
type IsMeAndIsUserDetailed < ExpectsMe extends boolean | null , Detailed extends boolean > =
2022-12-04 14:34:05 +00:00
Detailed extends true ?
2022-01-18 13:27:10 +00:00
ExpectsMe extends true ? Packed < 'MeDetailed' > :
ExpectsMe extends false ? Packed < 'UserDetailedNotMe' > :
Packed < 'UserDetailed' > :
Packed < 'UserLite' > ;
2022-02-19 05:05:32 +00:00
const ajv = new Ajv ( ) ;
2023-04-20 20:10:31 +00:00
// It is important that localUsernameSchema does not allow any usernames
// containing dots because those are used for system actors.
2022-03-26 06:34:00 +00:00
const localUsernameSchema = { type : 'string' , pattern : /^\w{1,20}$/ . toString ( ) . slice ( 1 , - 1 ) } as const ;
const passwordSchema = { type : 'string' , minLength : 1 } as const ;
const nameSchema = { type : 'string' , minLength : 1 , maxLength : 50 } as const ;
2022-11-11 11:28:57 +00:00
const descriptionSchema = { type : 'string' , minLength : 1 , maxLength : 2048 } as const ;
2022-03-26 06:34:00 +00:00
const locationSchema = { type : 'string' , minLength : 1 , maxLength : 50 } as const ;
const birthdaySchema = { type : 'string' , pattern : /^([0-9]{4})-([0-9]{2})-([0-9]{2})$/ . toString ( ) . slice ( 1 , - 1 ) } as const ;
function isLocalUser ( user : User ) : user is ILocalUser ;
2022-12-08 00:32:05 +00:00
function isLocalUser < T extends { host : User [ ' host ' ] } > ( user : T ) : user is T & { host : null ; token : string ; } ;
2022-03-26 06:34:00 +00:00
function isLocalUser ( user : User | { host : User [ 'host' ] } ) : boolean {
return user . host == null ;
}
function isRemoteUser ( user : User ) : user is IRemoteUser ;
function isRemoteUser < T extends { host : User [ ' host ' ] } > ( user : T ) : user is T & { host : string ; } ;
function isRemoteUser ( user : User | { host : User [ 'host' ] } ) : boolean {
return ! isLocalUser ( user ) ;
}
export const UserRepository = db . getRepository ( User ) . extend ( {
localUsernameSchema ,
passwordSchema ,
nameSchema ,
descriptionSchema ,
locationSchema ,
birthdaySchema ,
2022-02-19 05:05:32 +00:00
//#region Validators
2022-03-26 06:34:00 +00:00
validateLocalUsername : ajv.compile ( localUsernameSchema ) ,
validatePassword : ajv.compile ( passwordSchema ) ,
validateName : ajv.compile ( nameSchema ) ,
validateDescription : ajv.compile ( descriptionSchema ) ,
validateLocation : ajv.compile ( locationSchema ) ,
validateBirthday : ajv.compile ( birthdaySchema ) ,
2022-02-19 05:05:32 +00:00
//#endregion
2022-03-26 06:34:00 +00:00
async getRelation ( me : User [ 'id' ] , target : User [ 'id' ] ) {
2022-05-29 06:15:52 +00:00
return awaitAll ( {
2019-04-07 12:50:36 +00:00
id : target ,
2022-05-29 06:15:52 +00:00
isFollowing : Followings.count ( {
where : {
followerId : me ,
followeeId : target ,
} ,
take : 1 ,
} ) . then ( n = > n > 0 ) ,
isFollowed : Followings.count ( {
where : {
followerId : target ,
followeeId : me ,
} ,
take : 1 ,
} ) . then ( n = > n > 0 ) ,
hasPendingFollowRequestFromYou : FollowRequests.count ( {
where : {
followerId : me ,
followeeId : target ,
} ,
take : 1 ,
} ) . then ( n = > n > 0 ) ,
hasPendingFollowRequestToYou : FollowRequests.count ( {
where : {
followerId : target ,
followeeId : me ,
} ,
take : 1 ,
} ) . then ( n = > n > 0 ) ,
isBlocking : Blockings.count ( {
where : {
blockerId : me ,
blockeeId : target ,
} ,
take : 1 ,
} ) . then ( n = > n > 0 ) ,
isBlocked : Blockings.count ( {
where : {
blockerId : target ,
blockeeId : me ,
} ,
take : 1 ,
} ) . then ( n = > n > 0 ) ,
isMuted : Mutings.count ( {
where : {
muterId : me ,
muteeId : target ,
} ,
take : 1 ,
} ) . then ( n = > n > 0 ) ,
2022-10-06 23:20:38 +00:00
isRenoteMuted : RenoteMutings.count ( {
where : {
muterId : me ,
muteeId : target ,
} ,
take : 1 ,
} ) . then ( n = > n > 0 ) ,
2022-05-29 06:15:52 +00:00
} ) ;
2022-03-26 06:34:00 +00:00
} ,
2019-04-07 12:50:36 +00:00
2022-03-26 06:34:00 +00:00
async getHasUnreadMessagingMessage ( userId : User [ 'id' ] ) : Promise < boolean > {
2022-12-30 12:45:19 +00:00
return await db . query (
` SELECT EXISTS (
SELECT 1
FROM "messaging_message"
WHERE
"recipientId" = $1
AND
NOT "isRead"
AND
"userId" NOT IN (
SELECT "muteeId"
FROM "muting"
WHERE "muterId" = $1
)
UNION
SELECT 1
FROM "messaging_message"
JOIN "user_group_joining"
ON "messaging_message" . "groupId" = "user_group_joining" . "userGroupId"
WHERE
2023-01-13 20:55:14 +00:00
"user_group_joining" . "userId" = $1
AND
2022-12-30 12:45:19 +00:00
"messaging_message" . "userId" != $1
AND
NOT $1 = ANY ( "messaging_message" . "reads" )
AND
"messaging_message" . "createdAt" > "user_group_joining" . "createdAt"
) AS exists ` ,
[ userId ]
) . then ( res = > res [ 0 ] . exists ) ;
2022-03-26 06:34:00 +00:00
} ,
2019-05-18 11:36:33 +00:00
2022-03-26 06:34:00 +00:00
async getHasUnreadAnnouncement ( userId : User [ 'id' ] ) : Promise < boolean > {
2022-12-30 12:45:19 +00:00
return await db . query (
` SELECT EXISTS (SELECT 1 FROM "announcement" WHERE "id" NOT IN (SELECT "announcementId" FROM "announcement_read" WHERE "userId" = $ 1)) AS exists ` ,
[ userId ]
) . then ( res = > res [ 0 ] . exists ) ;
2022-03-26 06:34:00 +00:00
} ,
2020-01-29 19:37:25 +00:00
2022-03-26 06:34:00 +00:00
async getHasUnreadAntenna ( userId : User [ 'id' ] ) : Promise < boolean > {
2022-12-30 12:45:19 +00:00
return await db . query (
` SELECT EXISTS (SELECT 1 FROM "antenna_note" WHERE NOT "read" AND "antennaId" IN (SELECT "id" FROM "antenna" WHERE "userId" = $ 1)) AS exists ` ,
[ userId ]
) . then ( res = > res [ 0 ] . exists ) ;
2022-03-26 06:34:00 +00:00
} ,
2020-01-29 19:37:25 +00:00
2022-03-26 06:34:00 +00:00
async getHasUnreadChannel ( userId : User [ 'id' ] ) : Promise < boolean > {
2022-12-30 12:45:19 +00:00
return await db . query (
` SELECT EXISTS (SELECT 1 FROM "note_unread" WHERE "noteChannelId" IN (SELECT "followeeId" FROM "channel_following" WHERE "followerId" = $ 1)) AS exists ` ,
[ userId ]
) . then ( res = > res [ 0 ] . exists ) ;
2022-03-26 06:34:00 +00:00
} ,
2020-08-18 13:44:21 +00:00
2022-03-26 06:34:00 +00:00
async getHasUnreadNotification ( userId : User [ 'id' ] ) : Promise < boolean > {
2022-12-30 12:45:19 +00:00
return await db . query (
` SELECT EXISTS (SELECT 1 FROM "notification" WHERE NOT "isRead" AND "notifieeId" = $ 1 AND "notifierId" NOT IN (SELECT "muteeId" FROM "muting" WHERE "muterId" = $ 1)) AS exists ` ,
[ userId ]
) . then ( res = > res [ 0 ] . exists ) ;
2022-03-26 06:34:00 +00:00
} ,
2020-01-29 19:37:25 +00:00
2022-03-26 06:34:00 +00:00
async getHasPendingReceivedFollowRequest ( userId : User [ 'id' ] ) : Promise < boolean > {
2022-12-30 12:45:19 +00:00
return await db . query (
` SELECT EXISTS (SELECT 1 FROM "follow_request" WHERE "followeeId" = $ 1) AS exists ` ,
[ userId ]
) . then ( res = > res [ 0 ] . exists ) ;
2022-03-26 06:34:00 +00:00
} ,
2020-02-15 00:10:49 +00:00
2022-03-26 06:34:00 +00:00
getOnlineStatus ( user : User ) : 'unknown' | 'online' | 'active' | 'offline' {
2021-04-19 15:15:53 +00:00
if ( user . hideOnlineStatus ) return 'unknown' ;
2021-04-17 06:30:26 +00:00
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'
) ;
2022-03-26 06:34:00 +00:00
} ,
2021-04-17 06:30:26 +00:00
2022-04-17 12:18:18 +00:00
async getAvatarUrl ( user : User ) : Promise < string > {
if ( user . avatar ) {
return DriveFiles . getPublicUrl ( user . avatar , true ) || this . getIdenticonUrl ( user . id ) ;
} else if ( user . avatarId ) {
const avatar = await DriveFiles . findOneByOrFail ( { id : user.avatarId } ) ;
return DriveFiles . getPublicUrl ( avatar , true ) || this . getIdenticonUrl ( user . id ) ;
} else {
return this . getIdenticonUrl ( user . id ) ;
}
} ,
getAvatarUrlSync ( user : User ) : string {
2022-02-27 04:59:10 +00:00
if ( user . avatar ) {
return DriveFiles . getPublicUrl ( user . avatar , true ) || this . getIdenticonUrl ( user . id ) ;
2021-10-24 12:02:50 +00:00
} else {
2022-02-27 04:59:10 +00:00
return this . getIdenticonUrl ( user . id ) ;
2021-10-24 12:02:50 +00:00
}
2022-03-26 06:34:00 +00:00
} ,
2021-10-24 12:02:50 +00:00
2022-03-26 06:34:00 +00:00
getIdenticonUrl ( userId : User [ 'id' ] ) : string {
2022-02-27 04:59:10 +00:00
return ` ${ config . url } /identicon/ ${ userId } ` ;
2022-03-26 06:34:00 +00:00
} ,
2022-02-27 04:59:10 +00:00
2023-05-19 22:22:38 +00:00
/ * *
* Determines whether the followers / following of user ` user ` are visibile to user ` me ` .
* /
async areFollowersVisibleTo ( user : User , me : { id : User [ 'id' ] } | null | undefined ) : Promise < boolean > {
const profile = await UserProfiles . findOneByOrFail ( { userId : user.id } ) ;
switch ( profile . ffVisibility ) {
case 'public' :
return true ;
case 'followers' :
if ( me == null ) {
return false ;
} else if ( me . id === user . id ) {
return true ;
} else {
return await Followings . count ( {
where : {
followerId : me.id ,
followeeId : user.id ,
} ,
take : 1 ,
} ) . then ( n = > n > 0 ) ;
}
case 'private' :
return me ? . id === user . id ;
2023-05-19 22:32:18 +00:00
case 'nobody' :
return false ;
2023-05-19 22:22:38 +00:00
}
2023-05-23 21:56:30 +00:00
} ,
2023-05-19 22:22:38 +00:00
2022-03-26 06:34:00 +00:00
async pack < ExpectsMe extends boolean | null = null , D extends boolean = false > (
2019-04-07 12:50:36 +00:00
src : User [ 'id' ] | User ,
2021-03-24 02:05:37 +00:00
me ? : { id : User [ 'id' ] } | null | undefined ,
2019-04-07 12:50:36 +00:00
options ? : {
2022-01-18 13:27:10 +00:00
detail? : D ,
2019-04-07 12:50:36 +00:00
includeSecrets? : boolean ,
2022-04-17 12:18:18 +00:00
} ,
2022-01-18 13:27:10 +00:00
) : Promise < IsMeAndIsUserDetailed < ExpectsMe , D > > {
2019-04-07 12:50:36 +00:00
const opts = Object . assign ( {
detail : false ,
2021-12-09 14:58:30 +00:00
includeSecrets : false ,
2019-04-07 12:50:36 +00:00
} , options ) ;
2022-02-27 04:59:10 +00:00
let user : User ;
if ( typeof src === 'object' ) {
user = src ;
2022-03-26 06:34:00 +00:00
if ( src . avatar === undefined && src . avatarId ) src . avatar = await DriveFiles . findOneBy ( { id : src.avatarId } ) ? ? null ;
if ( src . banner === undefined && src . bannerId ) src . banner = await DriveFiles . findOneBy ( { id : src.bannerId } ) ? ? null ;
2022-02-27 04:59:10 +00:00
} else {
2022-03-26 06:34:00 +00:00
user = await this . findOneOrFail ( {
where : { id : src } ,
relations : {
avatar : true ,
banner : true ,
} ,
2022-02-27 04:59:10 +00:00
} ) ;
}
2021-03-24 02:05:37 +00:00
const meId = me ? me.id : null ;
2022-01-18 13:27:10 +00:00
const isMe = meId === user . id ;
2019-04-07 12:50:36 +00:00
2022-01-18 13:27:10 +00:00
const relation = meId && ! isMe && opts . detail ? await this . getRelation ( meId , user . id ) : null ;
2021-03-22 02:38:32 +00:00
const pins = opts . detail ? await UserNotePinings . createQueryBuilder ( 'pin' )
. where ( 'pin.userId = :userId' , { userId : user.id } )
. innerJoinAndSelect ( 'pin.note' , 'note' )
2021-03-22 03:41:38 +00:00
. orderBy ( 'pin.id' , 'DESC' )
2021-03-22 02:38:32 +00:00
. getMany ( ) : [ ] ;
2022-03-26 06:34:00 +00:00
const profile = opts . detail ? await UserProfiles . findOneByOrFail ( { userId : user.id } ) : null ;
2019-04-07 12:50:36 +00:00
2023-05-19 22:22:38 +00:00
const ffVisible = await this . areFollowersVisibleTo ( user , me ) ;
2023-05-27 18:42:10 +00:00
const followingCount = ! opts . detail ? null :
2023-05-19 22:22:38 +00:00
ffVisible ? user.followingCount : null ;
2021-11-07 09:04:32 +00:00
2023-05-27 18:42:10 +00:00
const followersCount = ! opts . detail ? null :
2023-05-19 22:22:38 +00:00
ffVisible ? user.followersCount : null ;
2021-11-07 09:04:32 +00:00
2019-04-23 13:35:26 +00:00
const packed = {
2019-04-07 12:50:36 +00:00
id : user.id ,
name : user.name ,
username : user.username ,
host : user.host ,
2022-04-17 12:18:18 +00:00
avatarUrl : this.getAvatarUrlSync ( user ) ,
2022-02-27 04:59:10 +00:00
avatarBlurhash : user.avatar?.blurhash || null ,
2023-02-11 18:17:11 +00:00
isAdmin : user.isAdmin ,
isModerator : user.isModerator ,
isBot : user.isBot ,
isCat : user.isCat ,
2022-11-13 17:45:31 +00:00
instance : ! user . host ? undefined : userInstanceCache . fetch ( user . host )
. then ( instance = > ! instance ? undefined : {
name : instance.name ,
softwareName : instance.softwareName ,
softwareVersion : instance.softwareVersion ,
iconUrl : instance.iconUrl ,
faviconUrl : instance.faviconUrl ,
themeColor : instance.themeColor ,
} ) ,
2021-03-21 15:44:38 +00:00
emojis : populateEmojis ( user . emojis , user . host ) ,
2021-04-17 06:30:26 +00:00
onlineStatus : this.getOnlineStatus ( user ) ,
2022-11-22 14:55:59 +00:00
movedTo : ! user . movedToId ? undefined : this . pack ( user . movedTo ? ? user . movedToId , me , {
. . . opts ,
detail : false ,
} ) ,
2019-04-07 12:50:36 +00:00
. . . ( opts . detail ? {
2019-04-12 16:43:22 +00:00
url : profile ! . url ,
2021-04-16 08:34:06 +00:00
uri : user.uri ,
2019-04-23 13:35:26 +00:00
createdAt : user.createdAt.toISOString ( ) ,
updatedAt : user.updatedAt ? user . updatedAt . toISOString ( ) : null ,
2022-01-18 13:27:10 +00:00
lastFetchedAt : user.lastFetchedAt ? user . lastFetchedAt . toISOString ( ) : null ,
2022-02-27 04:59:10 +00:00
bannerUrl : user.banner ? DriveFiles . getPublicUrl ( user . banner , false ) : null ,
bannerBlurhash : user.banner?.blurhash || null ,
2019-04-14 02:58:10 +00:00
isLocked : user.isLocked ,
2023-02-11 18:17:11 +00:00
isSilenced : user.isSilenced ,
isSuspended : user.isSuspended ,
2019-04-12 16:43:22 +00:00
description : profile ! . description ,
location : profile ! . location ,
birthday : profile ! . birthday ,
2021-02-13 03:28:26 +00:00
lang : profile ! . lang ,
2019-07-17 15:11:39 +00:00
fields : profile ! . fields ,
2021-11-07 09:04:32 +00:00
followersCount : followersCount || 0 ,
followingCount : followingCount || 0 ,
2019-04-07 12:50:36 +00:00
notesCount : user.notesCount ,
pinnedNoteIds : pins.map ( pin = > pin . noteId ) ,
2021-03-24 02:05:37 +00:00
pinnedNotes : Notes.packMany ( pins . map ( pin = > pin . note ! ) , me , {
2021-12-09 14:58:30 +00:00
detail : true ,
2019-04-07 12:50:36 +00:00
} ) ,
2019-07-06 21:56:13 +00:00
pinnedPageId : profile ! . pinnedPageId ,
2021-03-24 02:05:37 +00:00
pinnedPage : profile ! . pinnedPageId ? Pages . pack ( profile ! . pinnedPageId , me ) : null ,
2021-10-17 16:16:59 +00:00
publicReactions : profile ! . publicReactions ,
2021-11-07 09:04:32 +00:00
ffVisibility : profile ! . ffVisibility ,
2019-05-03 09:55:24 +00:00
twoFactorEnabled : profile ! . twoFactorEnabled ,
2019-07-06 16:38:36 +00:00
usePasswordLessLogin : profile ! . usePasswordLessLogin ,
2019-07-03 11:18:07 +00:00
securityKeys : profile ! . twoFactorEnabled
2022-03-26 06:34:00 +00:00
? UserSecurityKeys . countBy ( {
2021-12-09 14:58:30 +00:00
userId : user.id ,
2019-07-03 11:18:07 +00:00
} ) . then ( result = > result >= 1 )
: false ,
2019-04-07 12:50:36 +00:00
} : { } ) ,
2022-01-18 13:27:10 +00:00
. . . ( opts . detail && isMe ? {
2019-04-07 12:50:36 +00:00
avatarId : user.avatarId ,
bannerId : user.bannerId ,
2020-02-18 10:05:11 +00:00
injectFeaturedNote : profile ! . injectFeaturedNote ,
2021-02-06 13:47:15 +00:00
receiveAnnouncementEmail : profile ! . receiveAnnouncementEmail ,
2019-04-12 16:43:22 +00:00
alwaysMarkNsfw : profile ! . alwaysMarkNsfw ,
carefulBot : profile ! . carefulBot ,
2019-05-26 23:41:24 +00:00
autoAcceptFollowed : profile ! . autoAcceptFollowed ,
2020-11-25 12:31:34 +00:00
noCrawle : profile ! . noCrawle ,
2020-12-11 12:16:20 +00:00
isExplorable : user.isExplorable ,
2023-02-01 22:22:26 +00:00
isDeleted : user.isDeleted != null ,
2021-04-17 06:30:26 +00:00
hideOnlineStatus : user.hideOnlineStatus ,
2020-08-18 13:44:21 +00:00
hasUnreadSpecifiedNotes : NoteUnreads.count ( {
where : { userId : user.id , isSpecified : true } ,
2021-12-09 14:58:30 +00:00
take : 1 ,
2020-08-18 13:44:21 +00:00
} ) . then ( count = > count > 0 ) ,
hasUnreadMentions : NoteUnreads.count ( {
where : { userId : user.id , isMentioned : true } ,
2021-12-09 14:58:30 +00:00
take : 1 ,
2020-08-18 13:44:21 +00:00
} ) . then ( count = > count > 0 ) ,
2020-01-29 19:37:25 +00:00
hasUnreadAnnouncement : this.getHasUnreadAnnouncement ( user . id ) ,
hasUnreadAntenna : this.getHasUnreadAntenna ( user . id ) ,
2020-08-18 13:44:21 +00:00
hasUnreadChannel : this.getHasUnreadChannel ( user . id ) ,
2019-05-18 11:36:33 +00:00
hasUnreadMessagingMessage : this.getHasUnreadMessagingMessage ( user . id ) ,
2020-01-29 19:37:25 +00:00
hasUnreadNotification : this.getHasUnreadNotification ( user . id ) ,
2020-02-15 00:10:49 +00:00
hasPendingReceivedFollowRequest : this.getHasPendingReceivedFollowRequest ( user . id ) ,
2020-07-27 04:34:20 +00:00
mutedWords : profile ! . mutedWords ,
2021-12-09 12:38:56 +00:00
mutedInstances : profile ! . mutedInstances ,
2021-02-13 03:28:26 +00:00
mutingNotificationTypes : profile ! . mutingNotificationTypes ,
emailNotificationTypes : profile ! . emailNotificationTypes ,
2023-02-11 18:17:11 +00:00
showTimelineReplies : user.showTimelineReplies ,
2022-11-17 21:24:38 +00:00
federateBlocks : user ! . federateBlocks ,
2019-04-07 12:50:36 +00:00
} : { } ) ,
2019-04-10 09:10:09 +00:00
. . . ( opts . includeSecrets ? {
2019-04-12 16:43:22 +00:00
email : profile ! . email ,
emailVerified : profile ! . emailVerified ,
2019-07-03 11:18:07 +00:00
securityKeysList : profile ! . twoFactorEnabled
? UserSecurityKeys . find ( {
where : {
2021-12-09 14:58:30 +00:00
userId : user.id ,
2019-07-03 11:18:07 +00:00
} ,
2022-03-26 06:34:00 +00:00
select : {
id : true ,
name : true ,
lastUsed : true ,
} ,
2019-07-03 11:18:07 +00:00
} )
2021-12-09 14:58:30 +00:00
: [ ] ,
2019-04-10 09:10:09 +00:00
} : { } ) ,
2019-04-07 12:50:36 +00:00
. . . ( relation ? {
isFollowing : relation.isFollowing ,
isFollowed : relation.isFollowed ,
hasPendingFollowRequestFromYou : relation.hasPendingFollowRequestFromYou ,
hasPendingFollowRequestToYou : relation.hasPendingFollowRequestToYou ,
isBlocking : relation.isBlocking ,
isBlocked : relation.isBlocked ,
isMuted : relation.isMuted ,
2022-10-06 23:20:38 +00:00
isRenoteMuted : relation.isRenoteMuted ,
2021-12-09 14:58:30 +00:00
} : { } ) ,
2022-01-18 13:27:10 +00:00
} as Promiseable < Packed < ' User ' > > as Promiseable < IsMeAndIsUserDetailed < ExpectsMe , D > > ;
2019-04-23 13:35:26 +00:00
return await awaitAll ( packed ) ;
2022-03-26 06:34:00 +00:00
} ,
2019-04-07 12:50:36 +00:00
2022-03-26 06:34:00 +00:00
packMany < D extends boolean = false > (
2019-04-25 04:27:07 +00:00
users : ( User [ 'id' ] | User ) [ ] ,
2021-03-24 02:05:37 +00:00
me ? : { id : User [ 'id' ] } | null | undefined ,
2019-04-25 04:27:07 +00:00
options ? : {
2022-01-18 13:27:10 +00:00
detail? : D ,
2019-04-25 04:27:07 +00:00
includeSecrets? : boolean ,
2022-04-17 12:18:18 +00:00
} ,
2022-01-18 13:27:10 +00:00
) : Promise < IsUserDetailed < D > [ ] > {
2019-04-25 04:27:07 +00:00
return Promise . all ( users . map ( u = > this . pack ( u , me , options ) ) ) ;
2022-03-26 06:34:00 +00:00
} ,
isLocalUser ,
isRemoteUser ,
} ) ;