diff --git a/app/config/testing/cms.php b/app/config/testing/cms.php index caa73b460..ed586eb9a 100644 --- a/app/config/testing/cms.php +++ b/app/config/testing/cms.php @@ -2,6 +2,17 @@ return array( + /* + |-------------------------------------------------------------------------- + | Specifies the default CMS theme + |-------------------------------------------------------------------------- + | + | This parameter value can be overridden by the CMS back-end settings. + | + */ + + 'activeTheme' => 'test', + /* |-------------------------------------------------------------------------- | Plugins directory @@ -66,14 +77,16 @@ return array( /* |-------------------------------------------------------------------------- - | Specifies the default CMS theme + | Determines if a friendly error page should be used. |-------------------------------------------------------------------------- | - | This parameter value can be overridden by the CMS back-end settings. + | If this value is set to true, a friendly error page is used when an + | exception is encountered. You must create a CMS page with route "/error" + | to set the contents of this page. Otherwise the default error page is shown. | */ - 'activeTheme' => 'test', + 'customErrorPage' => true, /* |-------------------------------------------------------------------------- @@ -88,7 +101,7 @@ return array( */ 'enableAssetCache' => false, - + /* |-------------------------------------------------------------------------- | Disables Twig caching for unit tests diff --git a/modules/backend/ServiceProvider.php b/modules/backend/ServiceProvider.php index 9f3dd231d..2c6f0f0ea 100644 --- a/modules/backend/ServiceProvider.php +++ b/modules/backend/ServiceProvider.php @@ -104,6 +104,15 @@ class ServiceProvider extends ModuleServiceProvider 'context' => 'mysettings', 'keywords' => 'backend::lang.myaccount.menu_keywords', ], + 'access_logs' => [ + 'label' => 'backend::lang.access_log.menu_label', + 'description' => 'backend::lang.access_log.menu_description', + 'category' => 'Logs', + 'icon' => 'icon-lock', + 'url' => Backend::url('backend/accesslogs'), + 'permissions' => ['backend.access_admin_logs'], + 'order' => 800 + ], ]); }); diff --git a/modules/backend/assets/css/october.css b/modules/backend/assets/css/october.css index 062c9b5af..36616a5ec 100644 --- a/modules/backend/assets/css/october.css +++ b/modules/backend/assets/css/october.css @@ -9178,151 +9178,151 @@ table.table.data .list-tree a.list-expand-collapse { table.table.data tr.list-tree-level-1 a.list-expand-collapse { left: 30px; } -table.table.data tr.list-tree-level-1 td.list-data-column-1 { +table.table.data tr.list-tree-level-1 td.list-cell-index-1 { padding-left: 35px; } table.table.data tr.list-tree-level-2 a.list-expand-collapse { left: 40px; } -table.table.data tr.list-tree-level-2 td.list-data-column-1 { +table.table.data tr.list-tree-level-2 td.list-cell-index-1 { padding-left: 45px; } table.table.data tr.list-tree-level-3 a.list-expand-collapse { left: 50px; } -table.table.data tr.list-tree-level-3 td.list-data-column-1 { +table.table.data tr.list-tree-level-3 td.list-cell-index-1 { padding-left: 55px; } table.table.data tr.list-tree-level-4 a.list-expand-collapse { left: 60px; } -table.table.data tr.list-tree-level-4 td.list-data-column-1 { +table.table.data tr.list-tree-level-4 td.list-cell-index-1 { padding-left: 65px; } table.table.data tr.list-tree-level-5 a.list-expand-collapse { left: 70px; } -table.table.data tr.list-tree-level-5 td.list-data-column-1 { +table.table.data tr.list-tree-level-5 td.list-cell-index-1 { padding-left: 75px; } table.table.data tr.list-tree-level-6 a.list-expand-collapse { left: 80px; } -table.table.data tr.list-tree-level-6 td.list-data-column-1 { +table.table.data tr.list-tree-level-6 td.list-cell-index-1 { padding-left: 85px; } table.table.data tr.list-tree-level-7 a.list-expand-collapse { left: 90px; } -table.table.data tr.list-tree-level-7 td.list-data-column-1 { +table.table.data tr.list-tree-level-7 td.list-cell-index-1 { padding-left: 95px; } table.table.data tr.list-tree-level-8 a.list-expand-collapse { left: 100px; } -table.table.data tr.list-tree-level-8 td.list-data-column-1 { +table.table.data tr.list-tree-level-8 td.list-cell-index-1 { padding-left: 105px; } table.table.data tr.list-tree-level-9 a.list-expand-collapse { left: 110px; } -table.table.data tr.list-tree-level-9 td.list-data-column-1 { +table.table.data tr.list-tree-level-9 td.list-cell-index-1 { padding-left: 115px; } table.table.data tr.list-tree-level-10 a.list-expand-collapse { left: 120px; } -table.table.data tr.list-tree-level-10 td.list-data-column-1 { +table.table.data tr.list-tree-level-10 td.list-cell-index-1 { padding-left: 125px; } table.table.data tr.list-tree-level-11 a.list-expand-collapse { left: 130px; } -table.table.data tr.list-tree-level-11 td.list-data-column-1 { +table.table.data tr.list-tree-level-11 td.list-cell-index-1 { padding-left: 135px; } table.table.data tr.list-tree-level-12 a.list-expand-collapse { left: 140px; } -table.table.data tr.list-tree-level-12 td.list-data-column-1 { +table.table.data tr.list-tree-level-12 td.list-cell-index-1 { padding-left: 145px; } table.table.data tr.list-tree-level-13 a.list-expand-collapse { left: 150px; } -table.table.data tr.list-tree-level-13 td.list-data-column-1 { +table.table.data tr.list-tree-level-13 td.list-cell-index-1 { padding-left: 155px; } table.table.data tr.list-tree-level-14 a.list-expand-collapse { left: 160px; } -table.table.data tr.list-tree-level-14 td.list-data-column-1 { +table.table.data tr.list-tree-level-14 td.list-cell-index-1 { padding-left: 165px; } table.table.data tr.list-tree-level-15 a.list-expand-collapse { left: 170px; } -table.table.data tr.list-tree-level-15 td.list-data-column-1 { +table.table.data tr.list-tree-level-15 td.list-cell-index-1 { padding-left: 175px; } table.table.data tr.list-tree-level-16 a.list-expand-collapse { left: 180px; } -table.table.data tr.list-tree-level-16 td.list-data-column-1 { +table.table.data tr.list-tree-level-16 td.list-cell-index-1 { padding-left: 185px; } table.table.data tr.list-tree-level-17 a.list-expand-collapse { left: 190px; } -table.table.data tr.list-tree-level-17 td.list-data-column-1 { +table.table.data tr.list-tree-level-17 td.list-cell-index-1 { padding-left: 195px; } table.table.data tr.list-tree-level-18 a.list-expand-collapse { left: 200px; } -table.table.data tr.list-tree-level-18 td.list-data-column-1 { +table.table.data tr.list-tree-level-18 td.list-cell-index-1 { padding-left: 205px; } table.table.data tr.list-tree-level-19 a.list-expand-collapse { left: 210px; } -table.table.data tr.list-tree-level-19 td.list-data-column-1 { +table.table.data tr.list-tree-level-19 td.list-cell-index-1 { padding-left: 215px; } table.table.data tr.list-tree-level-20 a.list-expand-collapse { left: 220px; } -table.table.data tr.list-tree-level-20 td.list-data-column-1 { +table.table.data tr.list-tree-level-20 td.list-cell-index-1 { padding-left: 225px; } table.table.data tr.list-tree-level-21 a.list-expand-collapse { left: 230px; } -table.table.data tr.list-tree-level-21 td.list-data-column-1 { +table.table.data tr.list-tree-level-21 td.list-cell-index-1 { padding-left: 235px; } table.table.data tr.list-tree-level-22 a.list-expand-collapse { left: 240px; } -table.table.data tr.list-tree-level-22 td.list-data-column-1 { +table.table.data tr.list-tree-level-22 td.list-cell-index-1 { padding-left: 245px; } table.table.data tr.list-tree-level-23 a.list-expand-collapse { left: 250px; } -table.table.data tr.list-tree-level-23 td.list-data-column-1 { +table.table.data tr.list-tree-level-23 td.list-cell-index-1 { padding-left: 255px; } table.table.data tr.list-tree-level-24 a.list-expand-collapse { left: 260px; } -table.table.data tr.list-tree-level-24 td.list-data-column-1 { +table.table.data tr.list-tree-level-24 td.list-cell-index-1 { padding-left: 265px; } table.table.data tr.list-tree-level-25 a.list-expand-collapse { left: 270px; } -table.table.data tr.list-tree-level-25 td.list-data-column-1 { +table.table.data tr.list-tree-level-25 td.list-cell-index-1 { padding-left: 275px; } .list-preview { @@ -9499,6 +9499,13 @@ table.table.data tr.list-tree-level-25 td.list-data-column-1 { .control-simplelist ul { padding-left: 15px; } +.control-simplelist.form-control ul { + margin-bottom: 0; +} +.control-simplelist.form-control li { + padding-top: 5px; + padding-bottom: 5px; +} .control-simplelist.with-icons ul, .control-simplelist.with-checkboxes ul, .control-simplelist.is-selectable ul { diff --git a/modules/backend/assets/less/controls/lists.less b/modules/backend/assets/less/controls/lists.less index 4648b493b..5c0e9db14 100644 --- a/modules/backend/assets/less/controls/lists.less +++ b/modules/backend/assets/less/controls/lists.less @@ -273,7 +273,7 @@ table.table.data { .makeTreeLevel(@count) when (@count < 26) { tr.list-tree-level-@{count} { a.list-expand-collapse { left: 20px + (10 * @count); } - td.list-data-column-1 { padding-left: 25px + (10 * @count); } + td.list-cell-index-1 { padding-left: 25px + (10 * @count); } } .makeTreeLevel(@count + 1); } diff --git a/modules/backend/assets/less/controls/simplelist.less b/modules/backend/assets/less/controls/simplelist.less index f2b8ecf3e..b8cb4f136 100644 --- a/modules/backend/assets/less/controls/simplelist.less +++ b/modules/backend/assets/less/controls/simplelist.less @@ -33,6 +33,14 @@ ul { padding-left: 15px; } + &.form-control { + ul { margin-bottom: 0; } + li { + padding-top: 5px; + padding-bottom: 5px; + } + } + &.with-icons, &.with-checkboxes, &.is-selectable { ul { list-style-type: none; diff --git a/modules/backend/behaviors/FormController.php b/modules/backend/behaviors/FormController.php index 589d626fb..02cc43ba1 100644 --- a/modules/backend/behaviors/FormController.php +++ b/modules/backend/behaviors/FormController.php @@ -25,7 +25,7 @@ class FormController extends ControllerBehavior /** * @var Backend\Classes\WidgetBase Reference to the widget object. */ - private $formWidget; + protected $formWidget; /** * {@inheritDoc} @@ -47,7 +47,7 @@ class FormController extends ControllerBehavior /** * @var array List of prepared models that require saving. */ - private $modelsToSave = []; + protected $modelsToSave = []; /** * Behavior constructor @@ -349,7 +349,7 @@ class FormController extends ControllerBehavior * @param array $extras Any extra params to include in the language string variables * @return string The translated string. */ - private function getLang($name, $default = null, $extras = []) + protected function getLang($name, $default = null, $extras = []) { $name = $this->getConfig($name, $default); $vars = [ @@ -567,7 +567,7 @@ class FormController extends ControllerBehavior // Internals // - private function prepareModelsToSave($model, $saveData) + protected function prepareModelsToSave($model, $saveData) { $this->modelsToSave = []; $this->setModelAttributes($model, $saveData); @@ -580,7 +580,7 @@ class FormController extends ControllerBehavior * @param Model $model Model to save to * @return array The collection of models to save. */ - private function setModelAttributes($model, $saveData) + protected function setModelAttributes($model, $saveData) { $this->modelsToSave[] = $model; diff --git a/modules/backend/behaviors/ListController.php b/modules/backend/behaviors/ListController.php index 77896c924..444a0f2fe 100644 --- a/modules/backend/behaviors/ListController.php +++ b/modules/backend/behaviors/ListController.php @@ -19,22 +19,22 @@ class ListController extends ControllerBehavior /** * @var array List definitions, keys for alias and value for configuration. */ - private $listDefinitions; + protected $listDefinitions; /** * @var string The primary list alias to use. Default: list */ - private $primaryDefinition; + protected $primaryDefinition; /** * @var Backend\Classes\WidgetBase Reference to the list widget object. */ - private $listWidgets = []; + protected $listWidgets = []; /** * @var WidgetBase Reference to the toolbar widget objects. */ - private $toolbarWidgets = []; + protected $toolbarWidgets = []; /** * {@inheritDoc} diff --git a/modules/backend/behaviors/RelationController.php b/modules/backend/behaviors/RelationController.php index ec7a7e062..0f479d814 100644 --- a/modules/backend/behaviors/RelationController.php +++ b/modules/backend/behaviors/RelationController.php @@ -26,22 +26,22 @@ class RelationController extends ControllerBehavior /** * @var Backend\Classes\WidgetBase Reference to the toolbar widget object. */ - private $toolbarWidget; + protected $toolbarWidget; /** * @var Backend\Classes\WidgetBase Reference to the widget used for viewing (list or form). */ - private $viewWidget; + protected $viewWidget; /** * @var Backend\Classes\WidgetBase Reference to the widget used for relation management. */ - private $manageWidget; + protected $manageWidget; /** * @var Backend\Classes\WidgetBase Reference to widget for relations with pivot data. */ - private $pivotWidget; + protected $pivotWidget; /** * {@inheritDoc} @@ -61,12 +61,12 @@ class RelationController extends ControllerBehavior /** * @var array Original configuration values */ - private $originalConfig; + protected $originalConfig; /** * @var bool Has the behavior been initialized. */ - private $initialized = false; + protected $initialized = false; /** * @var string Relationship type @@ -154,6 +154,9 @@ class RelationController extends ControllerBehavior */ public function initRelation($model, $field = null) { + if ($field == null) + $field = post(self::PARAM_FIELD); + $this->config = $this->originalConfig; $this->model = $model; $this->field = $field; @@ -323,7 +326,7 @@ class RelationController extends ControllerBehavior * @param string $field The relationship field. * @return string The active field name. */ - private function validateField($field = null) + protected function validateField($field = null) { $field = $field ?: post(self::PARAM_FIELD); @@ -403,7 +406,7 @@ class RelationController extends ControllerBehavior /** * Returns the existing record IDs for the relation. */ - private function findExistingRelationIds($checkIds = null) + protected function findExistingRelationIds($checkIds = null) { $results = $this->relationObject ->getBaseQuery() diff --git a/modules/backend/behaviors/UserPreferencesModel.php b/modules/backend/behaviors/UserPreferencesModel.php index bc186a983..c88e61afa 100644 --- a/modules/backend/behaviors/UserPreferencesModel.php +++ b/modules/backend/behaviors/UserPreferencesModel.php @@ -85,7 +85,7 @@ class UserPreferencesModel extends SettingsModel * Checks if a key is legitimate or should be added to * the field value collection */ - private function isKeyAllowed($key) + protected function isKeyAllowed($key) { /* * Let the core columns through diff --git a/modules/backend/classes/AuthManager.php b/modules/backend/classes/AuthManager.php index f115514be..41b992f76 100644 --- a/modules/backend/classes/AuthManager.php +++ b/modules/backend/classes/AuthManager.php @@ -37,17 +37,17 @@ class AuthManager extends RainAuthManager /** * @var array Cache of registration callbacks. */ - private $callbacks = []; + protected $callbacks = []; /** * @var array List of registered permissions. */ - private $permissions = []; + protected $permissions = []; /** * @var array Cache of registered permissions. */ - private $permissionCache = false; + protected $permissionCache = false; /** * Registers a callback function that defines authentication permissions. diff --git a/modules/backend/classes/BackendController.php b/modules/backend/classes/BackendController.php index ea5b2172c..a1a9b8147 100644 --- a/modules/backend/classes/BackendController.php +++ b/modules/backend/classes/BackendController.php @@ -75,7 +75,7 @@ class BackendController extends ControllerBase * @param string $action Specifies a method name to execute. * @return ControllerBase Returns the backend controller object */ - private function findController($controller, $action, $dirPrefix = null) + protected function findController($controller, $action, $dirPrefix = null) { /* * Workaround: Composer does not support case insensitivity. diff --git a/modules/backend/classes/FormField.php b/modules/backend/classes/FormField.php index e14b2f481..267b78bc0 100644 --- a/modules/backend/classes/FormField.php +++ b/modules/backend/classes/FormField.php @@ -53,12 +53,12 @@ class FormField public $options; /** - * @var string Specifies a side. Possible values: auto, left, right, full + * @var string Specifies a side. Possible values: auto, left, right, full. */ public $span = 'full'; /** - * @var string Specifies a size. Possible values: tiny, small, large, huge, giant + * @var string Specifies a size. Possible values: tiny, small, large, huge, giant. */ public $size = 'large'; @@ -88,12 +88,12 @@ class FormField public $comment; /** - * @var string Specifies the comment position + * @var string Specifies the comment position. */ public $commentPosition = 'below'; /** - * @var string Specifies if the comment is in HTML format + * @var string Specifies if the comment is in HTML format. */ public $commentHtml = false; diff --git a/modules/backend/classes/ListColumn.php b/modules/backend/classes/ListColumn.php index a4ee78683..ea9d14346 100644 --- a/modules/backend/classes/ListColumn.php +++ b/modules/backend/classes/ListColumn.php @@ -51,15 +51,25 @@ class ListColumn public $relation; /** - * @var string Specify a CSS class to attach to the list row element. + * @var string Specify a CSS class to attach to the list cell element. */ public $cssClass; /** - * @var string Specify a format or style for the column value, such as a Date + * @var string Specify a format or style for the column value, such as a Date. */ public $format; + /** + * @var string Specifies a path for partial-type fields. + */ + public $path; + + /** + * @var array Raw field configuration. + */ + public $config; + /** * Constructor */ @@ -75,19 +85,30 @@ class ListColumn * - number - numeric column, aligned right * @param string $type Specifies a render mode as described above */ - public function displayAs($type) + public function displayAs($type, $config) { - $this->type = $type; + $this->type = strtolower($type) ?: $this->type; + $this->config = $this->evalConfig($config); return $this; } /** - * Specifies CSS classes to apply to the table row element. + * Process options and apply them to this object. + * @param array $config + * @return array */ - public function cssClass($class) + protected function evalConfig($config) { - $this->cssClass = $class; - return $this; + if (isset($config['cssClass'])) $this->cssClass = $config['cssClass']; + if (isset($config['searchable'])) $this->searchable = $config['searchable']; + if (isset($config['sortable'])) $this->sortable = $config['sortable']; + if (isset($config['invisible'])) $this->invisible = $config['invisible']; + if (isset($config['select'])) $this->sqlSelect = $config['select']; + if (isset($config['relation'])) $this->relation = $config['relation']; + if (isset($config['format'])) $this->format = $config['format']; + if (isset($config['path'])) $this->path = $config['path']; + + return $config; } } \ No newline at end of file diff --git a/modules/backend/classes/NavigationManager.php b/modules/backend/classes/NavigationManager.php index 340ef76ce..8b21c68f4 100644 --- a/modules/backend/classes/NavigationManager.php +++ b/modules/backend/classes/NavigationManager.php @@ -17,18 +17,18 @@ class NavigationManager /** * @var array Cache of registration callbacks. */ - private $callbacks = []; + protected $callbacks = []; /** * @var array List of registered items. */ - private $items; + protected $items; - private $contextSidenavPartials = []; + protected $contextSidenavPartials = []; - private $contextOwner; - private $contextMainMenuItemCode; - private $contextSideMenuItemCode; + protected $contextOwner; + protected $contextMainMenuItemCode; + protected $contextSideMenuItemCode; static $mainItemDefaults = [ 'code' => null, @@ -419,7 +419,7 @@ class NavigationManager * @param array $items A collection of menu items * @return array The filtered menu items */ - private function filterItemPermissions($user, array $items) + protected function filterItemPermissions($user, array $items) { $items = array_filter($items, function($item) use ($user) { if (!$item->permissions || !count($item->permissions)) @@ -436,7 +436,7 @@ class NavigationManager * @param object $item * @return string */ - private function makeItemKey($owner, $code) + protected function makeItemKey($owner, $code) { return strtoupper($owner).'.'.strtoupper($code); } diff --git a/modules/backend/classes/WidgetManager.php b/modules/backend/classes/WidgetManager.php index 59fb88e9f..007ad3571 100644 --- a/modules/backend/classes/WidgetManager.php +++ b/modules/backend/classes/WidgetManager.php @@ -27,7 +27,7 @@ class WidgetManager /** * @var array Cache of report widget registration callbacks. */ - private $formWidgetCallbacks = []; + protected $formWidgetCallbacks = []; /** * @var array An array of report widgets. @@ -42,7 +42,7 @@ class WidgetManager /** * @var array Cache of report widget registration callbacks. */ - private $reportWidgetCallbacks = []; + protected $reportWidgetCallbacks = []; /** * @var array An array where keys are aliases and values are class names. diff --git a/modules/backend/controllers/AccessLogs.php b/modules/backend/controllers/AccessLogs.php new file mode 100644 index 000000000..19961285b --- /dev/null +++ b/modules/backend/controllers/AccessLogs.php @@ -0,0 +1,41 @@ + post('password') ], true); + // Log the sign in event + AccessLog::add($user); + // Load version updates VersionManager::instance()->updateAll(); diff --git a/modules/backend/controllers/accesslogs/_hint.htm b/modules/backend/controllers/accesslogs/_hint.htm new file mode 100644 index 000000000..66c293f29 --- /dev/null +++ b/modules/backend/controllers/accesslogs/_hint.htm @@ -0,0 +1,4 @@ + +
+ = e(trans('backend::lang.access_log.hint', ['days' => 60])) ?> +
\ No newline at end of file diff --git a/modules/backend/controllers/accesslogs/_list_toolbar.htm b/modules/backend/controllers/accesslogs/_list_toolbar.htm new file mode 100644 index 000000000..449ba7d85 --- /dev/null +++ b/modules/backend/controllers/accesslogs/_list_toolbar.htm @@ -0,0 +1,3 @@ +