@ -20,6 +20,12 @@ const uuidv4 = require('uuid').v4;
const { SiteError , SiteService } = require ( '../../lib/site-lib' ) ;
/ *
* The entire concept of "get a user" is in flux right now . It ' s best to just
* ignore what ' s happening in this service right now , and focus on other
* features in the sytem .
* /
class UserService extends SiteService {
constructor ( dtp ) {
@ -174,7 +180,7 @@ class UserService extends SiteService {
async emailOptOut ( userId , category ) {
userId = mongoose . Types . ObjectId ( userId ) ;
const user = await this . getUserAccount ( userId ) ;
const user = await this . getLocal UserAccount ( userId ) ;
if ( ! user ) {
throw new SiteError ( 406 , 'Invalid opt-out token' ) ;
}
@ -199,7 +205,6 @@ class UserService extends SiteService {
throw SiteError ( 403 , 'Invalid user account operation' ) ;
}
// strip characters we don't want to allow in username
userDefinition . username = striptags ( userDefinition . username . trim ( ) . replace ( /[^A-Za-z0-9\-_]/gi , '' ) ) ;
const username_lc = userDefinition . username . toLowerCase ( ) ;
@ -221,7 +226,6 @@ class UserService extends SiteService {
}
async updateForAdmin ( user , userDefinition ) {
// strip characters we don't want to allow in username
userDefinition . username = striptags ( userDefinition . username . trim ( ) . replace ( /[^A-Za-z0-9\-_]/gi , '' ) ) ;
const username_lc = userDefinition . username . toLowerCase ( ) ;
@ -265,7 +269,6 @@ class UserService extends SiteService {
const updateOp = { $set : { } , $unset : { } } ;
// strip characters we don't want to allow in username
updateOp . $set . username = striptags ( userDefinition . username . trim ( ) . replace ( /[^A-Za-z0-9\-_]/gi , '' ) ) ;
if ( ! updateOp . $set . username || ( updateOp . $set . username . length === 0 ) ) {
throw new SiteError ( 400 , 'Must include a username' ) ;
@ -303,7 +306,7 @@ class UserService extends SiteService {
} , options ) ;
const accountEmail = account . username . trim ( ) . toLowerCase ( ) ;
const accountUsername = await this . filterUsername ( accountEmail ) ;
const accountUsername = this . filterUsername ( accountEmail ) ;
this . log . debug ( 'locating user record' , { accountEmail , accountUsername } ) ;
const user = await User
@ -393,28 +396,23 @@ class UserService extends SiteService {
) ;
}
filterUserObject ( user ) {
const filteredUser = {
_ id : user . _ id ,
created : user . created ,
displayName : user . displayName ,
username : user . username ,
username_lc : user . username_lc ,
bio : user . bio ,
flags : user . flags ,
permissions : user . permissions ,
picture : user . picture ,
} ;
if ( filteredUser . flags && filteredUser . flags . _ id ) {
delete filteredUser . flags . _ id ;
async getLocalUserId ( username ) {
const user = await User . findOne ( { username_lc : username } ) . select ( '_id' ) . lean ( ) ;
if ( ! user ) {
return ; // undefined
}
if ( filteredUser . permissions && filteredUser . permissions . _ id ) {
delete filteredUser . permissions . _ id ;
return user . _ id ;
}
async getCoreUserId ( username ) {
const user = await CoreUser . findOne ( { username_lc : username } ) . select ( '_id' ) . lean ( ) ;
if ( ! user ) {
return ; // undefined
}
return filteredUser ;
return user . _ id ;
}
async getUserAccount ( userId ) {
async getLocal UserAccount ( userId ) {
const user = await User
. findById ( userId )
. select ( '+email +flags +permissions +optIn +picture' )
@ -427,11 +425,47 @@ class UserService extends SiteService {
return user ;
}
async getUserAccounts ( pagination , username ) {
async getCoreUserAccount ( userId ) {
const user = await User
. findById ( userId )
. select ( '+email +flags +permissions +optIn +picture' )
. populate ( this . populateUser )
. lean ( ) ;
if ( ! user ) {
throw new SiteError ( 404 , 'Core member account not found' ) ;
}
user . type = 'CoreUser' ;
return user ;
}
async getLocalUserProfile ( userId ) {
const user = await User
. findById ( userId )
. select ( '+email +flags +settings' )
. populate ( this . populateUser )
. lean ( ) ;
user . type = 'User' ;
return user ;
}
async getCoreUserProfile ( userId ) {
const user = await CoreUser
. findById ( userId )
. select ( '+core +flags +settings' )
. populate ( this . populateUser )
. lean ( ) ;
user . type = 'CoreUser' ;
return user ;
}
async searchLocalUserAccounts ( pagination , username ) {
let search = { } ;
if ( username ) {
username = this . filterUsername ( username ) ;
search . username_lc = { $regex : ` ^ ${ username . toLowerCase ( ) . trim ( ) } ` } ;
}
const users = await User
. find ( search )
. sort ( { username_lc : 1 } )
@ -444,60 +478,24 @@ class UserService extends SiteService {
return users . map ( ( user ) => { user . type = 'User' ; return user ; } ) ;
}
async getUserProfile ( userId ) {
let user ;
try {
userId = mongoose . Types . ObjectId ( userId ) ; // will throw if invalid format
user = User . findById ( userId ) ;
} catch ( error ) {
user = User . findOne ( { username : userId } ) ;
}
user = await user
. select ( '+email +flags +settings' )
. populate ( this . populateUser )
. lean ( ) ;
return user ;
}
async getPublicProfile ( type , username ) {
if ( ! username || ( typeof username !== 'string' ) ) {
throw new SiteError ( 406 , 'Invalid username' ) ;
}
async searchCoreUserAccounts ( pagination , username ) {
let search = { } ;
username = username . trim ( ) . toLowerCase ( ) ;
if ( username . length === 0 ) {
throw new SiteError ( 406 , 'Invalid username' ) ;
username = this . filterUsername ( username ) ;
if ( username ) {
search . username_lc = { $regex : ` ^ ${ username . toLowerCase ( ) . trim ( ) } ` } ;
}
let user ;
switch ( type ) {
case 'CoreUser' :
user = await CoreUser
. findOne ( { username_lc : username } )
. select ( '_id created username username_lc displayName bio picture header core' )
. populate ( this . populateUser )
. lean ( ) ;
if ( user ) {
user . type = 'CoreUser' ;
}
break ;
case 'User' :
user = await User
. findOne ( { username_lc : username } )
. select ( '_id created username username_lc displayName bio picture header' )
. populate ( this . populateUser )
. lean ( ) ;
if ( user ) {
user . type = 'User' ;
}
break ;
default :
throw new SiteError ( 400 , 'Invalid user account type' ) ;
}
const users = await CoreUser
. find ( search )
. sort ( { username_lc : 1 } )
. select ( '+core +coreUserId +flags +permissions +optIn' )
. skip ( pagination . skip )
. limit ( pagination . cpp )
. lean ( )
;
return user ;
return users . map ( ( user ) => { user . type = 'CoreUser' ; return user ; } ) ;
}
async getRecent ( maxCount = 3 ) {
@ -579,10 +577,6 @@ class UserService extends SiteService {
return actions ;
}
async filterUsername ( username ) {
return striptags ( username . trim ( ) . toLowerCase ( ) ) . replace ( /\W/g , '' ) ;
}
async checkUsername ( username ) {
if ( ! username || ( typeof username !== 'string' ) || ( username . length === 0 ) ) {
throw new SiteError ( 406 , 'Invalid username' ) ;
@ -598,6 +592,34 @@ class UserService extends SiteService {
}
}
filterUsername ( username ) {
while ( username [ 0 ] === '@' ) {
username = username . slice ( 1 ) ;
}
return striptags ( username . trim ( ) . toLowerCase ( ) ) . replace ( /\W/g , '' ) ;
}
filterUserObject ( user ) {
const filteredUser = {
_ id : user . _ id ,
created : user . created ,
displayName : user . displayName ,
username : user . username ,
username_lc : user . username_lc ,
bio : user . bio ,
flags : user . flags ,
permissions : user . permissions ,
picture : user . picture ,
} ;
if ( filteredUser . flags && filteredUser . flags . _ id ) {
delete filteredUser . flags . _ id ;
}
if ( filteredUser . permissions && filteredUser . permissions . _ id ) {
delete filteredUser . permissions . _ id ;
}
return filteredUser ;
}
async recordProfileView ( user , req ) {
const { resource : resourceService } = this . dtp . services ;
await resourceService . recordView ( req , 'User' , user . _ id ) ;
@ -653,6 +675,41 @@ class UserService extends SiteService {
await User . updateOne ( { _ id : user . _ id } , { $unset : { 'picture' : '' } } ) ;
}
async updateHeaderImage ( user , file ) {
const { image : imageService } = this . dtp . services ;
await this . removeHeaderImage ( user . header ) ;
const images = [
{
width : 1400 ,
height : 400 ,
format : 'jpeg' ,
formatParameters : {
quality : 80 ,
} ,
} ,
] ;
await imageService . processImageFile ( user , file , images ) ;
await User . updateOne (
{ _ id : user . _ id } ,
{
$set : {
'header' : images [ 0 ] . image . _ id ,
} ,
} ,
) ;
}
async removeHeaderImage ( user ) {
const { image : imageService } = this . dtp . services ;
user = await this . getUserAccount ( user . _ id ) ;
if ( user . header ) {
await imageService . deleteImage ( user . header ) ;
}
await User . updateOne ( { _ id : user . _ id } , { $unset : { 'header' : '' } } ) ;
}
async blockUser ( user , blockedUser ) {
if ( user . _ id . equals ( blockedUser . _ id ) ) {
throw new SiteError ( 406 , "You can't block yourself" ) ;