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>
|
||||
<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/system/Announcement" v-if="can.messages" class="dropdown-item">System Announcements</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a href="/auth/logout" class="dropdown-item">Sign-Out of {{ app_name }}</a>
|
||||
</div>
|
||||
@ -64,6 +65,7 @@ export default class NavBarComponent extends Component {
|
||||
|
||||
async vue_on_create() {
|
||||
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()
|
||||
}
|
||||
|
||||
|
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()
|
||||
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
|
||||
|
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() {
|
||||
const Application = this.models.get('Application')
|
||||
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' }],
|
||||
'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.',
|
||||
|
||||
announcement_not_found: 'Announcement not found with that ID.',
|
||||
|
||||
invalid_ldap_client_id: 'Invalid ldap_client_id:',
|
||||
invalid_oauth_client_id: 'Invalid oauth_client_id:',
|
||||
invalid_saml_service_provider_id: 'Invalid saml_service_provider_id:',
|
||||
|
Loading…
Reference in New Issue
Block a user