mirror of https://github.com/MISP/MISP
new: [Dashboard] system
- Dashboard - modular similar to restSearch - build your own widgets - use a set of visualisation options (more coming!) - full access to internal functions for queries - auto discover core and 3rd party widgets - rearrange / configure widgets for each user individually - rearrange / resize widgets - settings can be configured by a site-admin on behalf of others - modules have a self-explain mode to guide users - caching mechanism for the modules / org - set homepage / user - various other fixespull/5635/head
parent
4bfcc3211b
commit
0d4df7c98b
|
@ -103,3 +103,4 @@ tools/mkdocs
|
|||
.ropeproject/
|
||||
vagrant/.vagrant/
|
||||
vagrant/*.log
|
||||
/app/Lib/Dashboard/Custom/*
|
||||
|
|
|
@ -46,7 +46,7 @@ class AppController extends Controller
|
|||
|
||||
public $helpers = array('Utility', 'OrgImg', 'FontAwesome', 'UserName');
|
||||
|
||||
private $__queryVersion = '98';
|
||||
private $__queryVersion = '99';
|
||||
public $pyMispVersion = '2.4.122';
|
||||
public $phpmin = '7.2';
|
||||
public $phprec = '7.4';
|
||||
|
@ -510,6 +510,18 @@ class AppController extends Controller
|
|||
}
|
||||
}
|
||||
$this->components['RestResponse']['sql_dump'] = $this->sql_dump;
|
||||
$this->loadModel('UserSetting');
|
||||
$homepage = $this->UserSetting->find('first', array(
|
||||
'recursive' => -1,
|
||||
'conditions' => array(
|
||||
'UserSetting.user_id' => $this->Auth->user('id'),
|
||||
'UserSetting.setting' => 'homepage'
|
||||
),
|
||||
'contain' => array('User.id', 'User.org_id')
|
||||
));
|
||||
if (!empty($homepage)) {
|
||||
$this->set('homepage', $homepage['UserSetting']['value']);
|
||||
}
|
||||
}
|
||||
|
||||
private function __rateLimitCheck()
|
||||
|
|
|
@ -71,6 +71,13 @@ class ACLComponent extends Component
|
|||
'view' => array('*'),
|
||||
'viewPicture' => array('*'),
|
||||
),
|
||||
'dashboards' => array(
|
||||
'getForm' => array('*'),
|
||||
'index' => array('*'),
|
||||
'updateSettings' => array('*'),
|
||||
'getEmptyWidget' => array('*'),
|
||||
'renderWidget' => array('*')
|
||||
),
|
||||
'decayingModel' => array(
|
||||
"update" => array(),
|
||||
"export" => array('*'),
|
||||
|
@ -575,7 +582,8 @@ class ACLComponent extends Component
|
|||
'view' => array('*'),
|
||||
'setSetting' => array('*'),
|
||||
'getSetting' => array('*'),
|
||||
'delete' => array('*')
|
||||
'delete' => array('*'),
|
||||
'setHomePage' => array('*')
|
||||
),
|
||||
'warninglists' => array(
|
||||
'checkValue' => array('perm_auth'),
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
<?php
|
||||
App::uses('AppController', 'Controller');
|
||||
|
||||
class DashboardsController extends AppController
|
||||
{
|
||||
public $components = array('Session', 'RequestHandler');
|
||||
|
||||
public function beforeFilter()
|
||||
{
|
||||
parent::beforeFilter();
|
||||
$this->Security->unlockedActions = array('renderWidget', 'updateSettings', 'getForm');
|
||||
}
|
||||
|
||||
public $paginate = array(
|
||||
'limit' => 60,
|
||||
'maxLimit' => 9999
|
||||
);
|
||||
|
||||
public function index()
|
||||
{
|
||||
$this->loadModel('UserSetting');
|
||||
$params = array(
|
||||
'conditions' => array(
|
||||
'UserSetting.user_id' => $this->Auth->user('id'),
|
||||
'UserSetting.setting' => 'dashboard'
|
||||
)
|
||||
);
|
||||
$userSettings = $this->UserSetting->find('first', $params);
|
||||
if (empty($userSettings)) {
|
||||
$userSettings = array(
|
||||
'UserSetting' => array(
|
||||
'setting' => 'dashboard',
|
||||
'value' => array(
|
||||
array(
|
||||
'widget' => 'MispStatusWidget',
|
||||
'config' => array(
|
||||
),
|
||||
'position' => array(
|
||||
'x' => 0,
|
||||
'y' => 0,
|
||||
'width' => 2,
|
||||
'height' => 2
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
$widgets = array();
|
||||
foreach ($userSettings['UserSetting']['value'] as $widget) {
|
||||
$dashboardWidget = $this->Dashboard->loadWidget($widget['widget']);
|
||||
$widget['width'] = $dashboardWidget->width;
|
||||
$widget['height'] = $dashboardWidget->height;
|
||||
$widget['title'] = $dashboardWidget->title;
|
||||
$widgets[] = $widget;
|
||||
}
|
||||
$this->layout = 'dashboard';
|
||||
$this->set('widgets', $widgets);
|
||||
}
|
||||
|
||||
public function getForm($action = 'edit')
|
||||
{
|
||||
if ($this->request->is('post') || $this->request->is('put')) {
|
||||
$data = $this->request->data;
|
||||
if ($action === 'edit' && !isset($data['widget'])) {
|
||||
throw new InvalidArgumentException(__('No widget name passed.'));
|
||||
}
|
||||
if (empty($data['config'])) {
|
||||
$data['config'] = '';
|
||||
}
|
||||
if ($action === 'add') {
|
||||
$data['widget_options'] = $this->Dashboard->loadAllWidgets();
|
||||
} else {
|
||||
$dashboardWidget = $this->Dashboard->loadWidget($data['widget']);
|
||||
$data['description'] = empty($dashboardWidget->description) ? '' : $dashboardWidget->description;
|
||||
$data['params'] = empty($dashboardWidget->params) ? array() : $dashboardWidget->params;
|
||||
$data['params'] = array_merge(array('alias' => __('Alias to use as the title of the widget')), $data['params']);
|
||||
}
|
||||
$this->set('data', $data);
|
||||
$this->layout = false;
|
||||
$this->render($action);
|
||||
}
|
||||
}
|
||||
|
||||
public function updateSettings()
|
||||
{
|
||||
if ($this->request->is('post')) {
|
||||
$this->UserSetting = ClassRegistry::init('UserSetting');
|
||||
if (!isset($this->request->data['value'])) {
|
||||
throw new InvalidArgumentException(__('No setting data found.'));
|
||||
}
|
||||
$data = array(
|
||||
'UserSetting' => array(
|
||||
'user_id' => $this->Auth->user('id'),
|
||||
'setting' => 'dashboard',
|
||||
'value' => $this->request->data['value']
|
||||
)
|
||||
);
|
||||
$result = $this->UserSetting->setSetting($this->Auth->user(), $data);
|
||||
if ($result) {
|
||||
return $this->RestResponse->saveSuccessResponse('Dashboard', 'updateSettings', false, false, __('Settings updated.'));
|
||||
}
|
||||
return $this->RestResponse->saveFailResponse('Dashboard', 'updateSettings', false, $this->UserSetting->validationErrors, $this->response->type());
|
||||
}
|
||||
}
|
||||
|
||||
public function getEmptyWidget($widget, $k = 1)
|
||||
{
|
||||
$dashboardWidget = $this->Dashboard->loadWidget($widget);
|
||||
if (empty($dashboardWidget)) {
|
||||
throw new NotFoundException(__('Invalid widget.'));
|
||||
}
|
||||
$this->layout = false;
|
||||
$widget = array(
|
||||
'config' => isset($dashboardWidget->config) ? $dashboardWidget->height : '',
|
||||
'title' => $dashboardWidget->title,
|
||||
'alias' => isset($dashboardWidget->alias) ? $dashboardWidget->alias : $dashboardWidget->title,
|
||||
'widget' => $widget
|
||||
);
|
||||
$this->set('k', $k);
|
||||
$this->set('widget', $widget);
|
||||
}
|
||||
|
||||
public function renderWidget($force = false)
|
||||
{
|
||||
if ($this->request->is('post')) {
|
||||
if (empty($this->request->data['data'])) {
|
||||
$this->request->data = array('data' => $this->request->data);
|
||||
|
||||
}
|
||||
if (empty($this->request->data['data'])) {
|
||||
throw new MethodNotAllowedException(__('You need to specify the widget to use along with the configuration.'));
|
||||
}
|
||||
$value = $this->request->data['data'];
|
||||
$dashboardWidget = $this->Dashboard->loadWidget($value['widget']);
|
||||
$this->layout = false;
|
||||
$this->set('title', $dashboardWidget->title);
|
||||
$redis = $this->Dashboard->setupRedis();
|
||||
$org_scope = $this->_isSiteAdmin() ? 0 : $this->Auth->user('org_id');
|
||||
$lookup_hash = hash('sha256', $value['widget'] . $value['config']);
|
||||
$data = $redis->get('misp:dashboard:' . $org_scope . ':' . $lookup_hash);
|
||||
if (empty($data)) {
|
||||
$data = $dashboardWidget->handler($this->Auth->user(), json_decode($value['config'], true));
|
||||
$redis->set('misp:dashboard:' . $org_scope . ':' . $lookup_hash, json_encode(array('data' => $data)));
|
||||
$redis->expire('misp:dashboard:' . $org_scope . ':' . $lookup_hash, 60);
|
||||
} else {
|
||||
$data = json_decode($data, true)['data'];
|
||||
}
|
||||
$this->set('data', $data);
|
||||
$this->render('/Dashboards/Widgets/' . $dashboardWidget->render);
|
||||
} else {
|
||||
throw new MethodNotAllowedException(__('This endpoint can only be reached via POST requests.'));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -25,6 +25,12 @@ class UserSettingsController extends AppController
|
|||
)
|
||||
);
|
||||
|
||||
public function beforeFilter()
|
||||
{
|
||||
parent::beforeFilter();
|
||||
$this->Security->unlockedActions = array('setHomePage');
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$filterData = array(
|
||||
|
@ -172,49 +178,7 @@ class UserSettingsController extends AppController
|
|||
$userSetting = array(
|
||||
'user_id' => $this->Auth->user('id')
|
||||
);
|
||||
if (!empty($this->request->data['UserSetting']['user_id']) && is_numeric($this->request->data['UserSetting']['user_id'])) {
|
||||
$user = $this->UserSetting->User->find('first', array(
|
||||
'recursive' => -1,
|
||||
'conditions' => array('User.id' => $this->request->data['UserSetting']['user_id']),
|
||||
'fields' => array('User.org_id')
|
||||
));
|
||||
if (
|
||||
$this->_isSiteAdmin() ||
|
||||
($this->_isAdmin() && ($user['User']['org_id'] == $this->Auth->user('org_id')))
|
||||
) {
|
||||
$userSetting['user_id'] = $this->request->data['UserSetting']['user_id'];
|
||||
}
|
||||
}
|
||||
if (empty($this->request->data['UserSetting']['setting']) || !isset($this->request->data['UserSetting']['setting'])) {
|
||||
throw new MethodNotAllowedException(__('This endpoint expects both a setting and a value to be set.'));
|
||||
}
|
||||
if (!$this->UserSetting->checkSettingValidity($this->request->data['UserSetting']['setting'])) {
|
||||
throw new MethodNotAllowedException(__('Invalid setting.'));
|
||||
}
|
||||
$settingPermCheck = $this->UserSetting->checkSettingAccess($this->Auth->user(), $this->request->data['UserSetting']['setting']);
|
||||
if ($settingPermCheck !== true) {
|
||||
throw new MethodNotAllowedException(__('This setting is restricted and requires the following permission(s): %s', $settingPermCheck));
|
||||
}
|
||||
$userSetting['setting'] = $this->request->data['UserSetting']['setting'];
|
||||
if ($this->request->data['UserSetting']['value'] !== '') {
|
||||
$userSetting['value'] = json_encode(json_decode($this->request->data['UserSetting']['value'], true));
|
||||
} else {
|
||||
$userSetting['value'] = '';
|
||||
}
|
||||
$existingSetting = $this->UserSetting->find('first', array(
|
||||
'recursive' => -1,
|
||||
'conditions' => array(
|
||||
'UserSetting.user_id' => $userSetting['user_id'],
|
||||
'UserSetting.setting' => $userSetting['setting']
|
||||
)
|
||||
));
|
||||
if (empty($existingSetting)) {
|
||||
$this->UserSetting->create();
|
||||
} else {
|
||||
$userSetting['id'] = $existingSetting['UserSetting']['id'];
|
||||
}
|
||||
// save the setting
|
||||
$result = $this->UserSetting->save(array('UserSetting' => $userSetting));
|
||||
$result = $this->UserSetting->setSetting($this->Auth->user(), $this->request->data);
|
||||
if ($result) {
|
||||
// if we've managed to save our setting
|
||||
if ($this->_isRest()) {
|
||||
|
@ -358,4 +322,26 @@ class UserSettingsController extends AppController
|
|||
throw new MethodNotAllowedException(__('Expecting POST or DELETE request.'));
|
||||
}
|
||||
}
|
||||
|
||||
public function setHomePage()
|
||||
{
|
||||
if (!$this->request->is('post')) {
|
||||
throw new MethodNotAllowedException(__('This endpoint only aaccepts POST requests.'));
|
||||
}
|
||||
if (empty($this->request->data['path'])) {
|
||||
$this->request->data = array('path' => $this->request->data);
|
||||
}
|
||||
if (empty($this->request->data['path'])) {
|
||||
throw new InvalidArgumentException(__('No path POSTed.'));
|
||||
}
|
||||
$setting = array(
|
||||
'UserSetting' => array(
|
||||
'user_id' => $this->Auth->user('id'),
|
||||
'setting' => 'homepage',
|
||||
'value' => json_encode(array('path' => $this->request->data['path']))
|
||||
)
|
||||
);
|
||||
$result = $this->UserSetting->setSetting($this->Auth->user(), $setting);
|
||||
return $this->RestResponse->saveSuccessResponse('UserSettings', 'setHomePage', false, $this->response->type(), 'Homepage set to ' . $this->request->data['path']);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1195,7 +1195,19 @@ class UsersController extends AppController
|
|||
// Events list
|
||||
$url = $this->Session->consume('pre_login_requested_url');
|
||||
if (empty($url)) {
|
||||
$url = array('controller' => 'events', 'action' => 'index');
|
||||
$homepage = $this->User->UserSetting->find('first', array(
|
||||
'recursive' => -1,
|
||||
'conditions' => array(
|
||||
'UserSetting.user_id' => $this->Auth->user('id'),
|
||||
'UserSetting.setting' => 'homepage'
|
||||
),
|
||||
'contain' => array('User.id', 'User.org_id')
|
||||
));
|
||||
if (!empty($homepage)) {
|
||||
$url = $homepage['UserSetting']['value']['path'];
|
||||
} else {
|
||||
$url = array('controller' => 'events', 'action' => 'index');
|
||||
}
|
||||
}
|
||||
$this->redirect($url);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
|
||||
class MispStatusWidget
|
||||
{
|
||||
public $title = 'MISP Status';
|
||||
public $render = 'SimpleList';
|
||||
public $width = 2;
|
||||
public $height = 2;
|
||||
public $params = array();
|
||||
public $description = 'Basic widget showing some user related MISP notifications.';
|
||||
|
||||
|
||||
public function handler($user, $options = array())
|
||||
{
|
||||
$this->Event = ClassRegistry::init('Event');
|
||||
// the last login in the session is not updated after the login - only in the db, so let's fetch it.
|
||||
$lastLogin = $user['last_login'];
|
||||
$data = array();
|
||||
$data[] = array(
|
||||
'title' => __('Events modified'),
|
||||
'value' => count($this->Event->fetchEventIds($user, false, false, false, true, $lastLogin)),
|
||||
'html' => sprintf(
|
||||
' (<a href="%s">%s</a>)',
|
||||
Configure::read('MISP.baseurl') . '/events/index/timestamp:' . (time() - 86400),
|
||||
'View'
|
||||
)
|
||||
);
|
||||
$data[] = array(
|
||||
'title' => __('Events published'),
|
||||
'value' => count($this->Event->fetchEventIds($user, false, false, false, true, false, $lastLogin)),
|
||||
'html' => sprintf(
|
||||
' (<a href="%s">%s</a>)',
|
||||
Configure::read('MISP.baseurl') . '/events/index/published:1/timestamp:' . (time() - 86400),
|
||||
'View'
|
||||
)
|
||||
);
|
||||
$notifications = $this->Event->populateNotifications($user);
|
||||
if (!empty($notifications['proposalCount'])) {
|
||||
$data[] = array(
|
||||
'title' => __('Pending proposals'),
|
||||
'value' => $notifications['proposalCount'],
|
||||
'html' => sprintf(
|
||||
' (<a href="%s">%s</a>)',
|
||||
Configure::read('MISP.baseurl') . '/shadow_attributes/index/all:0',
|
||||
'View'
|
||||
)
|
||||
);
|
||||
}
|
||||
if (!empty($notifications['proposalEventCount'])) {
|
||||
$data[] = array(
|
||||
'title' => __('Events with proposals'),
|
||||
'value' => $notifications['proposalEventCount'],
|
||||
'html' => sprintf(
|
||||
' (<a href="%s">%s</a>)',
|
||||
Configure::read('MISP.baseurl') . '/events/proposalEventIndex',
|
||||
'View'
|
||||
)
|
||||
);
|
||||
}
|
||||
if (!empty($notifications['delegationCount'])) {
|
||||
$data[] = array(
|
||||
'title' => __('Delegation requests'),
|
||||
'value' => $notifications['delegationCount'],
|
||||
'html' => sprintf(
|
||||
' (<a href="%s">%s</a>)',
|
||||
Configure::read('MISP.baseurl') . '/event_delegations/index/context:pending',
|
||||
'View'
|
||||
)
|
||||
);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
class TrendingTagsWidget
|
||||
{
|
||||
public $title = 'Trending Tags';
|
||||
public $render = 'BarChart';
|
||||
public $width = 3;
|
||||
public $height = 4;
|
||||
public $params = array(
|
||||
'time_window' => 'The time window, going back in seconds, that should be included.',
|
||||
'exclude' => 'List of substrings to exclude tags by - for example "sofacy" would exclude any tag containing sofacy.',
|
||||
'include' => 'List of substrings to include tags by - for example "sofacy" would include any tag containing sofacy.'
|
||||
);
|
||||
public $placeholder =
|
||||
'{
|
||||
"time_window": "86400",
|
||||
"exclude": ["tlp:", "pap:"],
|
||||
"include": ["misp-galaxy:", "my-internal-taxonomy"]
|
||||
}';
|
||||
public $description = 'Widget showing the trending tags over the past x seconds, along with the possibility to include/exclude tags.';
|
||||
|
||||
public function handler($user, $options = array())
|
||||
{
|
||||
$this->Event = ClassRegistry::init('Event');
|
||||
$params = array(
|
||||
'metadata' => 1,
|
||||
'timestamp' => time() - (empty($options['time_window']) ? 8640000 : $options['time_window'])
|
||||
);
|
||||
$eventIds = $this->Event->filterEventIds($user, $params);
|
||||
$params['eventid'] = $eventIds;
|
||||
$events = array();
|
||||
if (!empty($eventIds)) {
|
||||
$events = $this->Event->fetchEvent($user, $params);
|
||||
}
|
||||
$tags = array();
|
||||
$tagColours = array();
|
||||
$rules['exclusions'] = empty($options['exclude']) ? array() : $options['exclude'];
|
||||
$rules['inclusions'] = empty($options['exclude']) ? array() : $options['exclude'];
|
||||
foreach ($events as $event) {
|
||||
foreach ($event['EventTag'] as $et) {
|
||||
if ($this->checkTag($options, $et['Tag']['name'])) {
|
||||
if (empty($tags[$et['Tag']['name']])) {
|
||||
$tags[$et['Tag']['name']] = 1;
|
||||
$tagColours[$et['Tag']['name']] = $et['Tag']['colour'];
|
||||
} else {
|
||||
$tags[$et['Tag']['name']] += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
arsort($tags);
|
||||
$data['data'] = array_slice($tags, 0, 10);
|
||||
$data['colours'] = $tagColours;
|
||||
return $data;
|
||||
}
|
||||
|
||||
private function checkTag($options, $tag)
|
||||
{
|
||||
if (!empty($options['exclude'])) {
|
||||
foreach ($options['exclude'] as $exclude) {
|
||||
if (strpos($tag, $exclude) !== false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($options['include'])) {
|
||||
foreach ($options['include'] as $include) {
|
||||
if (strpos($tag, $include) !== false) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
App::uses('AppModel', 'Model');
|
||||
class Dashboard extends AppModel
|
||||
{
|
||||
public $useTable = false;
|
||||
|
||||
public function loadWidget($name)
|
||||
{
|
||||
if (file_exists(APP . 'Lib/Dashboard/' . $name . '.php')) {
|
||||
App::uses($name, 'Dashboard');
|
||||
} else if (file_exists(APP . 'Lib/Dashboard/Custom/' . $name . '.php')) {
|
||||
App::uses($name, 'Dashboard/Custom');
|
||||
} else {
|
||||
throw new NotFoundException(__('Invalid widget or widget not found.'));
|
||||
}
|
||||
$widget = new $name();
|
||||
return $widget;
|
||||
}
|
||||
|
||||
public function loadAllWidgets()
|
||||
{
|
||||
$dir = new Folder(APP . 'Lib/Dashboard');
|
||||
$customdir = new Folder(APP . 'Lib/Dashboard/Custom');
|
||||
$widgetFiles = $dir->find('.*Widget\.php');
|
||||
$customWidgetFiles = $customdir->find('.*Widget\.php');
|
||||
$widgets = array();
|
||||
foreach ($widgetFiles as $widgetFile) {
|
||||
$className = substr($widgetFile, 0, strlen($widgetFile) -4);
|
||||
$widgets[$className] = $this->__extractMeta($className, false);
|
||||
}
|
||||
return $widgets;
|
||||
}
|
||||
|
||||
private function __extractMeta($className, $custom)
|
||||
{
|
||||
App::uses($className, 'Dashboard' . $custom ? '/Custom' : '');
|
||||
$widgetClass = new $className();
|
||||
$widget = array(
|
||||
'widget' => $className,
|
||||
'title' => $widgetClass->title,
|
||||
'render' => $widgetClass->render,
|
||||
'params' => empty($widgetClass->params) ? array() : $widgetClass->params,
|
||||
'description' => empty($widgetClass->description) ? $widgetClass->title : $widgetClass->description,
|
||||
'height' => empty($widgetClass->height) ? 1 : $widgetClass->height,
|
||||
'width' => empty($widgetClass->width) ? 1 : $widgetClass->width,
|
||||
'placeholder' => empty($widgetClass->placeholder) ? '' : $widgetClass->placeholder
|
||||
);
|
||||
return $widget;
|
||||
}
|
||||
}
|
|
@ -1717,6 +1717,9 @@ class Event extends AppModel
|
|||
'recursive' => -1,
|
||||
'fields' => $fields
|
||||
);
|
||||
if (isset($params['order'])) {
|
||||
$find_params['order'] = $params['order'];
|
||||
}
|
||||
if (isset($params['limit'])) {
|
||||
// Get the count (but not the actual data) of results for paginators
|
||||
$result_count = $this->find('count', $find_params);
|
||||
|
|
|
@ -49,6 +49,24 @@ class UserSetting extends AppModel
|
|||
'dashboard_access' => array(
|
||||
'placeholder' => 1,
|
||||
'restricted' => 'perm_site_admin'
|
||||
),
|
||||
'dashboard' => array(
|
||||
'placeholder' => array(
|
||||
array(
|
||||
'widget' => 'MispStatusWidget',
|
||||
'config' => array(
|
||||
),
|
||||
'position' => array(
|
||||
'x' => 0,
|
||||
'y' => 0,
|
||||
'width' => 2,
|
||||
'height' => 2
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
'homepage' => array(
|
||||
'path' => '/events/index'
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -279,4 +297,56 @@ class UserSetting extends AppModel
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function setSetting($user, &$data)
|
||||
{
|
||||
$userSetting = array();
|
||||
if (!empty($data['UserSetting']['user_id']) && is_numeric($data['UserSetting']['user_id'])) {
|
||||
$user_to_edit = $this->User->find('first', array(
|
||||
'recursive' => -1,
|
||||
'conditions' => array('User.id' => $data['UserSetting']['user_id']),
|
||||
'fields' => array('User.org_id')
|
||||
));
|
||||
if (
|
||||
!empty($user['Role']['perm_site_admin']) ||
|
||||
(!empty($user['Role']['perm_admin']) && ($user_to_edit['User']['org_id'] == $user['org_id']))
|
||||
) {
|
||||
$userSetting['user_id'] = $data['UserSetting']['user_id'];
|
||||
}
|
||||
}
|
||||
if (empty($userSetting['user_id'])) {
|
||||
$userSetting['user_id'] = $user['id'];
|
||||
}
|
||||
if (empty($data['UserSetting']['setting']) || !isset($data['UserSetting']['setting'])) {
|
||||
throw new MethodNotAllowedException(__('This endpoint expects both a setting and a value to be set.'));
|
||||
}
|
||||
if (!$this->checkSettingValidity($data['UserSetting']['setting'])) {
|
||||
throw new MethodNotAllowedException(__('Invalid setting.'));
|
||||
}
|
||||
$settingPermCheck = $this->checkSettingAccess($user, $data['UserSetting']['setting']);
|
||||
if ($settingPermCheck !== true) {
|
||||
throw new MethodNotAllowedException(__('This setting is restricted and requires the following permission(s): %s', $settingPermCheck));
|
||||
}
|
||||
$userSetting['setting'] = $data['UserSetting']['setting'];
|
||||
if ($data['UserSetting']['value'] !== '') {
|
||||
$userSetting['value'] = $data['UserSetting']['value'];
|
||||
} else {
|
||||
$userSetting['value'] = '';
|
||||
}
|
||||
$existingSetting = $this->find('first', array(
|
||||
'recursive' => -1,
|
||||
'conditions' => array(
|
||||
'UserSetting.user_id' => $userSetting['user_id'],
|
||||
'UserSetting.setting' => $userSetting['setting']
|
||||
)
|
||||
));
|
||||
if (empty($existingSetting)) {
|
||||
$this->create();
|
||||
} else {
|
||||
$userSetting['id'] = $existingSetting['UserSetting']['id'];
|
||||
}
|
||||
// save the setting
|
||||
$result = $this->save(array('UserSetting' => $userSetting));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,189 @@
|
|||
<div class="attributes <?php if (!isset($ajax) || !$ajax) echo 'form';?>">
|
||||
<?php
|
||||
$url_params = $action == 'add' ? 'add/' . $event_id : 'edit/' . $attribute['Attribute']['id'];
|
||||
echo $this->Form->create('Attribute', array('id', 'url' => '/attributes/' . $url_params));
|
||||
?>
|
||||
<fieldset>
|
||||
<legend><?php echo $action == 'add' ? __('Add Attribute') : __('Edit Attribute'); ?></legend>
|
||||
<div id="formWarning" class="message ajaxMessage"></div>
|
||||
<div id="compositeWarning" class="message <?php echo !empty($ajax) ? 'ajaxMessage' : '';?>" style="display:none;">Did you consider adding an object instead of a composite attribute?</div>
|
||||
<div class="add_attribute_fields">
|
||||
<?php
|
||||
echo $this->Form->hidden('event_id');
|
||||
echo $this->Form->input('category', array(
|
||||
'empty' => __('(choose one)'),
|
||||
'label' => __('Category ') . $this->element('formInfo', array('type' => 'category')),
|
||||
));
|
||||
echo $this->Form->input('type', array(
|
||||
'empty' => __('(first choose category)'),
|
||||
'label' => __('Type ') . $this->element('formInfo', array('type' => 'type')),
|
||||
));
|
||||
|
||||
$initialDistribution = 5;
|
||||
if (Configure::read('MISP.default_attribute_distribution') != null) {
|
||||
if (Configure::read('MISP.default_attribute_distribution') === 'event') {
|
||||
$initialDistribution = 5;
|
||||
} else {
|
||||
$initialDistribution = Configure::read('MISP.default_attribute_distribution');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
<div class="input clear"></div>
|
||||
<?php
|
||||
$distArray = array(
|
||||
'options' => array($distributionLevels),
|
||||
'label' => __('Distribution ') . $this->element('formInfo', array('type' => 'distribution')),
|
||||
);
|
||||
|
||||
if ($action == 'add') {
|
||||
$distArray['selected'] = $initialDistribution;
|
||||
}
|
||||
|
||||
echo $this->Form->input('distribution', $distArray);
|
||||
?>
|
||||
<div id="SGContainer" style="display:none;">
|
||||
<?php
|
||||
if (!empty($sharingGroups)) {
|
||||
echo $this->Form->input('sharing_group_id', array(
|
||||
'options' => array($sharingGroups),
|
||||
'label' => __('Sharing Group'),
|
||||
));
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
echo $this->Form->input('value', array(
|
||||
'type' => 'textarea',
|
||||
'error' => array('escape' => false),
|
||||
'div' => 'input clear',
|
||||
'class' => 'input-xxlarge'
|
||||
));
|
||||
?>
|
||||
<div class="input clear"></div>
|
||||
<?php
|
||||
echo $this->Form->input('comment', array(
|
||||
'type' => 'text',
|
||||
'label' => __('Contextual Comment'),
|
||||
'error' => array('escape' => false),
|
||||
'div' => 'input clear',
|
||||
'class' => 'input-xxlarge'
|
||||
));
|
||||
?>
|
||||
<div class="input clear"></div>
|
||||
<?php
|
||||
echo $this->Form->input('to_ids', array(
|
||||
'label' => __('for Intrusion Detection System'),
|
||||
'type' => 'checkbox'
|
||||
));
|
||||
echo $this->Form->input('batch_import', array(
|
||||
'type' => 'checkbox'
|
||||
));
|
||||
echo '<div class="input clear"></div>';
|
||||
echo $this->Form->input('disable_correlation', array(
|
||||
'type' => 'checkbox'
|
||||
));
|
||||
?>
|
||||
</div>
|
||||
</fieldset>
|
||||
<p id="notice_message" style="display:none;"></p>
|
||||
<?php if ($ajax): ?>
|
||||
<div class="overlay_spacing">
|
||||
<span id="submitButton" class="btn btn-primary" style="margin-bottom:5px;float:left;" title="<?php echo __('Submit'); ?>" role="button" tabindex="0" aria-label="<?php echo __('Submit'); ?>" onClick="submitPopoverForm('<?php echo $action == 'add' ? $event_id : $attribute['Attribute']['id'];?>', '<?php echo $action; ?>')"><?php echo __('Submit'); ?></span>
|
||||
<span class="btn btn-inverse" style="float:right;" title="<?php echo __('Cancel'); ?>" role="button" tabindex="0" aria-label="<?php echo __('Cancel'); ?>" id="cancel_attribute_add"><?php echo __('Cancel'); ?></span>
|
||||
</div>
|
||||
<?php
|
||||
else:
|
||||
?>
|
||||
<?php
|
||||
echo $this->Form->button('Submit', array('class' => 'btn btn-primary'));
|
||||
endif;
|
||||
echo $this->Form->end();
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
if (!$ajax) {
|
||||
$event['Event']['id'] = $event_id;
|
||||
$event['Event']['published'] = $published;
|
||||
echo $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'event', 'menuItem' => 'addAttribute', 'event' => $event));
|
||||
}
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
var notice_list_triggers = <?php echo $notice_list_triggers; ?>;
|
||||
var fieldsArray = new Array('AttributeCategory', 'AttributeType', 'AttributeValue', 'AttributeDistribution', 'AttributeComment', 'AttributeToIds', 'AttributeBatchImport', 'AttributeSharingGroupId');
|
||||
<?php
|
||||
$formInfoTypes = array('distribution' => 'Distribution', 'category' => 'Category', 'type' => 'Type');
|
||||
echo 'var formInfoFields = ' . json_encode($formInfoTypes) . PHP_EOL;
|
||||
foreach ($formInfoTypes as $formInfoType => $humanisedName) {
|
||||
echo 'var ' . $formInfoType . 'FormInfoValues = {' . PHP_EOL;
|
||||
foreach ($info[$formInfoType] as $key => $formInfoData) {
|
||||
echo '"' . $key . '": "<span class=\"blue bold\">' . h($formInfoData['key']) . '</span>: ' . h($formInfoData['desc']) . '<br />",' . PHP_EOL;
|
||||
}
|
||||
echo '}' . PHP_EOL;
|
||||
}
|
||||
?>
|
||||
|
||||
//
|
||||
//Generate Category / Type filtering array
|
||||
//
|
||||
var category_type_mapping = new Array();
|
||||
<?php
|
||||
foreach ($categoryDefinitions as $category => $def) {
|
||||
echo "category_type_mapping['" . addslashes($category) . "'] = {";
|
||||
$first = true;
|
||||
foreach ($def['types'] as $type) {
|
||||
if ($first) $first = false;
|
||||
else echo ', ';
|
||||
echo "'" . addslashes($type) . "' : '" . addslashes($type) . "'";
|
||||
}
|
||||
echo "}; \n";
|
||||
}
|
||||
?>
|
||||
|
||||
var composite_types = <?php echo json_encode($compositeTypes); ?>;
|
||||
|
||||
$(document).ready(function() {
|
||||
<?php
|
||||
if ($action == 'edit'):
|
||||
?>
|
||||
checkNoticeList('attribute');
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
initPopoverContent('Attribute');
|
||||
$('#AttributeDistribution').change(function() {
|
||||
if ($('#AttributeDistribution').val() == 4) $('#SGContainer').show();
|
||||
else $('#SGContainer').hide();
|
||||
});
|
||||
|
||||
$("#AttributeCategory").on('change', function(e) {
|
||||
formCategoryChanged('Attribute');
|
||||
if ($(this).val() === 'Internal reference') {
|
||||
$("#AttributeDistribution").val('0');
|
||||
$('#SGContainer').hide();
|
||||
}
|
||||
});
|
||||
|
||||
$("#AttributeCategory, #AttributeType").change(function() {
|
||||
checkNoticeList('attribute');
|
||||
});
|
||||
|
||||
$("#AttributeCategory, #AttributeType, #AttributeDistribution").change(function() {
|
||||
var start = $("#AttributeType").val();
|
||||
initPopoverContent('Attribute');
|
||||
$("#AttributeType").val(start);
|
||||
if ($.inArray(start, composite_types) > -1) {
|
||||
$('#compositeWarning').show();
|
||||
} else {
|
||||
$('#compositeWarning').hide();
|
||||
}
|
||||
});
|
||||
<?php if ($ajax): ?>
|
||||
$('#cancel_attribute_add').click(function() {
|
||||
cancelPopoverForm();
|
||||
});
|
||||
|
||||
<?php endif; ?>
|
||||
});
|
||||
</script>
|
||||
<?php echo $this->Js->writeBuffer(); // Write cached scripts
|
|
@ -0,0 +1,32 @@
|
|||
<table style="border-spacing:0px;">
|
||||
<?php
|
||||
if (!empty($data['logarithmic'])) {
|
||||
$max = max($data['logarithmic']);
|
||||
} else {
|
||||
$max = max($data['data']);
|
||||
}
|
||||
foreach ($data['data'] as $entry => $count) {
|
||||
$value = $count;
|
||||
if (!empty($data['logarithmic'])) {
|
||||
$value = $data['logarithmic'][$entry];
|
||||
}
|
||||
echo sprintf(
|
||||
'<tr><td style="%s">%s</td><td style="%s">%s</td></tr>',
|
||||
'text-align:right;width:33%;',
|
||||
h($entry),
|
||||
'width:100%',
|
||||
sprintf(
|
||||
'<div title="%s" style="%s">%s</div>',
|
||||
h($entry) . ': ' . h($count),
|
||||
sprintf(
|
||||
'background-color:%s; width:%s; color:white; text-align:center;',
|
||||
(empty($data['colours'][$entry]) ? '#0088cc' : h($data['colours'][$entry])),
|
||||
100 * h($value) / $max . '%;'
|
||||
),
|
||||
h($count)
|
||||
),
|
||||
' '
|
||||
);
|
||||
}
|
||||
?>
|
||||
</table>
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
foreach ($data as $element) {
|
||||
echo sprintf(
|
||||
'<div><span class="bold">%s</span>: <span class="blue">%s</span>%s</div>',
|
||||
h($element['title']),
|
||||
empty($element['value']) ? '' : h($element['value']),
|
||||
empty($element['html']) ? '' : $element['html']
|
||||
);
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
$modelForForm = 'Dashboard';
|
||||
$paramsHtml = '';
|
||||
if (!empty($data['params'])) {
|
||||
foreach ($data['params'] as $param => $desc) {
|
||||
$paramsHtml .= sprintf(
|
||||
'<span class="bold">%s</span>: %s<br />',
|
||||
h($param),
|
||||
h($desc)
|
||||
);
|
||||
}
|
||||
}
|
||||
echo $this->element('genericElements/Form/genericForm', array(
|
||||
'form' => $this->Form,
|
||||
'url' => 'updateSettings',
|
||||
'data' => array(
|
||||
'title' => __('Add Widget'),
|
||||
'model' => 'Dashboard',
|
||||
'fields' => array(
|
||||
array(
|
||||
'field' => 'widget',
|
||||
'class' => 'input span6',
|
||||
'options' => Hash::combine($data['widget_options'], '{s}.widget', '{s}.title')
|
||||
),
|
||||
array(
|
||||
'field' => 'width',
|
||||
'class' => 'input',
|
||||
'type' => 'number',
|
||||
'default' => 1,
|
||||
'stayInLine' => 1
|
||||
),
|
||||
array(
|
||||
'field' => 'height',
|
||||
'type' => 'number',
|
||||
'class' => 'input',
|
||||
'default' => 1
|
||||
),
|
||||
array(
|
||||
'field'=> 'config',
|
||||
'type' => 'textarea',
|
||||
'class' => 'input span6',
|
||||
'div' => 'input clear',
|
||||
'label' => __('Config')
|
||||
)
|
||||
),
|
||||
'submit' => array(
|
||||
'action' => 'edit',
|
||||
'ajaxSubmit' => sprintf(
|
||||
"submitDashboardAddWidget()"
|
||||
)
|
||||
),
|
||||
'description' => '<p class="black widget-description"><span></p><p class="bold">Parameters</p><p class="widget-parameters"></p>'
|
||||
)
|
||||
));
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
var widget_options = <?= json_encode($data['widget_options']) ?>;
|
||||
|
||||
function setDashboardWidgetChoice() {
|
||||
var current_choice = $('#DashboardWidget').val();
|
||||
var current_widget_data = widget_options[current_choice];
|
||||
$('#DashboardWidth').val(current_widget_data['width']);
|
||||
$('.widget-description').text(current_widget_data['description']);
|
||||
$('#DashboardHeight').val(current_widget_data['height']);
|
||||
$('#DashboardConfig').attr('placeholder', current_widget_data['placeholder']);
|
||||
$('.widget-parameters').empty();
|
||||
$.each(current_widget_data['params'], function(index,value) {
|
||||
$('.widget-parameters').append(
|
||||
$('<span>')
|
||||
.attr('class', 'bold')
|
||||
.text(index)
|
||||
).append(
|
||||
$('<span>')
|
||||
.text(': ' + value)
|
||||
).append(
|
||||
$('<br>')
|
||||
)
|
||||
});
|
||||
//$('#DashboardConfig').val(JSON.stringify(current_widget_data['params'], null, 2));
|
||||
}
|
||||
|
||||
$('#DashboardWidget').change(function() {
|
||||
setDashboardWidgetChoice();
|
||||
});
|
||||
|
||||
$(document).ready(function() {
|
||||
setDashboardWidgetChoice();
|
||||
});
|
||||
</script>
|
||||
<?php echo $this->Js->writeBuffer(); // Write cached scripts
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
$modelForForm = 'Dashboard';
|
||||
$paramsHtml = '';
|
||||
if (!empty($data['params'])) {
|
||||
foreach ($data['params'] as $param => $desc) {
|
||||
$paramsHtml .= sprintf(
|
||||
'<span class="bold">%s</span>: %s<br />',
|
||||
h($param),
|
||||
h($desc)
|
||||
);
|
||||
}
|
||||
}
|
||||
echo $this->element('genericElements/Form/genericForm', array(
|
||||
'form' => $this->Form,
|
||||
'url' => 'updateSettings',
|
||||
'data' => array(
|
||||
'title' => __('Edit Widget'),
|
||||
'model' => 'Dashboard',
|
||||
'fields' => array(
|
||||
array(
|
||||
'field'=> 'config',
|
||||
'type' => 'textarea',
|
||||
'class' => 'input span6',
|
||||
'div' => 'input clear',
|
||||
'label' => __('Config'),
|
||||
'default' => empty($data['config']) ? '' : json_encode($data['config'], JSON_PRETTY_PRINT)
|
||||
)
|
||||
),
|
||||
'submit' => array(
|
||||
'action' => 'edit',
|
||||
'ajaxSubmit' => sprintf(
|
||||
"submitDashboardForm('%s')",
|
||||
h($data['id'])
|
||||
)
|
||||
),
|
||||
'description' => sprintf(
|
||||
'<p class="black">%s<span></p><p class="bold">Parameters</p><p>%s</p>',
|
||||
h($data['description']),
|
||||
$paramsHtml
|
||||
)
|
||||
)
|
||||
));
|
||||
?>
|
|
@ -0,0 +1 @@
|
|||
<?= $this->element('/dashboard/widget', array('widget' => $widget, 'k' => $k)); ?>
|
|
@ -0,0 +1,50 @@
|
|||
<div class="index">
|
||||
<div class="grid-stack" data-gs-min-row:"10">
|
||||
<?php
|
||||
$layout = '';
|
||||
foreach ($widgets as $k => $widget) {
|
||||
$layout .= $this->element('/dashboard/widget', array('widget' => $widget, 'k' => $k));
|
||||
}
|
||||
echo $layout;
|
||||
?>
|
||||
</div>
|
||||
<div class="hidden" id="last-element-counter" data-element-counter="<?= h($k) ?>"></div>
|
||||
</div>
|
||||
<?php
|
||||
echo $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'dashboard', 'menuItem' => 'dashboardIndex'));
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
|
||||
function resetDashboardGrid(grid) {
|
||||
$('.grid-stack-item').each(function() {
|
||||
updateDashboardWidget(this);
|
||||
});
|
||||
saveDashboardState();
|
||||
$('.edit-widget').click(function() {
|
||||
el = $(this).closest('.grid-stack-item');
|
||||
data = {
|
||||
id: el.attr('id'),
|
||||
config: JSON.parse(el.attr('config')),
|
||||
widget: el.attr('widget'),
|
||||
alias: el.attr('alias')
|
||||
}
|
||||
openGenericModalPost(baseurl + '/dashboards/getForm/edit', data);
|
||||
});
|
||||
$('.remove-widget').click(function() {
|
||||
el = $(this).closest('.grid-stack-item');
|
||||
grid.removeWidget(el);
|
||||
saveDashboardState();
|
||||
});
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
var grid = GridStack.init();
|
||||
resetDashboardGrid(grid);
|
||||
grid.on('change', function(event, items) {
|
||||
saveDashboardState();
|
||||
});
|
||||
grid.on('added', function(event, items) {
|
||||
resetDashboardGrid(grid);
|
||||
});
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
echo sprintf(
|
||||
'<div id="widget_%s" class="grid-stack-item" data-gs-x="%s" data-gs-y="%s" data-gs-width="%s" data-gs-height="%s" style="%s" config="%s" widget="%s">%s<div class="widget-data"> </div></div>',
|
||||
h($k),
|
||||
isset($widget['position']['x']) ? h($widget['position']['x']) : 1,
|
||||
isset($widget['position']['y']) ? h($widget['position']['y']) : 1,
|
||||
isset($widget['position']['width']) ? h($widget['position']['width']) : 2,
|
||||
isset($widget['position']['height']) ? h($widget['position']['height']) : 2,
|
||||
'border: 1px solid #0088cc;',
|
||||
empty($widget['config']) ? '[]' : h(json_encode($widget['config'])),
|
||||
h($widget['widget']),
|
||||
sprintf(
|
||||
'<div class="grid-stack-item-content"><div class="widgetTitle"><span class="widgetTitleText">%s</span> %s %s</div><div class="widgetContent">%s</div></div>',
|
||||
empty($widget['config']['alias']) ? h($widget['title']) : h($widget['config']['alias']),
|
||||
sprintf(
|
||||
'<span class="fas fa-edit edit-widget" title="%s"></span>',
|
||||
__('Configure widget')
|
||||
),
|
||||
sprintf(
|
||||
'<span class="fas fa-trash remove-widget" title="%s"></span>',
|
||||
__('Remove widget')
|
||||
),
|
||||
' '
|
||||
)
|
||||
);
|
||||
?>
|
|
@ -96,7 +96,8 @@
|
|||
sprintf(
|
||||
'<div class="modal-body modal-body-long">%s</div>',
|
||||
sprintf(
|
||||
'%s<fieldset>%s%s</fieldset>%s%s',
|
||||
'%s%s<fieldset>%s%s</fieldset>%s%s',
|
||||
empty($data['description']) ? '' : $data['description'],
|
||||
$formCreate,
|
||||
$ajaxFlashMessage,
|
||||
$fieldsString,
|
||||
|
|
|
@ -2,6 +2,22 @@
|
|||
<ul class="nav nav-list">
|
||||
<?php
|
||||
switch ($menuList) {
|
||||
case 'dashboard':
|
||||
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
|
||||
'element_id' => 'dashboardIndex',
|
||||
'url' => '/dashboards',
|
||||
'text' => __('View Dashboard')
|
||||
));
|
||||
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
|
||||
'element_id' => 'dashboardAdd',
|
||||
'url' => '#',
|
||||
'text' => __('Add Widget'),
|
||||
'onClick' => array(
|
||||
'function' => 'openGenericModalPost',
|
||||
'params' => array($baseurl . '/dashboards/getForm/add')
|
||||
),
|
||||
));
|
||||
break;
|
||||
case 'event':
|
||||
$dataEventId = isset($event['Event']['id']) ? h($event['Event']['id']) : 0;
|
||||
echo '<div id="hiddenSideMenuData" class="hidden" data-event-id="' . $dataEventId . '"></div>';
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
$menu = array(
|
||||
array(
|
||||
'type' => 'root',
|
||||
'url' => $baseurl . '/',
|
||||
'url' =>empty($homepage['path']) ? '$baseurl' : $baseurl . h($homepage['path']),
|
||||
'html' => (Configure::read('MISP.home_logo') ? $logo = '<img src="' . $baseurl . '/img/custom/' . Configure::read('MISP.home_logo') . '" style="height:24px;">' : __('Home'))
|
||||
),
|
||||
array(
|
||||
|
@ -402,12 +402,17 @@
|
|||
$menu_right = array(
|
||||
array(
|
||||
'type' => 'root',
|
||||
'url' => $baseurl . '/',
|
||||
'url' => '#',
|
||||
'html' => '<span class="fas fa-star" id="setHomePage" onClick="setHomePage();" title="Set the current page as your home page in MISP"></span>'
|
||||
),
|
||||
array(
|
||||
'type' => 'root',
|
||||
'url' =>empty($homepage['path']) ? '$baseurl' : $baseurl . h($homepage['path']),
|
||||
'html' => '<span class="logoBlueStatic bold" id="smallLogo">MISP</span>'
|
||||
),
|
||||
array(
|
||||
'type' => 'root',
|
||||
'url' => '/users/dashboard',
|
||||
'url' => '/dashboards',
|
||||
'html' => sprintf(
|
||||
'<span class="white" title="%s">%s%s %s</span>',
|
||||
h($me['email']),
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<?php echo $this->Html->charset(); ?>
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<title>
|
||||
<?php echo $title_for_layout, ' - '. h(Configure::read('MISP.title_text') ? Configure::read('MISP.title_text') : 'MISP'); ?>
|
||||
</title>
|
||||
<?php
|
||||
$css_collection = array(
|
||||
'bootstrap',
|
||||
//'bootstrap4',
|
||||
'bootstrap-datepicker',
|
||||
'bootstrap-colorpicker',
|
||||
'famfamfam-flags',
|
||||
'font-awesome',
|
||||
'jquery-ui',
|
||||
'chosen.min',
|
||||
'main',
|
||||
'gridstack.min',
|
||||
array('print', array('media' => 'print'))
|
||||
);
|
||||
if (Configure::read('MISP.custom_css')) {
|
||||
$css_collection[] = preg_replace('/\.css$/i', '', Configure::read('MISP.custom_css'));
|
||||
}
|
||||
$js_collection = array(
|
||||
'jquery',
|
||||
'misp-touch',
|
||||
'jquery-ui',
|
||||
'chosen.jquery.min',
|
||||
'gridstack.all'
|
||||
);
|
||||
echo $this->element('genericElements/assetLoader', array(
|
||||
'css' => $css_collection,
|
||||
'js' => $js_collection,
|
||||
'meta' => 'icon'
|
||||
));
|
||||
?>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div id="popover_form" class="ajax_popover_form"></div>
|
||||
<div id="popover_form_large" class="ajax_popover_form ajax_popover_form_large"></div>
|
||||
<div id="popover_form_x_large" class="ajax_popover_form ajax_popover_form_x_large"></div>
|
||||
<div id="popover_matrix" class="ajax_popover_form ajax_popover_matrix"></div>
|
||||
<div id="popover_box" class="popover_box"></div>
|
||||
<div id="screenshot_box" class="screenshot_box"></div>
|
||||
<div id="confirmation_box" class="confirmation_box"></div>
|
||||
<div id="gray_out" class="gray_out"></div>
|
||||
<div id="container">
|
||||
<?php
|
||||
echo $this->element('global_menu');
|
||||
$topPadding = '50';
|
||||
if (!empty($debugMode) && $debugMode != 'debugOff') {
|
||||
$topPadding = '0';
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<div id="flashContainer" style="padding-top:<?php echo $topPadding; ?>px; !important;">
|
||||
<div id="main-view-container" class="container-fluid ">
|
||||
<?php
|
||||
echo $this->Flash->render();
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<?php
|
||||
echo $this->fetch('content');
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
echo $this->element('genericElements/assetLoader', array(
|
||||
'js' => array(
|
||||
'bootstrap',
|
||||
'bootstrap-timepicker',
|
||||
'bootstrap-datepicker',
|
||||
'bootstrap-colorpicker',
|
||||
'misp',
|
||||
'keyboard-shortcuts'
|
||||
)
|
||||
));
|
||||
echo $this->element('footer');
|
||||
echo $this->element('sql_dump');
|
||||
?>
|
||||
<div id = "ajax_success_container" class="ajax_container">
|
||||
<div id="ajax_success" class="ajax_result ajax_success"></div>
|
||||
</div>
|
||||
<div id = "ajax_fail_container" class="ajax_container">
|
||||
<div id="ajax_fail" class="ajax_result ajax_fail"></div>
|
||||
</div>
|
||||
<div class="loading">
|
||||
<div class="spinner"></div>
|
||||
<div class="loadingText"><?php echo __('Loading');?></div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
<?php
|
||||
if (!isset($debugMode)):
|
||||
?>
|
||||
$(window).scroll(function(e) {
|
||||
$('.actions').css('left',-$(window).scrollLeft());
|
||||
});
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
var tabIsActive = true;
|
||||
var baseurl = '<?php echo $baseurl; ?>';
|
||||
var here = '<?php
|
||||
if (substr($this->params['action'], 0, 6) === 'admin_') {
|
||||
echo $baseurl . '/admin/' . h($this->params['controller']) . '/' . h(substr($this->params['action'], 6));
|
||||
} else {
|
||||
echo $baseurl . '/' . h($this->params['controller']) . '/' . h($this->params['action']);
|
||||
}
|
||||
?>';
|
||||
$(document).ready(function(){
|
||||
$(window).blur(function() {
|
||||
tabIsActive = false;
|
||||
});
|
||||
$(window).focus(function() {
|
||||
tabIsActive = true;
|
||||
});
|
||||
<?php
|
||||
if (!Configure::read('MISP.disable_auto_logout') and $me):
|
||||
?>
|
||||
checkIfLoggedIn();
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
if ($('.alert').text().indexOf("$flashErrorMessage") >= 0) {
|
||||
var flashMessageLink = '<span class="useCursorPointer underline bold" onClick="flashErrorPopover();">here</span>';
|
||||
$('.alert').html(($('.alert').html().replace("$flashErrorMessage", flashMessageLink)));
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because one or more lines are too long
|
@ -2515,3 +2515,11 @@ table tr:hover .down-expand-button {
|
|||
color: white;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.widgetTitle {
|
||||
font-weight: bold;
|
||||
color: #0088cc;
|
||||
width: 100%;
|
||||
font-size: 125%;
|
||||
margin:5px;
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1185,6 +1185,22 @@ function openGenericModal(url) {
|
|||
});
|
||||
}
|
||||
|
||||
function openGenericModalPost(url, body) {
|
||||
$.ajax({
|
||||
data: body,
|
||||
type: "post",
|
||||
url: url,
|
||||
success: function (data) {
|
||||
$('#genericModal').remove();
|
||||
$('body').append(data);
|
||||
$('#genericModal').modal();
|
||||
},
|
||||
error: function (data, textStatus, errorThrown) {
|
||||
showMessage('fail', textStatus + ": " + errorThrown);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function submitPopoverForm(context_id, referer, update_context_id, modal, popover_dissmis_id_to_close) {
|
||||
var url = null;
|
||||
var context = 'event';
|
||||
|
@ -4859,3 +4875,113 @@ function queryDeprecatedEndpointUsage() {
|
|||
format: 'yyyy-mm-dd',
|
||||
});
|
||||
}());
|
||||
|
||||
function submitDashboardForm(id) {
|
||||
var configData = $('#DashboardConfig').val();
|
||||
if (configData != '') {
|
||||
configData = JSON.parse(configData);
|
||||
} else {
|
||||
configData = {};
|
||||
}
|
||||
configData = JSON.stringify(configData);
|
||||
$('#' + id).attr('config', configData);
|
||||
updateDashboardWidget($('#' + id));
|
||||
$('#genericModal').modal('hide');
|
||||
saveDashboardState();
|
||||
}
|
||||
|
||||
function submitDashboardAddWidget() {
|
||||
var widget = $('#DashboardWidget').val();
|
||||
var config = $('#DashboardConfig').val();
|
||||
var width = $('#DashboardWidth').val();
|
||||
var height = $('#DashboardHeight').val();
|
||||
var el = null;
|
||||
var k = $('#last-element-counter').data('data-element-counter');
|
||||
$.ajax({
|
||||
url: baseurl + '/dashboards/getEmptyWidget/' + widget + '/' + (k+1),
|
||||
type: 'GET',
|
||||
success: function(data) {
|
||||
el = data;
|
||||
var grid = GridStack.init();
|
||||
grid.addWidget(
|
||||
el,
|
||||
{
|
||||
"width": width,
|
||||
"height": height,
|
||||
"autoposition": 1
|
||||
}
|
||||
);
|
||||
},
|
||||
complete: function(data) {
|
||||
$('#genericModal').modal('hide');
|
||||
},
|
||||
error: function(data) {
|
||||
handleGenericAjaxResponse({'saved':false, 'errors':['Could not fetch empty widget.']});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function saveDashboardState() {
|
||||
var dashBoardSettings = [];
|
||||
$('.grid-stack-item').each(function(index) {
|
||||
if ($(this).attr('config') !== undefined && $(this).attr('widget') !== undefined) {
|
||||
var config = $(this).attr('config');
|
||||
config = JSON.parse(config);
|
||||
var temp = {
|
||||
'widget': $(this).attr('widget'),
|
||||
'config': config,
|
||||
'position': {
|
||||
'x': $(this).attr('data-gs-x'),
|
||||
'y': $(this).attr('data-gs-y'),
|
||||
'width': $(this).attr('data-gs-width'),
|
||||
'height': $(this).attr('data-gs-height')
|
||||
}
|
||||
};
|
||||
dashBoardSettings.push(temp);
|
||||
}
|
||||
});
|
||||
$.ajax({
|
||||
data: {value: dashBoardSettings},
|
||||
success:function (data, textStatus) {
|
||||
showMessage('success', 'Dashboard settings saved.');
|
||||
},
|
||||
error: function (jqXHR, textStatus, errorThrown) {
|
||||
showMessage('fail', textStatus + ": " + errorThrown);
|
||||
},
|
||||
type: "post",
|
||||
url: baseurl + '/dashboards/updateSettings',
|
||||
});
|
||||
}
|
||||
|
||||
function updateDashboardWidget(element) {
|
||||
var container = $(element).find('.widgetContent');
|
||||
var titleText = $(element).find('.widgetTitleText');
|
||||
var temp = JSON.parse($(element).attr('config'));
|
||||
if (temp['alias'] !== undefined) {
|
||||
titleText.text(temp['alias']);
|
||||
}
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: baseurl + '/dashboards/renderWidget',
|
||||
data: {
|
||||
config: $(element).attr('config'),
|
||||
widget: $(element).attr('widget')
|
||||
},
|
||||
success:function (data, textStatus) {
|
||||
container.html(data);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function setHomePage() {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: baseurl + '/userSettings/setHomePage',
|
||||
data: {
|
||||
path: window.location.pathname
|
||||
},
|
||||
success:function (data, textStatus) {
|
||||
showMessage('success', 'Homepage set.');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue