import AbstractApiModule from 'adapt-authoring-api'
/**
* Module which handles user management
* @memberof users
* @extends {AbstractApiModule}
*/
class UsersModule extends AbstractApiModule {
/** @override */
async setValues () {
await super.setValues()
/** @ignore */ this.schemaName = 'user'
/** @ignore */ this.collectionName = 'users'
}
/**
* Initialises the module
* @return {Promise}
*/
async init () {
await super.init()
const [mongodb, server] = await this.app.waitForModule('mongodb', 'server')
await mongodb.setIndex(this.collectionName, 'email', { unique: true })
server.api.addHandlerMiddleware(this.updateAccess.bind(this))
this.requestHook.tap(this.onRequest.bind(this))
if (this.getConfig('forceLowerCaseEmail')) {
this.preInsertHook.tap(this.forceLowerCaseEmail)
this.preUpdateHook.tap((ogDoc, updateData) => this.forceLowerCaseEmail(updateData))
}
}
forceLowerCaseEmail (data) {
if (data.email) data.email = data.email.toLowerCase()
}
/** @override */
async processRequestMiddleware (req, res, next) {
super.processRequestMiddleware(req, res, () => {
req.apiData.schemaName = req.auth.userSchemaName
next()
})
}
/**
* Updates the user access timestamp
* @param {external:ExpressRequest} req
* @param {external:ExpressResponse} res
* @param {Function} next
*/
updateAccess (req, res, next) {
const _id = req.auth?.user?._id
if (_id) { // note we only log any errors, as it's not necessarily a problem
this.update({ _id }, { lastAccess: new Date().toISOString() })
.catch(e => this.log('warn', `Failed to update user lastAccess, ${e}`))
}
next()
}
/**
* Adds the current user _id to an incoming request to API
* @param {external:ExpressRequest} req
*/
async onRequest (req) {
if (req.apiData.config.route === '/me') {
req.params._id = req.apiData.query._id = req.auth.user._id
// users shouldn't be able to disable themselves
if (req.apiData.data.isEnabled) delete req.apiData.data.isEnabled
}
if (req.method === 'DELETE' && (req.apiData.query._id === req.auth.user._id)) {
throw this.app.errors.USER_SELF_DELETE_ILLEGAL
.setData({ id: req.user._id })
}
}
/** @override */
async insert (data, options, mongoOptions) {
try {
return await super.insert(data, options, mongoOptions)
} catch (e) {
if (e.code === this.app.errors.MONGO_DUPL_INDEX) throw this.app.errors.DUPL_USER.setData({ email: data.email })
throw e
}
}
/** @override */
async find (query, options = {}, mongoOptions = {}) {
query.email = this.getConfig('forceLowerCaseEmail') ? query.email?.toLowerCase() : undefined
return super.find(query, options, mongoOptions)
}
}
export default UsersModule