auth/controllers/Forms.js

const Controller = require('libflitter/controller/Controller')

/**
 * @module flitter-auth/controllers/Forms
 */

/**
 * Controller for displaying and processing registrations/logins/etc.
 * @extends module:libflitter/controller/Controller~Controller
 */
class Forms extends Controller {
    /**
     * Specify the services required by this controller.
     * The configs service is loaded automatically.
     * @returns {Array<string>}
     */
    static get services() {
        return [...super.services, 'configs']
    }

    /**
     * Show the registration page specific to a provider.
     * @param {express/request} req - the incoming request
     * @param {express/response} res - the outgoing response
     * @param {function} next - callback handler for errors, etc.
     * @return {Promise<*>}
     */
    async registration_provider_get(req, res, next){
        return req.auth_provider.handle_register_get(req, res, next)
    }

    /**
     * Do the action to create a new user with the request body.
     * This is a middleware that should not send a response.
     * @param {express/request} req - the request
     * @param {express/response} res - the response
     * @param {function} next - the next function in the stack
     * @returns {Promise<*>}
     */
    async registration_provider_create_user(req, res, next) {
        const errors = await req.auth_provider.validate_registration(req.body)

        // If there are validation errors, display the form with errors.
        if ( errors && errors.length > 0 ){
            res.status(400)
            return res.page(req.auth_provider.registration_view(), {
                errors,
                title: 'Register',
                heading_text: 'Hi, there. Register to continue:',
                form_data: req.body,
                provider_name: req.auth_provider.config.name,
            })
        }

        const user_data = await req.auth_provider.get_registration_args(req.body)
        const user = req.auth_provider.register.apply(req.auth_provider, user_data)
        return next()
    }

    /**
     * Presents a view showing that the user has registered successfully.
     * @param {express/request} req - the request
     * @param {express/response} res - the response
     * @param {function} next - the next function in the stack
     * @returns {Promise<*>}
     */
    async registration_provider_present_user_created(req, res, next) {
        return res.page('auth:form_page', {
            title: 'Success!',
            message: 'Thanks for registering. You\'ll now be redirected to login with your new account.',
            button_text: 'Login',
            button_link: './login',
            provider_name: req.auth_provider.config.name,
        })
    }

    /**
     * Handle a GET request to the login page. Usually displays the login form.
     * Calls the 'handle_login_get' method on the auth provider.
     * @param {express/request} req - the request
     * @param {express/response} res - the response
     * @param {function} next - the next function in the stack
     * @returns {Promise<*>}
     */
    async login_provider_get(req, res, next){
        return req.auth_provider.handle_login_get(req, res, next)
    }

    /**
     * Middleware that attempts to authenticate a user. If the authentication
     * via the auth provider succeeds, the auth session is created and the next
     * handler in the stack is called. Otherwise, the login view is returned with
     * the error object.
     * @param {express/request} req - the request
     * @param {express/response} res - the response
     * @param {function} next - the next function in the stack
     * @returns {Promise<*>}
     */
    async login_provider_authenticate_user(req, res, next) {
        const errors = await req.auth_provider.validate_login(req.body)

        if ( errors && errors.length > 0 ){
            res.status(400)
            return res.page(req.auth_provider.login_view(), {
                errors,
                title: 'Login',
                heading_text: 'Hi, there. Login to continue:',
                provider_name: req.auth_provider.config.name,
            })
        }

        const login_args = await req.auth_provider.get_login_args(req.body)

        const user = await req.auth_provider.login.apply(req.auth_provider, login_args)

        if ( !user ){
            return res.page(req.auth_provider.login_view(), {
                title: 'Login',
                heading_text: 'Hi, there. Login to continue:',
                errors: ['Invalid username or password.'],
                provider_name: req.auth_provider.config.name,
            })
        }

        await req.auth_provider.session(req, user)
        next()
    }

    /**
     * Sends the response for a successful login authentication.
     * @param {express/request} req - the request
     * @param {express/response} res - the response
     * @param {function} next - the next function in the stack
     * @returns {Promise<*>}
     */
    async login_provider_present_success(req, res, next) {
        if ( req.session.auth.flow ){
            const destination = req.session.auth.flow
            req.session.auth.flow = false
            return res.redirect(destination)
        } else {
            return res.redirect(this.configs.get('auth.default_login_route'))
        }
    }

    /**
     * Cleans the auth session on a logout request. This is a middleware
     * that shouldn't return a response if everything is successful.
     * @param {express/request} req - the request
     * @param {express/response} res - the response
     * @param {function} next - the next function in the stack
     * @returns {Promise<*>}
     */
    async logout_provider_clean_session(req, res, next) {
        await req.auth_provider.logout(req)
        return next()
    }

    /**
     * Returns the response signifying a successful logout.
     * @param {express/request} req - the request
     * @param {express/response} res - the response
     * @param {function} next - the next function in the stack
     * @returns {Promise<*>}
     */
    async logout_provider_present_success(req, res, next) {
        return res.page(req.auth_provider.logout_view(), {
            title: 'Good-Bye',
            message: 'You\'ve been successfully logged-out. Come back soon!',
            button_text: 'Continue',
            button_link: '/',
            provider_name: req.auth_provider.config.name,
        })
    }
}

module.exports = exports = Forms