2020-03-01 18:05:21 +01:00
< ? php
App :: uses ( 'AppController' , 'Controller' );
2021-02-03 17:47:51 +01:00
/**
* @ property Dashboard $Dashboard
*/
2020-03-01 18:05:21 +01:00
class DashboardsController extends AppController
{
public $components = array ( 'Session' , 'RequestHandler' );
2020-03-19 14:39:52 +01:00
public $helpers = array ( 'ScopedCSS' );
2020-03-01 18:05:21 +01:00
public function beforeFilter ()
{
parent :: beforeFilter ();
2022-05-07 19:02:41 +02:00
$this -> Security -> unlockedActions [] = 'renderWidget' ;
$this -> Security -> unlockedActions [] = 'getForm' ;
2022-05-06 10:20:17 +02:00
if ( $this -> request -> action === 'renderWidget' ) {
$this -> Security -> doNotGenerateToken = true ;
}
2020-03-01 18:05:21 +01:00
}
public $paginate = array (
2022-05-07 19:02:41 +02:00
'limit' => 60 ,
'maxLimit' => 9999
2020-03-01 18:05:21 +01:00
);
2020-03-08 23:36:27 +01:00
public function index ( $template_id = false )
2020-03-01 18:05:21 +01:00
{
2020-03-08 23:36:27 +01:00
if ( empty ( $template_id )) {
$params = array (
'conditions' => array (
'UserSetting.user_id' => $this -> Auth -> user ( 'id' ),
'UserSetting.setting' => 'dashboard'
)
);
2022-05-07 19:02:41 +02:00
$userSettings = $this -> User -> UserSetting -> find ( 'first' , $params );
2020-03-08 23:36:27 +01:00
} else {
$dashboardTemplate = $this -> Dashboard -> getDashboardTemplate ( $this -> Auth -> user (), $template_id );
if ( empty ( $dashboardTemplate )) {
throw new NotFoundException ( __ ( 'Invalid dashboard template.' ));
}
}
2020-03-08 23:54:02 +01:00
if ( empty ( $userSettings ) && empty ( $dashboardTemplate )) {
2020-03-08 23:36:27 +01:00
$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 );
}
}
2020-03-01 18:05:21 +01:00
$userSettings = array (
'UserSetting' => array (
'setting' => 'dashboard' ,
2020-03-08 23:36:27 +01:00
'value' => $value
2020-03-01 18:05:21 +01:00
)
);
}
$widgets = array ();
foreach ( $userSettings [ 'UserSetting' ][ 'value' ] as $widget ) {
2020-03-08 23:36:27 +01:00
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
}
2020-03-01 18:05:21 +01:00
}
$this -> set ( 'widgets' , $widgets );
}
public function getForm ( $action = 'edit' )
{
2023-02-08 15:53:13 +01:00
if ( $this -> request -> is ([ 'post' , 'put' ])) {
2020-03-01 18:05:21 +01:00
$data = $this -> request -> data ;
if ( empty ( $data [ 'config' ])) {
$data [ 'config' ] = '' ;
}
2023-08-11 09:53:21 +02:00
if ( ! empty ( $data [ 'id' ]) && ! preg_match ( '/^[\w\d_]+$/i' , $data [ 'id' ])) {
throw new BadRequestException ( __ ( 'Invalid widget id provided.' ));
}
2020-03-01 18:05:21 +01:00
if ( $action === 'add' ) {
2020-03-02 00:32:26 +01:00
$data [ 'widget_options' ] = $this -> Dashboard -> loadAllWidgets ( $this -> Auth -> user ());
2023-02-08 15:53:13 +01:00
} else if ( $action === 'edit' ) {
if ( ! isset ( $data [ 'widget' ])) {
throw new BadRequestException ( __ ( 'No widget name passed.' ));
}
2020-03-01 23:56:40 +01:00
$dashboardWidget = $this -> Dashboard -> loadWidget ( $this -> Auth -> user (), $data [ 'widget' ]);
2020-03-01 18:05:21 +01:00
$data [ 'description' ] = empty ( $dashboardWidget -> description ) ? '' : $dashboardWidget -> description ;
$data [ 'params' ] = empty ( $dashboardWidget -> params ) ? array () : $dashboardWidget -> params ;
2020-03-24 12:01:57 +01:00
$data [ 'params' ] = array_merge ( $data [ 'params' ], array ( 'widget_config' => __ ( 'Configuration of the widget that will be passed to the render. Check the view for more information' )));
2020-03-01 18:05:21 +01:00
$data [ 'params' ] = array_merge ( array ( 'alias' => __ ( 'Alias to use as the title of the widget' )), $data [ 'params' ]);
2023-02-08 15:53:13 +01:00
} else {
throw new BadRequestException ( __ ( 'Invalid action provided, just add or edit is supported.' ));
2020-03-01 18:05:21 +01:00
}
$this -> set ( 'data' , $data );
$this -> layout = false ;
$this -> render ( $action );
}
}
public function updateSettings ()
{
if ( $this -> request -> is ( 'post' )) {
2021-06-04 16:35:32 +02:00
if ( ! isset ( $this -> request -> data [ 'Dashboard' ][ 'value' ])) {
2020-03-01 18:05:21 +01:00
throw new InvalidArgumentException ( __ ( 'No setting data found.' ));
}
$data = array (
'UserSetting' => array (
'setting' => 'dashboard' ,
2021-06-04 16:35:32 +02:00
'value' => $this -> request -> data [ 'Dashboard' ][ 'value' ]
2020-03-01 18:05:21 +01:00
)
);
2022-05-07 19:02:41 +02:00
$result = $this -> User -> UserSetting -> setSetting ( $this -> Auth -> user (), $data );
2020-03-01 18:05:21 +01:00
if ( $result ) {
return $this -> RestResponse -> saveSuccessResponse ( 'Dashboard' , 'updateSettings' , false , false , __ ( 'Settings updated.' ));
}
2022-05-07 19:02:41 +02:00
return $this -> RestResponse -> saveFailResponse ( 'Dashboard' , 'updateSettings' , false , $this -> User -> UserSetting -> validationErrors , $this -> response -> type ());
2020-03-01 18:05:21 +01:00
}
}
public function getEmptyWidget ( $widget , $k = 1 )
{
2020-03-01 23:56:40 +01:00
$dashboardWidget = $this -> Dashboard -> loadWidget ( $this -> Auth -> user (), $widget );
2020-03-01 18:05:21 +01:00
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 );
}
2020-03-10 10:58:41 +01:00
public function renderWidget ( $widget_id , $force = false )
2020-03-01 18:05:21 +01:00
{
2022-10-08 13:05:46 +02:00
$user = $this -> _closeSession ();
2021-02-03 17:47:51 +01:00
if ( ! $this -> request -> is ( 'post' )) {
throw new MethodNotAllowedException ( __ ( 'This endpoint can only be reached via POST requests.' ));
}
2020-03-01 18:05:21 +01:00
2021-02-03 17:47:51 +01:00
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' ];
2022-10-20 14:54:36 +02:00
$valueConfig = $this -> _jsonDecode ( $value [ 'config' ]);
2021-11-25 12:13:58 +01:00
$dashboardWidget = $this -> Dashboard -> loadWidget ( $user , $value [ 'widget' ]);
2021-02-03 17:47:51 +01:00
2022-10-08 13:05:46 +02:00
$cacheLifetime = $dashboardWidget -> cacheLifetime ? ? false ;
if ( $cacheLifetime !== false ) {
$orgScope = $this -> _isSiteAdmin () ? 0 : $user [ 'org_id' ];
$lookupHash = sha1 ( $value [ 'widget' ] . $value [ 'config' ], true );
$cacheKey = " misp:dashboard: $orgScope : $lookupHash " ;
$redis = RedisTool :: init ();
$data = $redis -> get ( $cacheKey );
if ( ! empty ( $data )) {
$data = RedisTool :: deserialize ( $data );
} else {
$data = $dashboardWidget -> handler ( $user , $valueConfig );
$redis -> setex ( $cacheKey , $cacheLifetime , RedisTool :: serialize ( $data ));
2020-03-01 18:05:21 +01:00
}
} else {
2022-10-08 13:05:46 +02:00
$data = $dashboardWidget -> handler ( $user , $valueConfig );
2020-03-01 18:05:21 +01:00
}
2023-02-09 11:42:21 +01:00
$renderer = method_exists ( $dashboardWidget , 'getRenderer' ) ? $dashboardWidget -> getRenderer ( $valueConfig ) : $dashboardWidget -> render ;
2021-02-03 17:47:51 +01:00
$config = array (
2023-02-09 11:42:21 +01:00
'render' => $renderer ,
2021-02-03 17:47:51 +01:00
'autoRefreshDelay' => empty ( $dashboardWidget -> autoRefreshDelay ) ? false : $dashboardWidget -> autoRefreshDelay ,
'widget_config' => empty ( $valueConfig [ 'widget_config' ]) ? array () : $valueConfig [ 'widget_config' ]
);
2023-06-26 18:15:17 +02:00
if ( ! empty ( $this -> request -> params [ 'named' ][ 'exportjson' ])) {
return $this -> RestResponse -> viewData ( $data );
2023-08-07 14:32:21 +02:00
} else if ( ! empty ( $this -> request -> params [ 'named' ][ 'exportcsv' ])) {
$csv = '' ;
$toConvert = ! empty ( $data ) ? ( ! empty ( $data [ 'data' ]) ? $data [ 'data' ] : $data ) : [];
if ( ! empty ( $toConvert )) {
$firstElement = key ( $toConvert );
if ( is_string ( $firstElement )) {
foreach ( $toConvert as $key => $value ) {
$csv .= sprintf ( '%s,%s' , $key , json_encode ( $value )) . PHP_EOL ;
}
} else { // second element is an array
$csv = array_map ( function ( $row ) {
$flattened = array_values ( Hash :: flatten ( $row ));
2023-08-09 10:24:34 +02:00
$stringified = array_map ( 'strval' , $flattened );
2023-08-09 14:56:24 +02:00
$quotified = array_map ( function ( $item ) { return sprintf ( '"%s"' , $item ); }, $stringified );
return implode ( ',' , $quotified );
2023-08-07 14:32:21 +02:00
}, $toConvert );
2023-08-09 14:56:24 +02:00
$rowKey = implode ( ',' , array_map ( function ( $item ) {
return sprintf ( '"%s"' , $item );
}, array_map ( 'strval' , array_keys ( Hash :: flatten ( $toConvert [ 0 ])))));
2023-08-09 10:24:34 +02:00
$csv = $rowKey . PHP_EOL . implode ( PHP_EOL , array_values ( $csv ));
2023-08-07 14:32:21 +02:00
}
}
2023-08-09 14:56:24 +02:00
return $this -> RestResponse -> viewData ( $csv , 'text/csv' , false , true );
2023-06-26 18:15:17 +02:00
}
2021-02-03 17:47:51 +01:00
$this -> layout = false ;
$this -> set ( 'title' , $dashboardWidget -> title );
$this -> set ( 'widget_id' , $widget_id );
$this -> set ( 'data' , $data );
$this -> set ( 'config' , $config );
$this -> render ( 'widget_loader' );
2020-03-01 18:05:21 +01:00
}
2020-03-08 23:36:27 +01:00
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 ;
2020-03-10 11:21:35 +01:00
if ( empty ( $update )) { // save the template stored in user setting and make it persistent
2022-05-07 19:02:41 +02:00
$data [ 'value' ] = $this -> User -> UserSetting -> getSetting ( $this -> Auth -> user ( 'id' ), 'dashboard' );
2020-03-10 11:21:35 +01:00
}
2020-03-08 23:36:27 +01:00
$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 ;
}
$permFlags = array ( 0 => __ ( 'Unrestricted' ));
foreach ( $this -> User -> Role -> permFlags as $perm_flag => $perm_data ) {
$permFlags [ $perm_flag ] = $perm_data [ 'text' ];
}
$options = array (
2020-03-10 10:52:53 +01:00
'org_id' => (
2020-03-08 23:36:27 +01:00
array (
0 => __ ( 'Unrestricted' )
2020-03-10 10:52:53 +01:00
) + // avoid re-indexing
2020-03-08 23:36:27 +01:00
$this -> User -> Organisation -> find ( 'list' , array (
'fields' => array (
'Organisation.id' , 'Organisation.name'
),
'conditions' => array ( 'Organisation.local' => 1 )
))
),
2020-03-10 10:52:53 +01:00
'role_id' => (
2020-03-08 23:36:27 +01:00
array (
0 => __ ( 'Unrestricted' )
2020-03-10 10:52:53 +01:00
) + // avoid re-indexing
2020-03-08 23:36:27 +01:00
$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 ();
2023-05-16 14:04:32 +02:00
// load all widgets for internal use, won't be displayed to the user. Thus we circumvent the ACL on it.
$accessible_widgets = array_keys ( $this -> Dashboard -> loadAllWidgets ( $this -> Auth -> user ()));
2020-03-08 23:36:27 +01:00
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 {
2020-03-09 00:14:59 +01:00
$this -> paginate [ 'contain' ] = array (
'User.id' , 'User.email'
);
2020-03-08 23:36:27 +01:00
$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' ]);
2023-05-16 14:04:32 +02:00
$temp = [];
foreach ( $element [ 'Dashboard' ][ 'widgets' ] as $widget ) {
if ( in_array ( $widget , $accessible_widgets )) {
$temp [ 'allow' ][] = $widget ;
} else {
$temp [ 'deny' ][] = $widget ;
}
}
$element [ 'Dashboard' ][ 'widgets' ] = $temp ;
2020-03-09 00:14:59 +01:00
if ( $element [ 'Dashboard' ][ 'user_id' ] != $this -> Auth -> user ( 'id' )) {
$element [ 'User' ][ 'email' ] = '' ;
}
2020-03-08 23:36:27 +01:00
}
2021-02-02 20:25:06 +01:00
$this -> set ( 'passedArgs' , json_encode ( $this -> passedArgs ));
2020-03-08 23:36:27 +01:00
$this -> set ( 'data' , $data );
}
}
2020-03-09 00:08:23 +01:00
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' );
}
}
2020-03-01 18:05:21 +01:00
}