From f1bd6e1ad48f73fe44c0f6dac69220df502e8391 Mon Sep 17 00:00:00 2001 From: garrettmills Date: Wed, 12 Aug 2020 22:07:53 -0500 Subject: [PATCH] Add support for login intercept messages and announcements --- app/controllers/api/v1/Auth.controller.js | 7 ++++ app/controllers/api/v1/System.controller.js | 26 +++++++++++++- app/models/LoginMessage.model.js | 39 +++++++++++++++++++++ app/models/system/Announcement.model.js | 10 ++++++ app/routing/routers/auth/forms.routes.js | 10 ++++++ config/traps.config.js | 8 +++++ 6 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 app/models/LoginMessage.model.js diff --git a/app/controllers/api/v1/Auth.controller.js b/app/controllers/api/v1/Auth.controller.js index 23edb8b..1346560 100644 --- a/app/controllers/api/v1/Auth.controller.js +++ b/app/controllers/api/v1/Auth.controller.js @@ -605,6 +605,13 @@ class AuthController extends Controller { // Create a login tracking activity await this.activity.login(req) + // If there are login messages, show those + const LoginMessage = this.models.get('LoginMessage') + const messages = await LoginMessage.for_user(user) + if ( messages.length > 0 ) { + await req.trap.begin('login_message', { session_only: true }) + } + return res.api({ success: true, session_created: !!req.body.create_session, diff --git a/app/controllers/api/v1/System.controller.js b/app/controllers/api/v1/System.controller.js index 0bc5658..f6a81c5 100644 --- a/app/controllers/api/v1/System.controller.js +++ b/app/controllers/api/v1/System.controller.js @@ -2,7 +2,7 @@ const { Controller } = require('libflitter') class ReflectController extends Controller { static get services() { - return [...super.services, 'routers', 'models', 'activity'] + return [...super.services, 'routers', 'models', 'activity', 'Vue'] } async get_announcements(req, res, next) { @@ -80,6 +80,30 @@ class ReflectController extends Controller { await announcement.delete() return res.api() } + + async show_login_message(req, res) { + const LoginMessage = this.models.get('LoginMessage') + const messages = await LoginMessage.for_user(req.user) + const message = messages[0] + + return this.Vue.auth_message(res, { + message: `

${message.title}

${message.message}`, + next_destination: '/auth/login-message/dismiss', + }) + } + + async dismiss_login_message(req, res) { + const LoginMessage = this.models.get('LoginMessage') + const messages = await LoginMessage.for_user(req.user) + const message = messages[0] + + await message.mark_seen() + + if ( req.trap.has_trap('login_message') ) + await req.trap.end() + + return res.redirect(req.session?.auth?.flow || '/dash') + } } module.exports = exports = ReflectController diff --git a/app/models/LoginMessage.model.js b/app/models/LoginMessage.model.js new file mode 100644 index 0000000..76ca5f5 --- /dev/null +++ b/app/models/LoginMessage.model.js @@ -0,0 +1,39 @@ +const { Model } = require('flitter-orm') + +class LoginMessageModel extends Model { + static get schema() { + return { + seen: {type: Boolean, default: false}, + expires: {type: Date, default: () => { + const date = new Date + date.setYear(date.getUTCFullYear() + 1) + return date + }}, + title: String, + message: String, + user_id: String, + } + } + + static async for_user(user) { + return this.find({ user_id: user.id, seen: false, expires: { $gt: new Date } }) + } + + static async create(user, title, message) { + const msg = new this({ + message, + title, + user_id: user.id, + }) + + await msg.save() + return msg + } + + async mark_seen() { + this.seen = true + return this.save() + } +} + +module.exports = exports = LoginMessageModel diff --git a/app/models/system/Announcement.model.js b/app/models/system/Announcement.model.js index e738ac2..9e348bd 100644 --- a/app/models/system/Announcement.model.js +++ b/app/models/system/Announcement.model.js @@ -66,6 +66,8 @@ class AnnouncementModel extends Model { await this.populate_emails() } else if ( this.type === 'banner' ) { await this.populate_banners() + } else if ( this.type === 'login' ) { + await this.populate_logins() } } @@ -92,6 +94,14 @@ class AnnouncementModel extends Model { await Message.create(user, `${this.title} - ${this.message}`) } } + + async populate_logins() { + const users = await this.all_users() + const LoginMessage = this.models.get('LoginMessage') + for ( const user of users ) { + await LoginMessage.create(user, this.title, this.message) + } + } } module.exports = exports = AnnouncementModel diff --git a/app/routing/routers/auth/forms.routes.js b/app/routing/routers/auth/forms.routes.js index 9faf7b3..e979d67 100644 --- a/app/routing/routers/auth/forms.routes.js +++ b/app/routing/routers/auth/forms.routes.js @@ -66,6 +66,16 @@ const index = { 'controller::auth:Forms.logout_provider_clean_session', 'controller::auth:Forms.logout_provider_present_success', ], + + '/login-message': [ + 'middleware::auth:UserOnly', + 'controller::api:v1:System.show_login_message', + ], + + '/login-message/dismiss': [ + 'middleware::auth:UserOnly', + 'controller::api:v1:System.dismiss_login_message', + ], }, post: { diff --git a/config/traps.config.js b/config/traps.config.js index a207296..064fbb0 100644 --- a/config/traps.config.js +++ b/config/traps.config.js @@ -21,6 +21,14 @@ const traps_config = { '/api/v1/locale/batch', ], }, + login_message: { + redirect_to: '/auth/login-message', + allowed_routes: [ + '/auth/logout', + '/auth/login-message', + '/auth/login-message/dismiss', + ], + }, }, }