mirror of https://github.com/MISP/MISP
Merge branch '2.4' of github.com:MISP/MISP into 2.4
commit
83542716e5
|
@ -76,7 +76,11 @@ class ACLComponent extends Component
|
|||
'index' => array('*'),
|
||||
'updateSettings' => array('*'),
|
||||
'getEmptyWidget' => array('*'),
|
||||
'renderWidget' => array('*')
|
||||
'renderWidget' => array('*'),
|
||||
'listTemplates' => array('*'),
|
||||
'saveTemplate' => array('*'),
|
||||
'export' => array('*'),
|
||||
'import' => array('*')
|
||||
),
|
||||
'decayingModel' => array(
|
||||
"update" => array(),
|
||||
|
|
|
@ -16,43 +16,65 @@ class DashboardsController extends AppController
|
|||
'maxLimit' => 9999
|
||||
);
|
||||
|
||||
public function index()
|
||||
public function index($template_id = false)
|
||||
{
|
||||
$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($template_id)) {
|
||||
$params = array(
|
||||
'conditions' => array(
|
||||
'UserSetting.user_id' => $this->Auth->user('id'),
|
||||
'UserSetting.setting' => 'dashboard'
|
||||
)
|
||||
);
|
||||
$userSettings = $this->UserSetting->find('first', $params);
|
||||
} else {
|
||||
$dashboardTemplate = $this->Dashboard->getDashboardTemplate($this->Auth->user(), $template_id);
|
||||
if (empty($dashboardTemplate)) {
|
||||
throw new NotFoundException(__('Invalid dashboard template.'));
|
||||
}
|
||||
}
|
||||
if (empty($userSettings) && empty($dashboardTemplate)) {
|
||||
$dashboardTemplate = $this->Dashboard->getDashboardTemplate($this->Auth->user());
|
||||
}
|
||||
if (empty($userSettings)) {
|
||||
if (empty($dashboardTemplate)) {
|
||||
$value = array(
|
||||
array(
|
||||
'widget' => 'MispStatusWidget',
|
||||
'config' => array(
|
||||
),
|
||||
'position' => array(
|
||||
'x' => 0,
|
||||
'y' => 0,
|
||||
'width' => 2,
|
||||
'height' => 2
|
||||
)
|
||||
)
|
||||
);
|
||||
} else {
|
||||
$value = $dashboardTemplate['Dashboard']['value'];
|
||||
if (!is_array($value)) {
|
||||
$value = json_decode($value, true);
|
||||
}
|
||||
}
|
||||
$userSettings = array(
|
||||
'UserSetting' => array(
|
||||
'setting' => 'dashboard',
|
||||
'value' => array(
|
||||
array(
|
||||
'widget' => 'MispStatusWidget',
|
||||
'config' => array(
|
||||
),
|
||||
'position' => array(
|
||||
'x' => 0,
|
||||
'y' => 0,
|
||||
'width' => 2,
|
||||
'height' => 2
|
||||
)
|
||||
)
|
||||
)
|
||||
'value' => $value
|
||||
)
|
||||
);
|
||||
}
|
||||
$widgets = array();
|
||||
foreach ($userSettings['UserSetting']['value'] as $widget) {
|
||||
$dashboardWidget = $this->Dashboard->loadWidget($this->Auth->user(), $widget['widget']);
|
||||
$widget['width'] = $dashboardWidget->width;
|
||||
$widget['height'] = $dashboardWidget->height;
|
||||
$widget['title'] = $dashboardWidget->title;
|
||||
$widgets[] = $widget;
|
||||
try {
|
||||
$dashboardWidget = $this->Dashboard->loadWidget($this->Auth->user(), $widget['widget']);
|
||||
$widget['width'] = $dashboardWidget->width;
|
||||
$widget['height'] = $dashboardWidget->height;
|
||||
$widget['title'] = $dashboardWidget->title;
|
||||
$widgets[] = $widget;
|
||||
} catch (Exception $e) {
|
||||
// continue, we just don't load the widget
|
||||
}
|
||||
}
|
||||
$this->layout = 'dashboard';
|
||||
$this->set('widgets', $widgets);
|
||||
|
@ -162,4 +184,236 @@ class DashboardsController extends AppController
|
|||
throw new MethodNotAllowedException(__('This endpoint can only be reached via POST requests.'));
|
||||
}
|
||||
}
|
||||
|
||||
public function import()
|
||||
{
|
||||
if ($this->request->is('post')) {
|
||||
if (!empty($this->request->data['Dashboard'])) {
|
||||
$this->request->data = json_decode($this->request->data['Dashboard']['value'], true);
|
||||
}
|
||||
if (!empty($this->request->data['UserSetting'])) {
|
||||
$this->request->data = $this->request->data['UserSetting']['value'];
|
||||
}
|
||||
$result = $this->Dashboard->import($this->Auth->user(), $this->request->data);
|
||||
if ($this->_isRest()) {
|
||||
if ($result) {
|
||||
return $this->RestResponse->saveSuccessResponse('Dashboard', 'import', false, false, __('Settings updated.'));
|
||||
}
|
||||
return $this->RestResponse->saveFailResponse('Dashboard', 'import', false, __('Settings could not be updated.'), $this->response->type());
|
||||
} else {
|
||||
if ($result) {
|
||||
$this->Flash->success(__('Settings updated.'));
|
||||
} else {
|
||||
$this->Flash->error(__('Settings could not be updated.'));
|
||||
}
|
||||
$this->redirect($this->baseurl . '/dashboards');
|
||||
}
|
||||
}
|
||||
$this->layout = false;
|
||||
}
|
||||
|
||||
public function export()
|
||||
{
|
||||
$data = $this->Dashboard->export($this->Auth->user());
|
||||
if ($this->_isRest()) {
|
||||
return $this->RestResponse->viewData($data, $this->response->type());
|
||||
} else {
|
||||
$this->set('data', $data);
|
||||
$this->layout = false;
|
||||
}
|
||||
}
|
||||
|
||||
public function saveTemplate($update = false)
|
||||
{
|
||||
if (!empty($update)) {
|
||||
$conditions = array('Dashboard.id' => $update);
|
||||
if (Validation::uuid($update)) {
|
||||
$conditions = array('Dashboard.uuid' => $update);
|
||||
}
|
||||
$existingDashboard = $this->Dashboard->find('first', array(
|
||||
'recursive' => -1,
|
||||
'conditions' => $conditions
|
||||
));
|
||||
if (
|
||||
empty($existingDashboard) ||
|
||||
(!$this->_isSiteAdmin() && $existingDashboard['Dashboard']['user_id'] != $this->Auth->user('id'))
|
||||
) {
|
||||
throw new NotFoundException(__('Invalid dashboard template.'));
|
||||
}
|
||||
}
|
||||
if ($this->request->is('post') || $this->request->is('put')) {
|
||||
if (isset($this->request->data['Dashboard'])) {
|
||||
$this->request->data = $this->request->data['Dashboard'];
|
||||
}
|
||||
$data = $this->request->data;
|
||||
$data['value'] = $this->UserSetting->getSetting($this->Auth->user('id'), 'dashboard');
|
||||
$result = $this->Dashboard->saveDashboardTemplate($this->Auth->user(), $data, $update);
|
||||
if ($this->_isRest()) {
|
||||
if ($result) {
|
||||
return $this->RestResponse->saveSuccessResponse('Dashboard', 'saveDashboardTemplate', false, false, __('Dashboard template updated.'));
|
||||
}
|
||||
return $this->RestResponse->saveFailResponse('Dashboard', 'import', false, __('Dashboard template could not be updated.'), $this->response->type());
|
||||
} else {
|
||||
if ($result) {
|
||||
$this->Flash->success(__('Dashboard template updated.'));
|
||||
} else {
|
||||
$this->Flash->error(__('Dashboard template could not be updated.'));
|
||||
}
|
||||
$this->redirect($this->baseurl . '/dashboards/listTemplates');
|
||||
}
|
||||
} else {
|
||||
$this->layout = false;
|
||||
}
|
||||
$this->loadModel('User');
|
||||
$permFlags = array(0 => __('Unrestricted'));
|
||||
foreach ($this->User->Role->permFlags as $perm_flag => $perm_data) {
|
||||
$permFlags[$perm_flag] = $perm_data['text'];
|
||||
}
|
||||
$options = array(
|
||||
'org_id' => array_merge(
|
||||
array(
|
||||
0 => __('Unrestricted')
|
||||
),
|
||||
$this->User->Organisation->find('list', array(
|
||||
'fields' => array(
|
||||
'Organisation.id', 'Organisation.name'
|
||||
),
|
||||
'conditions' => array('Organisation.local' => 1)
|
||||
))
|
||||
),
|
||||
'role_id' => array_merge(
|
||||
array(
|
||||
0 => __('Unrestricted')
|
||||
),
|
||||
$this->User->Role->find('list', array(
|
||||
'fields' => array(
|
||||
'Role.id', 'Role.name'
|
||||
)
|
||||
))
|
||||
),
|
||||
'role_perms' => $permFlags
|
||||
);
|
||||
if (!empty($update)) {
|
||||
$this->request->data = $existingDashboard;
|
||||
}
|
||||
$this->set('options', $options);
|
||||
}
|
||||
|
||||
public function listTemplates()
|
||||
{
|
||||
$conditions = array();
|
||||
if (!$this->_isSiteAdmin()) {
|
||||
$permission_flags = array();
|
||||
foreach ($this->Auth->user('Role') as $perm => $value) {
|
||||
if (strpos($perm, 'perm_') !== false && !empty($value)) {
|
||||
$permission_flags[] = $perm;
|
||||
}
|
||||
}
|
||||
$conditions['AND'] = array(
|
||||
array(
|
||||
'OR' => array(
|
||||
'Dashboard.user_id' => $this->Auth->user('id'),
|
||||
'AND' => array(
|
||||
'Dashboard.selectable' => 1,
|
||||
array(
|
||||
'OR' => array(
|
||||
array('Dashboard.restrict_to_org_id' => $this->Auth->user('org_id')),
|
||||
array('Dashboard.restrict_to_org_id' => 0)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'OR' => array(
|
||||
array('Dashboard.restrict_to_role_id' => $this->Auth->user('role_id')),
|
||||
array('Dashboard.restrict_to_role_id' => 0)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'OR' => array(
|
||||
array('Dashboard.restrict_to_permission_flag' => $permission_flags),
|
||||
array('Dashboard.restrict_to_permission_flag' => 0)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
if (!empty($this->passedArgs['value'])) {
|
||||
$conditions['AND'][] = array(
|
||||
'OR' => array(
|
||||
'LOWER(Dashboard.name) LIKE' => '%' . strtolower(trim($this->passedArgs['value'])) . '%',
|
||||
'LOWER(Dashboard.description) LIKE' => '%' . strtolower(trim($this->passedArgs['value'])) . '%',
|
||||
'LOWER(Dashboard.uuid) LIKE' => strtolower(trim($this->passedArgs['value']))
|
||||
)
|
||||
);
|
||||
}
|
||||
$this->paginate['conditions'] = $conditions;
|
||||
if ($this->_isRest()) {
|
||||
$params = array(
|
||||
'conditions' => $conditions,
|
||||
'recursive' => -1
|
||||
);
|
||||
$paramsToPass = array('limit', 'page');
|
||||
foreach ($paramsToPass as $p) {
|
||||
if (!empty($this->passedArgs[$p])) {
|
||||
$params[$p] = $this->passedArgs[$p];
|
||||
}
|
||||
}
|
||||
$data = $this->Dashboard->find('all', $params);
|
||||
foreach ($data as &$element) {
|
||||
$element['Dashboard']['value'] = json_decode($element['Dashboard']['value'], true);
|
||||
}
|
||||
return $this->RestResponse->viewData(
|
||||
$data,
|
||||
$this->response->type()
|
||||
);
|
||||
} else {
|
||||
$this->paginate['contain'] = array(
|
||||
'User.id', 'User.email'
|
||||
);
|
||||
$data = $this->paginate();
|
||||
foreach ($data as &$element) {
|
||||
$element['Dashboard']['value'] = json_decode($element['Dashboard']['value'], true);
|
||||
$widgets = array();
|
||||
foreach ($element['Dashboard']['value'] as $val) {
|
||||
$widgets[$val['widget']] = 1;
|
||||
}
|
||||
$element['Dashboard']['widgets'] = array_keys($widgets);
|
||||
sort($element['Dashboard']['widgets']);
|
||||
if ($element['Dashboard']['user_id'] != $this->Auth->user('id')) {
|
||||
$element['User']['email'] = '';
|
||||
}
|
||||
}
|
||||
$this->set('passedArgs', $this->passedArgs);
|
||||
$this->set('data', $data);
|
||||
}
|
||||
}
|
||||
|
||||
public function deleteTemplate($id)
|
||||
{
|
||||
$conditions = array();
|
||||
if (Validation::uuid($id)) {
|
||||
$conditions['AND'][] = array('Dashboard.uuid' => $id);
|
||||
} else {
|
||||
$conditions['AND'][] = array('Dashboard.id' => $id);
|
||||
}
|
||||
if (!$this->_isSiteAdmin()) {
|
||||
$conditions['AND'][] = array('Dashboard.user_id' => $this->Auth->user('id'));
|
||||
}
|
||||
$dashboard = $this->Dashboard->find('first', array(
|
||||
'conditions' => $conditions,
|
||||
'recursive' => -1
|
||||
));
|
||||
if (empty($dashboard)) {
|
||||
throw new NotFoundException(__('Invalid dashboard template.'));
|
||||
}
|
||||
$this->Dashboard->delete($dashboard['Dashboard']['id']);
|
||||
$message = __('Dashboard template removed.');
|
||||
if ($this->_isRest()) {
|
||||
return $this->RestResponse->saveSuccessResponse('Dashboard', 'delete', $id, false, $message);
|
||||
} else {
|
||||
$this->Flash->success($message);
|
||||
$this->redirect($this->baseurl . '/dashboards/listTemplates');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
class WhoamiWidget
|
||||
{
|
||||
public $title = 'Whoami';
|
||||
public $render = 'SimpleList';
|
||||
public $width = 2;
|
||||
public $height = 2;
|
||||
public $params = array();
|
||||
public $description = 'Shows information about the currently logged in user.';
|
||||
public $cacheLifetime = false;
|
||||
public $autoRefreshDelay = 3;
|
||||
|
||||
public function handler($user, $options = array())
|
||||
{
|
||||
$this->Log = ClassRegistry::init('Log');
|
||||
$entries = $this->Log->find('all', array(
|
||||
'recursive' => -1,
|
||||
'conditions' => array('action' => 'login', 'user_id' => $user['id']),
|
||||
'order' => 'id desc',
|
||||
'limit' => 5,
|
||||
'fields' => array('created', 'ip')
|
||||
));
|
||||
foreach ($entries as &$entry) {
|
||||
$entry = $entry['Log']['created'] . ' --- ' . (empty($entry['Log']['ip']) ? 'IP not logged' : $entry['Log']['ip']);
|
||||
}
|
||||
return array(
|
||||
array('title' => 'Email', 'value' => $user['email']),
|
||||
array('title' => 'Role', 'value' => $user['Role']['name']),
|
||||
array('title' => 'Organisation', 'value' => $user['Organisation']['name']),
|
||||
array('title' => 'IP', 'value' => empty($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['REMOTE_ADDR'] : $_SERVER['HTTP_X_FORWARDED_FOR']),
|
||||
array('title' => 'Last logins', 'value' => $entries)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -77,7 +77,7 @@ class AppModel extends Model
|
|||
27 => false, 28 => false, 29 => false, 30 => false, 31 => false, 32 => false,
|
||||
33 => false, 34 => false, 35 => false, 36 => false, 37 => false, 38 => false,
|
||||
39 => false, 40 => false, 41 => false, 42 => false, 43 => false, 44 => false,
|
||||
45 => false, 46 => false, 47 => false, 48 => false
|
||||
45 => false, 46 => false, 47 => false, 48 => false, 49 => false
|
||||
);
|
||||
|
||||
public $advanced_updates_description = array(
|
||||
|
@ -1327,6 +1327,28 @@ class AppModel extends Model
|
|||
$this->__addIndex('taxonomy_predicates', 'numerical_value');
|
||||
$this->__addIndex('taxonomy_entries', 'numerical_value');
|
||||
break;
|
||||
case 49:
|
||||
$sqlArray[] = "CREATE TABLE IF NOT EXISTS dashboards (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`uuid` varchar(40) COLLATE utf8_bin NOT NULL,
|
||||
`name` varchar(191) NOT NULL,
|
||||
`description` text,
|
||||
`default` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`selectable` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`user_id` int(11) NOT NULL DEFAULT 0,
|
||||
`restrict_to_org_id` int(11) NOT NULL DEFAULT 0,
|
||||
`restrict_to_role_id` int(11) NOT NULL DEFAULT 0,
|
||||
`restrict_to_permission_flag` varchar(191) NOT NULL DEFAULT '',
|
||||
`value` text,
|
||||
`timestamp` int(11) NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
INDEX `name` (`name`),
|
||||
INDEX `uuid` (`uuid`),
|
||||
INDEX `user_id` (`user_id`),
|
||||
INDEX `restrict_to_org_id` (`restrict_to_org_id`),
|
||||
INDEX `restrict_to_permission_flag` (`restrict_to_permission_flag`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;";
|
||||
break;
|
||||
case 'fixNonEmptySharingGroupID':
|
||||
$sqlArray[] = 'UPDATE `events` SET `sharing_group_id` = 0 WHERE `distribution` != 4;';
|
||||
$sqlArray[] = 'UPDATE `attributes` SET `sharing_group_id` = 0 WHERE `distribution` != 4;';
|
||||
|
|
|
@ -2,9 +2,34 @@
|
|||
App::uses('AppModel', 'Model');
|
||||
class Dashboard extends AppModel
|
||||
{
|
||||
public $useTable = false;
|
||||
public $recursive = -1;
|
||||
|
||||
public function loadWidget($user, $name)
|
||||
public $actsAs = array(
|
||||
'Containable',
|
||||
);
|
||||
|
||||
public $validate = array(
|
||||
'user_id' => 'numeric',
|
||||
'org_id' => 'numeric',
|
||||
'role_id' => 'numeric',
|
||||
'uuid' => array(
|
||||
'uuid' => array(
|
||||
'rule' => array('custom', '/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$/'),
|
||||
'message' => 'Please provide a valid UUID'
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
public $belongsTo = array(
|
||||
'User',
|
||||
'Role',
|
||||
'Organisation' => array(
|
||||
'className' => 'Organisation',
|
||||
'foreignKey' => 'org_id'
|
||||
)
|
||||
);
|
||||
|
||||
public function loadWidget($user, $name, $returnOnException = false)
|
||||
{
|
||||
$name = str_replace('/', '', $name);
|
||||
if (file_exists(APP . 'Lib/Dashboard/' . $name . '.php')) {
|
||||
|
@ -24,12 +49,18 @@ class Dashboard extends AppModel
|
|||
}
|
||||
}
|
||||
if (!$found) {
|
||||
if ($returnOnException) {
|
||||
return false;
|
||||
}
|
||||
throw new NotFoundException(__('Invalid widget or widget not found.'));
|
||||
}
|
||||
}
|
||||
$widget = new $name();
|
||||
if (method_exists($widget, 'checkPermissions')) {
|
||||
if (!$widget->checkPermissions($user)) {
|
||||
if ($returnOnException) {
|
||||
return false;
|
||||
}
|
||||
throw new NotFoundException(__('Invalid widget or widget not found.'));
|
||||
}
|
||||
}
|
||||
|
@ -85,4 +116,167 @@ class Dashboard extends AppModel
|
|||
);
|
||||
return $widget;
|
||||
}
|
||||
|
||||
public function import($user, $value, $targetUser = false)
|
||||
{
|
||||
$this->User = ClassRegistry::init('User');
|
||||
if (empty($targetUser)) {
|
||||
$targetUser = $user;
|
||||
} else if (!is_array($targetUser)) {
|
||||
$targetUser = $this->User->getAuthUser($targetUser);
|
||||
}
|
||||
if (empty($targetUser)) {
|
||||
throw new NotFoundException(__('Invalid user.'));
|
||||
}
|
||||
$settingsToSave = array();
|
||||
foreach ($value as $widgetConfig) {
|
||||
$widget = $this->loadWidget($targetUser, $widgetConfig['widget'], true);
|
||||
if (!empty($widget)) {
|
||||
$settingsToSave[] = $widgetConfig;
|
||||
}
|
||||
}
|
||||
$data = array(
|
||||
'UserSetting' => array(
|
||||
'user_id' => $targetUser['id'],
|
||||
'setting' => 'dashboard',
|
||||
'value' => $settingsToSave
|
||||
)
|
||||
);
|
||||
return $this->User->UserSetting->setSetting($user, $data);
|
||||
}
|
||||
|
||||
public function export($user)
|
||||
{
|
||||
$this->User = ClassRegistry::init('User');
|
||||
$data = $this->User->UserSetting->find('first', array(
|
||||
'recursive' => -1,
|
||||
'conditions' => array(
|
||||
'UserSetting.user_id' => $user['id'],
|
||||
'UserSetting.setting' => 'dashboard'
|
||||
)
|
||||
));
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function getDashboardTemplate($user, $dashboard_id = false)
|
||||
{
|
||||
if (empty($dashboard_id)) {
|
||||
$conditions = array(
|
||||
'Dashboard.default' => 1
|
||||
);
|
||||
} else {
|
||||
if (Validation::uuid($dashboard_id)) {
|
||||
$conditions = array(
|
||||
'Dashboard.uuid' => $dashboard_id
|
||||
);
|
||||
} else {
|
||||
$conditions = array(
|
||||
'Dashboard.id' => $dashboard_id
|
||||
);
|
||||
}
|
||||
}
|
||||
$template = $this->find('first', array(
|
||||
'recursive' => -1,
|
||||
'conditions' => $conditions
|
||||
));
|
||||
if (empty($template)) {
|
||||
return array();
|
||||
}
|
||||
if (empty($user['Role']['perm_site_admin'])) {
|
||||
if (
|
||||
$template['Dashboard']['user_id'] != $user['id'] &&
|
||||
(
|
||||
empty($template['Dashboard']['selectable']) ||
|
||||
(
|
||||
!empty($template['Dashboard']['restrict_to_org_id']) &&
|
||||
$template['Dashboard']['restrict_to_org_id'] != $user['org_id']
|
||||
) ||
|
||||
(
|
||||
!empty($template['Dashboard']['restrict_to_role_id']) &&
|
||||
$template['Dashboard']['restrict_to_role_id'] != $user['role_id']
|
||||
) ||
|
||||
(
|
||||
!empty($template['Dashboard']['restrict_to_permission_flag']) &&
|
||||
empty($user['role'][$template['Dashboard']['restrict_to_permission_flag']])
|
||||
)
|
||||
)
|
||||
) {
|
||||
return array();
|
||||
}
|
||||
}
|
||||
return $template;
|
||||
}
|
||||
|
||||
public function saveDashboardTemplate($user, $settings, $update = false)
|
||||
{
|
||||
$this->User = ClassRegistry::init('User');
|
||||
$data = $this->User->UserSetting->find('first', array(
|
||||
'recursive' => -1,
|
||||
'conditions' => array(
|
||||
'UserSetting.user_id' => $user['id'],
|
||||
'UserSetting.setting' => 'dashboard'
|
||||
)
|
||||
));
|
||||
$editableFields = array(
|
||||
'name',
|
||||
'description',
|
||||
'selectable',
|
||||
'value'
|
||||
);
|
||||
if ($user['Role']['perm_site_admin']) {
|
||||
$editableFields = array_merge(
|
||||
$editableFields,
|
||||
array(
|
||||
'default',
|
||||
'restrict_to_role_id',
|
||||
'restrict_to_permission_flag',
|
||||
'restrict_to_org_id'
|
||||
)
|
||||
);
|
||||
}
|
||||
if ($update) {
|
||||
$existingDashboard = $this->getDashboardTemplate($user, $update);
|
||||
if (empty($existingDashboard)) {
|
||||
throw new NotFoundException(__('Invalid dashboard template.'));
|
||||
}
|
||||
$data = $existingDashboard['Dashboard'];
|
||||
} else {
|
||||
$this->create();
|
||||
$data = array(
|
||||
'user_id' => $user['id'],
|
||||
'uuid' => CakeText::uuid()
|
||||
);
|
||||
if (empty($user['role']['perm_site_admin'])) {
|
||||
$data['restrict_to_org_id'] = $user['org_id'];
|
||||
}
|
||||
}
|
||||
foreach ($editableFields as $editable) {
|
||||
if (isset($settings[$editable])) {
|
||||
$data[$editable] = $settings[$editable];
|
||||
}
|
||||
}
|
||||
$data['timestamp'] = time();
|
||||
if (is_array($data['value'])) {
|
||||
$data['value'] = json_encode($data['value']);
|
||||
}
|
||||
if (!empty($data['default'])) {
|
||||
$this->__unsetPreviousDefault();
|
||||
}
|
||||
return $this->save(array('Dashboard' => $data));
|
||||
}
|
||||
|
||||
private function __unsetPreviousDefault()
|
||||
{
|
||||
$currentDefault = $this->find('first', array(
|
||||
'recursive' => -1,
|
||||
'conditions' => array(
|
||||
'Dashboard.default' => 1
|
||||
)
|
||||
));
|
||||
if (!empty($currentDefault)) {
|
||||
$currentDefault['Dashboard']['default'] = 0;
|
||||
$this->save($currentDefault);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -349,4 +349,19 @@ class UserSetting extends AppModel
|
|||
$result = $this->save(array('UserSetting' => $userSetting));
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getSetting($user_id, $setting)
|
||||
{
|
||||
$setting = $this->find('first', array(
|
||||
'recursive' => -1,
|
||||
'conditions' => array(
|
||||
'UserSetting.user_id' => $user_id,
|
||||
'UserSetting.setting' => $setting
|
||||
)
|
||||
));
|
||||
if (empty($setting)) {
|
||||
return array();
|
||||
}
|
||||
return $setting['UserSetting']['value'];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
$data = array(
|
||||
'title' => __('Export Dashboard Settings'),
|
||||
'content' => array(
|
||||
array(
|
||||
'paragraph' => __('Simply copy and share your dashboard settings below. Make sure that you sanitise it so that you do not share anything sensitive. Simply click on the JSON below to select it.')
|
||||
),
|
||||
array(
|
||||
'title' => __('Dashboard settings'),
|
||||
'code' => json_encode($data, JSON_PRETTY_PRINT)
|
||||
)
|
||||
)
|
||||
);
|
||||
echo $this->element('genericElements/infoModal', array('data' => $data));
|
||||
?>
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
echo $this->element('genericElements/Form/genericForm', array(
|
||||
'form' => $this->Form,
|
||||
'url' => 'updateSettings',
|
||||
'data' => array(
|
||||
'title' => __('Import Dashboard Configuration'),
|
||||
'model' => 'Dashboard',
|
||||
'fields' => array(
|
||||
array(
|
||||
'field'=> 'value',
|
||||
'type' => 'textarea',
|
||||
'class' => 'input span6',
|
||||
'div' => 'input clear',
|
||||
'label' => __('Config'),
|
||||
'default' => empty($data['config']) ? '' : json_encode($data['config'], JSON_PRETTY_PRINT)
|
||||
)
|
||||
),
|
||||
'submit' => array(
|
||||
'action' => 'import',
|
||||
'ajaxSubmit' => "$('#DashboardImportForm').submit();"
|
||||
),
|
||||
'description' => __('Import a configuration JSON as exported from another MISP instance.')
|
||||
)
|
||||
));
|
||||
?>
|
|
@ -0,0 +1,107 @@
|
|||
<?php
|
||||
echo '<div class="index">';
|
||||
echo $this->element('/genericElements/IndexTable/index_table', array(
|
||||
'data' => array(
|
||||
'data' => $data,
|
||||
'top_bar' => array(
|
||||
'children' => array(
|
||||
array(
|
||||
'type' => 'search',
|
||||
'button' => __('Filter'),
|
||||
'placeholder' => __('Enter value to search'),
|
||||
'data' => '',
|
||||
'searchKey' => 'value'
|
||||
)
|
||||
)
|
||||
),
|
||||
'fields' => array(
|
||||
array(
|
||||
'name' => __('Id'),
|
||||
'sort' => 'id',
|
||||
'class' => 'short',
|
||||
'data_path' => 'Dashboard.id',
|
||||
),
|
||||
array(
|
||||
'name' => __('UUID'),
|
||||
'sort' => 'uuid',
|
||||
'class' => 'short',
|
||||
'data_path' => 'Dashboard.uuid',
|
||||
),
|
||||
array(
|
||||
'name' => __('Owner'),
|
||||
'sort' => 'User.email',
|
||||
'class' => 'short',
|
||||
'data_path' => 'User.email',
|
||||
),
|
||||
array(
|
||||
'name' => __('Name'),
|
||||
'sort' => 'name',
|
||||
'class' => 'short',
|
||||
'data_path' => 'Dashboard.name',
|
||||
),
|
||||
array(
|
||||
'name' => __('Description'),
|
||||
'data_path' => 'Dashboard.description',
|
||||
),
|
||||
array(
|
||||
'name' => __('Widgets Used'),
|
||||
'data_path' => 'Dashboard.widgets',
|
||||
'element' => 'list'
|
||||
),
|
||||
array(
|
||||
'name' => __('Selectable'),
|
||||
'element' => 'boolean',
|
||||
'class' => 'short',
|
||||
'data_path' => 'Dashboard.selectable',
|
||||
),
|
||||
array(
|
||||
'name' => __('Default'),
|
||||
'element' => 'boolean',
|
||||
'class' => 'short',
|
||||
'data_path' => 'Dashboard.default',
|
||||
)
|
||||
),
|
||||
'title' => __('Dashboard Templates Index'),
|
||||
'description' => __('Users can create and save dashboard templates. Additionally, administrators can create selectable templates for the community and select a default to be used by new users.'),
|
||||
'actions' => array(
|
||||
array(
|
||||
'url' => '/dashboards/index',
|
||||
'url_params_data_paths' => array(
|
||||
'Dashboard.uuid'
|
||||
),
|
||||
'title' => 'Load and set template',
|
||||
'icon' => 'eye'
|
||||
),
|
||||
array(
|
||||
'onclick' => 'openGenericModal(\'' . $baseurl . '/dashboards/saveTemplate/[onclick_params_data_path]\');',
|
||||
'onclick_params_data_path' => 'Dashboard.uuid',
|
||||
'icon' => 'edit'
|
||||
),
|
||||
array(
|
||||
'url' => '/dashboards/deleteTemplate',
|
||||
'url_params_data_paths' => array(
|
||||
'Dashboard.uuid'
|
||||
),
|
||||
'postLink' => 1,
|
||||
'postLinkConfirm' => __('Are you sure you want to remove this dashboard template?'),
|
||||
'icon' => 'trash'
|
||||
)
|
||||
)
|
||||
)
|
||||
));
|
||||
echo '</div>';
|
||||
echo $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'dashboard', 'menuItem' => 'dashboardTemplateIndex'));
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
var passedArgsArray = <?php echo json_encode($passedArgs); ?>;
|
||||
$(document).ready(function() {
|
||||
$('#quickFilterButton').click(function() {
|
||||
runIndexQuickFilter();
|
||||
});
|
||||
$('#quickFilterField').on('keypress', function (e) {
|
||||
if(e.which === 13) {
|
||||
runIndexQuickFilter();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
echo $this->element('genericElements/Form/genericForm', array(
|
||||
'form' => $this->Form,
|
||||
'url' => 'saveDashboardTemplate',
|
||||
'data' => array(
|
||||
'title' => __('Save Dashboard Template'),
|
||||
'model' => 'Dashboard',
|
||||
'fields' => array(
|
||||
array(
|
||||
'field'=> 'name',
|
||||
'type' => 'text',
|
||||
'class' => 'input span6',
|
||||
'div' => 'input clear',
|
||||
'label' => __('Template Name')
|
||||
),
|
||||
array(
|
||||
'field'=> 'description',
|
||||
'type' => 'textarea',
|
||||
'class' => 'input span6',
|
||||
'div' => 'input clear',
|
||||
'label' => __('Description')
|
||||
),
|
||||
array(
|
||||
'field' => 'restrict_to_org_id',
|
||||
'options' => $options['org_id'],
|
||||
'class' => 'input span6',
|
||||
'div' => 'input clear',
|
||||
'label' => __('Restrict to organisation'),
|
||||
'requirements' => $isSiteAdmin
|
||||
),
|
||||
array(
|
||||
'field' => 'restrict_to_role_id',
|
||||
'options' => $options['role_id'],
|
||||
'class' => 'input span6',
|
||||
'div' => 'input clear',
|
||||
'label' => __('Restrict to role'),
|
||||
'requirements' => $isSiteAdmin
|
||||
),
|
||||
array(
|
||||
'field' => 'restrict_to_permission_flag',
|
||||
'options' => $options['role_perms'],
|
||||
'class' => 'input span6',
|
||||
'div' => 'input clear',
|
||||
'label' => __('Restrict to role permission flag'),
|
||||
'requirements' => $isSiteAdmin
|
||||
),
|
||||
array(
|
||||
'field' => 'selectable',
|
||||
'type' => 'checkbox',
|
||||
'class' => 'input',
|
||||
'div' => 'input',
|
||||
'label' => __('Selectable')
|
||||
),
|
||||
array(
|
||||
'field' => 'default',
|
||||
'type' => 'checkbox',
|
||||
'class' => 'input',
|
||||
'div' => 'input',
|
||||
'label' => __('Default'),
|
||||
'requirements' => $isSiteAdmin
|
||||
),
|
||||
),
|
||||
'submit' => array(
|
||||
'action' => 'import',
|
||||
'ajaxSubmit' => "$('#DashboardSaveTemplateForm').submit();"
|
||||
),
|
||||
'description' => __('Save your current dashboard state as a template for others to reuse.')
|
||||
)
|
||||
));
|
||||
?>
|
|
@ -32,14 +32,14 @@
|
|||
});
|
||||
var container_<?= $randomNumber ?> = $('#world-map-<?= $randomNumber ?>').parent().parent();
|
||||
|
||||
function resizeDashboardWorldMap() {
|
||||
var width = container_<?= $randomNumber ?>.width();
|
||||
var height = container_<?= $randomNumber ?>.height() - 60;
|
||||
$('#world-map-<?= $randomNumber ?>').css('width', width + 'px');
|
||||
$('#world-map-<?= $randomNumber ?>').css('height', height + 'px');
|
||||
$('#world-map-<?= $randomNumber ?>').vectorMap('get','mapObject').updateSize();
|
||||
function resizeDashboardWorldMap(id) {
|
||||
var width = eval('container_' + id + '.width()');
|
||||
var height = eval('container_' + id + '.height() - 60');
|
||||
$('#world-map-' + id).css('width', width + 'px');
|
||||
$('#world-map-' + id).css('height', height + 'px');
|
||||
$('#world-map-' + id).vectorMap('get','mapObject').updateSize();
|
||||
}
|
||||
$(document).ready(function() {
|
||||
resizeDashboardWorldMap();
|
||||
resizeDashboardWorldMap(<?= $randomNumber ?>);
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
* - model: The model used to create the form (such as Attribute, Event)
|
||||
* - fields: an array with each element generating an input field
|
||||
* - field is the actual field name (such as org_id, name, etc) which is required
|
||||
* - optional fields: default, type, options, placeholder, label - these are passed directly to $this->Form->input()
|
||||
* - optional fields: default, type, options, placeholder, label - these are passed directly to $this->Form->input(),
|
||||
* - requirements: boolean, if false is passed the field is skipped
|
||||
* - metafields: fields that are outside of the scope of the form itself
|
||||
- use these to define dynamic form fields, or anything that will feed into the regular fields via JS population
|
||||
* - submit: The submit button itself. By default it will simply submit to the form as defined via the 'model' field
|
||||
|
@ -22,6 +23,9 @@
|
|||
$formCreate = $this->Form->create($modelForForm);
|
||||
if (!empty($data['fields'])) {
|
||||
foreach ($data['fields'] as $fieldData) {
|
||||
if (isset($fieldData['requirements']) && !$fieldData['requirements']) {
|
||||
continue;
|
||||
}
|
||||
if (is_array($fieldData)) {
|
||||
if (empty($fieldData['label'])) {
|
||||
$fieldData['label'] = Inflector::humanize($fieldData['field']);
|
||||
|
|
|
@ -8,7 +8,9 @@
|
|||
* - title: title of the action. Automatically generates aria labels too
|
||||
* - postLink: convert the button into a POST request
|
||||
* - postLinkConfirm: As the user to confirm the POST before submission with the given message
|
||||
* - onClick: custom onClick action instead of a simple GET/POST request
|
||||
* - onclick: custom onclick action instead of a simple GET/POST request
|
||||
* - onclick_params_data_path: pass a data path param to the onclick field. requires [onclick_params_data_path] in the onclick field
|
||||
* as a needle for replacement
|
||||
* - icon: FA icon (added using the helper, knowing the fa domain is not needed, just add the short name such as "edit")
|
||||
* - requirement evaluates to true/false
|
||||
* - complex_requirement - add complex requirements via lambda functions:
|
||||
|
@ -55,12 +57,20 @@
|
|||
empty($action['postLinkConfirm'])? '' : $action['postLinkConfirm']
|
||||
);
|
||||
} else {
|
||||
if (!empty($action['onclick']) && !empty($action['onclick_params_data_path'])) {
|
||||
$action['onclick'] = str_replace(
|
||||
'[onclick_params_data_path]',
|
||||
h(Hash::extract($row, $action['onclick_params_data_path'])[0]),
|
||||
$action['onclick']
|
||||
);
|
||||
|
||||
}
|
||||
echo sprintf(
|
||||
'<a href="%s" title="%s" aria-label="%s" %s><i class="black %s"></i></a> ',
|
||||
$url,
|
||||
empty($action['title']) ? '' : h($action['title']),
|
||||
empty($action['title']) ? '' : h($action['title']),
|
||||
empty($action['onclick']) ? '' : sprintf('onclick="%s"', $action['onclick']),
|
||||
empty($action['onclick']) ? '' : sprintf('onClick="%s"', $action['onclick']),
|
||||
$this->FontAwesome->getClass($action['icon'])
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
$data = Hash::extract($row, $field['data_path']);
|
||||
foreach ($data as &$element) {
|
||||
$element = h($element);
|
||||
}
|
||||
$data = implode('<br />', $data);
|
||||
echo $data;
|
||||
?>
|
|
@ -10,7 +10,8 @@
|
|||
'field' => $field,
|
||||
'row' => $row,
|
||||
'column' => $column,
|
||||
'data_path' => empty($field['data_path']) ? '' : $field['data_path'], 'k' => $k
|
||||
'data_path' => empty($field['data_path']) ? '' : $field['data_path'],
|
||||
'k' => $k
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -17,6 +17,38 @@
|
|||
'params' => array($baseurl . '/dashboards/getForm/add')
|
||||
),
|
||||
));
|
||||
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
|
||||
'element_id' => 'dashboardImport',
|
||||
'url' => '#',
|
||||
'text' => __('Import Config JSON'),
|
||||
'onClick' => array(
|
||||
'function' => 'openGenericModal',
|
||||
'params' => array($baseurl . '/dashboards/import')
|
||||
),
|
||||
));
|
||||
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
|
||||
'element_id' => 'dashboardExport',
|
||||
'url' => '#',
|
||||
'text' => __('Export Config JSON'),
|
||||
'onClick' => array(
|
||||
'function' => 'openGenericModal',
|
||||
'params' => array($baseurl . '/dashboards/export')
|
||||
),
|
||||
));
|
||||
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
|
||||
'element_id' => 'dashboardSave',
|
||||
'url' => '#',
|
||||
'text' => __('Save Dashboard Config'),
|
||||
'onClick' => array(
|
||||
'function' => 'openGenericModal',
|
||||
'params' => array($baseurl . '/dashboards/saveTemplate')
|
||||
),
|
||||
));
|
||||
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
|
||||
'element_id' => 'dashboardTemplateIndex',
|
||||
'url' => '/dashboards/listTemplates',
|
||||
'text' => __('List Dashboard Templates')
|
||||
));
|
||||
break;
|
||||
case 'event':
|
||||
$dataEventId = isset($event['Event']['id']) ? h($event['Event']['id']) : 0;
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
/*
|
||||
* Generic modal builder
|
||||
*
|
||||
* Simply pass a JSON with the following keys set:
|
||||
* - title: A title for the modal
|
||||
* - content: array of ordered content elements
|
||||
* - title: A label for a content element (optional)
|
||||
* - paragraph: Text to be displayed (optional)
|
||||
* - html: HTML to be displayed directly (optional)
|
||||
* - code: Code snipet to be displayed - copy pastable (optional)
|
||||
*/
|
||||
$contents = '';
|
||||
foreach ($data['content'] as $content) {
|
||||
$contents .= sprintf(
|
||||
'%s%s%s%s',
|
||||
empty($content['title']) ? '' : sprintf('<h4>%s</h4>', h($content['title'])),
|
||||
empty($content['paragraph']) ? '' : sprintf('<p>%s</p>', h($content['paragraph'])),
|
||||
empty($content['html']) ? '' : sprintf('<div class="modalContentHtmlDiv">%s</div>', $content['html']),
|
||||
empty($content['code']) ? '' : sprintf('<pre class="quickSelect" onClick="quickSelect(this);">%s</pre>', h($content['code']))
|
||||
);
|
||||
}
|
||||
$action = $this->request->params['action'];
|
||||
$controller = $this->request->params['controller'];
|
||||
echo sprintf(
|
||||
'<div id="genericModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="genericModalLabel" aria-hidden="true">%s%s%s</div>',
|
||||
sprintf(
|
||||
'<div class="modal-header"><button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button><h3 id="genericModalLabel">%s</h3></div>',
|
||||
empty($data['title']) ?
|
||||
h(Inflector::humanize($action)) . ' ' . h(Inflector::singularize(Inflector::humanize($controller))) :
|
||||
h($data['title'])
|
||||
),
|
||||
sprintf(
|
||||
'<div class="modal-body modal-body-long">%s</div>',
|
||||
$contents
|
||||
),
|
||||
sprintf(
|
||||
'<div class="modal-footer"><button class="btn" data-dismiss="modal" aria-hidden="true" onClick="%s">%s</button></div>',
|
||||
'cancelPopoverForm();',
|
||||
__('Cancel')
|
||||
)
|
||||
);
|
||||
?>
|
|
@ -4459,6 +4459,14 @@ function checkNoticeList(type) {
|
|||
|
||||
}
|
||||
|
||||
function quickSelect(target) {
|
||||
var range = document.createRange();
|
||||
var selection = window.getSelection();
|
||||
range.selectNodeContents(target);
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
$('#quickFilterField').bind("enterKey",function(e){
|
||||
$('#quickFilterButton').trigger("click");
|
||||
|
@ -4499,11 +4507,7 @@ $(document).ready(function() {
|
|||
// clicking on an element with this class will select all of its contents in a
|
||||
// single click
|
||||
$('.quickSelect').click(function() {
|
||||
var range = document.createRange();
|
||||
var selection = window.getSelection();
|
||||
range.selectNodeContents(this);
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
quickSelect(this);
|
||||
});
|
||||
$(".cortex-json").click(function() {
|
||||
var cortex_data = $(this).data('cortex-json');
|
||||
|
|
Loading…
Reference in New Issue