feat: VivesPOS landing on Winter CMS 1.2 — theme + plugin + Dockerfile
Some checks are pending
Module sub-split / Sub-split (push) Waiting to run
Some checks are pending
Module sub-split / Sub-split (push) Waiting to run
- Base: wintercms/winter branch 1.2 (full framework) - Theme vivespos: Canvas 7 + Bootstrap 5 CDN, custom CSS - Layout: deferred GTM/GA4 tracking, JSON-LD SoftwareApplication - Partials: hero (offline-first), features, modes (offline/nube toggle), screenshots, pricing (3 planes), comparison, FAQ, CTA - Plugin VivesPOS.Site with ContactForm - Dockerfile: PHP 8.2 Apache, port 80, healthcheck - Added winter/wn-pages, blog, sitemap, seo plugins - Active theme set to vivespos
This commit is contained in:
43
modules/backend/controllers/AccessLogs.php
Normal file
43
modules/backend/controllers/AccessLogs.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php namespace Backend\Controllers;
|
||||
|
||||
use Backend;
|
||||
use BackendMenu;
|
||||
use Backend\Classes\Controller;
|
||||
use System\Classes\SettingsManager;
|
||||
|
||||
/**
|
||||
* Access Logs controller
|
||||
*
|
||||
* @package winter\wn-system-module
|
||||
* @author Alexey Bobkov, Samuel Georges
|
||||
*/
|
||||
class AccessLogs extends Controller
|
||||
{
|
||||
/**
|
||||
* @var array Extensions implemented by this controller.
|
||||
*/
|
||||
public $implement = [
|
||||
\Backend\Behaviors\ListController::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array Permissions required to view this page.
|
||||
*/
|
||||
public $requiredPermissions = ['system.access_logs'];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
BackendMenu::setContext('Winter.System', 'system', 'settings');
|
||||
SettingsManager::setContext('Winter.Backend', 'access_logs');
|
||||
}
|
||||
|
||||
public function index_onRefresh()
|
||||
{
|
||||
return $this->listRefresh();
|
||||
}
|
||||
}
|
||||
241
modules/backend/controllers/Auth.php
Normal file
241
modules/backend/controllers/Auth.php
Normal file
@@ -0,0 +1,241 @@
|
||||
<?php namespace Backend\Controllers;
|
||||
|
||||
use ApplicationException;
|
||||
use Backend;
|
||||
use BackendAuth;
|
||||
use Backend\Classes\Controller;
|
||||
use Config;
|
||||
use Exception;
|
||||
use Flash;
|
||||
use Mail;
|
||||
use Request;
|
||||
use ValidationException;
|
||||
use Validator;
|
||||
use Winter\Storm\Foundation\Http\Middleware\CheckForTrustedHost;
|
||||
|
||||
/**
|
||||
* Authentication controller
|
||||
*
|
||||
* @package winter\wn-backend-module
|
||||
* @author Alexey Bobkov, Samuel Georges
|
||||
*
|
||||
*/
|
||||
class Auth extends Controller
|
||||
{
|
||||
/**
|
||||
* @var array Public controller actions
|
||||
*/
|
||||
protected $publicActions = ['index', 'signin', 'signout', 'restore', 'reset'];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->layout = 'auth';
|
||||
}
|
||||
|
||||
/**
|
||||
* Default route, redirects to signin.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return Backend::redirect('backend/auth/signin');
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the log in page.
|
||||
*/
|
||||
public function signin()
|
||||
{
|
||||
if (BackendAuth::user()) {
|
||||
return Backend::redirect('backend');
|
||||
}
|
||||
|
||||
$this->bodyClass = 'signin';
|
||||
|
||||
// Clear Cache and any previous data to fix invalid security token issue
|
||||
$this->setResponseHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
|
||||
|
||||
try {
|
||||
if (post('postback')) {
|
||||
return $this->signin_onSubmit();
|
||||
}
|
||||
|
||||
$this->bodyClass .= ' preload';
|
||||
} catch (Exception $ex) {
|
||||
Flash::error($ex->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function signin_onSubmit()
|
||||
{
|
||||
$rules = [
|
||||
'login' => 'required|between:2,255',
|
||||
'password' => 'required|between:4,255'
|
||||
];
|
||||
|
||||
$validation = Validator::make(post(), $rules);
|
||||
if ($validation->fails()) {
|
||||
throw new ValidationException($validation);
|
||||
}
|
||||
|
||||
if (is_null($remember = Config::get('cms.backendForceRemember', true))) {
|
||||
$remember = (bool) post('remember');
|
||||
}
|
||||
|
||||
// Authenticate user
|
||||
$user = BackendAuth::authenticate([
|
||||
'login' => post('login'),
|
||||
'password' => post('password')
|
||||
], $remember);
|
||||
|
||||
// Redirect to the intended page after successful sign in
|
||||
return Backend::redirectIntended('backend');
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs out a backend user.
|
||||
*/
|
||||
public function signout()
|
||||
{
|
||||
if (BackendAuth::isImpersonator()) {
|
||||
BackendAuth::stopImpersonate();
|
||||
} else {
|
||||
BackendAuth::logout();
|
||||
}
|
||||
|
||||
// Add HTTP Header 'Clear Site Data' to purge all sensitive data upon signout
|
||||
if (Request::secure()) {
|
||||
$this->setResponseHeader('Clear-Site-Data', 'cache, cookies, storage, executionContexts');
|
||||
}
|
||||
|
||||
return Backend::redirect('backend');
|
||||
}
|
||||
|
||||
/**
|
||||
* Request a password reset verification code.
|
||||
*/
|
||||
public function restore()
|
||||
{
|
||||
$this->bodyClass = 'restore';
|
||||
|
||||
try {
|
||||
if (post('postback')) {
|
||||
return $this->restore_onSubmit();
|
||||
}
|
||||
} catch (Exception $ex) {
|
||||
Flash::error($ex->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits the restore form.
|
||||
*/
|
||||
public function restore_onSubmit()
|
||||
{
|
||||
// Force Trusted Host verification on password reset link generation
|
||||
// regardless of config to protect against host header poisoning
|
||||
$trustedHosts = Config::get('app.trustedHosts', false);
|
||||
if ($trustedHosts === false) {
|
||||
$hosts = CheckForTrustedHost::processTrustedHosts(true);
|
||||
|
||||
if (count($hosts)) {
|
||||
Request::setTrustedHosts($hosts);
|
||||
|
||||
// Trigger the host validation logic
|
||||
Request::getHost();
|
||||
}
|
||||
}
|
||||
|
||||
$rules = [
|
||||
'login' => 'required|between:2,255'
|
||||
];
|
||||
|
||||
$validation = Validator::make(post(), $rules);
|
||||
if ($validation->fails()) {
|
||||
throw new ValidationException($validation);
|
||||
}
|
||||
|
||||
$user = BackendAuth::findUserByLogin(post('login'));
|
||||
|
||||
if ($user) {
|
||||
$code = $user->getResetPasswordCode();
|
||||
$link = Backend::url('backend/auth/reset/' . $user->id . '/' . $code);
|
||||
|
||||
$data = [
|
||||
'name' => $user->full_name,
|
||||
'link' => $link,
|
||||
];
|
||||
|
||||
Mail::send('backend::mail.restore', $data, function ($message) use ($user) {
|
||||
$message->to($user->email, $user->full_name)->subject(trans('backend::lang.account.password_reset'));
|
||||
});
|
||||
}
|
||||
|
||||
Flash::success(trans('backend::lang.account.restore_success'));
|
||||
|
||||
return Backend::redirect('backend/auth/signin');
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset backend user password using verification code.
|
||||
*/
|
||||
public function reset($userId = null, $code = null)
|
||||
{
|
||||
$this->bodyClass = 'reset';
|
||||
|
||||
try {
|
||||
if (post('postback')) {
|
||||
return $this->reset_onSubmit();
|
||||
}
|
||||
|
||||
if (!$userId || !$code) {
|
||||
throw new ApplicationException(trans('backend::lang.account.reset_error'));
|
||||
}
|
||||
} catch (Exception $ex) {
|
||||
Flash::error($ex->getMessage());
|
||||
}
|
||||
|
||||
$this->vars['code'] = $code;
|
||||
$this->vars['id'] = $userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits the reset form.
|
||||
*/
|
||||
public function reset_onSubmit()
|
||||
{
|
||||
if (!post('id') || !post('code')) {
|
||||
throw new ApplicationException(trans('backend::lang.account.reset_error'));
|
||||
}
|
||||
|
||||
$rules = [
|
||||
'password' => 'required|between:4,255'
|
||||
];
|
||||
|
||||
$validation = Validator::make(post(), $rules);
|
||||
if ($validation->fails()) {
|
||||
throw new ValidationException($validation);
|
||||
}
|
||||
|
||||
$code = post('code');
|
||||
$user = BackendAuth::findUserById(post('id'));
|
||||
|
||||
if (!$user || !$user->checkResetPasswordCode($code)) {
|
||||
throw new ApplicationException(trans('backend::lang.account.reset_error'));
|
||||
}
|
||||
|
||||
if (!$user->attemptResetPassword($code, post('password'))) {
|
||||
throw new ApplicationException(trans('backend::lang.account.reset_fail'));
|
||||
}
|
||||
|
||||
$user->clearResetPassword();
|
||||
|
||||
Flash::success(trans('backend::lang.account.reset_success'));
|
||||
|
||||
return Backend::redirect('backend/auth/signin');
|
||||
}
|
||||
}
|
||||
196
modules/backend/controllers/Files.php
Normal file
196
modules/backend/controllers/Files.php
Normal file
@@ -0,0 +1,196 @@
|
||||
<?php namespace Backend\Controllers;
|
||||
|
||||
use View;
|
||||
use Cache;
|
||||
use Config;
|
||||
use Backend;
|
||||
use Response;
|
||||
use System\Models\File as FileModel;
|
||||
use Backend\Classes\Controller;
|
||||
use ApplicationException;
|
||||
use Exception;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Backend files controller
|
||||
*
|
||||
* Used for delivering protected system files, and generating URLs
|
||||
* for accessing them.
|
||||
*
|
||||
* @package winter\wn-backend-module
|
||||
* @author Alexey Bobkov, Samuel Georges
|
||||
*
|
||||
*/
|
||||
class Files extends Controller
|
||||
{
|
||||
/**
|
||||
* Output file, or fall back on the 404 page
|
||||
*/
|
||||
public function get($code = null)
|
||||
{
|
||||
try {
|
||||
return $this->findFileObject($code)->output('inline', true);
|
||||
}
|
||||
catch (Exception $ex) {
|
||||
}
|
||||
|
||||
return Response::make(View::make('backend::404'), 404);
|
||||
}
|
||||
|
||||
/**
|
||||
* Output thumbnail, or fall back on the 404 page
|
||||
*/
|
||||
public function thumb($code = null, $width = 100, $height = 100, $mode = 'auto', $extension = 'auto')
|
||||
{
|
||||
try {
|
||||
return $this->findFileObject($code)->outputThumb(
|
||||
$width,
|
||||
$height,
|
||||
compact('mode', 'extension'),
|
||||
true
|
||||
);
|
||||
}
|
||||
catch (Exception $ex) {
|
||||
}
|
||||
|
||||
return Response::make(View::make('backend::404'), 404);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to return a redirect to a temporary URL to the asset instead of streaming the asset - if supported
|
||||
*
|
||||
* @param System|Models\File $file
|
||||
* @param string|null $path Optional, defaults to the getDiskPath() of the file
|
||||
* @return string|null
|
||||
*/
|
||||
protected static function getTemporaryUrl($file, $path = null)
|
||||
{
|
||||
// Get the disk used
|
||||
$disk = $file->getDisk();
|
||||
|
||||
if (empty($path)) {
|
||||
$path = $file->getDiskPath();
|
||||
}
|
||||
|
||||
// Check to see if the URL has already been generated
|
||||
$pathKey = 'backend.file:' . $path;
|
||||
$url = Cache::get($pathKey, null);
|
||||
|
||||
if (is_null($url) && $disk->exists($path)) {
|
||||
$expires = now()->addSeconds(Config::get('cms.storage.uploads.temporaryUrlTTL', 3600));
|
||||
$url = Cache::remember($pathKey, $expires, function () use ($disk, $path, $expires) {
|
||||
// Attempt to generate a temporary URL, if a RuntimeException occurs it's "probably"
|
||||
// because the driver doesn't support that method
|
||||
try {
|
||||
return $disk->temporaryUrl($path, $expires);
|
||||
} catch (RuntimeException $ex) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Limit the return types to strings or null
|
||||
if (!is_string($url) || empty($url)) {
|
||||
$url = null;
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL for downloading a system file.
|
||||
* @param $file System\Models\File
|
||||
* @return string
|
||||
*/
|
||||
public static function getDownloadUrl($file)
|
||||
{
|
||||
$url = static::getTemporaryUrl($file);
|
||||
|
||||
if (!empty($url)) {
|
||||
return $url;
|
||||
} else {
|
||||
return Backend::url('backend/files/get/' . self::getUniqueCode($file));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL for downloading a system file.
|
||||
* @param $file System\Models\File
|
||||
* @param $width int
|
||||
* @param $height int
|
||||
* @param $options array
|
||||
* @return string
|
||||
*/
|
||||
public static function getThumbUrl($file, $width, $height, $options)
|
||||
{
|
||||
$url = static::getTemporaryUrl($file, $file->getDiskPath($file->getThumbFilename($width, $height, $options)));
|
||||
|
||||
if (!empty($url)) {
|
||||
return $url;
|
||||
} else {
|
||||
return Backend::url('backend/files/thumb/' . self::getUniqueCode($file)) . '/' . $width . '/' . $height . '/' . $options['mode'] . '/' . $options['extension'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a unique code used for masking the file identifier.
|
||||
* @param $file System\Models\File
|
||||
* @return string
|
||||
*/
|
||||
public static function getUniqueCode($file)
|
||||
{
|
||||
if (!$file) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$hash = md5($file->file_name . '!' . $file->disk_name);
|
||||
return base64_encode($file->id . '!' . $hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locates a file model based on the unique code.
|
||||
* @param $code string
|
||||
* @return System\Models\File
|
||||
*/
|
||||
protected function findFileObject($code)
|
||||
{
|
||||
if (!$code) {
|
||||
throw new ApplicationException('Missing code');
|
||||
}
|
||||
|
||||
$parts = explode('!', base64_decode($code));
|
||||
if (count($parts) < 2) {
|
||||
throw new ApplicationException('Invalid code');
|
||||
}
|
||||
|
||||
list($id, $hash) = $parts;
|
||||
|
||||
if (!$file = FileModel::find((int) $id)) {
|
||||
throw new ApplicationException('Unable to find file');
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the file model utilized for this request is
|
||||
* the one specified in the relationship configuration
|
||||
*/
|
||||
if ($file->attachment) {
|
||||
$fileModel = $file->attachment->{$file->field}()->getRelated();
|
||||
|
||||
/**
|
||||
* Only attempt to get file model through its assigned class
|
||||
* when the assigned class differs from the default one that
|
||||
* the file has already been loaded from
|
||||
*/
|
||||
if (get_class($file) !== get_class($fileModel)) {
|
||||
$file = $fileModel->find($file->id);
|
||||
}
|
||||
}
|
||||
|
||||
$verifyCode = self::getUniqueCode($file);
|
||||
if ($code != $verifyCode) {
|
||||
throw new ApplicationException('Invalid hash');
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
81
modules/backend/controllers/Index.php
Normal file
81
modules/backend/controllers/Index.php
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php namespace Backend\Controllers;
|
||||
|
||||
use Backend;
|
||||
use Redirect;
|
||||
use BackendMenu;
|
||||
use Backend\Classes\Controller;
|
||||
use Backend\Widgets\ReportContainer;
|
||||
|
||||
/**
|
||||
* Dashboard controller
|
||||
*
|
||||
* @package winter\wn-backend-module
|
||||
* @author Alexey Bobkov, Samuel Georges
|
||||
*
|
||||
*/
|
||||
class Index extends Controller
|
||||
{
|
||||
use \Backend\Traits\InspectableContainer;
|
||||
|
||||
/**
|
||||
* @var array Permissions required to view this page.
|
||||
* @see checkPermissionRedirect()
|
||||
*/
|
||||
public $requiredPermissions = [];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
BackendMenu::setContextOwner('Winter.Backend');
|
||||
|
||||
$this->addCss('/modules/backend/assets/css/dashboard/dashboard.css', 'core');
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
if ($redirect = $this->checkPermissionRedirect()) {
|
||||
return $redirect;
|
||||
}
|
||||
|
||||
$this->initReportContainer();
|
||||
|
||||
$this->pageTitle = 'backend::lang.dashboard.menu_label';
|
||||
|
||||
BackendMenu::setContextMainMenu('dashboard');
|
||||
}
|
||||
|
||||
public function index_onInitReportContainer()
|
||||
{
|
||||
$this->initReportContainer();
|
||||
|
||||
return ['#dashReportContainer' => $this->widget->reportContainer->render()];
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the report widget used by the dashboard
|
||||
* @param Model $model
|
||||
* @return void
|
||||
*/
|
||||
protected function initReportContainer()
|
||||
{
|
||||
new ReportContainer($this, 'config_dashboard.yaml');
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom permissions check that will redirect to the next
|
||||
* available menu item, if permission to this page is denied.
|
||||
*/
|
||||
protected function checkPermissionRedirect()
|
||||
{
|
||||
if (!$this->user->hasAccess('backend.access_dashboard')) {
|
||||
if ($first = array_first(BackendMenu::listMainMenuItems())) {
|
||||
return Redirect::intended($first->url);
|
||||
}
|
||||
return Backend::redirect('backend/myaccount');
|
||||
}
|
||||
}
|
||||
}
|
||||
38
modules/backend/controllers/Media.php
Normal file
38
modules/backend/controllers/Media.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php namespace Backend\Controllers;
|
||||
|
||||
use BackendMenu;
|
||||
use Backend\Classes\Controller;
|
||||
use Backend\Widgets\MediaManager;
|
||||
|
||||
/**
|
||||
* Backend Media Manager
|
||||
*
|
||||
* @package winter\wn-backend-module
|
||||
* @author Alexey Bobkov, Samuel Georges
|
||||
*/
|
||||
class Media extends Controller
|
||||
{
|
||||
/**
|
||||
* @var array Permissions required to view this page.
|
||||
*/
|
||||
public $requiredPermissions = ['media.*'];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
BackendMenu::setContext('Winter.Backend', 'media', true);
|
||||
$this->pageTitle = 'backend::lang.media.menu_label';
|
||||
|
||||
$manager = new MediaManager($this, 'manager');
|
||||
$manager->bindToController();
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$this->bodyClass = 'compact-container';
|
||||
}
|
||||
}
|
||||
92
modules/backend/controllers/MyAccount.php
Normal file
92
modules/backend/controllers/MyAccount.php
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
namespace Backend\Controllers;
|
||||
|
||||
use Backend\Behaviors\FormController;
|
||||
use Backend\Classes\Controller;
|
||||
use Backend\Facades\BackendAuth;
|
||||
use Backend\Facades\BackendMenu;
|
||||
use System\Classes\SettingsManager;
|
||||
use Winter\Storm\Database\Builder;
|
||||
|
||||
/**
|
||||
* My Account controller
|
||||
*
|
||||
* Allows any authenticated backend user to manage their own account settings.
|
||||
* Isolated from the Users controller to prevent privilege escalation via
|
||||
* handler dispatch on a controller with degraded permissions.
|
||||
*
|
||||
* @package winter\wn-backend-module
|
||||
* @author Winter CMS
|
||||
*/
|
||||
class MyAccount extends Controller
|
||||
{
|
||||
/**
|
||||
* @var array Extensions implemented by this controller.
|
||||
*/
|
||||
public $implement = [
|
||||
FormController::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array methods that are blocked from being called as actions
|
||||
*/
|
||||
protected $guarded = ['create', 'update', 'preview'];
|
||||
|
||||
/**
|
||||
* @var array Permissions required to view this page.
|
||||
* Empty array — any logged-in user can access their own account.
|
||||
*/
|
||||
public $requiredPermissions = [];
|
||||
|
||||
/**
|
||||
* @var string HTML body tag class
|
||||
*/
|
||||
public $bodyClass = 'compact-container';
|
||||
|
||||
public $formLayout = 'sidebar';
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
BackendMenu::setContext('Winter.System', 'system', 'users');
|
||||
SettingsManager::setContext('Winter.Backend', 'myaccount');
|
||||
}
|
||||
|
||||
public function formExtendQuery(Builder $query): void
|
||||
{
|
||||
$query->whereKey($this->user->getKey());
|
||||
}
|
||||
|
||||
/**
|
||||
* My Account page
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$this->pageTitle = 'backend::lang.myaccount.menu_label';
|
||||
return $this->asExtension('FormController')->update($this->user->id, 'myaccount');
|
||||
}
|
||||
|
||||
/**
|
||||
* Save handler for the My Account form
|
||||
*/
|
||||
public function index_onSave()
|
||||
{
|
||||
$result = $this->asExtension('FormController')->update_onSave($this->user->id, 'myaccount');
|
||||
|
||||
/*
|
||||
* If the password or login name has been updated, reauthenticate the user
|
||||
*/
|
||||
$loginChanged = $this->user->login != post('User[login]');
|
||||
$passwordChanged = strlen(post('User[password]'));
|
||||
if ($loginChanged || $passwordChanged) {
|
||||
BackendAuth::login($this->user->reload(), true);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
79
modules/backend/controllers/Preferences.php
Normal file
79
modules/backend/controllers/Preferences.php
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php namespace Backend\Controllers;
|
||||
|
||||
use Backend\Classes\Controller;
|
||||
use Backend\Facades\Backend;
|
||||
use Backend\Facades\BackendMenu;
|
||||
use Backend\Models\Preference as PreferenceModel;
|
||||
use Illuminate\Support\Facades\Lang;
|
||||
use System\Classes\SettingsManager;
|
||||
use Winter\Storm\Exception\ApplicationException;
|
||||
use Winter\Storm\Support\Facades\File;
|
||||
use Winter\Storm\Support\Facades\Flash;
|
||||
|
||||
/**
|
||||
* Editor Settings controller
|
||||
*
|
||||
* @package winter\wn-backend-module
|
||||
* @author Alexey Bobkov, Samuel Georges
|
||||
*
|
||||
*/
|
||||
class Preferences extends Controller
|
||||
{
|
||||
public $implement = [
|
||||
\Backend\Behaviors\FormController::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array Permissions required to view this page.
|
||||
*/
|
||||
public $requiredPermissions = ['backend.manage_preferences'];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->addJs('/modules/backend/assets/js/preferences/preferences.js', 'core');
|
||||
|
||||
BackendMenu::setContext('Winter.System', 'system', 'mysettings');
|
||||
SettingsManager::setContext('Winter.Backend', 'preferences');
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$this->pageTitle = 'backend::lang.backend_preferences.menu_label';
|
||||
$this->asExtension('FormController')->update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the code editor tab if there is no permission.
|
||||
*/
|
||||
public function formExtendFields($form)
|
||||
{
|
||||
if (!$this->user->hasAccess('backend.manage_own_editor')) {
|
||||
$form->removeTab('backend::lang.backend_preferences.code_editor');
|
||||
}
|
||||
}
|
||||
|
||||
public function index_onSave()
|
||||
{
|
||||
return $this->asExtension('FormController')->update_onSave();
|
||||
}
|
||||
|
||||
public function index_onResetDefault()
|
||||
{
|
||||
$model = $this->formFindModelObject();
|
||||
$model->resetDefault();
|
||||
|
||||
Flash::success(Lang::get('backend::lang.form.reset_success'));
|
||||
|
||||
return Backend::redirect('backend/preferences');
|
||||
}
|
||||
|
||||
public function formFindModelObject()
|
||||
{
|
||||
return PreferenceModel::instance();
|
||||
}
|
||||
}
|
||||
39
modules/backend/controllers/UserGroups.php
Normal file
39
modules/backend/controllers/UserGroups.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php namespace Backend\Controllers;
|
||||
|
||||
use BackendMenu;
|
||||
use Backend\Classes\Controller;
|
||||
use System\Classes\SettingsManager;
|
||||
|
||||
/**
|
||||
* Backend user groups controller
|
||||
*
|
||||
* @package winter\wn-backend-module
|
||||
* @author Alexey Bobkov, Samuel Georges
|
||||
*
|
||||
*/
|
||||
class UserGroups extends Controller
|
||||
{
|
||||
/**
|
||||
* @var array Extensions implemented by this controller.
|
||||
*/
|
||||
public $implement = [
|
||||
\Backend\Behaviors\FormController::class,
|
||||
\Backend\Behaviors\ListController::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array Permissions required to view this page.
|
||||
*/
|
||||
public $requiredPermissions = ['backend.manage_users'];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
BackendMenu::setContext('Winter.System', 'system', 'users');
|
||||
SettingsManager::setContext('Winter.System', 'administrators');
|
||||
}
|
||||
}
|
||||
51
modules/backend/controllers/UserRoles.php
Normal file
51
modules/backend/controllers/UserRoles.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace Backend\Controllers;
|
||||
|
||||
use Backend\Classes\Controller;
|
||||
use Backend\Facades\BackendMenu;
|
||||
use System\Classes\SettingsManager;
|
||||
|
||||
/**
|
||||
* Backend user groups controller
|
||||
*
|
||||
* @package winter\wn-backend-module
|
||||
* @author Alexey Bobkov, Samuel Georges
|
||||
*
|
||||
*/
|
||||
class UserRoles extends Controller
|
||||
{
|
||||
/**
|
||||
* @var array Extensions implemented by this controller.
|
||||
*/
|
||||
public $implement = [
|
||||
\Backend\Behaviors\FormController::class,
|
||||
\Backend\Behaviors\ListController::class,
|
||||
\Backend\Behaviors\RelationController::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array Permissions required to view this page.
|
||||
*/
|
||||
public $requiredPermissions = ['backend.manage_users'];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
BackendMenu::setContext('Winter.System', 'system', 'users');
|
||||
SettingsManager::setContext('Winter.System', 'administrators');
|
||||
|
||||
/*
|
||||
* Only super users can access
|
||||
*/
|
||||
$this->bindEvent('page.beforeDisplay', function () {
|
||||
if (!$this->user->isSuperUser()) {
|
||||
abort(403);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
258
modules/backend/controllers/Users.php
Normal file
258
modules/backend/controllers/Users.php
Normal file
@@ -0,0 +1,258 @@
|
||||
<?php
|
||||
|
||||
namespace Backend\Controllers;
|
||||
|
||||
use Backend\Behaviors\FormController;
|
||||
use Backend\Behaviors\ListController;
|
||||
use Backend\Behaviors\RelationController;
|
||||
use Backend\Classes\Controller;
|
||||
use Backend\Facades\Backend;
|
||||
use Backend\Facades\BackendAuth;
|
||||
use Backend\Facades\BackendMenu;
|
||||
use Backend\Models\UserGroup;
|
||||
use Illuminate\Support\Facades\Lang;
|
||||
use Illuminate\Support\Facades\Redirect;
|
||||
use Illuminate\Support\Facades\Response;
|
||||
use Illuminate\Support\Str;
|
||||
use System\Classes\SettingsManager;
|
||||
use Winter\Storm\Support\Facades\Flash;
|
||||
use Winter\Storm\Support\Facades\Mail;
|
||||
|
||||
/**
|
||||
* Backend user controller
|
||||
*
|
||||
* @package winter\wn-backend-module
|
||||
* @author Alexey Bobkov, Samuel Georges
|
||||
*
|
||||
*/
|
||||
class Users extends Controller
|
||||
{
|
||||
/**
|
||||
* @var array Extensions implemented by this controller.
|
||||
*/
|
||||
public $implement = [
|
||||
FormController::class,
|
||||
ListController::class,
|
||||
RelationController::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array Permissions required to view this page.
|
||||
*/
|
||||
public $requiredPermissions = ['backend.manage_users'];
|
||||
|
||||
/**
|
||||
* @var string HTML body tag class
|
||||
*/
|
||||
public $bodyClass = 'compact-container';
|
||||
|
||||
public $formLayout = 'sidebar';
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
BackendMenu::setContext('Winter.System', 'system', 'users');
|
||||
SettingsManager::setContext('Winter.System', 'administrators');
|
||||
}
|
||||
|
||||
/**
|
||||
* Extends the list query to hide superusers if the current user is not a superuser themselves
|
||||
*/
|
||||
public function listExtendQuery($query)
|
||||
{
|
||||
if (!$this->user->isSuperUser()) {
|
||||
$query->where('is_superuser', false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevents non-superusers from even seeing the is_superuser filter
|
||||
*/
|
||||
public function listFilterExtendScopes($filterWidget)
|
||||
{
|
||||
if (!$this->user->isSuperUser()) {
|
||||
$filterWidget->removeScope('is_superuser');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Strike out deleted records
|
||||
*/
|
||||
public function listInjectRowClass($record, $definition = null)
|
||||
{
|
||||
if ($record->trashed()) {
|
||||
return 'strike';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extends the form query to prevent non-superusers from accessing superusers at all
|
||||
*/
|
||||
public function formExtendQuery($query)
|
||||
{
|
||||
if (!$this->user->isSuperUser()) {
|
||||
$query->where('is_superuser', false);
|
||||
}
|
||||
|
||||
// Ensure soft-deleted records can still be managed
|
||||
$query->withTrashed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Before creating a new user, generate password if auto-generate is enabled
|
||||
*/
|
||||
public function formBeforeCreate($model)
|
||||
{
|
||||
if (post('User._auto_generate_password')) {
|
||||
$password = Str::random(22);
|
||||
$model->password = $password;
|
||||
$model->password_confirmation = $password;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update controller
|
||||
*/
|
||||
public function update($recordId, $context = null)
|
||||
{
|
||||
// Users cannot edit themselves, only use My Account
|
||||
if ($context != 'myaccount' && $recordId == $this->user->id) {
|
||||
return Backend::redirect('backend/myaccount');
|
||||
}
|
||||
|
||||
return $this->asExtension('FormController')->update($recordId, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle restoring users
|
||||
*/
|
||||
public function update_onRestore($recordId)
|
||||
{
|
||||
$this->formFindModelObject($recordId)->restore();
|
||||
|
||||
Flash::success(Lang::get('backend::lang.form.restore_success', ['name' => Lang::get('backend::lang.user.name')]));
|
||||
|
||||
return Redirect::refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* Impersonate this user
|
||||
*/
|
||||
public function update_onImpersonateUser($recordId)
|
||||
{
|
||||
if (!$this->user->hasAccess('backend.impersonate_users')) {
|
||||
return Response::make(Lang::get('backend::lang.page.access_denied.label'), 403);
|
||||
}
|
||||
|
||||
$model = $this->formFindModelObject($recordId);
|
||||
|
||||
BackendAuth::impersonate($model);
|
||||
|
||||
Flash::success(Lang::get('backend::lang.account.impersonate_success'));
|
||||
|
||||
return Backend::redirect('backend/myaccount');
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsuspend this user
|
||||
*/
|
||||
public function update_onUnsuspendUser($recordId)
|
||||
{
|
||||
$model = $this->formFindModelObject($recordId);
|
||||
|
||||
$model->unsuspend();
|
||||
|
||||
Flash::success(Lang::get('backend::lang.account.unsuspend_success'));
|
||||
|
||||
return Redirect::refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* Backward compatibility redirect to the new MyAccount controller.
|
||||
*/
|
||||
public function myaccount()
|
||||
{
|
||||
return Backend::redirect('backend/myaccount');
|
||||
}
|
||||
|
||||
/**
|
||||
* Add available permission fields to the User form.
|
||||
* Mark default groups as checked for new Users.
|
||||
*/
|
||||
public function formExtendFields($form)
|
||||
{
|
||||
if ($form->getContext() == 'myaccount') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$this->user->isSuperUser()) {
|
||||
$form->removeField('is_superuser');
|
||||
}
|
||||
|
||||
/*
|
||||
* Add permissions tab
|
||||
*/
|
||||
$form->addTabFields($this->generatePermissionsField());
|
||||
|
||||
/*
|
||||
* Mark default groups
|
||||
*/
|
||||
if (!$form->model->exists) {
|
||||
$defaultGroupIds = UserGroup::where('is_new_user_default', true)->lists('id');
|
||||
|
||||
$groupField = $form->getField('groups');
|
||||
if ($groupField) {
|
||||
$groupField->value = $defaultGroupIds;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the permissions editor widget to the form.
|
||||
* @return array
|
||||
*/
|
||||
protected function generatePermissionsField()
|
||||
{
|
||||
return [
|
||||
'permissions' => [
|
||||
'tab' => 'backend::lang.user.permissions',
|
||||
'type' => 'Backend\FormWidgets\PermissionEditor',
|
||||
'trigger' => [
|
||||
'action' => 'disable',
|
||||
'field' => 'is_superuser',
|
||||
'condition' => 'checked'
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Send password reset mail
|
||||
*/
|
||||
public function update_onManualPasswordReset($recordId)
|
||||
{
|
||||
$user = $this->formFindModelObject($recordId);
|
||||
|
||||
if ($user) {
|
||||
$code = $user->getResetPasswordCode();
|
||||
$link = Backend::url('backend/auth/reset/' . $user->id . '/' . $code);
|
||||
|
||||
$data = [
|
||||
'name' => $user->full_name,
|
||||
'link' => $link,
|
||||
];
|
||||
|
||||
Mail::send('backend::mail.restore', $data, function ($message) use ($user) {
|
||||
$message->to($user->email, $user->full_name)->subject(trans('backend::lang.account.password_reset'));
|
||||
});
|
||||
}
|
||||
|
||||
Flash::success(Lang::get('backend::lang.account.manual_password_reset_success'));
|
||||
|
||||
return Redirect::refresh();
|
||||
}
|
||||
}
|
||||
4
modules/backend/controllers/accesslogs/_hint.php
Normal file
4
modules/backend/controllers/accesslogs/_hint.php
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
<p>
|
||||
<?= e(trans('backend::lang.access_log.hint', ['days' => 60])) ?>
|
||||
</p>
|
||||
9
modules/backend/controllers/accesslogs/_list_toolbar.php
Normal file
9
modules/backend/controllers/accesslogs/_list_toolbar.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<div data-control="toolbar" class="loading-indicator-container">
|
||||
<a
|
||||
href="javascript:;"
|
||||
data-request="onRefresh"
|
||||
data-load-indicator="<?= e(trans('backend::lang.list.updating')) ?>"
|
||||
class="btn btn-primary wn-icon-refresh">
|
||||
<?= e(trans('backend::lang.list.refresh')) ?>
|
||||
</a>
|
||||
</div>
|
||||
16
modules/backend/controllers/accesslogs/config_filter.yaml
Normal file
16
modules/backend/controllers/accesslogs/config_filter.yaml
Normal file
@@ -0,0 +1,16 @@
|
||||
# ===================================
|
||||
# Filter Scope Definitions
|
||||
# ===================================
|
||||
|
||||
scopes:
|
||||
|
||||
created_at:
|
||||
label: backend::lang.access_log.created_at
|
||||
type: daterange
|
||||
conditions: created_at >= ':after' AND created_at <= ':before'
|
||||
|
||||
user:
|
||||
label: backend::lang.access_log.login
|
||||
modelClass: Backend\Models\User
|
||||
conditions: user_id in (:filtered)
|
||||
nameFrom: login
|
||||
17
modules/backend/controllers/accesslogs/config_list.yaml
Normal file
17
modules/backend/controllers/accesslogs/config_list.yaml
Normal file
@@ -0,0 +1,17 @@
|
||||
# ===================================
|
||||
# List Behavior Config
|
||||
# ===================================
|
||||
|
||||
title: backend::lang.access_log.menu_label
|
||||
list: ~/modules/backend/models/accesslog/columns.yaml
|
||||
modelClass: Backend\Models\AccessLog
|
||||
noRecordsMessage: backend::lang.list.no_records
|
||||
recordsPerPage: 30
|
||||
showSetup: true
|
||||
|
||||
toolbar:
|
||||
buttons: list_toolbar
|
||||
search:
|
||||
prompt: backend::lang.list.search_prompt
|
||||
|
||||
filter: config_filter.yaml
|
||||
5
modules/backend/controllers/accesslogs/index.php
Normal file
5
modules/backend/controllers/accesslogs/index.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<div class="padded-container container-flush">
|
||||
<?= $this->makeHintPartial('backend_accesslogs_hint', 'hint') ?>
|
||||
</div>
|
||||
|
||||
<?= $this->listRender() ?>
|
||||
33
modules/backend/controllers/auth/reset.php
Normal file
33
modules/backend/controllers/auth/reset.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<h2><?= e(trans('backend::lang.account.enter_new_password')) ?></h2>
|
||||
|
||||
<?= Form::open() ?>
|
||||
<input type="hidden" name="postback" value="1" />
|
||||
<input type="hidden" name="id" value="<?= e($id) ?>" />
|
||||
<input type="hidden" name="code" value="<?= e($code) ?>" />
|
||||
|
||||
<div class="form-elements" role="form">
|
||||
<div class="form-group text-field horizontal-form">
|
||||
|
||||
<!-- Password -->
|
||||
<input
|
||||
type="password"
|
||||
name="password"
|
||||
value=""
|
||||
class="form-control password icon lock"
|
||||
placeholder="<?= e(trans('backend::lang.account.password_placeholder')) ?>"
|
||||
autocomplete="off"
|
||||
maxlength="255" />
|
||||
|
||||
<!-- Submit Login -->
|
||||
<button type="submit" class="btn btn-primary pull-right">
|
||||
<?= e(trans('backend::lang.account.reset')) ?>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<p class="pull-right forgot-password">
|
||||
<a href="<?= Backend::url('backend/auth') ?>" class="text-muted">
|
||||
<?= e(trans('backend::lang.form.cancel')) ?>
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
<?= Form::close() ?>
|
||||
31
modules/backend/controllers/auth/restore.php
Normal file
31
modules/backend/controllers/auth/restore.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<h2><?= e(trans('backend::lang.account.enter_login')) ?></h2>
|
||||
|
||||
<?= Form::open() ?>
|
||||
<input type="hidden" name="postback" value="1" />
|
||||
|
||||
<div class="form-elements" role="form">
|
||||
<div class="form-group text-field horizontal-form">
|
||||
|
||||
<input
|
||||
type="text"
|
||||
name="login"
|
||||
value="<?= e(post('login')) ?>"
|
||||
class="form-control icon user"
|
||||
placeholder="<?= e(trans('backend::lang.account.login_placeholder')) ?>"
|
||||
autocomplete="off"
|
||||
maxlength="255" />
|
||||
|
||||
<button type="submit" class="btn btn-primary restore-button">
|
||||
<?= e(trans('backend::lang.account.restore')) ?>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<p class="pull-right forgot-password">
|
||||
<a href="<?= Backend::url('backend/auth') ?>" class="text-muted">
|
||||
<?= e(trans('backend::lang.form.cancel')) ?>
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
<?= Form::close() ?>
|
||||
|
||||
<?= $this->fireViewEvent('backend.auth.extendRestoreView') ?>
|
||||
60
modules/backend/controllers/auth/signin.php
Normal file
60
modules/backend/controllers/auth/signin.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<h2><?= e(Backend\Models\BrandSetting::get('app_tagline')) ?></h2>
|
||||
|
||||
<?= Form::open() ?>
|
||||
<input type="hidden" name="postback" value="1" />
|
||||
|
||||
<div class="form-elements" role="form">
|
||||
<div class="form-group text-field horizontal-form">
|
||||
|
||||
<!-- Login -->
|
||||
<input
|
||||
type="text"
|
||||
name="login"
|
||||
value="<?= e(post('login')) ?>"
|
||||
class="form-control icon user"
|
||||
placeholder="<?= e(trans('backend::lang.account.login_placeholder')) ?>"
|
||||
autocomplete="off"
|
||||
maxlength="255" />
|
||||
|
||||
<!-- Password -->
|
||||
<input
|
||||
type="password"
|
||||
name="password"
|
||||
value=""
|
||||
class="form-control icon lock"
|
||||
placeholder="<?= e(trans('backend::lang.account.password_placeholder')) ?>"
|
||||
autocomplete="off"
|
||||
maxlength="255" />
|
||||
|
||||
<!-- Submit Login -->
|
||||
<button type="submit" class="btn btn-primary login-button">
|
||||
<?= e(trans('backend::lang.account.login')) ?>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<?php if (is_null(config('cms.backendForceRemember', true))): ?>
|
||||
<!-- Remember checkbox -->
|
||||
<div class="form-group checkbox-field horizontal-form remember">
|
||||
<div class="checkbox custom-checkbox">
|
||||
<input
|
||||
type="checkbox"
|
||||
id="remember"
|
||||
name="remember" />
|
||||
<label for="remember">
|
||||
<?= e(trans('backend::lang.account.remember_me')) ?>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<p class="wn-icon-lock pull-right forgot-password">
|
||||
<!-- Forgot your password? -->
|
||||
<a href="<?= Backend::url('backend/auth/restore') ?>" class="text-muted">
|
||||
<?= e(trans('backend::lang.account.forgot_password')) ?>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
<?= Form::close() ?>
|
||||
|
||||
<?= $this->fireViewEvent('backend.auth.extendSigninView') ?>
|
||||
23
modules/backend/controllers/index/config_dashboard.yaml
Normal file
23
modules/backend/controllers/index/config_dashboard.yaml
Normal file
@@ -0,0 +1,23 @@
|
||||
# ===================================
|
||||
# Dashboard Config
|
||||
# ===================================
|
||||
|
||||
defaultWidgets:
|
||||
|
||||
welcome:
|
||||
class: Backend\ReportWidgets\Welcome
|
||||
sortOrder: 50
|
||||
configuration:
|
||||
ocWidgetWidth: 7
|
||||
|
||||
systemStatus:
|
||||
class: System\ReportWidgets\Status
|
||||
sortOrder: 60
|
||||
configuration:
|
||||
ocWidgetWidth: 7
|
||||
|
||||
activeTheme:
|
||||
class: Cms\ReportWidgets\ActiveTheme
|
||||
sortOrder: 70
|
||||
configuration:
|
||||
ocWidgetWidth: 5
|
||||
23
modules/backend/controllers/index/index.php
Normal file
23
modules/backend/controllers/index/index.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?= Form::open(['class'=>'layout-relative dashboard-container']) ?>
|
||||
<div id="dashReportContainer" class="report-container loading">
|
||||
<!-- Loading -->
|
||||
<div class="loading-indicator-container">
|
||||
<div class="loading-indicator indicator-center">
|
||||
<span></span>
|
||||
<div><?= e(trans('backend::lang.list.loading')) ?></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?= Form::close() ?>
|
||||
|
||||
<?php Block::put('head'); ?>
|
||||
<script>
|
||||
Snowboard.ready(() => {
|
||||
Snowboard.request(null, 'onInitReportContainer', {
|
||||
success: () => {
|
||||
$('#dashReportContainer').removeClass('loading');
|
||||
},
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<?php Block::endPut(true); ?>
|
||||
5
modules/backend/controllers/media/index.php
Normal file
5
modules/backend/controllers/media/index.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?= Block::put('body') ?>
|
||||
<?= Form::open(['class'=>'layout', 'onsubmit'=>'return false']) ?>
|
||||
<?= $this->widget->manager->render() ?>
|
||||
<?= Form::close() ?>
|
||||
<?= Block::endPut() ?>
|
||||
12
modules/backend/controllers/myaccount/config_form.yaml
Normal file
12
modules/backend/controllers/myaccount/config_form.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
# ===================================
|
||||
# Form Behavior Config
|
||||
# ===================================
|
||||
|
||||
name: backend::lang.user.name
|
||||
form: ~/modules/backend/models/user/fields.yaml
|
||||
modelClass: Backend\Models\User
|
||||
defaultRedirect: backend/myaccount
|
||||
|
||||
update:
|
||||
redirect: backend/myaccount
|
||||
redirectClose: backend/myaccount
|
||||
56
modules/backend/controllers/myaccount/index.php
Normal file
56
modules/backend/controllers/myaccount/index.php
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php if ($this->user->hasAccess('backend.manage_users')): ?>
|
||||
<?php Block::put('breadcrumb') ?>
|
||||
<ul>
|
||||
<li><a href="<?= Backend::url('backend/users') ?>"><?= e(trans('backend::lang.user.menu_label')) ?></a></li>
|
||||
<li><?= e(trans($this->pageTitle)) ?></li>
|
||||
</ul>
|
||||
<?php Block::endPut() ?>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if (!$this->fatalError): ?>
|
||||
|
||||
<?php Block::put('form-contents') ?>
|
||||
<div class="layout">
|
||||
|
||||
<div class="layout-row">
|
||||
<?= $this->formRenderOutsideFields() ?>
|
||||
<?= $this->formRenderPrimaryTabs() ?>
|
||||
</div>
|
||||
|
||||
<div class="form-buttons">
|
||||
<div class="loading-indicator-container">
|
||||
<button
|
||||
type="submit"
|
||||
data-request="onSave"
|
||||
data-browser-validate
|
||||
data-request-data="redirect:0"
|
||||
data-hotkey="ctrl+s, cmd+s"
|
||||
data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>"
|
||||
class="btn btn-primary">
|
||||
<?= e(trans('backend::lang.form.save')) ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<?php Block::endPut() ?>
|
||||
|
||||
<?php Block::put('form-sidebar') ?>
|
||||
<div class="hide-tabs"><?= $this->formRenderSecondaryTabs() ?></div>
|
||||
<?php Block::endPut() ?>
|
||||
|
||||
<?php Block::put('body') ?>
|
||||
<?= Form::open(['class'=>'layout stretch']) ?>
|
||||
<?= $this->makeLayout('form-with-sidebar') ?>
|
||||
<?= Form::close() ?>
|
||||
<?php Block::endPut() ?>
|
||||
|
||||
<?php else: ?>
|
||||
<div class="control-breadcrumb">
|
||||
<?= Block::placeholder('breadcrumb') ?>
|
||||
</div>
|
||||
<div class="padded-container">
|
||||
<p class="flash-message static error"><?= e(trans($this->fatalError)) ?></p>
|
||||
<p><a href="<?= Backend::url('backend') ?>" class="btn btn-default"><?= e(trans('backend::lang.form.return_to_list')) ?></a></p>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
24
modules/backend/controllers/preferences/_example_code.php
Normal file
24
modules/backend/controllers/preferences/_example_code.php
Normal file
@@ -0,0 +1,24 @@
|
||||
form, fieldset, h5, h6, pre, blockquote, ol, dl, dt, dd, address, dd, dtm, div, td, th, hr {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* This is a comment */
|
||||
body {
|
||||
background-color: white;
|
||||
font: 62.5% Helvetica, Arial, Tahoma, Verdana, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
span.alert {
|
||||
color: #ff0000;
|
||||
border: 1px solid #ff0000;
|
||||
padding: 2rem;
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
<p class="help-block" style="margin-bottom: -15px">
|
||||
<?= e(trans('backend::lang.editor.preview')) ?>:
|
||||
<a href="#" data-switch-lang="css">CSS</a> |
|
||||
<a href="#" data-switch-lang="html">HTML</a> |
|
||||
<a href="#" data-switch-lang="javascript">JavaScript</a> |
|
||||
<a href="#" data-switch-lang="twig">Twig</a> |
|
||||
<a href="#" data-switch-lang="php">PHP</a>
|
||||
</p>
|
||||
|
||||
<script type="x-template" data-lang-snippet="css">
|
||||
form, fieldset, h5, h6, pre, blockquote, ol, dl, dt, dd, address, dd, dtm, div, td, th, hr {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* This is a comment */
|
||||
body {
|
||||
background-color: white;
|
||||
font: 62.5% Helvetica, Arial, Tahoma, Verdana, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
span.alert {
|
||||
color: #ff0000;
|
||||
border: 1px solid #ff0000;
|
||||
padding: 2rem;
|
||||
}
|
||||
</script>
|
||||
|
||||
<script type="x-template" data-lang-snippet="html">
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Winter CMS</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Winter CMS</h1>
|
||||
<!-- The number one platform for content management -->
|
||||
|
||||
<div class="container">
|
||||
<p style="font-weight: bold">Winter CMS is a free, open-source, self-hosted CMS platform based on the Laravel PHP Framework.</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</script>
|
||||
|
||||
<script type="x-template" data-lang-snippet="javascript">
|
||||
((Snowboard) => {
|
||||
class WinterCms extends Snowboard.PluginBase {
|
||||
|
||||
// Create a new function
|
||||
myFunction(arg) {
|
||||
arg = arg.toLowerCase();
|
||||
|
||||
return arg;
|
||||
}
|
||||
|
||||
counter() {
|
||||
let count = 0;
|
||||
count = count + 1;
|
||||
|
||||
return count;
|
||||
}
|
||||
}
|
||||
})(winter.Snowboard)
|
||||
</script>
|
||||
|
||||
<script type="x-template" data-lang-snippet="twig">
|
||||
<h1>My Winter Page - {{ title }}</h1>
|
||||
|
||||
{% if show %}
|
||||
<p>Winter is coming!</p>
|
||||
{% else %}
|
||||
<p>Winter is not coming!</p>
|
||||
{% endif %}
|
||||
|
||||
{% for item in items %}
|
||||
<p>{{ item }}</p>
|
||||
{% endfor %}
|
||||
</script>
|
||||
|
||||
<script type="x-template" data-lang-snippet="php">
|
||||
<?php echo '<?php
|
||||
|
||||
namespace Winter;
|
||||
|
||||
use \Package\AnotherClass as BaseClass;
|
||||
|
||||
/**
|
||||
* This is Winter CMS.
|
||||
*
|
||||
* @author Winter CMS maintainers
|
||||
*/
|
||||
class Winter extends Laravel implements Simplicity
|
||||
{
|
||||
const NAME = \'Winter CMS\';
|
||||
|
||||
public string $site = \'My site\';
|
||||
|
||||
// You can construct anything
|
||||
public function __construct($site)
|
||||
{
|
||||
$this->site = $site;
|
||||
$this->begin();
|
||||
}
|
||||
|
||||
protected function begin()
|
||||
{
|
||||
$this->achieveAwesome();
|
||||
}
|
||||
}'; ?>
|
||||
</script>
|
||||
8
modules/backend/controllers/preferences/config_form.yaml
Normal file
8
modules/backend/controllers/preferences/config_form.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
# ===================================
|
||||
# Form Behavior Config
|
||||
# ===================================
|
||||
|
||||
name: backend::lang.backend_preferences.menu_label
|
||||
form: ~/modules/backend/models/preference/fields.yaml
|
||||
modelClass: Backend\Models\Preference
|
||||
defaultRedirect: system/settings
|
||||
41
modules/backend/controllers/preferences/index.php
Normal file
41
modules/backend/controllers/preferences/index.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php if (!$this->fatalError): ?>
|
||||
|
||||
<?= Form::open(['class'=>'layout']) ?>
|
||||
|
||||
<div class="layout-row">
|
||||
<?= $this->formRender() ?>
|
||||
</div>
|
||||
|
||||
<div class="form-buttons">
|
||||
<div class="loading-indicator-container">
|
||||
<button
|
||||
type="submit"
|
||||
data-request="onSave"
|
||||
data-browser-validate
|
||||
data-request-data="redirect:0"
|
||||
data-hotkey="ctrl+s, cmd+s"
|
||||
data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>"
|
||||
class="btn btn-primary">
|
||||
<?= e(trans('backend::lang.form.save')) ?>
|
||||
</button>
|
||||
|
||||
<span class="btn-text">
|
||||
<?= e(trans('backend::lang.form.or')) ?> <a href="<?= Backend::url('system/settings') ?>"><?= e(trans('backend::lang.form.cancel')) ?></a>
|
||||
</span>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-danger pull-right"
|
||||
data-request="onResetDefault"
|
||||
data-load-indicator="<?= e(trans('backend::lang.form.resetting')) ?>"
|
||||
data-request-confirm="<?= e(trans('backend::lang.form.action_confirm')) ?>">
|
||||
<?= e(trans('backend::lang.form.reset_default')) ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<?= Form::close() ?>
|
||||
|
||||
<?php else: ?>
|
||||
<p class="flash-message static error"><?= e(trans($this->fatalError)) ?></p>
|
||||
<p><a href="<?= Backend::url('system/settings') ?>" class="btn btn-default"><?= e(trans('system::lang.settings.return')) ?></a></p>
|
||||
<?php endif ?>
|
||||
8
modules/backend/controllers/usergroups/_list_toolbar.php
Normal file
8
modules/backend/controllers/usergroups/_list_toolbar.php
Normal file
@@ -0,0 +1,8 @@
|
||||
<div data-control="toolbar">
|
||||
<a href="<?= Backend::url('backend/users') ?>" class="btn btn-default wn-icon-chevron-left">
|
||||
<?= e(trans('backend::lang.user.return')) ?>
|
||||
</a>
|
||||
<a href="<?= Backend::url('backend/usergroups/create') ?>" class="btn btn-primary wn-icon-plus">
|
||||
<?= e(trans('backend::lang.user.group.new')) ?>
|
||||
</a>
|
||||
</div>
|
||||
16
modules/backend/controllers/usergroups/config_form.yaml
Normal file
16
modules/backend/controllers/usergroups/config_form.yaml
Normal file
@@ -0,0 +1,16 @@
|
||||
# ===================================
|
||||
# Form Behavior Config
|
||||
# ===================================
|
||||
|
||||
name: backend::lang.user.group.name
|
||||
form: ~/modules/backend/models/usergroup/fields.yaml
|
||||
modelClass: Backend\Models\UserGroup
|
||||
defaultRedirect: backend/usergroups
|
||||
|
||||
create:
|
||||
redirect: backend/usergroups/update/:id
|
||||
redirectClose: backend/usergroups
|
||||
|
||||
update:
|
||||
redirect: backend/usergroups
|
||||
redirectClose: backend/usergroups
|
||||
16
modules/backend/controllers/usergroups/config_list.yaml
Normal file
16
modules/backend/controllers/usergroups/config_list.yaml
Normal file
@@ -0,0 +1,16 @@
|
||||
# ===================================
|
||||
# List Behavior Config
|
||||
# ===================================
|
||||
|
||||
title: backend::lang.user.group.list_title
|
||||
list: ~/modules/backend/models/usergroup/columns.yaml
|
||||
modelClass: Backend\Models\UserGroup
|
||||
recordUrl: backend/usergroups/update/:id
|
||||
noRecordsMessage: backend::lang.list.no_records
|
||||
recordsPerPage: 25
|
||||
showSetup: true
|
||||
|
||||
toolbar:
|
||||
buttons: list_toolbar
|
||||
search:
|
||||
prompt: backend::lang.list.search_prompt
|
||||
46
modules/backend/controllers/usergroups/create.php
Normal file
46
modules/backend/controllers/usergroups/create.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php Block::put('breadcrumb') ?>
|
||||
<ul>
|
||||
<li><a href="<?= Backend::url('backend/users') ?>"><?= e(trans('backend::lang.user.menu_label')) ?></a></li>
|
||||
<li><a href="<?= Backend::url('backend/usergroups') ?>"><?= e(trans('backend::lang.user.group.menu_label')) ?></a></li>
|
||||
<li><?= e(trans($this->pageTitle)) ?></li>
|
||||
</ul>
|
||||
<?php Block::endPut() ?>
|
||||
|
||||
<?php if (!$this->fatalError): ?>
|
||||
|
||||
<?= Form::open(['class'=>'layout']) ?>
|
||||
|
||||
<div class="layout-row">
|
||||
<?= $this->formRender() ?>
|
||||
</div>
|
||||
|
||||
<div class="form-buttons">
|
||||
<div class="loading-indicator-container">
|
||||
<button
|
||||
type="submit"
|
||||
data-request="onSave"
|
||||
data-browser-validate
|
||||
data-hotkey="ctrl+s, cmd+s"
|
||||
data-load-indicator="<?= e(trans('backend::lang.form.creating')) ?>"
|
||||
class="btn btn-primary">
|
||||
<?= e(trans('backend::lang.form.create')) ?>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
data-request="onSave"
|
||||
data-browser-validate
|
||||
data-request-data="close:1"
|
||||
data-hotkey="ctrl+s, cmd+s"
|
||||
data-load-indicator="<?= e(trans('backend::lang.form.creating')) ?>"
|
||||
class="btn btn-default">
|
||||
<?= e(trans('backend::lang.form.create_and_close')) ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?= Form::close() ?>
|
||||
|
||||
<?php else: ?>
|
||||
<p class="flash-message static error"><?= e(trans($this->fatalError)) ?></p>
|
||||
<p><a href="<?= Backend::url('backend/usergroups') ?>" class="btn btn-default"><?= e(trans('backend::lang.user.group.return')) ?></a></p>
|
||||
<?php endif ?>
|
||||
54
modules/backend/controllers/usergroups/update.php
Normal file
54
modules/backend/controllers/usergroups/update.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php Block::put('breadcrumb') ?>
|
||||
<ul>
|
||||
<li><a href="<?= Backend::url('backend/users') ?>"><?= e(trans('backend::lang.user.menu_label')) ?></a></li>
|
||||
<li><a href="<?= Backend::url('backend/usergroups') ?>"><?= e(trans('backend::lang.user.group.menu_label')) ?></a></li>
|
||||
<li><?= e(trans($this->pageTitle)) ?></li>
|
||||
</ul>
|
||||
<?php Block::endPut() ?>
|
||||
|
||||
<?php if (!$this->fatalError): ?>
|
||||
|
||||
<?= Form::open(['class'=>'layout']) ?>
|
||||
|
||||
<div class="layout-row">
|
||||
<?= $this->formRender() ?>
|
||||
</div>
|
||||
|
||||
<div class="form-buttons">
|
||||
<div class="loading-indicator-container">
|
||||
<button
|
||||
type="submit"
|
||||
data-request="onSave"
|
||||
data-browser-validate
|
||||
data-request-data="redirect:0"
|
||||
data-hotkey="ctrl+s, cmd+s"
|
||||
data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>"
|
||||
class="btn btn-primary">
|
||||
<?= e(trans('backend::lang.form.save')) ?>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
data-request="onSave"
|
||||
data-browser-validate
|
||||
data-request-data="close:1"
|
||||
data-hotkey="ctrl+enter, cmd+enter"
|
||||
data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>"
|
||||
class="btn btn-default">
|
||||
<?= e(trans('backend::lang.form.save_and_close')) ?>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="wn-icon-trash-o btn-icon danger pull-right"
|
||||
data-request="onDelete"
|
||||
data-load-indicator="<?= e(trans('backend::lang.form.deleting')) ?>"
|
||||
data-request-confirm="<?= e(trans('backend::lang.user.group.delete_confirm')) ?>">
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?= Form::close() ?>
|
||||
|
||||
<?php else: ?>
|
||||
<p class="flash-message static error"><?= e(trans($this->fatalError)) ?></p>
|
||||
<p><a href="<?= Backend::url('backend/usergroups') ?>" class="btn btn-default"><?= e(trans('backend::lang.user.group.return')) ?></a></p>
|
||||
<?php endif ?>
|
||||
1
modules/backend/controllers/userroles/__users.php
Normal file
1
modules/backend/controllers/userroles/__users.php
Normal file
@@ -0,0 +1 @@
|
||||
<?= $this->relationRender('users') ?>
|
||||
8
modules/backend/controllers/userroles/_list_toolbar.php
Normal file
8
modules/backend/controllers/userroles/_list_toolbar.php
Normal file
@@ -0,0 +1,8 @@
|
||||
<div data-control="toolbar">
|
||||
<a href="<?= Backend::url('backend/users') ?>" class="btn btn-default wn-icon-chevron-left">
|
||||
<?= e(trans('backend::lang.user.return')) ?>
|
||||
</a>
|
||||
<a href="<?= Backend::url('backend/userroles/create') ?>" class="btn btn-primary wn-icon-plus">
|
||||
<?= e(trans('backend::lang.user.role.new')) ?>
|
||||
</a>
|
||||
</div>
|
||||
16
modules/backend/controllers/userroles/config_form.yaml
Normal file
16
modules/backend/controllers/userroles/config_form.yaml
Normal file
@@ -0,0 +1,16 @@
|
||||
# ===================================
|
||||
# Form Behavior Config
|
||||
# ===================================
|
||||
|
||||
name: backend::lang.user.role.name
|
||||
form: ~/modules/backend/models/userrole/fields.yaml
|
||||
modelClass: Backend\Models\UserRole
|
||||
defaultRedirect: backend/userroles
|
||||
|
||||
create:
|
||||
redirect: backend/userroles/update/:id
|
||||
redirectClose: backend/userroles
|
||||
|
||||
update:
|
||||
redirect: backend/userroles
|
||||
redirectClose: backend/userroles
|
||||
16
modules/backend/controllers/userroles/config_list.yaml
Normal file
16
modules/backend/controllers/userroles/config_list.yaml
Normal file
@@ -0,0 +1,16 @@
|
||||
# ===================================
|
||||
# List Behavior Config
|
||||
# ===================================
|
||||
|
||||
title: backend::lang.user.role.list_title
|
||||
list: ~/modules/backend/models/userrole/columns.yaml
|
||||
modelClass: Backend\Models\UserRole
|
||||
recordUrl: backend/userroles/update/:id
|
||||
noRecordsMessage: backend::lang.list.no_records
|
||||
recordsPerPage: 25
|
||||
showSetup: true
|
||||
|
||||
toolbar:
|
||||
buttons: list_toolbar
|
||||
search:
|
||||
prompt: backend::lang.list.search_prompt
|
||||
10
modules/backend/controllers/userroles/config_relation.yaml
Normal file
10
modules/backend/controllers/userroles/config_relation.yaml
Normal file
@@ -0,0 +1,10 @@
|
||||
# ===================================
|
||||
# Relation Behavior Config
|
||||
# ===================================
|
||||
|
||||
users:
|
||||
label: backend::lang.user.name
|
||||
view:
|
||||
list: ~/modules/backend/models/user/columns.yaml
|
||||
toolbarButtons: add|remove
|
||||
recordUrl: backend/users/update/:id
|
||||
46
modules/backend/controllers/userroles/create.php
Normal file
46
modules/backend/controllers/userroles/create.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php Block::put('breadcrumb') ?>
|
||||
<ul>
|
||||
<li><a href="<?= Backend::url('backend/users') ?>"><?= e(trans('backend::lang.user.menu_label')) ?></a></li>
|
||||
<li><a href="<?= Backend::url('backend/userroles') ?>"><?= e(trans('backend::lang.user.role.menu_label')) ?></a></li>
|
||||
<li><?= e(trans($this->pageTitle)) ?></li>
|
||||
</ul>
|
||||
<?php Block::endPut() ?>
|
||||
|
||||
<?php if (!$this->fatalError): ?>
|
||||
|
||||
<?= Form::open(['class'=>'layout']) ?>
|
||||
|
||||
<div class="layout-row">
|
||||
<?= $this->formRender() ?>
|
||||
</div>
|
||||
|
||||
<div class="form-buttons">
|
||||
<div class="loading-indicator-container">
|
||||
<button
|
||||
type="submit"
|
||||
data-request="onSave"
|
||||
data-browser-validate
|
||||
data-hotkey="ctrl+s, cmd+s"
|
||||
data-load-indicator="<?= e(trans('backend::lang.form.creating')) ?>"
|
||||
class="btn btn-primary">
|
||||
<?= e(trans('backend::lang.form.create')) ?>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
data-request="onSave"
|
||||
data-browser-validate
|
||||
data-request-data="close:1"
|
||||
data-hotkey="ctrl+s, cmd+s"
|
||||
data-load-indicator="<?= e(trans('backend::lang.form.creating')) ?>"
|
||||
class="btn btn-default">
|
||||
<?= e(trans('backend::lang.form.create_and_close')) ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?= Form::close() ?>
|
||||
|
||||
<?php else: ?>
|
||||
<p class="flash-message static error"><?= e(trans($this->fatalError)) ?></p>
|
||||
<p><a href="<?= Backend::url('backend/userroles') ?>" class="btn btn-default"><?= e(trans('backend::lang.user.role.return')) ?></a></p>
|
||||
<?php endif ?>
|
||||
54
modules/backend/controllers/userroles/update.php
Normal file
54
modules/backend/controllers/userroles/update.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php Block::put('breadcrumb') ?>
|
||||
<ul>
|
||||
<li><a href="<?= Backend::url('backend/users') ?>"><?= e(trans('backend::lang.user.menu_label')) ?></a></li>
|
||||
<li><a href="<?= Backend::url('backend/userroles') ?>"><?= e(trans('backend::lang.user.role.menu_label')) ?></a></li>
|
||||
<li><?= e(trans($this->pageTitle)) ?></li>
|
||||
</ul>
|
||||
<?php Block::endPut() ?>
|
||||
|
||||
<?php if (!$this->fatalError): ?>
|
||||
|
||||
<?= Form::open(['class'=>'layout']) ?>
|
||||
|
||||
<div class="layout-row">
|
||||
<?= $this->formRender() ?>
|
||||
</div>
|
||||
|
||||
<div class="form-buttons">
|
||||
<div class="loading-indicator-container">
|
||||
<button
|
||||
type="submit"
|
||||
data-request="onSave"
|
||||
data-browser-validate
|
||||
data-request-data="redirect:0"
|
||||
data-hotkey="ctrl+s, cmd+s"
|
||||
data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>"
|
||||
class="btn btn-primary">
|
||||
<?= e(trans('backend::lang.form.save')) ?>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
data-request="onSave"
|
||||
data-browser-validate
|
||||
data-request-data="close:1"
|
||||
data-hotkey="ctrl+enter, cmd+enter"
|
||||
data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>"
|
||||
class="btn btn-default">
|
||||
<?= e(trans('backend::lang.form.save_and_close')) ?>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="wn-icon-trash-o btn-icon danger pull-right"
|
||||
data-request="onDelete"
|
||||
data-load-indicator="<?= e(trans('backend::lang.form.deleting')) ?>"
|
||||
data-request-confirm="<?= e(trans('backend::lang.user.role.delete_confirm')) ?>">
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?= Form::close() ?>
|
||||
|
||||
<?php else: ?>
|
||||
<p class="flash-message static error"><?= e(trans($this->fatalError)) ?></p>
|
||||
<p><a href="<?= Backend::url('backend/userroles') ?>" class="btn btn-default"><?= e(trans('backend::lang.user.role.return')) ?></a></p>
|
||||
<?php endif ?>
|
||||
14
modules/backend/controllers/users/_btn_impersonate.php
Normal file
14
modules/backend/controllers/users/_btn_impersonate.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php if ($this->user->hasAccess('backend.impersonate_users')): ?>
|
||||
<div class="loading-indicator-container">
|
||||
<button
|
||||
type="button"
|
||||
data-request="onImpersonateUser"
|
||||
data-load-indicator="<?= e(trans('backend::lang.account.impersonate_working')) ?>"
|
||||
data-request-confirm="<?= e(trans('backend::lang.account.impersonate_confirm')) ?>"
|
||||
class="btn btn-danger wn-icon-user-secret"
|
||||
style="width: 100%; text-align: center"
|
||||
>
|
||||
<?= e(trans('backend::lang.account.impersonate')) ?>
|
||||
</button>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
12
modules/backend/controllers/users/_btn_password_reset.php
Normal file
12
modules/backend/controllers/users/_btn_password_reset.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<div class="loading-indicator-container">
|
||||
<button
|
||||
type="button"
|
||||
data-request="onManualPasswordReset"
|
||||
data-load-indicator="<?= e(trans('backend::lang.account.sending')) ?>"
|
||||
data-request-confirm="<?= e(trans('backend::lang.account.manual_password_reset_confirm')) ?>"
|
||||
class="btn btn-primary wn-icon-envelope"
|
||||
style="width: 100%; text-align: center"
|
||||
>
|
||||
<?= e(trans('backend::lang.account.password_reset_email')) ?>
|
||||
</button>
|
||||
</div>
|
||||
14
modules/backend/controllers/users/_btn_unsuspend.php
Normal file
14
modules/backend/controllers/users/_btn_unsuspend.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php if ($formModel->isSuspended()): ?>
|
||||
<div class="loading-indicator-container">
|
||||
<button
|
||||
type="button"
|
||||
data-request="onUnsuspendUser"
|
||||
data-load-indicator="<?= e(trans('backend::lang.account.unsuspend_working')) ?>"
|
||||
data-request-confirm="<?= e(trans('backend::lang.account.unsuspend_confirm')) ?>"
|
||||
class="btn btn-danger wn-icon-unlock-alt"
|
||||
style="width: 100%; text-align: center"
|
||||
>
|
||||
<?= e(trans('backend::lang.account.unsuspend')) ?>
|
||||
</button>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
9
modules/backend/controllers/users/_hint_trashed.php
Normal file
9
modules/backend/controllers/users/_hint_trashed.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<div class="layout-row min-size">
|
||||
<div class="callout callout-danger">
|
||||
<div class="header">
|
||||
<i class="icon-trash"></i>
|
||||
<h3><?= e(trans('backend::lang.user.trashed_hint_title')) ?></h3>
|
||||
<p><?= e(trans('backend::lang.user.trashed_hint_desc')) ?></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
29
modules/backend/controllers/users/_list_toolbar.php
Normal file
29
modules/backend/controllers/users/_list_toolbar.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<div data-control="toolbar">
|
||||
<a href="<?= Backend::url('backend/users/create') ?>" class="btn btn-primary wn-icon-plus">
|
||||
<?= e(trans('backend::lang.user.new')) ?>
|
||||
</a>
|
||||
<?php if ($this->user->isSuperUser()): ?>
|
||||
<a href="<?= Backend::url('backend/userroles') ?>" class="btn btn-default wn-icon-address-card">
|
||||
<?= e(trans('backend::lang.user.role.list_title')) ?>
|
||||
</a>
|
||||
<?php endif ?>
|
||||
<a href="<?= Backend::url('backend/usergroups') ?>" class="btn btn-default wn-icon-group">
|
||||
<?= e(trans('backend::lang.user.group.list_title')) ?>
|
||||
</a>
|
||||
<?php /* @todo
|
||||
<div class="btn-group">
|
||||
<button
|
||||
class="btn btn-default wn-icon-ban-circle"
|
||||
disabled="disabled"
|
||||
data-trigger-action="enable"
|
||||
data-trigger=".control-list input[type=checkbox]"
|
||||
data-trigger-condition="checked">Ban</button>
|
||||
<button
|
||||
class="btn btn-default wn-icon-trash-o"
|
||||
disabled="disabled"
|
||||
data-trigger-action="enable"
|
||||
data-trigger=".control-list input[type=checkbox]"
|
||||
data-trigger-condition="checked">Delete</button>
|
||||
</div>
|
||||
*/ ?>
|
||||
</div>
|
||||
30
modules/backend/controllers/users/config_filter.yaml
Normal file
30
modules/backend/controllers/users/config_filter.yaml
Normal file
@@ -0,0 +1,30 @@
|
||||
# ===================================
|
||||
# Filter Scope Definitions
|
||||
# ===================================
|
||||
|
||||
scopes:
|
||||
|
||||
is_superuser:
|
||||
label: backend::lang.user.superuser
|
||||
type: switch
|
||||
conditions:
|
||||
- is_superuser = 0
|
||||
- is_superuser = 1
|
||||
|
||||
login_date:
|
||||
label: backend::lang.user.last_login
|
||||
type: daterange
|
||||
conditions: last_login >= ':after' AND last_login <= ':before'
|
||||
|
||||
role_id:
|
||||
label: backend::lang.user.role.name
|
||||
modelClass: Backend\Models\UserRole
|
||||
conditions: role_id in (:filtered)
|
||||
nameFrom: name
|
||||
|
||||
show_deleted:
|
||||
label: backend::lang.user.show_deleted
|
||||
type: checkbox
|
||||
modelClass: Backend\Models\User
|
||||
scope: withTrashed
|
||||
default: 0
|
||||
16
modules/backend/controllers/users/config_form.yaml
Normal file
16
modules/backend/controllers/users/config_form.yaml
Normal file
@@ -0,0 +1,16 @@
|
||||
# ===================================
|
||||
# Form Behavior Config
|
||||
# ===================================
|
||||
|
||||
name: backend::lang.user.name
|
||||
form: ~/modules/backend/models/user/fields.yaml
|
||||
modelClass: Backend\Models\User
|
||||
defaultRedirect: backend/users
|
||||
|
||||
create:
|
||||
redirect: backend/users/update/:id
|
||||
redirectClose: backend/users
|
||||
|
||||
update:
|
||||
redirect: backend/users
|
||||
redirectClose: backend/users
|
||||
19
modules/backend/controllers/users/config_list.yaml
Normal file
19
modules/backend/controllers/users/config_list.yaml
Normal file
@@ -0,0 +1,19 @@
|
||||
# ===================================
|
||||
# List Behavior Config
|
||||
# ===================================
|
||||
|
||||
title: backend::lang.user.list_title
|
||||
list: ~/modules/backend/models/user/columns.yaml
|
||||
modelClass: Backend\Models\User
|
||||
recordUrl: backend/users/update/:id
|
||||
noRecordsMessage: backend::lang.list.no_records
|
||||
recordsPerPage: 20
|
||||
showSetup: true
|
||||
# showCheckboxes: true
|
||||
|
||||
toolbar:
|
||||
buttons: list_toolbar
|
||||
search:
|
||||
prompt: backend::lang.list.search_prompt
|
||||
|
||||
filter: config_filter.yaml
|
||||
31
modules/backend/controllers/users/config_relation.yaml
Normal file
31
modules/backend/controllers/users/config_relation.yaml
Normal file
@@ -0,0 +1,31 @@
|
||||
# ===================================
|
||||
# Relation Behavior Config
|
||||
# ===================================
|
||||
|
||||
throttle:
|
||||
label: backend::lang.user.throttle_tab_label
|
||||
view:
|
||||
list:
|
||||
columns:
|
||||
ip_address:
|
||||
label: backend::lang.user.throttle_ip_address
|
||||
searchable: true
|
||||
attempts:
|
||||
label: backend::lang.user.throttle_attempts
|
||||
width: 100px
|
||||
align: center
|
||||
last_attempt_at:
|
||||
label: backend::lang.user.throttle_last_attempt
|
||||
type: datetime
|
||||
searchable: true
|
||||
suspended_at:
|
||||
label: backend::lang.user.throttle_suspended_at
|
||||
type: datetime
|
||||
searchable: true
|
||||
toolbarButtons: delete|refresh
|
||||
showSearch: true
|
||||
showSorting: true
|
||||
recordsPerPage: 10
|
||||
defaultSort:
|
||||
column: last_attempt_at
|
||||
direction: desc
|
||||
68
modules/backend/controllers/users/myaccount.php
Normal file
68
modules/backend/controllers/users/myaccount.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php if ($this->user->hasAccess('backend.manage_users')): ?>
|
||||
<?php Block::put('breadcrumb') ?>
|
||||
<ul>
|
||||
<li><a href="<?= Backend::url('backend/users') ?>"><?= e(trans('backend::lang.user.menu_label')) ?></a></li>
|
||||
<li><?= e(trans($this->pageTitle)) ?></li>
|
||||
</ul>
|
||||
<?php Block::endPut() ?>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if (!$this->fatalError): ?>
|
||||
|
||||
<?php Block::put('form-contents') ?>
|
||||
<div class="layout">
|
||||
|
||||
<div class="layout-row">
|
||||
<?= $this->formRenderOutsideFields() ?>
|
||||
<?= $this->formRenderPrimaryTabs() ?>
|
||||
</div>
|
||||
|
||||
<div class="form-buttons">
|
||||
<div class="loading-indicator-container">
|
||||
<button
|
||||
type="submit"
|
||||
data-request="onSave"
|
||||
data-browser-validate
|
||||
data-request-data="redirect:0"
|
||||
data-hotkey="ctrl+s, cmd+s"
|
||||
data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>"
|
||||
class="btn btn-primary">
|
||||
<?= e(trans('backend::lang.form.save')) ?>
|
||||
</button>
|
||||
<?php if ($this->user->hasAccess('backend.manage_users')): ?>
|
||||
<button
|
||||
type="button"
|
||||
data-request="onSave"
|
||||
data-browser-validate
|
||||
data-request-data="close:1"
|
||||
data-hotkey="ctrl+enter, cmd+enter"
|
||||
data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>"
|
||||
class="btn btn-default">
|
||||
<?= e(trans('backend::lang.form.save_and_close')) ?>
|
||||
</button>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<?php Block::endPut() ?>
|
||||
|
||||
<?php Block::put('form-sidebar') ?>
|
||||
<div class="hide-tabs"><?= $this->formRenderSecondaryTabs() ?></div>
|
||||
<?php Block::endPut() ?>
|
||||
|
||||
<?php Block::put('body') ?>
|
||||
<?= Form::open(['class'=>'layout stretch']) ?>
|
||||
<?= $this->makeLayout('form-with-sidebar') ?>
|
||||
<?= Form::close() ?>
|
||||
<?php Block::endPut() ?>
|
||||
|
||||
<?php else: ?>
|
||||
<div class="control-breadcrumb">
|
||||
<?= Block::placeholder('breadcrumb') ?>
|
||||
</div>
|
||||
<div class="padded-container">
|
||||
<p class="flash-message static error"><?= e(trans($this->fatalError)) ?></p>
|
||||
<p><a href="<?= Backend::url('backend/users') ?>" class="btn btn-default"><?= e(trans('backend::lang.user.return')) ?></a></p>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
88
modules/backend/controllers/users/update.php
Normal file
88
modules/backend/controllers/users/update.php
Normal file
@@ -0,0 +1,88 @@
|
||||
<?php Block::put('breadcrumb') ?>
|
||||
<ul>
|
||||
<li><a href="<?= Backend::url('backend/users') ?>"><?= e(trans('backend::lang.user.menu_label')) ?></a></li>
|
||||
<li><?= e(trans($this->pageTitle)) ?></li>
|
||||
</ul>
|
||||
<?php Block::endPut() ?>
|
||||
|
||||
<?php if (!$this->fatalError): ?>
|
||||
|
||||
<?php Block::put('form-contents') ?>
|
||||
<?php if ($formModel->trashed()): ?>
|
||||
<?= $this->makePartial('hint_trashed') ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="layout">
|
||||
|
||||
<div class="layout-row">
|
||||
<?= $this->formRenderOutsideFields() ?>
|
||||
<?= $this->formRenderPrimaryTabs() ?>
|
||||
</div>
|
||||
|
||||
<div class="form-buttons">
|
||||
<div class="loading-indicator-container">
|
||||
<button
|
||||
type="submit"
|
||||
data-request="onSave"
|
||||
data-browser-validate
|
||||
data-request-data="redirect:0"
|
||||
data-hotkey="ctrl+s, cmd+s"
|
||||
data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>"
|
||||
class="btn btn-primary">
|
||||
<?= e(trans('backend::lang.form.save')) ?>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
data-request="onSave"
|
||||
data-browser-validate
|
||||
data-request-data="close:1"
|
||||
data-hotkey="ctrl+enter, cmd+enter"
|
||||
data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>"
|
||||
class="btn btn-default">
|
||||
<?= e(trans('backend::lang.form.save_and_close')) ?>
|
||||
</button>
|
||||
<span class="btn-text">
|
||||
<?= e(trans('backend::lang.form.or')) ?> <a href="<?= Backend::url('backend/users') ?>"><?= e(trans('backend::lang.form.cancel')) ?></a>
|
||||
</span>
|
||||
<?php if ($formModel->trashed()): ?>
|
||||
<button
|
||||
type="button"
|
||||
class="wn-icon-user-plus btn-icon info pull-right"
|
||||
data-request="onRestore"
|
||||
data-load-indicator="<?= e(trans('backend::lang.form.restoring')) ?>"
|
||||
data-request-confirm="<?= e(trans('backend::lang.form.confirm_restore')) ?>">
|
||||
</button>
|
||||
<?php else: ?>
|
||||
<button
|
||||
type="button"
|
||||
class="wn-icon-trash-o btn-icon danger pull-right"
|
||||
data-request="onDelete"
|
||||
data-load-indicator="<?= e(trans('backend::lang.form.deleting')) ?>"
|
||||
data-request-confirm="<?= e(trans('backend::lang.user.delete_confirm')) ?>">
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<?php Block::endPut() ?>
|
||||
|
||||
<?php Block::put('form-sidebar') ?>
|
||||
<div class="hide-tabs"><?= $this->formRenderSecondaryTabs() ?></div>
|
||||
<?php Block::endPut() ?>
|
||||
|
||||
<?php Block::put('body') ?>
|
||||
<?= Form::open(['class'=>'layout stretch']) ?>
|
||||
<?= $this->makeLayout('form-with-sidebar') ?>
|
||||
<?= Form::close() ?>
|
||||
<?php Block::endPut() ?>
|
||||
|
||||
<?php else: ?>
|
||||
<div class="control-breadcrumb">
|
||||
<?= Block::placeholder('breadcrumb') ?>
|
||||
</div>
|
||||
<div class="padded-container">
|
||||
<p class="flash-message static error"><?= e(trans($this->fatalError)) ?></p>
|
||||
<p><a href="<?= Backend::url('backend/users') ?>" class="btn btn-default"><?= e(trans('backend::lang.user.return')) ?></a></p>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
Reference in New Issue
Block a user