Files
speckle-server/packages/server/modules/core/services/users.js
T
Dimitrie Stefanescu 3ed4729c94 feat(server/invites): fixes a bug in 3rd party strategies & invites, and other changes
changes sender to no-reply@speckle.systems; updates invite email subject based on wether it's a
generic invite or a server invite, etc.
2021-03-22 18:44:58 +00:00

128 lines
3.7 KiB
JavaScript

'use strict'
const bcrypt = require( 'bcrypt' )
const crs = require( 'crypto-random-string' )
const appRoot = require( 'app-root-path' )
const knex = require( `${appRoot}/db/knex` )
const Users = ( ) => knex( 'users' )
const Acl = ( ) => knex( 'server_acl' )
module.exports = {
/*
Users
*/
async createUser( user ) {
let [ { count } ] = await Acl( ).where( { role: 'server:admin' } ).count( )
user.id = crs( { length: 10 } )
if ( user.password ) {
if ( user.password.length < 8 ) throw new Error( 'Password to short; needs to be 8 characters or longer.' )
user.passwordDigest = await bcrypt.hash( user.password, 10 )
}
delete user.password
let usr = await Users( ).select( 'id' ).where( { email: user.email } ).first( )
if ( usr ) throw new Error( 'Email taken. Try logging in?' )
let res = await Users( ).returning( 'id' ).insert( user )
if ( parseInt( count ) === 0 ) {
await Acl( ).insert( { userId: res[ 0 ], role: 'server:admin' } )
} else {
await Acl( ).insert( { userId: res[ 0 ], role: 'server:user' } )
}
return res[ 0 ]
},
async findOrCreateUser( { user, rawProfile } ) {
let existingUser = await Users( ).select( 'id' ).where( { email: user.email } ).first( )
if ( existingUser ) {
if ( user.suuid ) {
await module.exports.updateUser( existingUser.id, { suuid: user.suuid } )
}
existingUser.suuid = user.suuid
return existingUser
}
user.password = crs( { length: 20 } )
user.verified = true // because we trust the external identity provider, no?
return { id: await module.exports.createUser( user ), email: user.email }
},
async getUserById( { userId } ) {
let user = await Users( ).where( { id: userId } ).select( '*' ).first( )
delete user.passwordDigest
return user
},
// TODO: deprecate
async getUser( id ) {
let user = await Users( ).where( { id: id } ).select( '*' ).first( )
delete user.passwordDigest
return user
},
async getUserByEmail( { email } ) {
let user = await Users( ).where( { email: email } ).select( '*' ).first( )
if ( !user ) return null
delete user.passwordDigest
return user
},
async getUserRole( id ) {
let { role } = await Acl( ).where( { userId: id } ).select( 'role' ).first( )
return role
},
async updateUser( id, user ) {
delete user.id
delete user.passwordDigest
delete user.password
delete user.email
await Users( ).where( { id: id } ).update( user )
},
async updateUserPassword( { id, newPassword } ) {
if ( newPassword.length < 8 ) throw new Error( 'Password to short; needs to be 8 characters or longer.' )
let passwordDigest = await bcrypt.hash( newPassword, 10 )
await Users().where( { id:id } ).update( { passwordDigest } )
},
async searchUsers( searchQuery, limit, cursor ) {
limit = limit || 25
let query = Users( )
.select( 'id', 'name', 'bio', 'company', 'verified', 'avatar', 'createdAt' )
.where( queryBuilder => {
queryBuilder.where( { email: searchQuery } ) //match full email or partial name
queryBuilder.orWhere( 'name', 'ILIKE', `%${searchQuery}%` )
} )
if ( cursor )
query.andWhere( 'users.createdAt', '<', cursor )
query.orderBy( 'users.createdAt', 'desc' ).limit( limit )
let rows = await query
return { users: rows, cursor: rows.length > 0 ? rows[ rows.length - 1 ].createdAt.toISOString( ) : null }
},
async validatePasssword( { email, password } ) {
let { passwordDigest } = await Users( ).where( { email: email } ).select( 'passwordDigest' ).first( )
return bcrypt.compare( password, passwordDigest )
},
async deleteUser( id ) {
throw new Error( 'not implemented' )
}
}