diff --git a/config/cms.php b/config/cms.php index 0b12b46f2..e6f7c32b9 100644 --- a/config/cms.php +++ b/config/cms.php @@ -51,6 +51,24 @@ return [ 'backendForceSecure' => null, + /* + |-------------------------------------------------------------------------- + | Back-end login remember + |-------------------------------------------------------------------------- + | + | Define live duration of backend sessions : + | + | true - session never expire (cookie expiration in 5 years) + | + | false - session have a limited time (see session.lifetime) + | + | null - The form login display a checkbox that allow user to choose + | wanted behavior + | + */ + + 'backendForceRemember' => true, + /* |-------------------------------------------------------------------------- | Back-end timezone diff --git a/modules/backend/assets/css/october.css b/modules/backend/assets/css/october.css index a6034f8b3..e8dea756a 100644 --- a/modules/backend/assets/css/october.css +++ b/modules/backend/assets/css/october.css @@ -846,6 +846,7 @@ body.outer .layout > .layout-row > .layout-cell .outer-form-container h2{font-si body.outer .layout > .layout-row > .layout-cell .outer-form-container .horizontal-form{font-size:0;display:-webkit-box;display:-webkit-flex;display:-moz-flex;display:-ms-flexbox;display:-ms-flex;display:flex} body.outer .layout > .layout-row > .layout-cell .outer-form-container .horizontal-form input{vertical-align:top;margin-right:9px;display:inline-block;border:none;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px} body.outer .layout > .layout-row > .layout-cell .outer-form-container .horizontal-form button{background:#0181b9;text-align:center;font-size:13px;font-weight:600;height:40px;vertical-align:top;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box} +body.outer .layout > .layout-row > .layout-cell .outer-form-container .remember label {color:rgba(255,255,255,0.44)} body.outer .layout > .layout-row > .layout-cell .outer-form-container .forgot-password{margin-top:30px;font-size:13px;top:8px} body.outer .layout > .layout-row > .layout-cell .outer-form-container .forgot-password a{color:rgba(255,255,255,0.44)} body.outer .layout > .layout-row > .layout-cell .outer-form-container .forgot-password:before{color:rgba(255,255,255,0.44);font-size:14px;position:relative;margin-right:5px} diff --git a/modules/backend/assets/less/layout/outerlayout.less b/modules/backend/assets/less/layout/outerlayout.less index 9c549bdc0..2de805597 100644 --- a/modules/backend/assets/less/layout/outerlayout.less +++ b/modules/backend/assets/less/layout/outerlayout.less @@ -74,6 +74,12 @@ body.outer { } } + .remember { + label { + color: @color-outer-muted-text; + } + } + .forgot-password { margin-top: 30px; font-size: 13px; diff --git a/modules/backend/behaviors/relationcontroller/partials/_toolbar.htm b/modules/backend/behaviors/relationcontroller/partials/_toolbar.htm index 7e0c03224..3b23bd498 100644 --- a/modules/backend/behaviors/relationcontroller/partials/_toolbar.htm +++ b/modules/backend/behaviors/relationcontroller/partials/_toolbar.htm @@ -4,7 +4,7 @@ relationMakePartial('button_update', [ - 'relationManageId' => $relationViewModel->id + 'relationManageId' => $relationViewModel->getKey() ]) ?> relationMakePartial('button_'.$button) ?> diff --git a/modules/backend/classes/WidgetManager.php b/modules/backend/classes/WidgetManager.php index 5027b2009..67c4fe102 100644 --- a/modules/backend/classes/WidgetManager.php +++ b/modules/backend/classes/WidgetManager.php @@ -2,6 +2,7 @@ use Str; use System\Classes\PluginManager; +use Event; /** * Widget manager @@ -188,6 +189,23 @@ class WidgetManager } } + /** + * @event system.reportwidgets.extendItems + * Allows to append or remove a report widget. + * + * You will have access to the WidgetManager instance and be able to call the appropiated methods + * $manager->registerReportWidget(); + * $manager->removeReportWidget(); + * + * Example usage: + * + * Event::listen('system.reportwidgets.extendItems', function($manager) { + * $manager->removeReportWidget('Acme\ReportWidgets\YourWidget'); + * }); + * + */ + Event::fire('system.reportwidgets.extendItems', [$this]); + return $this->reportWidgets; } @@ -215,4 +233,19 @@ class WidgetManager { $this->reportWidgetCallbacks[] = $definitions; } + + /** + * Remove a registered ReportWidget. + * @param string $className Widget class name. + * @return void + */ + public function removeReportWidget($className) + { + if (!$this->reportWidgets) { + throw new SystemException('Unable to remove a widget before widgets are loaded.'); + } + + unset($this->reportWidgets[$className]); + } + } diff --git a/modules/backend/controllers/Auth.php b/modules/backend/controllers/Auth.php index c1545d6ae..6a6c72cb4 100644 --- a/modules/backend/controllers/Auth.php +++ b/modules/backend/controllers/Auth.php @@ -69,11 +69,15 @@ class Auth extends Controller throw new ValidationException($validation); } + if (is_null($remember = config('cms.backendForceRemember', true))) { + $remember = (bool) post('remember'); + } + // Authenticate user $user = BackendAuth::authenticate([ 'login' => post('login'), 'password' => post('password') - ], true); + ], $remember); // Load version updates UpdateManager::instance()->update(); diff --git a/modules/backend/controllers/auth/signin.htm b/modules/backend/controllers/auth/signin.htm index b508a74fd..7e186d337 100644 --- a/modules/backend/controllers/auth/signin.htm +++ b/modules/backend/controllers/auth/signin.htm @@ -32,6 +32,21 @@ + + +
+
+ + +
+
+ +

