2025-05-07 20:14:21 -07:00
import { toOid } from "@/src/helpers/inventoryHelpers" ;
2025-05-09 21:37:09 -07:00
import { getJSONfromString } from "@/src/helpers/stringHelpers" ;
2025-05-07 20:14:21 -07:00
import { Friendship } from "@/src/models/friendModel" ;
2025-05-09 21:37:09 -07:00
import { Account } from "@/src/models/loginModel" ;
import { getInventory } from "@/src/services/inventoryService" ;
2025-05-07 20:14:21 -07:00
import { getAccountIdForRequest } from "@/src/services/loginService" ;
import { IOid } from "@/src/types/commonTypes" ;
2025-05-09 21:37:09 -07:00
import { parallelForeach } from "@/src/utils/async-utils" ;
2025-05-07 20:14:21 -07:00
import { RequestHandler } from "express" ;
2025-05-09 21:37:09 -07:00
import { Types } from "mongoose" ;
2025-05-07 20:14:21 -07:00
export const removeFriendGetController : RequestHandler = async ( req , res ) = > {
const accountId = await getAccountIdForRequest ( req ) ;
if ( req . query . all ) {
const [ internalFriendships , externalFriendships ] = await Promise . all ( [
Friendship . find ( { owner : accountId } , "friend" ) ,
Friendship . find ( { friend : accountId } , "owner" )
] ) ;
const promises : Promise < void > [ ] = [ ] ;
const friends : IOid [ ] = [ ] ;
for ( const externalFriendship of externalFriendships ) {
if ( ! internalFriendships . find ( x = > x . friend . equals ( externalFriendship . owner ) ) ) {
promises . push ( Friendship . deleteOne ( { _id : externalFriendship._id } ) as unknown as Promise < void > ) ;
friends . push ( toOid ( externalFriendship . owner ) ) ;
}
}
await Promise . all ( promises ) ;
res . json ( {
Friends : friends
2025-05-09 21:37:09 -07:00
} satisfies IRemoveFriendsResponse ) ;
2025-05-07 20:14:21 -07:00
} else {
const friendId = req . query . friendId as string ;
await Promise . all ( [
Friendship . deleteOne ( { owner : accountId , friend : friendId } ) ,
Friendship . deleteOne ( { owner : friendId , friend : accountId } )
] ) ;
res . json ( {
2025-05-09 21:37:09 -07:00
Friends : [ { $oid : friendId } ]
} satisfies IRemoveFriendsResponse ) ;
2025-05-07 20:14:21 -07:00
}
} ;
2025-05-09 21:37:09 -07:00
export const removeFriendPostController : RequestHandler = async ( req , res ) = > {
const accountId = await getAccountIdForRequest ( req ) ;
const data = getJSONfromString < IBatchRemoveFriendsRequest > ( String ( req . body ) ) ;
const friends = new Set ( ( await Friendship . find ( { owner : accountId } , "friend" ) ) . map ( x = > x . friend ) ) ;
// TOVERIFY: Should pending friendships also be kept?
// Keep friends that have been online within threshold
await parallelForeach ( [ . . . friends ] , async friend = > {
const account = ( await Account . findById ( friend , "LastLogin" ) ) ! ;
const daysLoggedOut = ( Date . now ( ) - account . LastLogin . getTime ( ) ) / 86400 _000 ;
if ( daysLoggedOut < data . DaysLoggedOut ) {
friends . delete ( friend ) ;
}
} ) ;
if ( data . SkipClanmates ) {
const inventory = await getInventory ( accountId , "GuildId" ) ;
if ( inventory . GuildId ) {
await parallelForeach ( [ . . . friends ] , async friend = > {
const friendInventory = await getInventory ( friend . toString ( ) , "GuildId" ) ;
if ( friendInventory . GuildId ? . equals ( inventory . GuildId ) ) {
friends . delete ( friend ) ;
}
} ) ;
}
}
// Remove all remaining friends that aren't in SkipFriendIds & give response.
const promises = [ ] ;
const response : IOid [ ] = [ ] ;
for ( const friend of friends ) {
if ( ! data . SkipFriendIds . find ( skipFriendId = > checkFriendId ( skipFriendId , friend ) ) ) {
promises . push ( Friendship . deleteOne ( { owner : accountId , friend : friend } ) ) ;
promises . push ( Friendship . deleteOne ( { owner : friend , friend : accountId } ) ) ;
response . push ( toOid ( friend ) ) ;
}
}
await Promise . all ( promises ) ;
res . json ( {
Friends : response
} satisfies IRemoveFriendsResponse ) ;
} ;
// The friend ids format is a bit weird, e.g. when 6633b81e9dba0b714f28ff02 (A) is friends with 67cdac105ef1f4b49741c267 (B), A's friend id for B is 808000105ef1f40560ca079e and B's friend id for A is 8000b81e9dba0b06408a8075.
const checkFriendId = ( friendId : string , b : Types.ObjectId ) : boolean = > {
return friendId . substring ( 6 , 6 + 8 ) == b . toString ( ) . substring ( 6 , 6 + 8 ) ;
} ;
interface IBatchRemoveFriendsRequest {
DaysLoggedOut : number ;
SkipClanmates : boolean ;
SkipFriendIds : string [ ] ;
}
interface IRemoveFriendsResponse {
Friends : IOid [ ] ;
}