Add system announcements interface
This commit is contained in:
parent
143fccf179
commit
1458e4126b
@ -38,6 +38,7 @@ const template = `
|
|||||||
<h6 class="dropdown-header">Hello, {{ first_name }}.</h6>
|
<h6 class="dropdown-header">Hello, {{ first_name }}.</h6>
|
||||||
<a href="/dash/profile" class="dropdown-item">My Profile</a>
|
<a href="/dash/profile" class="dropdown-item">My Profile</a>
|
||||||
<a href="/dash/c/listing/reflect/Token" v-if="can.api_tokens" class="dropdown-item">API Tokens</a>
|
<a href="/dash/c/listing/reflect/Token" v-if="can.api_tokens" class="dropdown-item">API Tokens</a>
|
||||||
|
<a href="/dash/c/listing/system/Announcement" v-if="can.messages" class="dropdown-item">System Announcements</a>
|
||||||
<div class="dropdown-divider"></div>
|
<div class="dropdown-divider"></div>
|
||||||
<a href="/auth/logout" class="dropdown-item">Sign-Out of {{ app_name }}</a>
|
<a href="/auth/logout" class="dropdown-item">Sign-Out of {{ app_name }}</a>
|
||||||
</div>
|
</div>
|
||||||
@ -64,6 +65,7 @@ export default class NavBarComponent extends Component {
|
|||||||
|
|
||||||
async vue_on_create() {
|
async vue_on_create() {
|
||||||
this.can.api_tokens = await session.check_permissions('v1:reflect:tokens:list')
|
this.can.api_tokens = await session.check_permissions('v1:reflect:tokens:list')
|
||||||
|
this.can.messages = await session.check_permissions('v1:message:banners:create')
|
||||||
this.$forceUpdate()
|
this.$forceUpdate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
98
app/assets/app/resource/system/Announcement.resource.js
Normal file
98
app/assets/app/resource/system/Announcement.resource.js
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
import CRUDBase from '../CRUDBase.js'
|
||||||
|
|
||||||
|
class AnnouncementResource extends CRUDBase {
|
||||||
|
endpoint = '/api/v1/system/announcements'
|
||||||
|
required_fields = ['user_ids', 'group_ids', 'title', 'message', 'type']
|
||||||
|
permission_base = 'v1:system:announcements'
|
||||||
|
|
||||||
|
item = 'System Announcement'
|
||||||
|
plural = 'System Announcements'
|
||||||
|
|
||||||
|
listing_definition = {
|
||||||
|
display: `
|
||||||
|
System announcements are administrative messages that you want all or some of your users to see. These messages can be delivered via e-mail, as a message after login, or as a system banner announcement.
|
||||||
|
`,
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'Title',
|
||||||
|
field: 'title',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Message',
|
||||||
|
field: 'message',
|
||||||
|
renderer: (message) => String(message).slice(0, 150),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'resource',
|
||||||
|
position: 'main',
|
||||||
|
action: 'insert',
|
||||||
|
text: 'Create New',
|
||||||
|
color: 'success',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'resource',
|
||||||
|
position: 'row',
|
||||||
|
action: 'delete',
|
||||||
|
icon: 'fa fa-times',
|
||||||
|
color: 'danger',
|
||||||
|
confirm: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
form_definition = {
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'Title',
|
||||||
|
field: 'title',
|
||||||
|
type: 'text',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Message',
|
||||||
|
field: 'message',
|
||||||
|
type: 'textarea',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Users',
|
||||||
|
field: 'user_ids',
|
||||||
|
type: 'select.dynamic.multiple',
|
||||||
|
options: {
|
||||||
|
resource: 'auth/User',
|
||||||
|
display: (user) => `${user.last_name}, ${user.first_name} (${user.uid})`,
|
||||||
|
value: 'id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Groups',
|
||||||
|
field: 'group_ids',
|
||||||
|
type: 'select.dynamic.multiple',
|
||||||
|
options: {
|
||||||
|
resource: 'auth/Group',
|
||||||
|
display: (group) => `${group.name}`,
|
||||||
|
value: 'id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Type',
|
||||||
|
field: 'type',
|
||||||
|
type: 'select',
|
||||||
|
options: [
|
||||||
|
{ display: 'Login Intercept', value: 'login' },
|
||||||
|
{ display: 'E-Mail', value: 'email' },
|
||||||
|
{ display: 'System Banner', value: 'banner' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
handlers: {
|
||||||
|
insert: {
|
||||||
|
action: 'redirect',
|
||||||
|
next: '/dash/c/listing/system/Announcement',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const system_announcement = new AnnouncementResource()
|
||||||
|
export { system_announcement }
|
@ -40,6 +40,26 @@ class MessageController extends Controller {
|
|||||||
await message.dismiss()
|
await message.dismiss()
|
||||||
return res.api()
|
return res.api()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async create_banner(req, res, next) {
|
||||||
|
// expires, display_type = info, message, user_id?
|
||||||
|
const expires = req.body.expires
|
||||||
|
const display_type = req.body.display_type || 'info'
|
||||||
|
const message = req.body.message
|
||||||
|
const user_ids = req.body.user_ids
|
||||||
|
|
||||||
|
if ( !expires )
|
||||||
|
return res.status(400)
|
||||||
|
.message(`${req.T('api.missing_field')} expires`)
|
||||||
|
.api()
|
||||||
|
|
||||||
|
if ( !message )
|
||||||
|
return res.status(400)
|
||||||
|
.message(`${req.T('api.missing_field')} message`)
|
||||||
|
.api()
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = exports = MessageController
|
module.exports = exports = MessageController
|
||||||
|
84
app/controllers/api/v1/System.controller.js
Normal file
84
app/controllers/api/v1/System.controller.js
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
const { Controller } = require('libflitter')
|
||||||
|
|
||||||
|
class ReflectController extends Controller {
|
||||||
|
static get services() {
|
||||||
|
return [...super.services, 'routers', 'models', 'activity']
|
||||||
|
}
|
||||||
|
|
||||||
|
async get_announcements(req, res, next) {
|
||||||
|
const Announcement = this.models.get('system:Announcement')
|
||||||
|
const announcements = await Announcement.find()
|
||||||
|
|
||||||
|
const data = []
|
||||||
|
for ( const announcement of announcements ) {
|
||||||
|
data.push(await announcement.to_api())
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.api(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
async get_announcement(req, res, next) {
|
||||||
|
const Announcement = this.models.get('system:Announcement')
|
||||||
|
const announcement = await Announcement.findById(req.params.id)
|
||||||
|
|
||||||
|
if ( !announcement )
|
||||||
|
return res.status(404)
|
||||||
|
.message(req.T('api.announcement_not_found'))
|
||||||
|
.api()
|
||||||
|
|
||||||
|
return res.api(await announcement.to_api())
|
||||||
|
}
|
||||||
|
|
||||||
|
async create_announcement(req, res, next) {
|
||||||
|
const Announcement = this.models.get('system:Announcement')
|
||||||
|
|
||||||
|
const required_fields = ['title', 'message', 'user_ids', 'group_ids', 'type']
|
||||||
|
for ( const field of required_fields ) {
|
||||||
|
if ( !req.body[field] )
|
||||||
|
return res.status(400)
|
||||||
|
.message(`${req.T('api.missing_field')} ${field}`)
|
||||||
|
.api()
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !Array.isArray(req.body.user_ids) )
|
||||||
|
return res.status(400)
|
||||||
|
.message(`${req.T('api.improper_field')} user_ids`)
|
||||||
|
.api()
|
||||||
|
|
||||||
|
if ( !Array.isArray(req.body.group_ids) )
|
||||||
|
return res.status(400)
|
||||||
|
.message(`${req.T('api.improper_field')} group_ids`)
|
||||||
|
.api()
|
||||||
|
|
||||||
|
if ( !['email', 'login', 'banner'].includes(req.body.type) )
|
||||||
|
return res.status(400)
|
||||||
|
.message(`${req.T('api.improper_field')} type`)
|
||||||
|
.api()
|
||||||
|
|
||||||
|
const announcement = new Announcement({
|
||||||
|
title: req.body.title,
|
||||||
|
message: req.body.message,
|
||||||
|
user_ids: req.body.user_ids,
|
||||||
|
group_ids: req.body.group_ids,
|
||||||
|
type: req.body.type,
|
||||||
|
})
|
||||||
|
|
||||||
|
await announcement.save()
|
||||||
|
return res.api(await announcement.to_api())
|
||||||
|
}
|
||||||
|
|
||||||
|
async delete_announcement(req, res, next) {
|
||||||
|
const Announcement = this.models.get('system:Announcement')
|
||||||
|
const announcement = await Announcement.findById(req.params.id)
|
||||||
|
|
||||||
|
if ( !announcement )
|
||||||
|
return res.status(404)
|
||||||
|
.message(req.T('api.announcement_not_found'))
|
||||||
|
.api()
|
||||||
|
|
||||||
|
await announcement.delete()
|
||||||
|
return res.api()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = exports = ReflectController
|
@ -24,10 +24,6 @@ class ClientModel extends Model {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
can(scope) {
|
|
||||||
return this.api_scopes.includes()
|
|
||||||
}
|
|
||||||
|
|
||||||
async application() {
|
async application() {
|
||||||
const Application = this.models.get('Application')
|
const Application = this.models.get('Application')
|
||||||
return Application.findOne({ active: true, oauth_client_ids: this.id })
|
return Application.findOne({ active: true, oauth_client_ids: this.id })
|
||||||
|
26
app/models/system/Announcement.model.js
Normal file
26
app/models/system/Announcement.model.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
const { Model } = require('flitter-orm')
|
||||||
|
|
||||||
|
class AnnouncementModel extends Model {
|
||||||
|
static get schema() {
|
||||||
|
return {
|
||||||
|
title: String,
|
||||||
|
message: String,
|
||||||
|
user_ids: [String],
|
||||||
|
group_ids: [String],
|
||||||
|
type: String, // login | email | banner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async to_api() {
|
||||||
|
return {
|
||||||
|
id: this.id,
|
||||||
|
title: this.title,
|
||||||
|
message: this.message,
|
||||||
|
user_ids: this.user_ids,
|
||||||
|
group_ids: this.group_ids,
|
||||||
|
type: this.type,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = exports = AnnouncementModel
|
@ -17,6 +17,10 @@ const message_routes = {
|
|||||||
['middleware::api:Permission', { check: 'v1:message:banners:update' }],
|
['middleware::api:Permission', { check: 'v1:message:banners:update' }],
|
||||||
'controller::api:v1:Message.read_banner',
|
'controller::api:v1:Message.read_banner',
|
||||||
],
|
],
|
||||||
|
'/banners': [
|
||||||
|
['middleware::api:Permission', { check: 'v1:message:banners:create' }],
|
||||||
|
'controller::api:v1:Message.create_banner',
|
||||||
|
],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
34
app/routing/routers/api/v1/system.routes.js
Normal file
34
app/routing/routers/api/v1/system.routes.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
const system_routes = {
|
||||||
|
prefix: '/api/v1/system',
|
||||||
|
|
||||||
|
middleware: [
|
||||||
|
'auth:APIRoute'
|
||||||
|
],
|
||||||
|
|
||||||
|
get: {
|
||||||
|
'/announcements': [
|
||||||
|
['middleware::api:Permission', { check: 'v1:system:announcements:list' }],
|
||||||
|
'controller::api:v1:System.get_announcements',
|
||||||
|
],
|
||||||
|
'/announcements/:id': [
|
||||||
|
['middleware::api:Permission', { check: 'v1:system:announcements:get' }],
|
||||||
|
'controller::api:v1:System.get_announcement',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
post: {
|
||||||
|
'/announcements': [
|
||||||
|
['middleware::api:Permission', { check: 'v1:system:announcements:create'}],
|
||||||
|
'controller::api:v1:System.create_announcement',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
delete: {
|
||||||
|
'/announcements/:id': [
|
||||||
|
['middleware::api:Permission', { check: 'v1:system:announcements:delete' }],
|
||||||
|
'controller::api:v1:System.delete_announcement',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = exports = system_routes
|
@ -21,6 +21,8 @@ module.exports = exports = {
|
|||||||
|
|
||||||
app_pw_not_found: 'App password not found with that UUID.',
|
app_pw_not_found: 'App password not found with that UUID.',
|
||||||
|
|
||||||
|
announcement_not_found: 'Announcement not found with that ID.',
|
||||||
|
|
||||||
invalid_ldap_client_id: 'Invalid ldap_client_id:',
|
invalid_ldap_client_id: 'Invalid ldap_client_id:',
|
||||||
invalid_oauth_client_id: 'Invalid oauth_client_id:',
|
invalid_oauth_client_id: 'Invalid oauth_client_id:',
|
||||||
invalid_saml_service_provider_id: 'Invalid saml_service_provider_id:',
|
invalid_saml_service_provider_id: 'Invalid saml_service_provider_id:',
|
||||||
|
Loading…
Reference in New Issue
Block a user