diff --git a/modules/backend/formwidgets/DatePicker.php b/modules/backend/formwidgets/DatePicker.php index 4718bf946..b10789b22 100644 --- a/modules/backend/formwidgets/DatePicker.php +++ b/modules/backend/formwidgets/DatePicker.php @@ -46,6 +46,12 @@ class DatePicker extends FormWidgetBase */ public $yearRange = null; + /** + * @var int first day of the week + * eg: 0 (Sunday), 1 (Monday), 2 (Tuesday), etc. + */ + public $firstDay = 0; + // // Object properties // @@ -66,6 +72,7 @@ class DatePicker extends FormWidgetBase 'minDate', 'maxDate', 'yearRange', + 'firstDay', ]); $this->mode = strtolower($this->mode); @@ -112,6 +119,7 @@ class DatePicker extends FormWidgetBase $this->vars['minDate'] = $this->minDate; $this->vars['maxDate'] = $this->maxDate; $this->vars['yearRange'] = $this->yearRange; + $this->vars['firstDay'] = $this->firstDay; $this->vars['format'] = $this->format; $this->vars['formatMoment'] = $this->getDateFormatMoment(); $this->vars['formatAlias'] = $this->getDateFormatAlias(); diff --git a/modules/backend/formwidgets/PermissionEditor.php b/modules/backend/formwidgets/PermissionEditor.php index ebaa1692c..565ea3e68 100644 --- a/modules/backend/formwidgets/PermissionEditor.php +++ b/modules/backend/formwidgets/PermissionEditor.php @@ -44,7 +44,7 @@ class PermissionEditor extends FormWidgetBase } $this->vars['checkboxMode'] = $this->getControlMode() === 'checkbox'; - $this->vars['permissions'] = BackendAuth::listTabbedPermissions(); + $this->vars['permissions'] = $this->getFilteredPermissions(); $this->vars['baseFieldName'] = $this->getFieldName(); $this->vars['permissionsData'] = $permissionsData; $this->vars['field'] = $this->formField; @@ -55,11 +55,29 @@ class PermissionEditor extends FormWidgetBase */ public function getSaveValue($value) { - if (is_array($value)) { - return $value; + $newPermissions = is_array($value) ? array_map('intval', $value) : []; + + if (!empty($newPermissions)) { + $existingPermissions = $this->model->permissions; + + $allowedPermissions = array_map(function ($permissionObject) { + return $permissionObject->code; + }, array_flatten($this->getFilteredPermissions())); + + foreach ($newPermissions as $permission => $code) { + if ($code === 0) { + continue; + } + + if (in_array($permission, $allowedPermissions)) { + $existingPermissions[$permission] = $code; + } + } + + $newPermissions = $existingPermissions; } - return []; + return $newPermissions; } /** @@ -75,4 +93,30 @@ class PermissionEditor extends FormWidgetBase { return strlen($this->mode) ? $this->mode : 'radio'; } + + /** + * Returns the available permissions; removing those that the logged-in user does not have access to + * + * @return array The permissions that the logged-in user does have access to + */ + protected function getFilteredPermissions() + { + $permissions = BackendAuth::listTabbedPermissions(); + $user = BackendAuth::getUser(); + foreach ($permissions as $tab => $permissionsArray) { + foreach ($permissionsArray as $index => $permission) { + if (!$user->hasAccess($permission->code)) { + unset($permissionsArray[$index]); + } + } + + if (empty($permissionsArray)) { + unset($permissions[$tab]); + } else { + $permissions[$tab] = $permissionsArray; + } + } + + return $permissions; + } } diff --git a/modules/backend/formwidgets/RecordFinder.php b/modules/backend/formwidgets/RecordFinder.php index 49d1a58bc..32361efd6 100644 --- a/modules/backend/formwidgets/RecordFinder.php +++ b/modules/backend/formwidgets/RecordFinder.php @@ -179,6 +179,10 @@ class RecordFinder extends FormWidgetBase public function prepareVars() { $this->relationModel = $this->getLoadValue(); + + if ($this->formField->disabled) { + $this->previewMode = true; + } $this->vars['value'] = $this->getKeyValue(); $this->vars['field'] = $this->formField; diff --git a/modules/backend/formwidgets/Relation.php b/modules/backend/formwidgets/Relation.php index c5f4699e5..0812379a6 100644 --- a/modules/backend/formwidgets/Relation.php +++ b/modules/backend/formwidgets/Relation.php @@ -28,11 +28,6 @@ class Relation extends FormWidgetBase */ public $nameFrom = 'name'; - /** - * @var string Model column to use for the description reference - */ - public $descriptionFrom = 'description'; - /** * @var string Custom SQL column selection to use for the name reference */ @@ -69,7 +64,6 @@ class Relation extends FormWidgetBase { $this->fillFromConfig([ 'nameFrom', - 'descriptionFrom', 'emptyOption', 'scope', ]); diff --git a/modules/backend/formwidgets/Repeater.php b/modules/backend/formwidgets/Repeater.php index dd9bf7b82..efec0c143 100644 --- a/modules/backend/formwidgets/Repeater.php +++ b/modules/backend/formwidgets/Repeater.php @@ -91,6 +91,10 @@ class Repeater extends FormWidgetBase 'maxItems', ]); + if ($this->formField->disabled) { + $this->previewMode = true; + } + $fieldName = $this->formField->getName(false); $this->indexInputName = self::INDEX_PREFIX.$fieldName; $this->groupInputName = self::GROUP_PREFIX.$fieldName; @@ -116,6 +120,12 @@ class Repeater extends FormWidgetBase */ public function prepareVars() { + if ($this->previewMode) { + foreach ($this->formWidgets as $widget) { + $widget->previewMode = true; + } + } + $this->vars['indexInputName'] = $this->indexInputName; $this->vars['groupInputName'] = $this->groupInputName; diff --git a/modules/backend/formwidgets/RichEditor.php b/modules/backend/formwidgets/RichEditor.php index c8af07eab..75a291ba5 100644 --- a/modules/backend/formwidgets/RichEditor.php +++ b/modules/backend/formwidgets/RichEditor.php @@ -85,6 +85,7 @@ class RichEditor extends FormWidgetBase $this->vars['value'] = $this->getLoadValue(); $this->vars['toolbarButtons'] = $this->evalToolbarButtons(); + $this->vars['globalToolbarButtons'] = EditorSetting::getConfigured('html_toolbar_buttons'); $this->vars['allowEmptyTags'] = EditorSetting::getConfigured('html_allow_empty_tags'); $this->vars['allowTags'] = EditorSetting::getConfigured('html_allow_tags'); $this->vars['noWrapTags'] = EditorSetting::getConfigured('html_no_wrap_tags'); diff --git a/modules/backend/formwidgets/TagList.php b/modules/backend/formwidgets/TagList.php index 8064bd2ba..b0f594f99 100644 --- a/modules/backend/formwidgets/TagList.php +++ b/modules/backend/formwidgets/TagList.php @@ -122,7 +122,7 @@ class TagList extends FormWidgetBase foreach ($newTags as $newTag) { $newModel = $relationModel::create([$this->nameFrom => $newTag]); - $existingTags[$newModel->id] = $newTag; + $existingTags[$newModel->getKey()] = $newTag; } return array_keys($existingTags); diff --git a/modules/backend/formwidgets/datepicker/partials/_datepicker.htm b/modules/backend/formwidgets/datepicker/partials/_datepicker.htm index 53221db78..090c9a0b5 100644 --- a/modules/backend/formwidgets/datepicker/partials/_datepicker.htm +++ b/modules/backend/formwidgets/datepicker/partials/_datepicker.htm @@ -14,6 +14,7 @@ data-min-date="" data-max-date="" data-year-range="" + data-first-day="" > diff --git a/modules/backend/formwidgets/repeater/assets/js/repeater.js b/modules/backend/formwidgets/repeater/assets/js/repeater.js index d1fda348e..649abd0d6 100644 --- a/modules/backend/formwidgets/repeater/assets/js/repeater.js +++ b/modules/backend/formwidgets/repeater/assets/js/repeater.js @@ -1,6 +1,6 @@ /* * Field Repeater plugin - * + * * Data attributes: * - data-control="fieldrepeater" - enables the plugin on an element * - data-option="value" - an option with a value @@ -193,6 +193,11 @@ var $textInput = $('input[type=text]:first', $target) if ($textInput.length) { return $textInput.val() + } else { + var $disabledTextInput = $('.text-field:first > .form-control', $target) + if ($disabledTextInput.length) { + return $disabledTextInput.text() + } } return defaultText diff --git a/modules/backend/formwidgets/repeater/partials/_repeater.htm b/modules/backend/formwidgets/repeater/partials/_repeater.htm index 79cea1e78..aec9388e6 100644 --- a/modules/backend/formwidgets/repeater/partials/_repeater.htm +++ b/modules/backend/formwidgets/repeater/partials/_repeater.htm @@ -13,24 +13,26 @@ -

- - - - - - - - - -
+ previewMode): ?> +
+ + + + + + + + + +
+