Merge branch 'develop' into wip/image-resizing
This commit is contained in:
commit
b4dd25534e
|
|
@ -11,7 +11,7 @@ Thank you for your interest in contributing to the OctoberCMS project. We apprec
|
|||
|
||||
## Reporting a Security Vulnerability
|
||||
|
||||
Please review [our security policy](https://github.com/octobercms/october/security/policy) on how to report security vulnerabilities.
|
||||
Please review [our security policy](https://github.com/octobercms/october/security/policy) on how to report security vulnerabilities. Please do not report security vulnerabilities on GitHub.
|
||||
|
||||
## Reporting an issue with OctoberCMS
|
||||
|
||||
|
|
@ -21,6 +21,8 @@ We work hard to process bugs that are reported, to assist with this please ensur
|
|||
|
||||
- **Summary**: Make sure your summary reflects what the problem is and where it is. Provide as much detail as possible, the more information we have to work with the more likely it is that your problem can be solved.
|
||||
|
||||
- **Installed build and plugins**: Please provide the build number of October CMS that is exhibiting the fault, and the version numbers of any installed and active plugins on your installation. You may retrieve this information by logging in to the Backend and navigating to *Settings* and then *Updates & Plugins*.
|
||||
|
||||
- **Reproduce steps**: Clearly mention the steps to reproduce the bug.
|
||||
|
||||
- **Expected behavior**: Describe how OctoberCMS should behave on above mentioned steps.
|
||||
|
|
@ -61,7 +63,7 @@ We do our best to attend to all reported issues. If you have an important issue
|
|||
|
||||
>**NOTE:** Please don't use GitHub issues for suggesting a new feature. If you have a feature idea, the best place to suggest it is the [OctoberCMS website forum](https://octobercms.com/forum/chan/feature-requests).
|
||||
|
||||
Only use GitHub if you are planning on contributing a new feature and developing it. If you want to discuss your idea first, before "officially" posting it anywhere, you can always join us on [IRC](https://octobercms.com/chat) or [Slack](https://octobercms.slack.com).
|
||||
Only use GitHub if you are planning on contributing a new feature and developing it. If you want to discuss your idea first, before "officially" posting it anywhere, you can always join us on [Discord](https://discord.gg/gEKgwSZ).
|
||||
|
||||
#### GitHub feature requests
|
||||
|
||||
|
|
|
|||
|
|
@ -6,25 +6,18 @@ on:
|
|||
jobs:
|
||||
codeQuality:
|
||||
runs-on: ubuntu-latest
|
||||
name: PHP
|
||||
name: PHPCS
|
||||
steps:
|
||||
- name: Checkout changes
|
||||
uses: actions/checkout@v1
|
||||
- name: Install PHP
|
||||
uses: shivammathur/setup-php@master
|
||||
- name: Install PHP and PHP Code Sniffer
|
||||
uses: shivammathur/setup-php@v1
|
||||
with:
|
||||
php-version: 7.2
|
||||
- name: Install Composer dependencies
|
||||
run: composer install --no-interaction --no-progress --no-suggest
|
||||
- name: Reset October modules and library
|
||||
run: |
|
||||
git reset --hard HEAD
|
||||
rm -rf ./vendor/october/rain
|
||||
wget https://github.com/octobercms/library/archive/develop.zip -O ./vendor/october/develop.zip
|
||||
unzip ./vendor/october/develop.zip -d ./vendor/october
|
||||
mv ./vendor/october/library-develop ./vendor/october/rain
|
||||
composer dump-autoload
|
||||
php-version: '7.3'
|
||||
tools: phpcs
|
||||
- name: Setup problem matcher for PHPCS
|
||||
run: echo "::add-matcher::${{ github.workspace }}/.github/workflows/matchers/phpcs-matcher.json"
|
||||
- name: Run code quality checks
|
||||
run: |
|
||||
git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" && git fetch
|
||||
./vendor/bin/phpcs --colors -nq --report="full" --extensions="php" $(git diff --name-only --diff-filter=ACMR origin/${{ github.base_ref }} HEAD)
|
||||
phpcs --colors -nq --report="checkstyle" --extensions="php" $(git diff --name-only --diff-filter=ACMR origin/${{ github.base_ref }} HEAD)
|
||||
|
|
|
|||
|
|
@ -9,23 +9,16 @@ on:
|
|||
jobs:
|
||||
codeQuality:
|
||||
runs-on: ubuntu-latest
|
||||
name: PHP
|
||||
name: PHPCS
|
||||
steps:
|
||||
- name: Checkout changes
|
||||
uses: actions/checkout@v1
|
||||
- name: Install PHP
|
||||
uses: shivammathur/setup-php@master
|
||||
- name: Install PHP and PHP Code Sniffer
|
||||
uses: shivammathur/setup-php@v1
|
||||
with:
|
||||
php-version: 7.2
|
||||
- name: Install Composer dependencies
|
||||
run: composer install --no-interaction --no-progress --no-suggest
|
||||
- name: Reset October modules and library
|
||||
run: |
|
||||
git reset --hard HEAD
|
||||
rm -rf ./vendor/october/rain
|
||||
wget https://github.com/octobercms/library/archive/develop.zip -O ./vendor/october/develop.zip
|
||||
unzip ./vendor/october/develop.zip -d ./vendor/october
|
||||
mv ./vendor/october/library-develop ./vendor/october/rain
|
||||
composer dump-autoload
|
||||
php-version: '7.3'
|
||||
tools: phpcs
|
||||
- name: Setup problem matcher for PHPCS
|
||||
run: echo "::add-matcher::${{ github.workspace }}/.github/workflows/matchers/phpcs-matcher.json"
|
||||
- name: Run code quality checks
|
||||
run: ./vendor/bin/phpcs --colors -nq --report="full" --extensions="php" $(git show --name-only --pretty="" --diff-filter=ACMR ${{ github.sha }})
|
||||
run: phpcs --colors -nq --report="checkstyle" --extensions="php" $(git show --name-only --pretty="" --diff-filter=ACMR ${{ github.sha }})
|
||||
|
|
|
|||
|
|
@ -1,24 +0,0 @@
|
|||
name: Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
frontendTests:
|
||||
runs-on: ubuntu-latest
|
||||
name: JavaScript
|
||||
steps:
|
||||
- name: Checkout changes
|
||||
uses: actions/checkout@v1
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 8
|
||||
- name: Install Node dependencies
|
||||
run: npm install
|
||||
- name: Run tests
|
||||
run: npm run test
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"problemMatcher": [
|
||||
{
|
||||
"owner": "phpcs",
|
||||
"severity": "error",
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^<file name=\"(.*)\">$",
|
||||
"file": 1
|
||||
},
|
||||
{
|
||||
"regexp": "<error line=\"(\\d*)\" column=\"(\\d*)\" severity=\"(error|warning)\" message=\"(.*)\" source=\"(.*)(\"\\/>+)$",
|
||||
"line": 1,
|
||||
"column": 2,
|
||||
"severity": 3,
|
||||
"message": 4,
|
||||
"code": 5,
|
||||
"loop": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -8,37 +8,56 @@ on:
|
|||
pull_request:
|
||||
|
||||
jobs:
|
||||
frontendTests:
|
||||
runs-on: ubuntu-latest
|
||||
name: JavaScript
|
||||
steps:
|
||||
- name: Checkout changes
|
||||
uses: actions/checkout@v1
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 8
|
||||
- name: Install Node dependencies
|
||||
run: npm install
|
||||
- name: Run tests
|
||||
run: npm run test
|
||||
phpUnitTests:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
max-parallel: 6
|
||||
matrix:
|
||||
phpVersions: ['7.1', '7.2', '7.3', '7.4']
|
||||
phpVersions: ['7.2', '7.3', '7.4']
|
||||
fail-fast: false
|
||||
name: PHP ${{ matrix.phpVersions }}
|
||||
name: Unit Tests / PHP ${{ matrix.phpVersions }}
|
||||
steps:
|
||||
- name: Checkout changes
|
||||
uses: actions/checkout@v1
|
||||
- name: Install PHP
|
||||
uses: shivammathur/setup-php@master
|
||||
uses: shivammathur/setup-php@v1
|
||||
with:
|
||||
php-version: ${{ matrix.phpVersions }}
|
||||
extension-csv: mbstring, intl, gd, xml, sqlite
|
||||
extensions: mbstring, intl, gd, xml, sqlite
|
||||
- name: Setup problem matchers for PHPUnit
|
||||
run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
|
||||
- name: Set Composer cache
|
||||
id: composer-cache
|
||||
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
|
||||
- name: Cache Composer dependencies
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}
|
||||
restore-keys: ${{ runner.os }}-composer-
|
||||
- name: Install Composer dependencies
|
||||
run: composer install --no-interaction --no-progress --no-suggest --no-scripts
|
||||
- name: Reset October modules and library
|
||||
- name: Run post-update Composer scripts
|
||||
run: php artisan package:discover
|
||||
- name: Reset October modules
|
||||
run: |
|
||||
git reset --hard HEAD
|
||||
rm -rf ./vendor/october/rain
|
||||
wget https://github.com/octobercms/library/archive/develop.zip -O ./vendor/october/develop.zip
|
||||
unzip ./vendor/october/develop.zip -d ./vendor/october
|
||||
mv ./vendor/october/library-develop ./vendor/october/rain
|
||||
composer dump-autoload
|
||||
- name: Run post-update Composer scripts
|
||||
run: |
|
||||
php artisan october:util set build
|
||||
php artisan package:discover
|
||||
composer dumpautoload
|
||||
- name: Run Linting and Tests
|
||||
run: |
|
||||
./vendor/bin/parallel-lint --exclude vendor --exclude storage --exclude tests/fixtures/plugins/testvendor/goto/Plugin.php .
|
||||
./vendor/bin/phpunit
|
||||
./vendor/bin/phpunit --prepend ./vendor/october/rain/src/Support/helpers.php
|
||||
|
|
|
|||
|
|
@ -1,24 +1,32 @@
|
|||
/bootstrap/compiled.php
|
||||
# Composer ignores
|
||||
/vendor
|
||||
composer.phar
|
||||
.DS_Store
|
||||
.idea
|
||||
composer.lock
|
||||
|
||||
# Framework ignores
|
||||
.env
|
||||
.env.*.php
|
||||
.env.php
|
||||
selenium.php
|
||||
/bootstrap/compiled.php
|
||||
.phpunit.result.cache
|
||||
|
||||
# Hosting ignores
|
||||
php_errors.log
|
||||
nginx-error.log
|
||||
nginx-access.log
|
||||
nginx-ssl.access.log
|
||||
nginx-ssl.error.log
|
||||
php-errors.log
|
||||
sftp-config.json
|
||||
.ftpconfig
|
||||
selenium.php
|
||||
composer.lock
|
||||
package-lock.json
|
||||
/node_modules
|
||||
|
||||
# Editor ignores
|
||||
nbproject
|
||||
.idea
|
||||
.vscode
|
||||
_ide_helper.php
|
||||
|
||||
# for netbeans
|
||||
nbproject
|
||||
# Other ignores
|
||||
.DS_Store
|
||||
package-lock.json
|
||||
/node_modules
|
||||
|
|
|
|||
4
artisan
4
artisan
|
|
@ -28,7 +28,7 @@ $app = require_once __DIR__.'/bootstrap/app.php';
|
|||
|
|
||||
*/
|
||||
|
||||
$kernel = $app->make('Illuminate\Contracts\Console\Kernel');
|
||||
$kernel = $app->make(Illuminate\Contracts\Console\Kernel::class);
|
||||
|
||||
$status = $kernel->handle(
|
||||
$input = new Symfony\Component\Console\Input\ArgvInput,
|
||||
|
|
@ -48,4 +48,4 @@ $status = $kernel->handle(
|
|||
|
||||
$kernel->terminate($input, $status);
|
||||
|
||||
exit($status);
|
||||
exit($status);
|
||||
|
|
|
|||
|
|
@ -35,20 +35,3 @@ require $helperPath;
|
|||
*/
|
||||
|
||||
require __DIR__.'/../vendor/autoload.php';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Include The Compiled Class File
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| To dramatically increase your application's performance, you may use a
|
||||
| compiled class file which contains all of the classes commonly used
|
||||
| by a request. The Artisan "optimize" is used to create this file.
|
||||
|
|
||||
*/
|
||||
|
||||
$compiledPath = __DIR__.'/../storage/framework/compiled.php';
|
||||
|
||||
if (file_exists($compiledPath)) {
|
||||
require $compiledPath;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "october/october",
|
||||
"description": "OctoberCMS",
|
||||
"description": "October CMS",
|
||||
"homepage": "https://octobercms.com",
|
||||
"type": "project",
|
||||
"keywords": ["october", "cms", "octobercms", "laravel"],
|
||||
|
|
@ -24,37 +24,34 @@
|
|||
}
|
||||
],
|
||||
"support": {
|
||||
"paid": "https://octobercms.com/premium-support",
|
||||
"issues": "https://github.com/octobercms/october/issues",
|
||||
"forum": "https://octobercms.com/forum/",
|
||||
"docs": "https://octobercms.com/docs/",
|
||||
"irc": "irc://irc.freenode.net/october",
|
||||
"source": "https://github.com/octobercms/october"
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.0.8",
|
||||
"ext-mbstring": "*",
|
||||
"ext-openssl": "*",
|
||||
"october/rain": "~1.0",
|
||||
"october/system": "~1.0",
|
||||
"october/backend": "~1.0",
|
||||
"october/cms": "~1.0",
|
||||
"laravel/framework": "~5.5.40",
|
||||
"php": ">=7.2",
|
||||
"october/rain": "dev-develop as 1.0",
|
||||
"october/system": "dev-develop",
|
||||
"october/backend": "dev-develop",
|
||||
"october/cms": "dev-develop",
|
||||
"laravel/framework": "~6.0",
|
||||
"wikimedia/composer-merge-plugin": "1.4.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"fzaninotto/faker": "~1.7",
|
||||
"phpunit/phpunit": "~6.5",
|
||||
"phpunit/phpunit-selenium": "~1.2",
|
||||
"meyfa/phpunit-assert-gd": "1.1.0",
|
||||
"phpunit/phpunit": "^8.0|^9.0",
|
||||
"fzaninotto/faker": "~1.9",
|
||||
"squizlabs/php_codesniffer": "3.*",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.0"
|
||||
"php-parallel-lint/php-parallel-lint": "^1.0",
|
||||
"meyfa/phpunit-assert-gd": "^2.0.0",
|
||||
"dms/phpunit-arraysubset-asserts": "^0.1.0"
|
||||
},
|
||||
"autoload-dev": {
|
||||
"classmap": [
|
||||
"tests/concerns/InteractsWithAuthentication.php",
|
||||
"tests/fixtures/backend/models/UserFixture.php",
|
||||
"tests/TestCase.php",
|
||||
"tests/UiTestCase.php",
|
||||
"tests/PluginTestCase.php"
|
||||
]
|
||||
},
|
||||
|
|
@ -66,12 +63,21 @@
|
|||
"post-update-cmd": [
|
||||
"php artisan october:util set build",
|
||||
"php artisan package:discover"
|
||||
],
|
||||
"test": [
|
||||
"phpunit --stop-on-failure"
|
||||
],
|
||||
"lint": [
|
||||
"parallel-lint --exclude vendor --exclude storage --exclude tests/fixtures/plugins/testvendor/goto/Plugin.php ."
|
||||
],
|
||||
"sniff": [
|
||||
"phpcs --colors -nq --report=\"full\" --extensions=\"php\""
|
||||
]
|
||||
},
|
||||
"config": {
|
||||
"preferred-install": "dist",
|
||||
"platform": {
|
||||
"php": "7.0.8"
|
||||
"php": "7.2"
|
||||
}
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
|
|
|
|||
|
|
@ -111,21 +111,6 @@ return [
|
|||
|
||||
'cipher' => 'AES-256-CBC',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Logging Configuration
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may configure the log settings for your application. Out of
|
||||
| the box, Laravel uses the Monolog PHP logging library. This gives
|
||||
| you a variety of powerful log handlers / formatters to utilize.
|
||||
|
|
||||
| Available Settings: "single", "daily", "syslog", "errorlog"
|
||||
|
|
||||
*/
|
||||
|
||||
'log' => 'single',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Autoloaded Service Providers
|
||||
|
|
@ -144,6 +129,26 @@ return [
|
|||
'System\ServiceProvider',
|
||||
]),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Load automatically discovered packages
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| By default, October CMS disables the loading of discovered packages
|
||||
| through Laravel's package discovery service, in order to allow packages
|
||||
| used by plugins to be disabled if the plugin itself is disabled.
|
||||
|
|
||||
| Set this to `true` to enable automatic loading of these packages. This
|
||||
| will result in packages being loaded, even if the plugin using them is
|
||||
| disabled. This is NOT RECOMMENDED.
|
||||
|
|
||||
| Please note that packages defined in `app.providers` will still be loaded
|
||||
| even if discovery is disabled.
|
||||
|
|
||||
*/
|
||||
|
||||
'loadDiscoveredPackages' => false,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Class Aliases
|
||||
|
|
|
|||
|
|
@ -116,6 +116,7 @@ return [
|
|||
|
||||
'redis' => [
|
||||
|
||||
'client' => 'predis',
|
||||
'cluster' => false,
|
||||
|
||||
'default' => [
|
||||
|
|
|
|||
|
|
@ -20,5 +20,27 @@ return [
|
|||
*/
|
||||
|
||||
'decompileBackendAssets' => false,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Allow deep-level symlinks
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| October CMS, by default, will allow symlinks within the first level of
|
||||
| subdirectories. When this feature is enabled, the system will allow
|
||||
| symlinks to be used at any directory level. This can be useful for
|
||||
| symlinking individual plugins or themes.
|
||||
|
|
||||
| Please note that this has a negative effect on performance. This feature
|
||||
| abides by "cms.restrictBaseDir" - if enabled, symlinks cannot point to
|
||||
| resources outside of the root folder.
|
||||
|
|
||||
| true - allow symlinks at any level
|
||||
|
|
||||
| false - only allow symlinks at the first level of subdirectories (default)
|
||||
|
|
||||
*/
|
||||
|
||||
'allowDeepSymlinks' => false,
|
||||
|
||||
];
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ return [
|
|||
| by the framework. A "local" driver, as well as a variety of cloud
|
||||
| based drivers are available for your choosing. Just store away!
|
||||
|
|
||||
| Supported: "local", "s3", "rackspace"
|
||||
| Supported: "local", "ftp", "sftp", "s3", "rackspace"
|
||||
|
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Hash Driver
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option controls the default hash driver that will be used to hash
|
||||
| passwords for your application. By default, the bcrypt algorithm is
|
||||
| used; however, you remain free to modify this option if you wish.
|
||||
|
|
||||
| Supported: "bcrypt", "argon", "argon2id"
|
||||
|
|
||||
*/
|
||||
|
||||
'driver' => 'bcrypt',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Bcrypt Options
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify the configuration options that should be used when
|
||||
| passwords are hashed using the Bcrypt algorithm. This will allow you
|
||||
| to control the amount of time it takes to hash the given password.
|
||||
|
|
||||
*/
|
||||
|
||||
'bcrypt' => [
|
||||
'rounds' => env('BCRYPT_ROUNDS', 10),
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Argon Options
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify the configuration options that should be used when
|
||||
| passwords are hashed using the Argon algorithm. These will allow you
|
||||
| to control the amount of time it takes to hash the given password.
|
||||
|
|
||||
*/
|
||||
|
||||
'argon' => [
|
||||
'memory' => 1024,
|
||||
'threads' => 2,
|
||||
'time' => 2,
|
||||
],
|
||||
|
||||
];
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Log Channel
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option defines the default log channel that gets used when writing
|
||||
| messages to the logs. The name specified in this option should match
|
||||
| one of the channels defined in the "channels" configuration array.
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('LOG_CHANNEL', 'single'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Log Channels
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may configure the log channels for your application. Out of
|
||||
| the box, Laravel uses the Monolog PHP logging library. This gives
|
||||
| you a variety of powerful log handlers / formatters to utilize.
|
||||
|
|
||||
| Available Drivers: "single", "daily", "slack", "syslog",
|
||||
| "errorlog", "monolog",
|
||||
| "custom", "stack"
|
||||
|
|
||||
*/
|
||||
|
||||
'channels' => [
|
||||
'stack' => [
|
||||
'driver' => 'stack',
|
||||
'channels' => ['daily'],
|
||||
'ignore_exceptions' => false,
|
||||
],
|
||||
|
||||
'single' => [
|
||||
'driver' => 'single',
|
||||
'path' => storage_path('logs/system.log'),
|
||||
'level' => 'debug',
|
||||
],
|
||||
|
||||
'daily' => [
|
||||
'driver' => 'daily',
|
||||
'path' => storage_path('logs/system.log'),
|
||||
'level' => 'debug',
|
||||
'days' => 14,
|
||||
],
|
||||
|
||||
'slack' => [
|
||||
'driver' => 'slack',
|
||||
'url' => env('LOG_SLACK_WEBHOOK_URL'),
|
||||
'username' => 'October CMS Log',
|
||||
'emoji' => ':boom:',
|
||||
'level' => 'critical',
|
||||
],
|
||||
|
||||
'papertrail' => [
|
||||
'driver' => 'monolog',
|
||||
'level' => 'debug',
|
||||
'handler' => \Monolog\Handler\SyslogUdpHandler::class,
|
||||
'handler_with' => [
|
||||
'host' => env('PAPERTRAIL_URL'),
|
||||
'port' => env('PAPERTRAIL_PORT'),
|
||||
],
|
||||
],
|
||||
|
||||
'stderr' => [
|
||||
'driver' => 'monolog',
|
||||
'handler' => \Monolog\Handler\StreamHandler::class,
|
||||
'formatter' => env('LOG_STDERR_FORMATTER'),
|
||||
'with' => [
|
||||
'stream' => 'php://stderr',
|
||||
],
|
||||
],
|
||||
|
||||
'syslog' => [
|
||||
'driver' => 'syslog',
|
||||
'level' => 'debug',
|
||||
],
|
||||
|
||||
'errorlog' => [
|
||||
'driver' => 'errorlog',
|
||||
'level' => 'debug',
|
||||
],
|
||||
],
|
||||
|
||||
];
|
||||
|
|
@ -12,7 +12,7 @@ return [
|
|||
| your application here. By default, Laravel is setup for SMTP mail.
|
||||
|
|
||||
| Supported: "smtp", "sendmail", "mailgun", "mandrill", "ses",
|
||||
| "sparkpost", "log", "array"
|
||||
| "postmark", "sparkpost", "log", "array"
|
||||
|
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,10 @@ return [
|
|||
'secret' => '',
|
||||
],
|
||||
|
||||
'postmark' => [
|
||||
'token' => '',
|
||||
],
|
||||
|
||||
'ses' => [
|
||||
'key' => '',
|
||||
'secret' => '',
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ $app = require_once __DIR__.'/bootstrap/app.php';
|
|||
|
|
||||
*/
|
||||
|
||||
$kernel = $app->make('Illuminate\Contracts\Http\Kernel');
|
||||
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
|
||||
|
||||
$response = $kernel->handle(
|
||||
$request = Illuminate\Http\Request::capture()
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ class ServiceProvider extends ModuleServiceProvider
|
|||
$combiner->registerBundle('~/modules/backend/formwidgets/colorpicker/assets/less/colorpicker.less');
|
||||
$combiner->registerBundle('~/modules/backend/formwidgets/permissioneditor/assets/less/permissioneditor.less');
|
||||
$combiner->registerBundle('~/modules/backend/formwidgets/markdowneditor/assets/less/markdowneditor.less');
|
||||
$combiner->registerBundle('~/modules/backend/formwidgets/sensitive/assets/less/sensitive.less');
|
||||
|
||||
/*
|
||||
* Rich Editor is protected by DRM
|
||||
|
|
@ -199,6 +200,7 @@ class ServiceProvider extends ModuleServiceProvider
|
|||
$manager->registerFormWidget('Backend\FormWidgets\TagList', 'taglist');
|
||||
$manager->registerFormWidget('Backend\FormWidgets\MediaFinder', 'mediafinder');
|
||||
$manager->registerFormWidget('Backend\FormWidgets\NestedForm', 'nestedform');
|
||||
$manager->registerFormWidget('Backend\FormWidgets\Sensitive', 'sensitive');
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use Backend\Behaviors\ImportExportController\TranscodeFilter;
|
|||
use Illuminate\Database\Eloquent\MassAssignmentException;
|
||||
use League\Csv\Reader as CsvReader;
|
||||
use League\Csv\Writer as CsvWriter;
|
||||
use October\Rain\Parse\League\EscapeFormula as CsvEscapeFormula;
|
||||
use League\Csv\EscapeFormula as CsvEscapeFormula;
|
||||
use ApplicationException;
|
||||
use SplTempFileObject;
|
||||
use Exception;
|
||||
|
|
@ -624,9 +624,7 @@ class ImportExportController extends ControllerBehavior
|
|||
$csv->setDelimiter($options['delimiter']);
|
||||
$csv->setEnclosure($options['enclosure']);
|
||||
$csv->setEscape($options['escape']);
|
||||
|
||||
// Temporary until upgrading to league/csv >= 9.1.0 (will be $csv->addFormatter($formatter))
|
||||
$formatter = new CsvEscapeFormula();
|
||||
$csv->addFormatter(new CsvEscapeFormula());
|
||||
|
||||
/*
|
||||
* Add headers
|
||||
|
|
@ -662,9 +660,6 @@ class ImportExportController extends ControllerBehavior
|
|||
$record[] = $value;
|
||||
}
|
||||
|
||||
// Temporary until upgrading to league/csv >= 9.1.0
|
||||
$record = $formatter($record);
|
||||
|
||||
$csv->insertOne($record);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ class FormField
|
|||
/**
|
||||
* @var string Specifies a comment to accompany the field
|
||||
*/
|
||||
public $comment;
|
||||
public $comment = '';
|
||||
|
||||
/**
|
||||
* @var string Specifies the comment position.
|
||||
|
|
@ -139,7 +139,7 @@ class FormField
|
|||
/**
|
||||
* @var string Specifies a message to display when there is no value supplied (placeholder).
|
||||
*/
|
||||
public $placeholder;
|
||||
public $placeholder = '';
|
||||
|
||||
/**
|
||||
* @var array Contains a list of attributes specified in the field configuration.
|
||||
|
|
|
|||
|
|
@ -8,11 +8,13 @@
|
|||
"authors": [
|
||||
{
|
||||
"name": "Alexey Bobkov",
|
||||
"email": "aleksey.bobkov@gmail.com"
|
||||
"email": "aleksey.bobkov@gmail.com",
|
||||
"role": "Co-founder"
|
||||
},
|
||||
{
|
||||
"name": "Samuel Georges",
|
||||
"email": "daftspunky@gmail.com"
|
||||
"email": "daftspunky@gmail.com",
|
||||
"role": "Co-founder"
|
||||
},
|
||||
{
|
||||
"name": "Luke Towers",
|
||||
|
|
@ -22,9 +24,10 @@
|
|||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.0",
|
||||
"php": ">=7.2",
|
||||
"composer/installers": "~1.0",
|
||||
"october/rain": "~1.0"
|
||||
"october/rain": "~1.0",
|
||||
"laravel/framework": "~6.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ class DatabaseSeeder extends Seeder
|
|||
*/
|
||||
public function run()
|
||||
{
|
||||
Eloquent::unguard();
|
||||
|
||||
$this->call('Backend\Database\Seeds\SeedSetupAdmin');
|
||||
Eloquent::unguarded(function () {
|
||||
$this->call('Backend\Database\Seeds\SeedSetupAdmin');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,117 @@
|
|||
<?php namespace Backend\FormWidgets;
|
||||
|
||||
use Backend\Classes\FormWidgetBase;
|
||||
|
||||
/**
|
||||
* Sensitive widget.
|
||||
*
|
||||
* Renders a password field that can be optionally made visible
|
||||
*
|
||||
* @package october\backend
|
||||
*/
|
||||
class Sensitive extends FormWidgetBase
|
||||
{
|
||||
/**
|
||||
* @var bool If true, the sensitive field cannot be edited, but can be toggled.
|
||||
*/
|
||||
public $readOnly = false;
|
||||
|
||||
/**
|
||||
* @var bool If true, the sensitive field is disabled.
|
||||
*/
|
||||
public $disabled = false;
|
||||
|
||||
/**
|
||||
* @var bool If true, a button will be available to copy the value.
|
||||
*/
|
||||
public $allowCopy = false;
|
||||
|
||||
/**
|
||||
* @var string The string that will be used as a placeholder for an unrevealed sensitive value.
|
||||
*/
|
||||
public $hiddenPlaceholder = '__hidden__';
|
||||
|
||||
/**
|
||||
* @var bool If true, the sensitive input will be hidden if the user changes to another tab in their browser.
|
||||
*/
|
||||
public $hideOnTabChange = true;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected $defaultAlias = 'sensitive';
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->fillFromConfig([
|
||||
'readOnly',
|
||||
'disabled',
|
||||
'allowCopy',
|
||||
'hiddenPlaceholder',
|
||||
'hideOnTabChange',
|
||||
]);
|
||||
|
||||
if ($this->formField->disabled || $this->formField->readOnly) {
|
||||
$this->previewMode = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function render()
|
||||
{
|
||||
$this->prepareVars();
|
||||
|
||||
return $this->makePartial('sensitive');
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the view data for the widget partial.
|
||||
*/
|
||||
public function prepareVars()
|
||||
{
|
||||
$this->vars['readOnly'] = $this->readOnly;
|
||||
$this->vars['disabled'] = $this->disabled;
|
||||
$this->vars['hasValue'] = !empty($this->getLoadValue());
|
||||
$this->vars['allowCopy'] = $this->allowCopy;
|
||||
$this->vars['hiddenPlaceholder'] = $this->hiddenPlaceholder;
|
||||
$this->vars['hideOnTabChange'] = $this->hideOnTabChange;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reveals the value of a hidden, unmodified sensitive field.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function onShowValue()
|
||||
{
|
||||
return [
|
||||
'value' => $this->getLoadValue()
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getSaveValue($value)
|
||||
{
|
||||
if ($value === $this->hiddenPlaceholder) {
|
||||
$value = $this->getLoadValue();
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function loadAssets()
|
||||
{
|
||||
$this->addCss('css/sensitive.css', 'core');
|
||||
$this->addJs('js/sensitive.js', 'core');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
div[data-control="sensitive"] a[data-toggle],
|
||||
div[data-control="sensitive"] a[data-copy] {box-shadow:none;border:1px solid #d1d6d9;border-left:0}
|
||||
|
|
@ -0,0 +1,192 @@
|
|||
/*
|
||||
* Sensitive field widget plugin.
|
||||
*
|
||||
* Data attributes:
|
||||
* - data-control="sensitive" - enables the plugin on an element
|
||||
*
|
||||
* JavaScript API:
|
||||
* $('div#someElement').sensitive({...})
|
||||
*/
|
||||
+function ($) { "use strict";
|
||||
var Base = $.oc.foundation.base,
|
||||
BaseProto = Base.prototype
|
||||
|
||||
var Sensitive = function(element, options) {
|
||||
this.$el = $(element)
|
||||
this.options = options
|
||||
this.clean = Boolean(this.$el.data('clean'))
|
||||
this.hidden = true
|
||||
|
||||
this.$input = this.$el.find('[data-input]').first()
|
||||
this.$toggle = this.$el.find('[data-toggle]').first()
|
||||
this.$icon = this.$el.find('[data-icon]').first()
|
||||
this.$loader = this.$el.find('[data-loader]').first()
|
||||
this.$copy = this.$el.find('[data-copy]').first()
|
||||
|
||||
$.oc.foundation.controlUtils.markDisposable(element)
|
||||
Base.call(this)
|
||||
this.init()
|
||||
}
|
||||
|
||||
Sensitive.DEFAULTS = {
|
||||
readOnly: false,
|
||||
disabled: false,
|
||||
eventHandler: null,
|
||||
hideOnTabChange: false,
|
||||
}
|
||||
|
||||
Sensitive.prototype = Object.create(BaseProto)
|
||||
Sensitive.prototype.constructor = Sensitive
|
||||
|
||||
Sensitive.prototype.init = function() {
|
||||
this.$input.on('keydown', this.proxy(this.onInput))
|
||||
this.$toggle.on('click', this.proxy(this.onToggle))
|
||||
|
||||
if (this.options.hideOnTabChange) {
|
||||
// Watch for tab change or minimise
|
||||
document.addEventListener('visibilitychange', this.proxy(this.onTabChange))
|
||||
}
|
||||
|
||||
if (this.$copy.length) {
|
||||
this.$copy.on('click', this.proxy(this.onCopy))
|
||||
}
|
||||
}
|
||||
|
||||
Sensitive.prototype.dispose = function () {
|
||||
this.$input.off('keydown', this.proxy(this.onInput))
|
||||
this.$toggle.off('click', this.proxy(this.onToggle))
|
||||
|
||||
if (this.options.hideOnTabChange) {
|
||||
document.removeEventListener('visibilitychange', this.proxy(this.onTabChange))
|
||||
}
|
||||
|
||||
if (this.$copy.length) {
|
||||
this.$copy.off('click', this.proxy(this.onCopy))
|
||||
}
|
||||
|
||||
this.$input = this.$toggle = this.$icon = this.$loader = null
|
||||
this.$el = null
|
||||
|
||||
BaseProto.dispose.call(this)
|
||||
}
|
||||
|
||||
Sensitive.prototype.onInput = function() {
|
||||
if (this.clean) {
|
||||
this.clean = false
|
||||
this.$input.val('')
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
Sensitive.prototype.onToggle = function() {
|
||||
if (this.$input.val() !== '' && this.clean) {
|
||||
this.reveal()
|
||||
} else {
|
||||
this.toggleVisibility()
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
Sensitive.prototype.onTabChange = function() {
|
||||
if (document.hidden && !this.hidden) {
|
||||
this.toggleVisibility()
|
||||
}
|
||||
}
|
||||
|
||||
Sensitive.prototype.onCopy = function() {
|
||||
var that = this,
|
||||
deferred = $.Deferred(),
|
||||
isHidden = this.hidden
|
||||
|
||||
deferred.then(function () {
|
||||
if (that.hidden) {
|
||||
that.toggleVisibility()
|
||||
}
|
||||
|
||||
that.$input.focus()
|
||||
that.$input.select()
|
||||
|
||||
try {
|
||||
document.execCommand('copy')
|
||||
} catch (err) {
|
||||
}
|
||||
|
||||
that.$input.blur()
|
||||
if (isHidden) {
|
||||
that.toggleVisibility()
|
||||
}
|
||||
})
|
||||
|
||||
if (this.$input.val() !== '' && this.clean) {
|
||||
this.reveal(deferred)
|
||||
} else {
|
||||
deferred.resolve()
|
||||
}
|
||||
}
|
||||
|
||||
Sensitive.prototype.toggleVisibility = function() {
|
||||
if (this.hidden) {
|
||||
this.$input.attr('type', 'text')
|
||||
} else {
|
||||
this.$input.attr('type', 'password')
|
||||
}
|
||||
|
||||
this.$icon.toggleClass('icon-eye icon-eye-slash')
|
||||
|
||||
this.hidden = !this.hidden
|
||||
}
|
||||
|
||||
Sensitive.prototype.reveal = function(deferred) {
|
||||
var that = this
|
||||
this.$icon.css({
|
||||
visibility: 'hidden'
|
||||
})
|
||||
this.$loader.removeClass('hide')
|
||||
|
||||
this.$input.request(this.options.eventHandler, {
|
||||
success: function (data) {
|
||||
that.$input.val(data.value)
|
||||
that.clean = false
|
||||
|
||||
that.$icon.css({
|
||||
visibility: 'visible'
|
||||
})
|
||||
that.$loader.addClass('hide')
|
||||
|
||||
that.toggleVisibility()
|
||||
|
||||
if (deferred) {
|
||||
deferred.resolve()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
var old = $.fn.sensitive
|
||||
|
||||
$.fn.sensitive = function (option) {
|
||||
var args = Array.prototype.slice.call(arguments, 1), result
|
||||
this.each(function () {
|
||||
var $this = $(this)
|
||||
var data = $this.data('oc.sensitive')
|
||||
var options = $.extend({}, Sensitive.DEFAULTS, $this.data(), typeof option == 'object' && option)
|
||||
if (!data) $this.data('oc.sensitive', (data = new Sensitive(this, options)))
|
||||
if (typeof option == 'string') result = data[option].apply(data, args)
|
||||
if (typeof result != 'undefined') return false
|
||||
})
|
||||
|
||||
return result ? result : this
|
||||
}
|
||||
|
||||
$.fn.sensitive.noConflict = function () {
|
||||
$.fn.sensitive = old
|
||||
return this
|
||||
}
|
||||
|
||||
$(document).render(function () {
|
||||
$('[data-control="sensitive"]').sensitive()
|
||||
});
|
||||
|
||||
}(window.jQuery);
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
@import "../../../../assets/less/core/boot.less";
|
||||
|
||||
div[data-control="sensitive"] {
|
||||
a[data-toggle],
|
||||
a[data-copy] {
|
||||
box-shadow: none;
|
||||
border: 1px solid @input-group-addon-border-color;
|
||||
border-left: 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
<div
|
||||
data-control="sensitive"
|
||||
data-clean="true"
|
||||
data-event-handler="<?= $this->getEventHandler('onShowValue') ?>"
|
||||
<?php if ($hideOnTabChange): ?>data-hide-on-tab-change="true"<?php endif ?>
|
||||
>
|
||||
<div class="loading-indicator-container size-form-field">
|
||||
<div class="input-group">
|
||||
<input
|
||||
type="password"
|
||||
name="<?= $this->getFieldName() ?>"
|
||||
id="<?= $this->getId() ?>"
|
||||
value="<?= ($hasValue) ? $hiddenPlaceholder : '' ?>"
|
||||
placeholder="<?= e(trans($this->formField->placeholder)) ?>"
|
||||
class="form-control"
|
||||
<?php if ($this->previewMode): ?>disabled="disabled"<?php endif ?>
|
||||
autocomplete="off"
|
||||
data-input
|
||||
/>
|
||||
<?php if ($allowCopy): ?>
|
||||
<a
|
||||
href="javascript:;"
|
||||
class="input-group-addon btn btn-secondary"
|
||||
data-copy
|
||||
>
|
||||
<i class="icon-copy"></i>
|
||||
</a>
|
||||
<?php endif ?>
|
||||
<a
|
||||
href="javascript:;"
|
||||
class="input-group-addon btn btn-secondary"
|
||||
data-toggle
|
||||
>
|
||||
<i class="icon-eye" data-icon></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="loading-indicator hide" data-loader>
|
||||
<span class="p-a"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -5,7 +5,7 @@ use Lang;
|
|||
use Model;
|
||||
use Response;
|
||||
use League\Csv\Writer as CsvWriter;
|
||||
use October\Rain\Parse\League\EscapeFormula as CsvEscapeFormula;
|
||||
use League\Csv\EscapeFormula as CsvEscapeFormula;
|
||||
use ApplicationException;
|
||||
use SplTempFileObject;
|
||||
|
||||
|
|
@ -112,8 +112,7 @@ abstract class ExportModel extends Model
|
|||
$csv->setEscape($options['escape']);
|
||||
}
|
||||
|
||||
// Temporary until upgrading to league/csv >= 9.1.0 (will be $csv->addFormatter($formatter))
|
||||
$formatter = new CsvEscapeFormula();
|
||||
$csv->addFormatter(new CsvEscapeFormula());
|
||||
|
||||
/*
|
||||
* Add headers
|
||||
|
|
@ -128,10 +127,6 @@ abstract class ExportModel extends Model
|
|||
*/
|
||||
foreach ($results as $result) {
|
||||
$data = $this->matchDataToColumns($result, $columns);
|
||||
|
||||
// Temporary until upgrading to league/csv >= 9.1.0
|
||||
$data = $formatter($data);
|
||||
|
||||
$csv->insertOne($data);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use Str;
|
|||
use Lang;
|
||||
use Model;
|
||||
use League\Csv\Reader as CsvReader;
|
||||
use League\Csv\Statement as CsvStatement;
|
||||
|
||||
/**
|
||||
* Model used for importing data
|
||||
|
|
@ -108,11 +109,6 @@ abstract class ImportModel extends Model
|
|||
*/
|
||||
$reader = CsvReader::createFromPath($filePath, 'r');
|
||||
|
||||
// Filter out empty rows
|
||||
$reader->addFilter(function (array $row) {
|
||||
return count($row) > 1 || reset($row) !== null;
|
||||
});
|
||||
|
||||
if ($options['delimiter'] !== null) {
|
||||
$reader->setDelimiter($options['delimiter']);
|
||||
}
|
||||
|
|
@ -125,15 +121,11 @@ abstract class ImportModel extends Model
|
|||
$reader->setEscape($options['escape']);
|
||||
}
|
||||
|
||||
if ($options['firstRowTitles']) {
|
||||
$reader->setOffset(1);
|
||||
}
|
||||
|
||||
if (
|
||||
$options['encoding'] !== null &&
|
||||
$reader->isActiveStreamFilter()
|
||||
$reader->supportsStreamFilter()
|
||||
) {
|
||||
$reader->appendStreamFilter(sprintf(
|
||||
$reader->addStreamFilter(sprintf(
|
||||
'%s%s:%s',
|
||||
TranscodeFilter::FILTER_NAME,
|
||||
strtolower($options['encoding']),
|
||||
|
|
@ -141,8 +133,19 @@ abstract class ImportModel extends Model
|
|||
));
|
||||
}
|
||||
|
||||
// Create reader statement
|
||||
$stmt = (new CsvStatement)
|
||||
->where(function (array $row) {
|
||||
// Filter out empty rows
|
||||
return count($row) > 1 || reset($row) !== null;
|
||||
});
|
||||
|
||||
if ($options['firstRowTitles']) {
|
||||
$stmt = $stmt->offset(1);
|
||||
}
|
||||
|
||||
$result = [];
|
||||
$contents = $reader->fetch();
|
||||
$contents = $stmt->process($reader);
|
||||
foreach ($contents as $row) {
|
||||
$result[] = $this->processImportRow($row, $matches);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@ class User extends UserBase
|
|||
public $rules = [
|
||||
'email' => 'required|between:6,255|email|unique:backend_users',
|
||||
'login' => 'required|between:2,255|unique:backend_users',
|
||||
'password' => 'required:create|between:4,255|confirmed',
|
||||
'password_confirmation' => 'required_with:password|between:4,255'
|
||||
'password' => 'required:create|min:4|confirmed',
|
||||
'password_confirmation' => 'required_with:password|min:4'
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ App::before(function ($request) {
|
|||
'middleware' => ['web'],
|
||||
'prefix' => Config::get('cms.backendUri', 'backend')
|
||||
], function () {
|
||||
Route::any('{slug}', 'Backend\Classes\BackendController@run')->where('slug', '(.*)?');
|
||||
Route::any('{slug?}', 'Backend\Classes\BackendController@run')->where('slug', '(.*)?');
|
||||
})
|
||||
;
|
||||
|
||||
|
|
|
|||
|
|
@ -287,25 +287,14 @@ class Asset extends Extendable
|
|||
|
||||
$directory = $this->theme->getPath() . '/' . $this->dirName . '/';
|
||||
$filePath = $directory . $fileName;
|
||||
$path = realpath($filePath);
|
||||
|
||||
/**
|
||||
* If the path doesn't exist yet, then create it temporarily
|
||||
* in order to run realpath() resolution on it to verify the
|
||||
* final destination and then remove the temporary file.
|
||||
*/
|
||||
if (!$path) {
|
||||
touch($filePath);
|
||||
$path = realpath($filePath);
|
||||
unlink($filePath);
|
||||
}
|
||||
$resolvedPath = resolve_path($filePath);
|
||||
|
||||
// Limit paths to those under the theme's assets directory
|
||||
if (!starts_with($path, $directory)) {
|
||||
if (!starts_with($resolvedPath, $directory)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $path;
|
||||
return $resolvedPath;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -316,7 +316,8 @@ class CmsCompoundObject extends CmsObject
|
|||
|
||||
self::$objectComponentPropertyMap = $objectComponentMap;
|
||||
|
||||
Cache::put($key, base64_encode(serialize($objectComponentMap)), Config::get('cms.parsedPageCacheTTL', 10));
|
||||
$expiresAt = now()->addMinutes(Config::get('cms.parsedPageCacheTTL', 10));
|
||||
Cache::put($key, base64_encode(serialize($objectComponentMap)), $expiresAt);
|
||||
|
||||
if (array_key_exists($componentName, $objectComponentMap[$objectCode])) {
|
||||
return $objectComponentMap[$objectCode][$componentName];
|
||||
|
|
|
|||
|
|
@ -227,7 +227,16 @@ class CmsObject extends HalcyonModel implements CmsObjectContract
|
|||
$fileName = $this->fileName;
|
||||
}
|
||||
|
||||
return $this->theme->getPath().'/'.$this->getObjectTypeDirName().'/'.$fileName;
|
||||
$directory = $this->theme->getPath() . '/' . $this->getObjectTypeDirName() . '/';
|
||||
$filePath = $directory . $fileName;
|
||||
$resolvedPath = resolve_path($filePath);
|
||||
|
||||
// Limit paths to those under the corresponding theme directory
|
||||
if (!starts_with($resolvedPath, $directory)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $resolvedPath;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<?php namespace Cms\Classes;
|
||||
|
||||
use ApplicationException;
|
||||
use October\Rain\Support\Collection as CollectionBase;
|
||||
|
||||
/**
|
||||
|
|
@ -37,15 +38,32 @@ class CmsObjectCollection extends CollectionBase
|
|||
|
||||
/**
|
||||
* Returns objects whose properties match the supplied value.
|
||||
* @param string $property
|
||||
* @param string $value
|
||||
* @param bool $strict
|
||||
*
|
||||
* Note that this deviates from Laravel 6's Illuminate\Support\Traits\EnumeratesValues::where() method signature,
|
||||
* which uses ($key, $operator = null, $value = null) as parameters and that this class extends.
|
||||
*
|
||||
* To ensure backwards compatibility with our current Halcyon functionality, this method retains the original
|
||||
* parameters and functions the same way as before, with handling for the $value and $strict parameters to ensure
|
||||
* they match the previously expected formats. This means that you cannot use operators for "where" queries on
|
||||
* CMS object collections.
|
||||
*
|
||||
* @param string $property
|
||||
* @param string $value
|
||||
* @param bool $strict
|
||||
* @return static
|
||||
*/
|
||||
public function where($property, $value, $strict = true)
|
||||
public function where($property, $value = null, $strict = null)
|
||||
{
|
||||
return $this->filter(function ($object) use ($property, $value, $strict) {
|
||||
if (empty($value) || !is_string($value)) {
|
||||
throw new ApplicationException('You must provide a string value to compare with when executing a "where" '
|
||||
. 'query for CMS object collections.');
|
||||
}
|
||||
|
||||
if (!isset($strict) || !is_bool($strict)) {
|
||||
$strict = true;
|
||||
}
|
||||
|
||||
return $this->filter(function ($object) use ($property, $value, $strict) {
|
||||
if (!array_key_exists($property, $object->settings)) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -224,7 +224,8 @@ class CodeParser
|
|||
$cached = $this->getCachedInfo() ?: [];
|
||||
$cached[$this->filePath] = $cacheItem;
|
||||
|
||||
Cache::put($this->dataCacheKey, base64_encode(serialize($cached)), 1440);
|
||||
$expiresAt = now()->addMinutes(1440);
|
||||
Cache::put($this->dataCacheKey, base64_encode(serialize($cached)), $expiresAt);
|
||||
|
||||
self::$cache[$this->filePath] = $result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,10 +127,11 @@ class Router
|
|||
: $fileName;
|
||||
|
||||
$key = $this->getUrlListCacheKey();
|
||||
$expiresAt = now()->addMinutes(Config::get('cms.urlCacheTtl', 1));
|
||||
Cache::put(
|
||||
$key,
|
||||
base64_encode(serialize($urlList)),
|
||||
Config::get('cms.urlCacheTtl', 1)
|
||||
$expiresAt
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -251,7 +252,8 @@ class Router
|
|||
|
||||
$this->urlMap = $map;
|
||||
if ($cacheable) {
|
||||
Cache::put($key, base64_encode(serialize($map)), Config::get('cms.urlCacheTtl', 1));
|
||||
$expiresAt = now()->addMinutes(Config::get('cms.urlCacheTtl', 1));
|
||||
Cache::put($key, base64_encode(serialize($map)), $expiresAt);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -158,7 +158,8 @@ class Theme
|
|||
if ($checkDatabase && App::hasDatabase()) {
|
||||
try {
|
||||
try {
|
||||
$dbResult = Cache::remember(self::ACTIVE_KEY, 1440, function () {
|
||||
$expiresAt = now()->addMinutes(1440);
|
||||
$dbResult = Cache::remember(self::ACTIVE_KEY, $expiresAt, function () {
|
||||
return Parameter::applyKey(self::ACTIVE_KEY)->value('value');
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,11 +8,13 @@
|
|||
"authors": [
|
||||
{
|
||||
"name": "Alexey Bobkov",
|
||||
"email": "aleksey.bobkov@gmail.com"
|
||||
"email": "aleksey.bobkov@gmail.com",
|
||||
"role": "Co-founder"
|
||||
},
|
||||
{
|
||||
"name": "Samuel Georges",
|
||||
"email": "daftspunky@gmail.com"
|
||||
"email": "daftspunky@gmail.com",
|
||||
"role": "Co-founder"
|
||||
},
|
||||
{
|
||||
"name": "Luke Towers",
|
||||
|
|
@ -22,9 +24,10 @@
|
|||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.0",
|
||||
"php": ">=7.2",
|
||||
"composer/installers": "~1.0",
|
||||
"october/rain": "~1.0"
|
||||
"october/rain": "~1.0",
|
||||
"laravel/framework": "~6.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ App::before(function ($request) {
|
|||
* The CMS module intercepts all URLs that were not
|
||||
* handled by the back-end modules.
|
||||
*/
|
||||
Route::any('{slug}', 'Cms\Classes\CmsController@run')->where('slug', '(.*)?')->middleware('web');
|
||||
Route::any('{slug?}', 'Cms\Classes\CmsController@run')->where('slug', '(.*)?')->middleware('web');
|
||||
|
||||
/**
|
||||
* @event cms.route
|
||||
|
|
|
|||
|
|
@ -190,7 +190,8 @@ trait UrlMaker
|
|||
'mtime' => @File::lastModified($filePath)
|
||||
];
|
||||
|
||||
Cache::put($key, serialize($cached), Config::get('cms.parsedPageCacheTTL', 1440));
|
||||
$expiresAt = now()->addMinutes(Config::get('cms.parsedPageCacheTTL', 1440));
|
||||
Cache::put($key, serialize($cached), $expiresAt);
|
||||
|
||||
return static::$urlPageName = $baseFileName;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use Cms\Classes\Controller;
|
|||
use Cms\Classes\ComponentBase;
|
||||
use Illuminate\Pagination\Paginator;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Debug\HtmlDumper;
|
||||
use Symfony\Component\VarDumper\Dumper\HtmlDumper;
|
||||
use Symfony\Component\VarDumper\Cloner\VarCloner;
|
||||
use October\Rain\Database\Model;
|
||||
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@ class ServiceProvider extends ModuleServiceProvider
|
|||
}
|
||||
}
|
||||
|
||||
Paginator::useBootstrapThree();
|
||||
Paginator::defaultSimpleView('system::pagination.simple-default');
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ return [
|
|||
'Eloquent' => Illuminate\Database\Eloquent\Model::class,
|
||||
'Event' => Illuminate\Support\Facades\Event::class,
|
||||
'Hash' => Illuminate\Support\Facades\Hash::class,
|
||||
'Input' => Illuminate\Support\Facades\Input::class,
|
||||
'Lang' => Illuminate\Support\Facades\Lang::class,
|
||||
'Log' => Illuminate\Support\Facades\Log::class,
|
||||
'Mail' => Illuminate\Support\Facades\Mail::class,
|
||||
|
|
@ -30,7 +29,6 @@ return [
|
|||
'Storage' => Illuminate\Support\Facades\Storage::class,
|
||||
'Url' => Illuminate\Support\Facades\URL::class, // Preferred
|
||||
'URL' => Illuminate\Support\Facades\URL::class,
|
||||
'Validator' => Illuminate\Support\Facades\Validator::class,
|
||||
'View' => Illuminate\Support\Facades\View::class,
|
||||
|
||||
/*
|
||||
|
|
@ -42,6 +40,7 @@ return [
|
|||
'Config' => October\Rain\Support\Facades\Config::class,
|
||||
'Seeder' => October\Rain\Database\Updates\Seeder::class,
|
||||
'Flash' => October\Rain\Support\Facades\Flash::class,
|
||||
'Input' => October\Rain\Support\Facades\Input::class,
|
||||
'Form' => October\Rain\Support\Facades\Form::class,
|
||||
'Html' => October\Rain\Support\Facades\Html::class,
|
||||
'Http' => October\Rain\Support\Facades\Http::class,
|
||||
|
|
@ -52,6 +51,7 @@ return [
|
|||
'Twig' => October\Rain\Support\Facades\Twig::class,
|
||||
'DbDongle' => October\Rain\Support\Facades\DbDongle::class,
|
||||
'Schema' => October\Rain\Support\Facades\Schema::class,
|
||||
'Validator' => October\Rain\Support\Facades\Validator::class,
|
||||
'Cms' => Cms\Facades\Cms::class,
|
||||
'Backend' => Backend\Facades\Backend::class,
|
||||
'BackendMenu' => Backend\Facades\BackendMenu::class,
|
||||
|
|
@ -60,4 +60,12 @@ return [
|
|||
'SystemException' => October\Rain\Exception\SystemException::class,
|
||||
'ApplicationException' => October\Rain\Exception\ApplicationException::class,
|
||||
'ValidationException' => October\Rain\Exception\ValidationException::class,
|
||||
|
||||
/*
|
||||
* Fallback aliases
|
||||
*/
|
||||
// Input facade was removed in Laravel 6 - we are keeping it in the Rain library for backwards compatibility.
|
||||
'Illuminate\Support\Facades\Input' => October\Rain\Support\Facades\Input::class,
|
||||
// Illuminate's HtmlDumper was "dumped" in Laravel 6 - we'll route this to Symfony's HtmlDumper as Laravel have done.
|
||||
'Illuminate\Support\Debug\HtmlDumper' => Symfony\Component\VarDumper\Dumper\HtmlDumper::class,
|
||||
];
|
||||
|
|
|
|||
|
|
@ -10,11 +10,11 @@ use Route;
|
|||
use Config;
|
||||
use Request;
|
||||
use Response;
|
||||
use Assetic\Asset\FileAsset;
|
||||
use Assetic\Asset\AssetCache;
|
||||
use Assetic\Asset\AssetCollection;
|
||||
use Assetic\Factory\AssetFactory;
|
||||
use October\Rain\Parse\Assetic\FilesystemCache;
|
||||
use October\Rain\Assetic\Asset\FileAsset;
|
||||
use October\Rain\Assetic\Asset\AssetCache;
|
||||
use October\Rain\Assetic\Asset\AssetCollection;
|
||||
use October\Rain\Assetic\Cache\FilesystemCache;
|
||||
use October\Rain\Assetic\Factory\AssetFactory;
|
||||
use System\Helpers\Cache as CacheHelper;
|
||||
use ApplicationException;
|
||||
use DateTime;
|
||||
|
|
@ -126,22 +126,22 @@ class CombineAssets
|
|||
/*
|
||||
* Register JavaScript filters
|
||||
*/
|
||||
$this->registerFilter('js', new \October\Rain\Parse\Assetic\JavascriptImporter);
|
||||
$this->registerFilter('js', new \October\Rain\Assetic\Filter\JavascriptImporter);
|
||||
|
||||
/*
|
||||
* Register CSS filters
|
||||
*/
|
||||
$this->registerFilter('css', new \Assetic\Filter\CssImportFilter);
|
||||
$this->registerFilter(['css', 'less', 'scss'], new \Assetic\Filter\CssRewriteFilter);
|
||||
$this->registerFilter('less', new \October\Rain\Parse\Assetic\LessCompiler);
|
||||
$this->registerFilter('scss', new \October\Rain\Parse\Assetic\ScssCompiler);
|
||||
$this->registerFilter('css', new \October\Rain\Assetic\Filter\CssImportFilter);
|
||||
$this->registerFilter(['css', 'less', 'scss'], new \October\Rain\Assetic\Filter\CssRewriteFilter);
|
||||
$this->registerFilter('less', new \October\Rain\Assetic\Filter\LessCompiler);
|
||||
$this->registerFilter('scss', new \October\Rain\Assetic\Filter\ScssCompiler);
|
||||
|
||||
/*
|
||||
* Minification filters
|
||||
*/
|
||||
if ($this->useMinify) {
|
||||
$this->registerFilter('js', new \Assetic\Filter\JSMinFilter);
|
||||
$this->registerFilter(['css', 'less', 'scss'], new \October\Rain\Parse\Assetic\StylesheetMinify);
|
||||
$this->registerFilter('js', new \October\Rain\Assetic\Filter\JSMinFilter);
|
||||
$this->registerFilter(['css', 'less', 'scss'], new \October\Rain\Assetic\Filter\StylesheetMinify);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -134,10 +134,11 @@ class MediaLibrary
|
|||
$folderContents = $this->scanFolderContents($fullFolderPath);
|
||||
|
||||
$cached[$fullFolderPath] = $folderContents;
|
||||
$expiresAt = now()->addMinutes(Config::get('cms.storage.media.ttl', 10));
|
||||
Cache::put(
|
||||
$this->cacheKey,
|
||||
base64_encode(serialize($cached)),
|
||||
Config::get('cms.storage.media.ttl', 10)
|
||||
$expiresAt
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,11 +29,6 @@ class UpdateManager
|
|||
{
|
||||
use \October\Rain\Support\Traits\Singleton;
|
||||
|
||||
/**
|
||||
* @var array The notes for the current operation.
|
||||
*/
|
||||
protected $notes = [];
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Console\OutputStyle
|
||||
*/
|
||||
|
|
@ -345,13 +340,13 @@ class UpdateManager
|
|||
/*
|
||||
* Rollback modules
|
||||
*/
|
||||
if (isset($this->notesOutput)) {
|
||||
$this->migrator->setOutput($this->notesOutput);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
$rolledBack = $this->migrator->rollback($paths, ['pretend' => false]);
|
||||
|
||||
foreach ($this->migrator->getNotes() as $note) {
|
||||
$this->note($note);
|
||||
}
|
||||
|
||||
if (count($rolledBack) == 0) {
|
||||
break;
|
||||
}
|
||||
|
|
@ -403,13 +398,13 @@ class UpdateManager
|
|||
*/
|
||||
public function migrateModule($module)
|
||||
{
|
||||
$this->migrator->run(base_path() . '/modules/' . strtolower($module) . '/database/migrations');
|
||||
if (isset($this->notesOutput)) {
|
||||
$this->migrator->setOutput($this->notesOutput);
|
||||
}
|
||||
|
||||
$this->note($module);
|
||||
|
||||
foreach ($this->migrator->getNotes() as $note) {
|
||||
$this->note(' - ' . $note);
|
||||
}
|
||||
$this->migrator->run(base_path() . '/modules/'.strtolower($module).'/database/migrations');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
|
@ -518,13 +513,9 @@ class UpdateManager
|
|||
|
||||
$this->note($name);
|
||||
|
||||
$this->versionManager->resetNotes()->setNotesOutput($this->notesOutput);
|
||||
$this->versionManager->setNotesOutput($this->notesOutput);
|
||||
|
||||
if ($this->versionManager->updatePlugin($plugin) !== false) {
|
||||
foreach ($this->versionManager->getNotes() as $note) {
|
||||
$this->note($note);
|
||||
}
|
||||
}
|
||||
$this->versionManager->updatePlugin($plugin);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
|
@ -713,7 +704,8 @@ class UpdateManager
|
|||
}
|
||||
|
||||
$data = $this->requestServerData($type . '/popular');
|
||||
Cache::put($cacheKey, base64_encode(serialize($data)), 60);
|
||||
$expiresAt = now()->addMinutes(60);
|
||||
Cache::put($cacheKey, base64_encode(serialize($data)), $expiresAt);
|
||||
|
||||
foreach ($data as $product) {
|
||||
$code = array_get($product, 'code', -1);
|
||||
|
|
@ -802,35 +794,11 @@ class UpdateManager
|
|||
{
|
||||
if ($this->notesOutput !== null) {
|
||||
$this->notesOutput->writeln($message);
|
||||
} else {
|
||||
$this->notes[] = $message;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notes for the last operation.
|
||||
* @return array
|
||||
*/
|
||||
public function getNotes()
|
||||
{
|
||||
return $this->notes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the notes store.
|
||||
* @return self
|
||||
*/
|
||||
public function resetNotes()
|
||||
{
|
||||
$this->notesOutput = null;
|
||||
|
||||
$this->notes = [];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an output stream for writing notes.
|
||||
* @param Illuminate\Console\Command $output
|
||||
|
|
|
|||
|
|
@ -29,12 +29,6 @@ class VersionManager
|
|||
const HISTORY_TYPE_COMMENT = 'comment';
|
||||
const HISTORY_TYPE_SCRIPT = 'script';
|
||||
|
||||
/**
|
||||
* The notes for the current operation.
|
||||
* @var array
|
||||
*/
|
||||
protected $notes = [];
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Console\OutputStyle
|
||||
*/
|
||||
|
|
@ -426,6 +420,7 @@ class VersionManager
|
|||
* Execute the database PHP script
|
||||
*/
|
||||
$updateFile = $this->pluginManager->getPluginPath($code) . '/updates/' . $script;
|
||||
|
||||
$this->updater->packDown($updateFile);
|
||||
|
||||
Db::table('system_plugin_history')
|
||||
|
|
@ -508,35 +503,11 @@ class VersionManager
|
|||
{
|
||||
if ($this->notesOutput !== null) {
|
||||
$this->notesOutput->writeln($message);
|
||||
} else {
|
||||
$this->notes[] = $message;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notes for the last operation.
|
||||
* @return array
|
||||
*/
|
||||
public function getNotes()
|
||||
{
|
||||
return $this->notes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the notes store.
|
||||
* @return self
|
||||
*/
|
||||
public function resetNotes()
|
||||
{
|
||||
$this->notesOutput = null;
|
||||
|
||||
$this->notes = [];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an output stream for writing notes.
|
||||
* @param Illuminate\Console\Command $output
|
||||
|
|
@ -550,8 +521,7 @@ class VersionManager
|
|||
}
|
||||
|
||||
/**
|
||||
* @param $details
|
||||
*
|
||||
* Extract script and comments from version details
|
||||
* @return array
|
||||
*/
|
||||
protected function extractScriptsAndComments($details): array
|
||||
|
|
@ -566,7 +536,8 @@ class VersionManager
|
|||
$scripts = array_values(array_filter($details, function ($detail) use ($fileNamePattern) {
|
||||
return preg_match($fileNamePattern, $detail);
|
||||
}));
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$comments = (array)$details;
|
||||
$scripts = [];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,11 +8,13 @@
|
|||
"authors": [
|
||||
{
|
||||
"name": "Alexey Bobkov",
|
||||
"email": "aleksey.bobkov@gmail.com"
|
||||
"email": "aleksey.bobkov@gmail.com",
|
||||
"role": "Co-founder"
|
||||
},
|
||||
{
|
||||
"name": "Samuel Georges",
|
||||
"email": "daftspunky@gmail.com"
|
||||
"email": "daftspunky@gmail.com",
|
||||
"role": "Co-founder"
|
||||
},
|
||||
{
|
||||
"name": "Luke Towers",
|
||||
|
|
@ -22,9 +24,10 @@
|
|||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.0",
|
||||
"php": ">=7.2",
|
||||
"composer/installers": "~1.0",
|
||||
"october/rain": "~1.0"
|
||||
"october/rain": "~1.0",
|
||||
"laravel/framework": "~6.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
|
|
|||
|
|
@ -369,7 +369,7 @@ class OctoberEnv extends Command
|
|||
'SESSION_DRIVER' => 'driver',
|
||||
],
|
||||
'queue' => [
|
||||
'QUEUE_DRIVER' => 'default',
|
||||
'QUEUE_CONNECTION' => 'default',
|
||||
],
|
||||
'mail' => [
|
||||
'MAIL_DRIVER' => 'driver',
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ use Symfony\Component\Console\Input\InputOption;
|
|||
*/
|
||||
class OctoberUpdate extends Command
|
||||
{
|
||||
|
||||
/**
|
||||
* The console command name.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
use Lang;
|
||||
use Flash;
|
||||
use Config;
|
||||
use Request;
|
||||
use Backend;
|
||||
use BackendMenu;
|
||||
use System\Classes\SettingsManager;
|
||||
|
|
@ -139,6 +141,22 @@ class Settings extends Controller
|
|||
return $this->formWidget->render($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the form widget used by this behavior.
|
||||
*
|
||||
* @return \Backend\Widgets\Form
|
||||
*/
|
||||
public function formGetWidget()
|
||||
{
|
||||
if (is_null($this->formWidget)) {
|
||||
$item = $this->findSettingItem();
|
||||
$model = $this->createModel($item);
|
||||
$this->initWidgets($model);
|
||||
}
|
||||
|
||||
return $this->formWidget;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the widgets used by this action
|
||||
* Model $model
|
||||
|
|
@ -169,10 +187,22 @@ class Settings extends Controller
|
|||
}
|
||||
|
||||
/**
|
||||
* Locates a setting item for a module or plugin
|
||||
* Locates a setting item for a module or plugin.
|
||||
*
|
||||
* If none of the parameters are provided, they will be auto-guessed from the URL.
|
||||
*
|
||||
* @param string|null $author
|
||||
* @param string|null $plugin
|
||||
* @param string|null $code
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function findSettingItem($author, $plugin, $code)
|
||||
protected function findSettingItem($author = null, $plugin = null, $code = null)
|
||||
{
|
||||
if (is_null($author) || is_null($plugin)) {
|
||||
[$author, $plugin, $code] = $this->guessSettingItem();
|
||||
}
|
||||
|
||||
$manager = SettingsManager::instance();
|
||||
|
||||
$moduleOwner = $author;
|
||||
|
|
@ -187,4 +217,23 @@ class Settings extends Controller
|
|||
|
||||
return $item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Guesses the requested setting item from the current URL segments provided by the Request object.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function guessSettingItem()
|
||||
{
|
||||
$segments = Request::segments();
|
||||
|
||||
if (!empty(Config::get('cms.backendUri', 'backend'))) {
|
||||
array_splice($segments, 0, 4);
|
||||
} else {
|
||||
array_splice($segments, 0, 3);
|
||||
}
|
||||
|
||||
// Ensure there's at least 3 segments
|
||||
return array_pad($segments, 3, null);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@ class DatabaseSeeder extends Seeder
|
|||
*/
|
||||
public function run()
|
||||
{
|
||||
Eloquent::unguard();
|
||||
|
||||
$this->call('System\Database\Seeds\SeedSetupMailLayouts');
|
||||
Eloquent::unguarded(function () {
|
||||
$this->call('System\Database\Seeds\SeedSetupMailLayouts');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ return [
|
|||
'boolean' => 'The :attribute field must be true or false.',
|
||||
'confirmed' => 'The :attribute confirmation does not match.',
|
||||
'date' => 'The :attribute is not a valid date.',
|
||||
'date_equals' => 'The :attribute must be a date equal to :date.',
|
||||
'date_format' => 'The :attribute does not match the format :format.',
|
||||
'different' => 'The :attribute and :other must be different.',
|
||||
'digits' => 'The :attribute must be :digits digits.',
|
||||
|
|
@ -39,9 +40,22 @@ return [
|
|||
'dimensions' => 'The :attribute has invalid image dimensions.',
|
||||
'distinct' => 'The :attribute field has a duplicate value.',
|
||||
'email' => 'The :attribute must be a valid email address.',
|
||||
'ends_with' => 'The :attribute must end with one of the following: :values.',
|
||||
'exists' => 'The selected :attribute is invalid.',
|
||||
'file' => 'The :attribute must be a file.',
|
||||
'filled' => 'The :attribute field must have a value.',
|
||||
'gt' => [
|
||||
'numeric' => 'The :attribute must be greater than :value.',
|
||||
'file' => 'The :attribute must be greater than :value kilobytes.',
|
||||
'string' => 'The :attribute must be greater than :value characters.',
|
||||
'array' => 'The :attribute must have more than :value items.',
|
||||
],
|
||||
'gte' => [
|
||||
'numeric' => 'The :attribute must be greater than or equal :value.',
|
||||
'file' => 'The :attribute must be greater than or equal :value kilobytes.',
|
||||
'string' => 'The :attribute must be greater than or equal :value characters.',
|
||||
'array' => 'The :attribute must have :value items or more.',
|
||||
],
|
||||
'image' => 'The :attribute must be an image.',
|
||||
'in' => 'The selected :attribute is invalid.',
|
||||
'in_array' => 'The :attribute field does not exist in :other.',
|
||||
|
|
@ -50,6 +64,18 @@ return [
|
|||
'ipv4' => 'The :attribute must be a valid IPv4 address.',
|
||||
'ipv6' => 'The :attribute must be a valid IPv6 address.',
|
||||
'json' => 'The :attribute must be a valid JSON string.',
|
||||
'lt' => [
|
||||
'numeric' => 'The :attribute must be less than :value.',
|
||||
'file' => 'The :attribute must be less than :value kilobytes.',
|
||||
'string' => 'The :attribute must be less than :value characters.',
|
||||
'array' => 'The :attribute must have less than :value items.',
|
||||
],
|
||||
'lte' => [
|
||||
'numeric' => 'The :attribute must be less than or equal :value.',
|
||||
'file' => 'The :attribute must be less than or equal :value kilobytes.',
|
||||
'string' => 'The :attribute must be less than or equal :value characters.',
|
||||
'array' => 'The :attribute must not have more than :value items.',
|
||||
],
|
||||
'max' => [
|
||||
'numeric' => 'The :attribute may not be greater than :max.',
|
||||
'file' => 'The :attribute may not be greater than :max kilobytes.',
|
||||
|
|
@ -65,6 +91,7 @@ return [
|
|||
'array' => 'The :attribute must have at least :min items.',
|
||||
],
|
||||
'not_in' => 'The selected :attribute is invalid.',
|
||||
'not_regex' => 'The :attribute format is invalid.',
|
||||
'numeric' => 'The :attribute must be a number.',
|
||||
'present' => 'The :attribute field must be present.',
|
||||
'regex' => 'The :attribute format is invalid.',
|
||||
|
|
@ -82,11 +109,13 @@ return [
|
|||
'string' => 'The :attribute must be :size characters.',
|
||||
'array' => 'The :attribute must contain :size items.',
|
||||
],
|
||||
'starts_with' => 'The :attribute must start with one of the following: :values.',
|
||||
'string' => 'The :attribute must be a string.',
|
||||
'timezone' => 'The :attribute must be a valid zone.',
|
||||
'unique' => 'The :attribute has already been taken.',
|
||||
'uploaded' => 'The :attribute failed to upload.',
|
||||
'url' => 'The :attribute format is invalid.',
|
||||
'uuid' => 'The :attribute must be a valid UUID.',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ tabs:
|
|||
smtp_password:
|
||||
label: system::lang.mail.smtp_password
|
||||
tab: system::lang.mail.general
|
||||
type: sensitive
|
||||
span: right
|
||||
trigger:
|
||||
action: show
|
||||
|
|
@ -107,6 +108,7 @@ tabs:
|
|||
label: system::lang.mail.mailgun_secret
|
||||
commentAbove: system::lang.mail.mailgun_secret_comment
|
||||
tab: system::lang.mail.general
|
||||
type: sensitive
|
||||
trigger:
|
||||
action: show
|
||||
field: send_mode
|
||||
|
|
@ -116,6 +118,7 @@ tabs:
|
|||
label: system::lang.mail.mandrill_secret
|
||||
commentAbove: system::lang.mail.mandrill_secret_comment
|
||||
tab: system::lang.mail.general
|
||||
type: sensitive
|
||||
trigger:
|
||||
action: show
|
||||
field: send_mode
|
||||
|
|
@ -135,6 +138,7 @@ tabs:
|
|||
label: system::lang.mail.ses_secret
|
||||
commentAbove: system::lang.mail.ses_secret_comment
|
||||
tab: system::lang.mail.general
|
||||
type: sensitive
|
||||
span: right
|
||||
trigger:
|
||||
action: show
|
||||
|
|
@ -154,6 +158,7 @@ tabs:
|
|||
sparkpost_secret:
|
||||
label: system::lang.mail.sparkpost_secret
|
||||
commentAbove: system::lang.mail.sparkpost_secret_comment
|
||||
type: sensitive
|
||||
tab: system::lang.mail.general
|
||||
trigger:
|
||||
action: show
|
||||
|
|
|
|||
|
|
@ -15,9 +15,7 @@ return [
|
|||
Illuminate\Pagination\PaginationServiceProvider::class,
|
||||
Illuminate\Pipeline\PipelineServiceProvider::class,
|
||||
Illuminate\Queue\QueueServiceProvider::class,
|
||||
Illuminate\Redis\RedisServiceProvider::class,
|
||||
Illuminate\Session\SessionServiceProvider::class,
|
||||
Illuminate\Validation\ValidationServiceProvider::class,
|
||||
Illuminate\View\ViewServiceProvider::class,
|
||||
Laravel\Tinker\TinkerServiceProvider::class,
|
||||
|
||||
|
|
@ -36,5 +34,7 @@ return [
|
|||
October\Rain\Flash\FlashServiceProvider::class,
|
||||
October\Rain\Mail\MailServiceProvider::class,
|
||||
October\Rain\Argon\ArgonServiceProvider::class,
|
||||
October\Rain\Redis\RedisServiceProvider::class,
|
||||
October\Rain\Validation\ValidationServiceProvider::class,
|
||||
|
||||
];
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnFailure="false"
|
||||
syntaxCheck="false"
|
||||
>
|
||||
<testsuites>
|
||||
<testsuite name="October CMS Test Suite">
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ abstract class PluginTestCase extends TestCase
|
|||
$app['cache']->setDefaultDriver('array');
|
||||
$app->setLocale('en');
|
||||
|
||||
$app->singleton('auth', function ($app) {
|
||||
$app->singleton('backend.auth', function ($app) {
|
||||
$app['auth.loaded'] = true;
|
||||
|
||||
return AuthManager::instance();
|
||||
|
|
@ -67,7 +67,7 @@ abstract class PluginTestCase extends TestCase
|
|||
* Perform test case set up.
|
||||
* @return void
|
||||
*/
|
||||
public function setUp()
|
||||
public function setUp() : void
|
||||
{
|
||||
/*
|
||||
* Force reload of October singletons
|
||||
|
|
@ -105,7 +105,7 @@ abstract class PluginTestCase extends TestCase
|
|||
* Flush event listeners and collect garbage.
|
||||
* @return void
|
||||
*/
|
||||
public function tearDown()
|
||||
public function tearDown() : void
|
||||
{
|
||||
$this->flushModelEventListeners();
|
||||
parent::tearDown();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Plugin testing
|
||||
|
||||
Plugin unit tests can be performed by running `phpunit` in the base plugin directory.
|
||||
Individual plugin test cases can be run by running `../../../vendor/bin/phpunit` in the plugin's base directory (ex. `plugins/acme/demo`.
|
||||
|
||||
### Creating plugin tests
|
||||
|
||||
|
|
@ -58,7 +58,7 @@ The test class should extend the base class `PluginTestCase` and this is a speci
|
|||
|
||||
class BaseTestCase extends PluginTestCase
|
||||
{
|
||||
public function setUp()
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
|
|
@ -72,7 +72,7 @@ The test class should extend the base class `PluginTestCase` and this is a speci
|
|||
$pluginManager->bootAll(true);
|
||||
}
|
||||
|
||||
public function tearDown()
|
||||
public function tearDown(): void
|
||||
{
|
||||
parent::tearDown();
|
||||
|
||||
|
|
@ -96,39 +96,10 @@ To perform unit testing on the core October files, you should download a develop
|
|||
|
||||
### Unit tests
|
||||
|
||||
Unit tests can be performed by running `phpunit` in the root directory or inside `/tests/unit`.
|
||||
Unit tests can be performed by running `vendor/bin/phpunit` in the root directory of your October CMS installation.
|
||||
|
||||
### Functional tests
|
||||
|
||||
Functional tests can be performed by running `phpunit` in the `/tests/functional` directory. Ensure the following configuration is met:
|
||||
Functional tests can be performed by installing the [RainLab Dusk](https://octobercms.com/plugin/rainlab-dusk) in your October CMS installation. The RainLab Dusk plugin is powered by Laravel Dusk, a comprehensive testing suite for the Laravel framework that is designed to test interactions with a fully operational October CMS instance through a virtual browser.
|
||||
|
||||
- Active theme is `demo`
|
||||
- Language preference is `en`
|
||||
|
||||
#### Selenium set up
|
||||
|
||||
1. Download latest Java SE from http://java.sun.com/ and install
|
||||
1. Download a distribution archive of [Selenium Server](http://seleniumhq.org/download/).
|
||||
1. Unzip the distribution archive and copy selenium-server-standalone-2.42.2.jar (check the version suffix) to /usr/local/bin, for instance.
|
||||
1. Start the Selenium Server server by running `java -jar /usr/local/bin/selenium-server-standalone-2.42.2.jar`.
|
||||
|
||||
#### Selenium configuration
|
||||
|
||||
Create a new file `selenium.php` in the root directory, add the following content:
|
||||
|
||||
<?php
|
||||
|
||||
// Selenium server details
|
||||
define('TEST_SELENIUM_HOST', '127.0.0.1');
|
||||
define('TEST_SELENIUM_PORT', 4444);
|
||||
define('TEST_SELENIUM_BROWSER', '*firefox');
|
||||
|
||||
// Back-end URL
|
||||
define('TEST_SELENIUM_URL', 'http://localhost/backend/');
|
||||
|
||||
// Active Theme
|
||||
define('TEST_SELENIUM_THEME', 'demo');
|
||||
|
||||
// Back-end credentials
|
||||
define('TEST_SELENIUM_USER', 'admin');
|
||||
define('TEST_SELENIUM_PASS', 'admin');
|
||||
For information on installing and setting up your October CMS install to run functional tests, please review the [README](https://github.com/rainlab/dusk-plugin/blob/master/README.md) for the plugin.
|
||||
|
|
|
|||
|
|
@ -1,111 +0,0 @@
|
|||
<?php
|
||||
|
||||
class UiTestCase extends PHPUnit_Extensions_SeleniumTestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
/*
|
||||
* Look for selenium configuration
|
||||
*/
|
||||
if (file_exists($seleniumEnv = __DIR__.'/../selenium.php')) {
|
||||
require_once $seleniumEnv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure selenium
|
||||
*/
|
||||
if (!defined('TEST_SELENIUM_URL')) {
|
||||
return $this->markTestSkipped('Selenium skipped');
|
||||
}
|
||||
|
||||
if (defined('TEST_SELENIUM_HOST')) {
|
||||
$this->setHost(TEST_SELENIUM_HOST);
|
||||
}
|
||||
if (defined('TEST_SELENIUM_PORT')) {
|
||||
$this->setPort(TEST_SELENIUM_PORT);
|
||||
}
|
||||
if (defined('TEST_SELENIUM_BROWSER')) {
|
||||
$this->setBrowser(TEST_SELENIUM_BROWSER);
|
||||
}
|
||||
$this->setBrowserUrl(TEST_SELENIUM_URL);
|
||||
}
|
||||
|
||||
//
|
||||
// OctoberCMS Helpers
|
||||
//
|
||||
|
||||
protected function signInToBackend()
|
||||
{
|
||||
$this->open('backend');
|
||||
$this->type("name=login", TEST_SELENIUM_USER);
|
||||
$this->type("name=password", TEST_SELENIUM_PASS);
|
||||
$this->click("//button[@type='submit']");
|
||||
$this->waitForPageToLoad("30000");
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to the native getConfirmation() function
|
||||
*/
|
||||
protected function getSweetConfirmation($expectedText = null, $clickOk = true)
|
||||
{
|
||||
$this->waitForElementPresent("xpath=(//div[@class='sweet-alert showSweetAlert visible'])[1]");
|
||||
|
||||
if ($expectedText) {
|
||||
$this->verifyText("//div[@class='sweet-alert showSweetAlert visible']//h4", $expectedText);
|
||||
}
|
||||
|
||||
$this->verifyText("//div[@class='sweet-alert showSweetAlert visible']//button[@class='confirm btn btn-primary']", "OK");
|
||||
|
||||
if ($clickOk) {
|
||||
$this->click("xpath=(//div[@class='sweet-alert showSweetAlert visible']//button[@class='confirm btn btn-primary'])[1]");
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Selenium helpers
|
||||
//
|
||||
|
||||
protected function waitForElementPresent($target, $timeout = 60)
|
||||
{
|
||||
$second = 0;
|
||||
|
||||
while (true) {
|
||||
if ($second >= $timeout) {
|
||||
$this->fail('timeout');
|
||||
}
|
||||
|
||||
try {
|
||||
if ($this->isElementPresent($target)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception $e) {
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
++$second;
|
||||
}
|
||||
}
|
||||
|
||||
protected function waitForElementNotPresent($target, $timeout = 60)
|
||||
{
|
||||
$second = 0;
|
||||
|
||||
while (true) {
|
||||
if ($second >= $timeout) {
|
||||
$this->fail('timeout');
|
||||
}
|
||||
|
||||
try {
|
||||
if (!$this->isElementPresent($target)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception $e) {
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
++$second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -19,14 +19,3 @@ $loader->addDirectories([
|
|||
'modules',
|
||||
'plugins'
|
||||
]);
|
||||
|
||||
/*
|
||||
* Monkey patch PHPUnit\Framework\MockObject\Generator to avoid
|
||||
* "Function ReflectionType::__toString() is deprecated" warnings
|
||||
*/
|
||||
$generatorPatchPath = __DIR__ . '/resources/patches/php-generator-7.php';
|
||||
$generatorSourcePath = __DIR__ . '/../vendor/phpunit/phpunit-mock-objects/src/Generator.php';
|
||||
|
||||
if (file_exists($generatorSourcePath)) {
|
||||
file_put_contents($generatorSourcePath, file_get_contents($generatorPatchPath));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ trait InteractsWithAuthentication
|
|||
*/
|
||||
public function be(UserContract $user, $driver = null)
|
||||
{
|
||||
$this->app['auth']->setUser($user);
|
||||
$this->app['backend.auth']->setUser($user);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -66,7 +66,7 @@ trait InteractsWithAuthentication
|
|||
*/
|
||||
protected function isAuthenticated($guard = null)
|
||||
{
|
||||
return $this->app->make('auth')->guard($guard)->check();
|
||||
return $this->app->make('backend.auth')->guard($guard)->check();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -78,7 +78,7 @@ trait InteractsWithAuthentication
|
|||
*/
|
||||
public function assertAuthenticatedAs($user, $guard = null)
|
||||
{
|
||||
$expected = $this->app->make('auth')->guard($guard)->user();
|
||||
$expected = $this->app->make('backend.auth')->guard($guard)->user();
|
||||
|
||||
$this->assertNotNull($expected, 'The current user is not authenticated.');
|
||||
|
||||
|
|
@ -140,7 +140,7 @@ trait InteractsWithAuthentication
|
|||
*/
|
||||
protected function hasCredentials(array $credentials, $guard = null)
|
||||
{
|
||||
$provider = $this->app->make('auth')->guard($guard)->getProvider();
|
||||
$provider = $this->app->make('backend.auth')->guard($guard)->getProvider();
|
||||
|
||||
$user = $provider->retrieveByCredentials($credentials);
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ class Author extends Model
|
|||
*/
|
||||
public $belongsTo = [
|
||||
'user' => ['Database\Tester\Models\User', 'delete' => true],
|
||||
'country' => ['Database\Tester\Models\Country'],
|
||||
'user_soft' => ['Database\Tester\Models\SoftDeleteUser', 'key' => 'user_id', 'softDelete' => true],
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
<?php namespace Database\Tester\Models;
|
||||
|
||||
use Model;
|
||||
|
||||
class Country extends Model
|
||||
{
|
||||
|
||||
/**
|
||||
* @var string The database table used by the model.
|
||||
*/
|
||||
public $table = 'database_tester_countries';
|
||||
|
||||
/**
|
||||
* @var array Guarded fields
|
||||
*/
|
||||
protected $guarded = [];
|
||||
|
||||
public $hasMany = [
|
||||
'users' => [
|
||||
'Database\Tester\Models\User',
|
||||
],
|
||||
];
|
||||
|
||||
public $hasManyThrough = [
|
||||
'posts' => [
|
||||
'Database\Tester\Models\Post',
|
||||
'through' => 'Database\Tester\Models\Author',
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
class SoftDeleteCountry extends Country
|
||||
{
|
||||
use \October\Rain\Database\Traits\SoftDelete;
|
||||
}
|
||||
|
|
@ -17,6 +17,19 @@ class User extends Model
|
|||
/**
|
||||
* @var array Relations
|
||||
*/
|
||||
public $hasOne = [
|
||||
'author' => [
|
||||
'Database\Tester\Models\Author',
|
||||
]
|
||||
];
|
||||
|
||||
public $hasOneThrough = [
|
||||
'phone' => [
|
||||
'Database\Tester\Models\Phone',
|
||||
'through' => 'Database\Tester\Models\Author',
|
||||
],
|
||||
];
|
||||
|
||||
public $attachOne = [
|
||||
'avatar' => 'System\Models\File'
|
||||
];
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ class CreateAuthorsTable extends Migration
|
|||
$table->engine = 'InnoDB';
|
||||
$table->increments('id');
|
||||
$table->integer('user_id')->unsigned()->index()->nullable();
|
||||
$table->integer('country_id')->unsigned()->index()->nullable();
|
||||
$table->string('name')->nullable();
|
||||
$table->string('email')->nullable();
|
||||
$table->softDeletes();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
<?php namespace Database\Tester\Updates;
|
||||
|
||||
use Schema;
|
||||
use October\Rain\Database\Updates\Migration;
|
||||
|
||||
class CreateCountriesTable extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
Schema::create('database_tester_countries', function ($table) {
|
||||
$table->engine = 'InnoDB';
|
||||
$table->increments('id');
|
||||
$table->string('name')->nullable();
|
||||
$table->softDeletes();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('database_tester_countries');
|
||||
}
|
||||
}
|
||||
|
|
@ -9,3 +9,4 @@
|
|||
- create_users_table.php
|
||||
- create_event_log_table.php
|
||||
- create_meta_table.php
|
||||
- create_countries_table.php
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
console.log('script1.js');
|
||||
|
|
@ -0,0 +1 @@
|
|||
console.log('script2.js');
|
||||
|
|
@ -0,0 +1 @@
|
|||
console.log('subdir/script1.js');
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
<?php
|
||||
class AuthTest extends UiTestCase
|
||||
{
|
||||
public function testSignInAndOut()
|
||||
{
|
||||
$this->open('backend');
|
||||
|
||||
$cssLogoutLink = '#layout-mainmenu .mainmenu-accountmenu > ul > li:first-child > a';
|
||||
|
||||
try {
|
||||
$this->assertTitle('Administration Area');
|
||||
$this->assertTrue($this->isElementPresent("name=login"));
|
||||
$this->assertTrue($this->isElementPresent("name=password"));
|
||||
$this->assertTrue($this->isElementPresent("//button[@type='submit']"));
|
||||
$this->verifyText("//button[@type='submit']", "Login");
|
||||
}
|
||||
catch (PHPUnit_Framework_AssertionFailedError $e) {
|
||||
array_push($this->verificationErrors, $e->toString());
|
||||
}
|
||||
|
||||
/*
|
||||
* Sign in
|
||||
*/
|
||||
$this->type("name=login", TEST_SELENIUM_USER);
|
||||
$this->type("name=password", TEST_SELENIUM_PASS);
|
||||
$this->click("//button[@type='submit']");
|
||||
$this->waitForPageToLoad("30000");
|
||||
|
||||
try {
|
||||
$this->assertTitle('Dashboard | October CMS');
|
||||
$this->assertTrue($this->isElementPresent('css='.$cssLogoutLink));
|
||||
}
|
||||
catch (PHPUnit_Framework_AssertionFailedError $e) {
|
||||
array_push($this->verificationErrors, $e->toString());
|
||||
}
|
||||
|
||||
$this->verifyText('css='.$cssLogoutLink, "Sign out");
|
||||
|
||||
/*
|
||||
* Log out
|
||||
*/
|
||||
$this->click('css='.$cssLogoutLink);
|
||||
$this->waitForPageToLoad("30000");
|
||||
|
||||
try {
|
||||
$this->assertTitle('Administration Area');
|
||||
}
|
||||
catch (PHPUnit_Framework_AssertionFailedError $e) {
|
||||
array_push($this->verificationErrors, $e->toString());
|
||||
}
|
||||
}
|
||||
|
||||
public function testPasswordReset()
|
||||
{
|
||||
$this->open('backend');
|
||||
|
||||
try {
|
||||
$this->assertTrue($this->isElementPresent("link=exact:Forgot your password?"));
|
||||
}
|
||||
catch (PHPUnit_Framework_AssertionFailedError $e) {
|
||||
array_push($this->verificationErrors, $e->toString());
|
||||
}
|
||||
|
||||
$this->click('link=exact:Forgot your password?');
|
||||
$this->waitForPageToLoad("30000");
|
||||
|
||||
try {
|
||||
$this->assertTrue($this->isElementPresent("//button[@type='submit']"));
|
||||
$this->verifyText("//button[@type='submit']", "Restore");
|
||||
$this->assertTrue($this->isElementPresent("link=Cancel"));
|
||||
}
|
||||
catch (PHPUnit_Framework_AssertionFailedError $e) {
|
||||
array_push($this->verificationErrors, $e->toString());
|
||||
}
|
||||
|
||||
$this->type("name=login", TEST_SELENIUM_USER);
|
||||
sleep(1);
|
||||
$this->click("//button[@type='submit']");
|
||||
$this->waitForPageToLoad("30000");
|
||||
|
||||
try {
|
||||
$this->assertTitle('Administration Area');
|
||||
$this->assertTrue($this->isElementPresent("css=p.flash-message.success"));
|
||||
$this->verifyText("css=p.flash-message.success", "An email has been sent to your email address with password restore instructions.×");
|
||||
}
|
||||
catch (PHPUnit_Framework_AssertionFailedError $e) {
|
||||
array_push($this->verificationErrors, $e->toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,143 +0,0 @@
|
|||
<?php
|
||||
class TemplateTest extends UiTestCase
|
||||
{
|
||||
public function testOpenTemplates()
|
||||
{
|
||||
$this->signInToBackend();
|
||||
$this->open('cms');
|
||||
$this->waitForPageToLoad("30000");
|
||||
|
||||
// Fix the sidebar
|
||||
$this->click("xpath=(//a[@class='fix-button'])[1]");
|
||||
|
||||
/*
|
||||
* Page
|
||||
*/
|
||||
|
||||
// Create a new page
|
||||
$this->click("xpath=(//form[@data-template-type='page']//button[@data-control='create-template'])[1]");
|
||||
$this->waitForElementPresent("name=settings[title]");
|
||||
|
||||
// Populate page details
|
||||
$this->type('name=settings[title]', 'Functional Test Page');
|
||||
$this->type('name=settings[url]', '/xxx/functional/test/page');
|
||||
$this->type('name=fileName', 'xxx_functional_test_page');
|
||||
|
||||
// Save the new page
|
||||
$this->click("xpath=(//a[@data-request='onSave'])[1]");
|
||||
$this->waitForElementPresent("xpath=(//li[@data-tab-id='page-".TEST_SELENIUM_THEME."-xxx_functional_test_page.htm'])[1]");
|
||||
|
||||
// Close the tab
|
||||
$this->click("xpath=(//li[@data-tab-id='page-".TEST_SELENIUM_THEME."-xxx_functional_test_page.htm']/span[@class='tab-close'])[1]");
|
||||
|
||||
// Reopen the tab
|
||||
$this->waitForElementPresent("xpath=(//div[@id='TemplateList-pageList-template-list']//li[@data-item-path='xxx_functional_test_page.htm']/a)[1]");
|
||||
$this->click("xpath=(//div[@id='TemplateList-pageList-template-list']//li[@data-item-path='xxx_functional_test_page.htm']/a)[1]");
|
||||
$this->waitForElementPresent("name=settings[title]");
|
||||
sleep(1);
|
||||
|
||||
// Delete the page
|
||||
$this->click("xpath=(//button[@data-request='onDelete'])[1]");
|
||||
$this->getSweetConfirmation('Do you really want delete this page?');
|
||||
// $this->assertTrue((bool)preg_match('/^Do you really want delete this page[\s\S]$/',$this->getConfirmation()));
|
||||
$this->waitForElementNotPresent("name=settings[title]");
|
||||
|
||||
/*
|
||||
* Partial
|
||||
*/
|
||||
|
||||
// Click partials menu item
|
||||
$this->click("xpath=(//li[@data-menu-item='partials']/a)[1]");
|
||||
|
||||
// Create a new partial
|
||||
$this->click("xpath=(//form[@data-template-type='partial']//button[@data-control='create-template'])[1]");
|
||||
$this->waitForElementPresent("name=fileName");
|
||||
|
||||
// Populate partial details
|
||||
$this->type('name=fileName', 'xxx_functional_test_partial');
|
||||
$this->type('name=settings[description]', 'Test partial');
|
||||
|
||||
// Save the new partial
|
||||
$this->click("xpath=(//a[@data-request='onSave'])[1]");
|
||||
$this->waitForElementPresent("xpath=(//li[@data-tab-id='partial-".TEST_SELENIUM_THEME."-xxx_functional_test_partial.htm'])[1]");
|
||||
|
||||
// Close the tab
|
||||
$this->click("xpath=(//li[@data-tab-id='partial-".TEST_SELENIUM_THEME."-xxx_functional_test_partial.htm']/span[@class='tab-close'])[1]");
|
||||
|
||||
// Reopen the tab
|
||||
$this->waitForElementPresent("xpath=(//div[@id='TemplateList-partialList-template-list']//li[@data-item-path='xxx_functional_test_partial.htm']/a)[1]");
|
||||
$this->click("xpath=(//div[@id='TemplateList-partialList-template-list']//li[@data-item-path='xxx_functional_test_partial.htm']/a)[1]");
|
||||
$this->waitForElementPresent("name=fileName");
|
||||
sleep(1);
|
||||
|
||||
// Delete the partial
|
||||
$this->click("xpath=(//button[@data-request='onDelete'])[1]");
|
||||
$this->getSweetConfirmation('Do you really want delete this partial?');
|
||||
$this->waitForElementNotPresent("name=fileName");
|
||||
|
||||
/*
|
||||
* Layout
|
||||
*/
|
||||
|
||||
// Click layouts menu item
|
||||
$this->click("xpath=(//li[@data-menu-item='layouts']/a)[1]");
|
||||
|
||||
// Create a new layout
|
||||
$this->click("xpath=(//form[@data-template-type='layout']//button[@data-control='create-template'])[1]");
|
||||
$this->waitForElementPresent("name=fileName");
|
||||
|
||||
// Populate layout details
|
||||
$this->type('name=fileName', 'xxx_functional_test_layout');
|
||||
$this->type('name=settings[description]', 'Test layout');
|
||||
|
||||
// Save the new layout
|
||||
$this->click("xpath=(//a[@data-request='onSave'])[1]");
|
||||
$this->waitForElementPresent("xpath=(//li[@data-tab-id='layout-".TEST_SELENIUM_THEME."-xxx_functional_test_layout.htm'])[1]");
|
||||
|
||||
// Close the tab
|
||||
$this->click("xpath=(//li[@data-tab-id='layout-".TEST_SELENIUM_THEME."-xxx_functional_test_layout.htm']/span[@class='tab-close'])[1]");
|
||||
|
||||
// Reopen the tab
|
||||
$this->waitForElementPresent("xpath=(//div[@id='TemplateList-layoutList-template-list']//li[@data-item-path='xxx_functional_test_layout.htm']/a)[1]");
|
||||
$this->click("xpath=(//div[@id='TemplateList-layoutList-template-list']//li[@data-item-path='xxx_functional_test_layout.htm']/a)[1]");
|
||||
$this->waitForElementPresent("name=fileName");
|
||||
sleep(1);
|
||||
|
||||
// Delete the layout
|
||||
$this->click("xpath=(//button[@data-request='onDelete'])[1]");
|
||||
$this->getSweetConfirmation('Do you really want delete this layout?');
|
||||
$this->waitForElementNotPresent("name=fileName");
|
||||
|
||||
/*
|
||||
* Content
|
||||
*/
|
||||
|
||||
// Click contents menu item
|
||||
$this->click("xpath=(//li[@data-menu-item='content']/a)[1]");
|
||||
|
||||
// Create a new content
|
||||
$this->click("xpath=(//form[@data-template-type='content']//button[@data-control='create-template'])[1]");
|
||||
$this->waitForElementPresent("name=fileName");
|
||||
|
||||
// Populate content details
|
||||
$this->type('name=fileName', 'xxx_functional_test_content.txt');
|
||||
|
||||
// Save the new content
|
||||
$this->click("xpath=(//a[@data-request='onSave'])[1]");
|
||||
$this->waitForElementPresent("xpath=(//li[@data-tab-id='content-".TEST_SELENIUM_THEME."-xxx_functional_test_content.txt'])[1]");
|
||||
|
||||
// Close the tab
|
||||
$this->click("xpath=(//li[@data-tab-id='content-".TEST_SELENIUM_THEME."-xxx_functional_test_content.txt']/span[@class='tab-close'])[1]");
|
||||
|
||||
// Reopen the tab
|
||||
$this->waitForElementPresent("xpath=(//div[@id='TemplateList-contentList-template-list']//li[@data-item-path='xxx_functional_test_content.txt']/a)[1]");
|
||||
$this->click("xpath=(//div[@id='TemplateList-contentList-template-list']//li[@data-item-path='xxx_functional_test_content.txt']/a)[1]");
|
||||
$this->waitForElementPresent("name=fileName");
|
||||
sleep(1);
|
||||
|
||||
// Delete the content
|
||||
$this->click("xpath=(//button[@data-request='onDelete'])[1]");
|
||||
$this->getSweetConfirmation('Do you really want delete this content file?');
|
||||
$this->waitForElementNotPresent("name=fileName");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit backupGlobals="false"
|
||||
backupStaticAttributes="false"
|
||||
bootstrap="../../bootstrap/autoload.php"
|
||||
colors="true"
|
||||
convertErrorsToExceptions="true"
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnFailure="true"
|
||||
syntaxCheck="false"
|
||||
>
|
||||
<testsuites>
|
||||
<testsuite name="October Test Suite">
|
||||
<directory>./</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
</phpunit>
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -4,7 +4,7 @@ use October\Rain\Exception\SystemException;
|
|||
|
||||
class AuthManagerTest extends TestCase
|
||||
{
|
||||
public function setUp()
|
||||
public function setUp(): void
|
||||
{
|
||||
$this->createApplication();
|
||||
|
||||
|
|
@ -23,7 +23,7 @@ class AuthManagerTest extends TestCase
|
|||
]);
|
||||
}
|
||||
|
||||
public function tearDown()
|
||||
public function tearDown(): void
|
||||
{
|
||||
AuthManager::forgetInstance();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,18 +59,18 @@ class NavigationManagerTest extends TestCase
|
|||
$manager->setContext('October.Tester', 'blog');
|
||||
|
||||
$items = $manager->listSideMenuItems();
|
||||
$this->assertInternalType('array', $items);
|
||||
$this->assertIsArray($items);
|
||||
$this->assertArrayHasKey('posts', $items);
|
||||
$this->assertArrayHasKey('categories', $items);
|
||||
|
||||
$this->assertInternalType('object', $items['posts']);
|
||||
$this->assertIsObject($items['posts']);
|
||||
$this->assertObjectHasAttribute('code', $items['posts']);
|
||||
$this->assertObjectHasAttribute('owner', $items['posts']);
|
||||
$this->assertEquals('posts', $items['posts']->code);
|
||||
$this->assertEquals('October.Tester', $items['posts']->owner);
|
||||
|
||||
$this->assertObjectHasAttribute('permissions', $items['posts']);
|
||||
$this->assertInternalType('array', $items['posts']->permissions);
|
||||
$this->assertIsArray($items['posts']->permissions);
|
||||
$this->assertCount(1, $items['posts']->permissions);
|
||||
|
||||
$this->assertObjectHasAttribute('order', $items['posts']);
|
||||
|
|
@ -92,7 +92,7 @@ class NavigationManagerTest extends TestCase
|
|||
|
||||
$items = $manager->listMainMenuItems();
|
||||
|
||||
$this->assertInternalType('array', $items);
|
||||
$this->assertIsArray($items);
|
||||
$this->assertArrayHasKey('OCTOBER.TESTER.PRINT', $items);
|
||||
|
||||
$item = $items['OCTOBER.TESTER.PRINT'];
|
||||
|
|
@ -143,10 +143,10 @@ class NavigationManagerTest extends TestCase
|
|||
$manager->setContext('October.Tester', 'blog');
|
||||
$items = $manager->listSideMenuItems();
|
||||
|
||||
$this->assertInternalType('array', $items);
|
||||
$this->assertIsArray($items);
|
||||
$this->assertArrayHasKey('foo', $items);
|
||||
|
||||
$this->assertInternalType('object', $items['foo']);
|
||||
$this->assertIsObject($items['foo']);
|
||||
$this->assertObjectHasAttribute('code', $items['foo']);
|
||||
$this->assertObjectHasAttribute('owner', $items['foo']);
|
||||
$this->assertObjectHasAttribute('order', $items['foo']);
|
||||
|
|
@ -156,7 +156,7 @@ class NavigationManagerTest extends TestCase
|
|||
$this->assertEquals('October.Tester', $items['foo']->owner);
|
||||
|
||||
$this->assertObjectHasAttribute('permissions', $items['foo']);
|
||||
$this->assertInternalType('array', $items['foo']->permissions);
|
||||
$this->assertIsArray($items['foo']->permissions);
|
||||
$this->assertCount(2, $items['foo']->permissions);
|
||||
$this->assertContains('october.tester.access_foo', $items['foo']->permissions);
|
||||
$this->assertContains('october.tester.access_bar', $items['foo']->permissions);
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ class BackendHelperTest extends TestCase
|
|||
$assets = $backendHelper->decompileAsset('tests/fixtures/backend/assets/compilation.js');
|
||||
|
||||
$this->assertCount(2, $assets);
|
||||
$this->assertContains('file1.js', $assets[0]);
|
||||
$this->assertContains('file2.js', $assets[1]);
|
||||
$this->assertStringContainsString('file1.js', $assets[0]);
|
||||
$this->assertStringContainsString('file2.js', $assets[1]);
|
||||
}
|
||||
|
||||
public function testDecompileMissingFile()
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ class WidgetMakerTest extends TestCase
|
|||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setUp()
|
||||
public function setUp() : void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,119 @@
|
|||
<?php
|
||||
|
||||
use Cms\Classes\Theme;
|
||||
use Cms\Classes\Asset;
|
||||
|
||||
class AssetTest extends TestCase
|
||||
{
|
||||
public function testLoad()
|
||||
{
|
||||
$theme = Theme::load('test');
|
||||
|
||||
// Valid direct path
|
||||
$this->assertStringContainsString(
|
||||
'console.log(\'script1.js\');',
|
||||
Asset::load($theme, 'js/script1.js')->content
|
||||
);
|
||||
|
||||
// Valid direct subdirectory path
|
||||
$this->assertStringContainsString(
|
||||
'console.log(\'subdir/script1.js\');',
|
||||
Asset::load($theme, 'js/subdir/script1.js')->content
|
||||
);
|
||||
|
||||
// Valid relative path
|
||||
$this->assertStringContainsString(
|
||||
'console.log(\'script2.js\');',
|
||||
Asset::load($theme, 'js/subdir/../script2.js')->content
|
||||
);
|
||||
|
||||
// Invalid theme path
|
||||
$this->assertNull(
|
||||
Asset::load($theme, 'js/invalid.js')
|
||||
);
|
||||
|
||||
// Check that we cannot break out of assets directory
|
||||
$this->assertNull(
|
||||
Asset::load($theme, '../../../../js/helpers/fakeDom.js')
|
||||
);
|
||||
$this->assertNull(
|
||||
Asset::load($theme, '../content/html-content.htm')
|
||||
);
|
||||
|
||||
// Check that we cannot load directories directly
|
||||
$this->assertNull(
|
||||
Asset::load($theme, 'js/subdir')
|
||||
);
|
||||
|
||||
// Check that we definitely cannot load external PHP files
|
||||
$this->assertNull(
|
||||
Asset::load($theme, '../../../../../config/database.php')
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetPath()
|
||||
{
|
||||
// Test some pathing fringe cases
|
||||
|
||||
$theme = Theme::load('test');
|
||||
$assetClass = new Asset($theme);
|
||||
$themeDir = $theme->getPath();
|
||||
|
||||
// Direct paths
|
||||
$this->assertEquals(
|
||||
$themeDir . '/assets/js/script1.js',
|
||||
$assetClass->getFilePath('js/script1.js')
|
||||
);
|
||||
$this->assertEquals(
|
||||
$themeDir . '/assets/js/script1.js',
|
||||
$assetClass->getFilePath('/js/script1.js')
|
||||
);
|
||||
|
||||
// Direct path to a directory
|
||||
$this->assertEquals(
|
||||
$themeDir . '/assets/js/subdir',
|
||||
$assetClass->getFilePath('/js/subdir')
|
||||
);
|
||||
$this->assertEquals(
|
||||
$themeDir . '/assets/js/subdir',
|
||||
$assetClass->getFilePath('/js/subdir/')
|
||||
);
|
||||
|
||||
// Relative paths
|
||||
$this->assertEquals(
|
||||
$themeDir . '/assets/js/script2.js',
|
||||
$assetClass->getFilePath('./js/script2.js')
|
||||
);
|
||||
$this->assertEquals(
|
||||
$themeDir . '/assets/js/script2.js',
|
||||
$assetClass->getFilePath('/js/subdir/../script2.js')
|
||||
);
|
||||
|
||||
// Missing file, but valid directory (allows for new files)
|
||||
$this->assertEquals(
|
||||
$themeDir . '/assets/js/missing.js',
|
||||
$assetClass->getFilePath('/js/missing.js')
|
||||
);
|
||||
$this->assertEquals(
|
||||
$themeDir . '/assets/js/missing.js',
|
||||
$assetClass->getFilePath('js/missing.js')
|
||||
);
|
||||
|
||||
// Missing file and missing directory (new directories are created as needed)
|
||||
$this->assertEquals(
|
||||
$themeDir . '/assets/js/missing/missing.js',
|
||||
$assetClass->getFilePath('/js/missing/missing.js')
|
||||
);
|
||||
|
||||
// Ensure we cannot get paths outside of the assets directory
|
||||
$this->assertFalse(
|
||||
$assetClass->getFilePath('../../../../js/helpers/fakeDom.js')
|
||||
);
|
||||
$this->assertFalse(
|
||||
$assetClass->getFilePath('../content/html-content.htm')
|
||||
);
|
||||
$this->assertFalse(
|
||||
$assetClass->getFilePath('../../../../../config/database.php')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -30,7 +30,7 @@ class TestTemporaryCmsCompoundObject extends CmsCompoundObject
|
|||
|
||||
class CmsCompoundObjectTest extends TestCase
|
||||
{
|
||||
public function setUp()
|
||||
public function setUp() : void
|
||||
{
|
||||
parent::setUp();
|
||||
Model::clearBootedModels();
|
||||
|
|
@ -44,16 +44,16 @@ class CmsCompoundObjectTest extends TestCase
|
|||
$theme = Theme::load('test');
|
||||
|
||||
$obj = TestCmsCompoundObject::load($theme, 'compound.htm');
|
||||
$this->assertContains("\$controller->data['something'] = 'some value'", $obj->code);
|
||||
$this->assertStringContainsString("\$controller->data['something'] = 'some value'", $obj->code);
|
||||
$this->assertEquals('<p>This is a paragraph</p>', $obj->markup);
|
||||
$this->assertInternalType('array', $obj->settings);
|
||||
$this->assertIsArray($obj->settings);
|
||||
$this->assertArrayHasKey('var', $obj->settings);
|
||||
$this->assertEquals('value', $obj->settings['var']);
|
||||
|
||||
$this->assertArrayHasKey('components', $obj->settings);
|
||||
|
||||
$this->assertArrayHasKey('section', $obj->settings['components']);
|
||||
$this->assertInternalType('array', $obj->settings['components']['section']);
|
||||
$this->assertIsArray($obj->settings['components']['section']);
|
||||
$this->assertArrayHasKey('version', $obj->settings['components']['section']);
|
||||
$this->assertEquals(10, $obj->settings['components']['section']['version']);
|
||||
|
||||
|
|
@ -69,7 +69,7 @@ class CmsCompoundObjectTest extends TestCase
|
|||
|
||||
$obj = TestCmsCompoundObject::load($theme, 'component.htm');
|
||||
$this->assertArrayHasKey('components', $obj->settings);
|
||||
$this->assertInternalType('array', $obj->settings['components']);
|
||||
$this->assertIsArray($obj->settings['components']);
|
||||
$this->assertArrayHasKey('testArchive', $obj->settings['components']);
|
||||
$this->assertArrayHasKey('posts-per-page', $obj->settings['components']['testArchive']);
|
||||
$this->assertEquals(10, $obj->settings['components']['testArchive']['posts-per-page']);
|
||||
|
|
@ -82,7 +82,7 @@ class CmsCompoundObjectTest extends TestCase
|
|||
$obj = TestCmsCompoundObject::load($theme, 'components.htm');
|
||||
$this->assertArrayHasKey('components', $obj->settings);
|
||||
|
||||
$this->assertInternalType('array', $obj->settings['components']);
|
||||
$this->assertIsArray($obj->settings['components']);
|
||||
$this->assertArrayHasKey('testArchive firstAlias', $obj->settings['components']);
|
||||
$this->assertArrayHasKey('October\Tester\Components\Post secondAlias', $obj->settings['components']);
|
||||
|
||||
|
|
@ -108,7 +108,7 @@ class CmsCompoundObjectTest extends TestCase
|
|||
$properties = $obj->getComponentProperties('October\Tester\Components\Post');
|
||||
$emptyProperties = $obj->getComponentProperties('October\Tester\Components\Archive');
|
||||
$notExistingProperties = $obj->getComponentProperties('This\Is\Not\Component');
|
||||
$this->assertInternalType('array', $properties);
|
||||
$this->assertIsArray($properties);
|
||||
$this->assertArrayHasKey('show-featured', $properties);
|
||||
$this->assertTrue((bool)$properties['show-featured']);
|
||||
$this->assertEquals('true', $properties['show-featured']);
|
||||
|
|
@ -148,18 +148,18 @@ class CmsCompoundObjectTest extends TestCase
|
|||
$this->assertEquals($testContent, $obj->getContent());
|
||||
$this->assertEquals('testcompound.htm', $obj->getFileName());
|
||||
$this->assertEquals('<p>This is a paragraph</p>', $obj->markup);
|
||||
$this->assertInternalType('array', $obj->settings);
|
||||
$this->assertIsArray($obj->settings);
|
||||
$this->assertArrayHasKey('var', $obj->settings);
|
||||
$this->assertEquals('value', $obj->settings['var']);
|
||||
|
||||
$this->assertArrayHasKey('components', $obj->settings);
|
||||
|
||||
$this->assertInternalType('array', $obj->settings['components']['section']);
|
||||
$this->assertIsArray($obj->settings['components']['section']);
|
||||
$this->assertArrayHasKey('version', $obj->settings['components']['section']);
|
||||
$this->assertEquals(10, $obj->settings['components']['section']['version']);
|
||||
|
||||
$this->assertEquals('value', $obj->var);
|
||||
$this->assertInternalType('array', $obj->settings['components']['section']);
|
||||
$this->assertIsArray($obj->settings['components']['section']);
|
||||
$this->assertArrayHasKey('version', $obj->settings['components']['section']);
|
||||
$this->assertEquals(10, $obj->settings['components']['section']['version']);
|
||||
|
||||
|
|
@ -173,18 +173,18 @@ class CmsCompoundObjectTest extends TestCase
|
|||
$this->assertEquals($testContent, $obj->getContent());
|
||||
$this->assertEquals('testcompound.htm', $obj->getFileName());
|
||||
$this->assertEquals('<p>This is a paragraph</p>', $obj->markup);
|
||||
$this->assertInternalType('array', $obj->settings);
|
||||
$this->assertIsArray($obj->settings);
|
||||
$this->assertArrayHasKey('var', $obj->settings);
|
||||
$this->assertEquals('value', $obj->settings['var']);
|
||||
|
||||
$this->assertArrayHasKey('components', $obj->settings);
|
||||
|
||||
$this->assertInternalType('array', $obj->settings['components']['section']);
|
||||
$this->assertIsArray($obj->settings['components']['section']);
|
||||
$this->assertArrayHasKey('version', $obj->settings['components']['section']);
|
||||
$this->assertEquals(10, $obj->settings['components']['section']['version']);
|
||||
|
||||
$this->assertEquals('value', $obj->var);
|
||||
$this->assertInternalType('array', $obj->settings['components']['section']);
|
||||
$this->assertIsArray($obj->settings['components']['section']);
|
||||
$this->assertArrayHasKey('version', $obj->settings['components']['section']);
|
||||
$this->assertEquals(10, $obj->settings['components']['section']['version']);
|
||||
}
|
||||
|
|
@ -280,14 +280,14 @@ class CmsCompoundObjectTest extends TestCase
|
|||
$obj = TestParsedCmsCompoundObject::load($theme, 'viewbag.htm');
|
||||
$this->assertNull($obj->code);
|
||||
$this->assertEquals('<p>Chop Suey!</p>', $obj->markup);
|
||||
$this->assertInternalType('array', $obj->settings);
|
||||
$this->assertIsArray($obj->settings);
|
||||
$this->assertArrayHasKey('var', $obj->settings);
|
||||
$this->assertEquals('value', $obj->settings['var']);
|
||||
|
||||
$this->assertArrayHasKey('components', $obj->settings);
|
||||
|
||||
$this->assertArrayHasKey('viewBag', $obj->settings['components']);
|
||||
$this->assertInternalType('array', $obj->settings['components']['viewBag']);
|
||||
$this->assertIsArray($obj->settings['components']['viewBag']);
|
||||
$this->assertArrayHasKey('title', $obj->settings['components']['viewBag']);
|
||||
$this->assertEquals('Toxicity', $obj->settings['components']['viewBag']['title']);
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use October\Rain\Halcyon\Model;
|
|||
|
||||
class CmsObjectQueryTest extends TestCase
|
||||
{
|
||||
public function setUp()
|
||||
public function setUp() : void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
|
|
|
|||
|
|
@ -148,12 +148,11 @@ class CmsObjectTest extends TestCase
|
|||
$this->assertNull($obj->something);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \October\Rain\Exception\ValidationException
|
||||
* @expectedExceptionMessage Invalid file name
|
||||
*/
|
||||
public function testFillInvalidFileNameSymbol()
|
||||
{
|
||||
$this->expectException(\October\Rain\Exception\ValidationException::class);
|
||||
$this->expectExceptionMessage('Invalid file name');
|
||||
|
||||
$theme = Theme::load('apitest');
|
||||
|
||||
$testContents = 'mytestcontent';
|
||||
|
|
@ -164,12 +163,11 @@ class CmsObjectTest extends TestCase
|
|||
$obj->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \October\Rain\Exception\ValidationException
|
||||
* @expectedExceptionMessage Invalid file name
|
||||
*/
|
||||
public function testFillInvalidFileNamePath()
|
||||
{
|
||||
$this->expectException(\October\Rain\Exception\ValidationException::class);
|
||||
$this->expectExceptionMessage('Invalid file name');
|
||||
|
||||
$theme = Theme::load('apitest');
|
||||
|
||||
$testContents = 'mytestcontent';
|
||||
|
|
@ -180,12 +178,11 @@ class CmsObjectTest extends TestCase
|
|||
$obj->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \October\Rain\Exception\ValidationException
|
||||
* @expectedExceptionMessage Invalid file name
|
||||
*/
|
||||
public function testFillInvalidFileSlash()
|
||||
{
|
||||
$this->expectException(\October\Rain\Exception\ValidationException::class);
|
||||
$this->expectExceptionMessage('Invalid file name');
|
||||
|
||||
$theme = Theme::load('apitest');
|
||||
|
||||
$testContents = 'mytestcontent';
|
||||
|
|
@ -196,12 +193,11 @@ class CmsObjectTest extends TestCase
|
|||
$obj->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \October\Rain\Exception\ValidationException
|
||||
* @expectedExceptionMessage The File Name field is required
|
||||
*/
|
||||
public function testFillEmptyFileName()
|
||||
{
|
||||
$this->expectException(\October\Rain\Exception\ValidationException::class);
|
||||
$this->expectExceptionMessage('The File Name field is required');
|
||||
|
||||
$theme = Theme::load('apitest');
|
||||
|
||||
$testContents = 'mytestcontent';
|
||||
|
|
@ -266,11 +262,12 @@ class CmsObjectTest extends TestCase
|
|||
|
||||
/**
|
||||
* @depends testRename
|
||||
* @expectedException \October\Rain\Exception\ApplicationException
|
||||
* @expectedExceptionMessage already exists
|
||||
*/
|
||||
public function testRenameToExistingFile()
|
||||
{
|
||||
$this->expectException(\October\Rain\Exception\ApplicationException::class);
|
||||
$this->expectExceptionMessageMatches('/already\sexists/');
|
||||
|
||||
$theme = Theme::load('apitest');
|
||||
|
||||
$srcFilePath = $theme->getPath().'/testobjects/anotherobj.htm';
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use Cms\Classes\Controller;
|
|||
|
||||
class CodeParserTest extends TestCase
|
||||
{
|
||||
public function setUp()
|
||||
public function setUp() : void
|
||||
{
|
||||
parent::setup();
|
||||
|
||||
|
|
@ -41,7 +41,7 @@ class CodeParserTest extends TestCase
|
|||
$parser = new CodeParser($layout);
|
||||
$info = $parser->parse();
|
||||
|
||||
$this->assertInternalType('array', $info);
|
||||
$this->assertIsArray($info);
|
||||
$this->assertArrayHasKey('filePath', $info);
|
||||
$this->assertArrayHasKey('className', $info);
|
||||
$this->assertArrayHasKey('source', $info);
|
||||
|
|
@ -78,7 +78,7 @@ class CodeParserTest extends TestCase
|
|||
|
||||
$parser = new CodeParser($layout);
|
||||
$info = $parser->parse();
|
||||
$this->assertInternalType('array', $info);
|
||||
$this->assertIsArray($info);
|
||||
$this->assertEquals('request-cache', $info['source']);
|
||||
$this->assertFileExists($info['filePath']);
|
||||
|
||||
|
|
@ -91,7 +91,7 @@ class CodeParserTest extends TestCase
|
|||
|
||||
$parser = new CodeParser($layout);
|
||||
$info = $parser->parse();
|
||||
$this->assertInternalType('array', $info);
|
||||
$this->assertIsArray($info);
|
||||
$this->assertEquals('cache', $info['source']);
|
||||
$this->assertFileExists($info['filePath']);
|
||||
|
||||
|
|
@ -101,7 +101,7 @@ class CodeParserTest extends TestCase
|
|||
|
||||
$parser = new CodeParser($layout);
|
||||
$info = $parser->parse();
|
||||
$this->assertInternalType('array', $info);
|
||||
$this->assertIsArray($info);
|
||||
$this->assertEquals('request-cache', $info['source']);
|
||||
$this->assertFileExists($info['filePath']);
|
||||
|
||||
|
|
@ -110,13 +110,14 @@ class CodeParserTest extends TestCase
|
|||
*/
|
||||
|
||||
$this->assertTrue(@touch($layout->getFilePath()));
|
||||
clearstatcache();
|
||||
$layout = Layout::load($theme, 'php-parser-test.htm');
|
||||
$this->assertNotEmpty($layout);
|
||||
$parser = new CodeParser($layout);
|
||||
$property->setValue($parser, []);
|
||||
|
||||
$info = $parser->parse();
|
||||
$this->assertInternalType('array', $info);
|
||||
$this->assertIsArray($info);
|
||||
$this->assertEquals('parser', $info['source']);
|
||||
$this->assertFileExists($info['filePath']);
|
||||
}
|
||||
|
|
@ -131,7 +132,7 @@ class CodeParserTest extends TestCase
|
|||
$parser = new CodeParser($layout);
|
||||
$info = $parser->parse();
|
||||
|
||||
$this->assertInternalType('array', $info);
|
||||
$this->assertIsArray($info);
|
||||
$this->assertArrayHasKey('filePath', $info);
|
||||
$this->assertArrayHasKey('className', $info);
|
||||
$this->assertArrayHasKey('source', $info);
|
||||
|
|
@ -157,7 +158,7 @@ class CodeParserTest extends TestCase
|
|||
$parser = new CodeParser($page);
|
||||
$info = $parser->parse();
|
||||
|
||||
$this->assertInternalType('array', $info);
|
||||
$this->assertIsArray($info);
|
||||
$this->assertArrayHasKey('filePath', $info);
|
||||
$this->assertArrayHasKey('className', $info);
|
||||
$this->assertArrayHasKey('source', $info);
|
||||
|
|
@ -191,7 +192,7 @@ class CodeParserTest extends TestCase
|
|||
$parser = new CodeParser($page);
|
||||
$info = $parser->parse();
|
||||
|
||||
$this->assertInternalType('array', $info);
|
||||
$this->assertIsArray($info);
|
||||
$this->assertArrayHasKey('filePath', $info);
|
||||
$this->assertArrayHasKey('className', $info);
|
||||
$this->assertArrayHasKey('source', $info);
|
||||
|
|
@ -220,7 +221,7 @@ class CodeParserTest extends TestCase
|
|||
$parser = new CodeParser($page);
|
||||
$info = $parser->parse();
|
||||
|
||||
$this->assertInternalType('array', $info);
|
||||
$this->assertIsArray($info);
|
||||
$this->assertArrayHasKey('filePath', $info);
|
||||
$this->assertArrayHasKey('className', $info);
|
||||
$this->assertArrayHasKey('source', $info);
|
||||
|
|
@ -255,7 +256,7 @@ class CodeParserTest extends TestCase
|
|||
$parser = new CodeParser($page);
|
||||
$info = $parser->parse();
|
||||
|
||||
$this->assertInternalType('array', $info);
|
||||
$this->assertIsArray($info);
|
||||
$this->assertArrayHasKey('filePath', $info);
|
||||
$this->assertArrayHasKey('className', $info);
|
||||
$this->assertArrayHasKey('source', $info);
|
||||
|
|
@ -284,7 +285,7 @@ class CodeParserTest extends TestCase
|
|||
$parser = new CodeParser($page);
|
||||
$info = $parser->parse();
|
||||
|
||||
$this->assertInternalType('array', $info);
|
||||
$this->assertIsArray($info);
|
||||
$this->assertArrayHasKey('filePath', $info);
|
||||
$this->assertArrayHasKey('className', $info);
|
||||
$this->assertArrayHasKey('source', $info);
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use Cms\Classes\ComponentManager;
|
|||
|
||||
class ComponentManagerTest extends TestCase
|
||||
{
|
||||
public function setUp()
|
||||
public function setUp() : void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use October\Rain\Halcyon\Model;
|
|||
|
||||
class ControllerTest extends TestCase
|
||||
{
|
||||
public function setUp()
|
||||
public function setUp() : void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
|
|
@ -69,7 +69,7 @@ class ControllerTest extends TestCase
|
|||
$response = $controller->run('/some-page-that-doesnt-exist');
|
||||
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Response', $response);
|
||||
$content = $response->getContent();
|
||||
$this->assertInternalType('string', $content);
|
||||
$this->assertIsString($content);
|
||||
$this->assertEquals('<p>Page not found</p>', $content);
|
||||
}
|
||||
|
||||
|
|
@ -83,16 +83,15 @@ class ControllerTest extends TestCase
|
|||
$response = $controller->run('/');
|
||||
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Response', $response);
|
||||
$content = $response->getContent();
|
||||
$this->assertInternalType('string', $content);
|
||||
$this->assertIsString($content);
|
||||
$this->assertEquals('<h1>My Webpage</h1>', trim($content));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Cms\Classes\CmsException
|
||||
* @expectedExceptionMessage is not found
|
||||
*/
|
||||
public function testLayoutNotFound()
|
||||
{
|
||||
$this->expectException(\Cms\Classes\CmsException::class);
|
||||
$this->expectExceptionMessageMatches('/is\snot\sfound/');
|
||||
|
||||
$theme = Theme::load('test');
|
||||
$controller = new Controller($theme);
|
||||
$response = $controller->run('/no-layout');
|
||||
|
|
@ -146,12 +145,11 @@ class ControllerTest extends TestCase
|
|||
$this->assertEquals("<div>LAYOUT CONTENT <h1>This page is a subdirectory</h1></div>", $response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Twig\Error\RuntimeError
|
||||
* @expectedExceptionMessage is not found
|
||||
*/
|
||||
public function testPartialNotFound()
|
||||
{
|
||||
$this->expectException(\Twig\Error\RuntimeError::class);
|
||||
$this->expectExceptionMessageMatches('/is\snot\sfound/');
|
||||
|
||||
$theme = Theme::load('test');
|
||||
$controller = new Controller($theme);
|
||||
$response = $controller->run('/no-partial')->getContent();
|
||||
|
|
@ -193,12 +191,11 @@ class ControllerTest extends TestCase
|
|||
return $requestMock;
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Cms\Classes\CmsException
|
||||
* @expectedExceptionMessage AJAX handler 'onNoHandler' was not found.
|
||||
*/
|
||||
public function testAjaxHandlerNotFound()
|
||||
{
|
||||
$this->expectException(\Cms\Classes\CmsException::class);
|
||||
$this->expectExceptionMessage('AJAX handler \'onNoHandler\' was not found.');
|
||||
|
||||
Request::swap($this->configAjaxRequestMock('onNoHandler', ''));
|
||||
|
||||
$theme = Theme::load('test');
|
||||
|
|
@ -206,12 +203,11 @@ class ControllerTest extends TestCase
|
|||
$controller->run('/ajax-test');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Cms\Classes\CmsException
|
||||
* @expectedExceptionMessage Invalid AJAX handler name: delete.
|
||||
*/
|
||||
public function testAjaxInvalidHandlerName()
|
||||
{
|
||||
$this->expectException(\Cms\Classes\CmsException::class);
|
||||
$this->expectExceptionMessage('Invalid AJAX handler name: delete.');
|
||||
|
||||
Request::swap($this->configAjaxRequestMock('delete'));
|
||||
|
||||
$theme = Theme::load('test');
|
||||
|
|
@ -219,12 +215,11 @@ class ControllerTest extends TestCase
|
|||
$controller->run('/ajax-test');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Cms\Classes\CmsException
|
||||
* @expectedExceptionMessage Invalid partial name: p:artial.
|
||||
*/
|
||||
public function testAjaxInvalidPartial()
|
||||
{
|
||||
$this->expectException(\Cms\Classes\CmsException::class);
|
||||
$this->expectExceptionMessage('Invalid partial name: p:artial.');
|
||||
|
||||
Request::swap($this->configAjaxRequestMock('onTest', 'p:artial'));
|
||||
|
||||
$theme = Theme::load('test');
|
||||
|
|
@ -232,12 +227,11 @@ class ControllerTest extends TestCase
|
|||
$controller->run('/ajax-test');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Cms\Classes\CmsException
|
||||
* @expectedExceptionMessage The partial 'partial' is not found.
|
||||
*/
|
||||
public function testAjaxPartialNotFound()
|
||||
{
|
||||
$this->expectException(\Cms\Classes\CmsException::class);
|
||||
$this->expectExceptionMessage('The partial \'partial\' is not found.');
|
||||
|
||||
Request::swap($this->configAjaxRequestMock('onTest', 'partial'));
|
||||
|
||||
$theme = Theme::load('test');
|
||||
|
|
@ -255,7 +249,7 @@ class ControllerTest extends TestCase
|
|||
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Response', $response);
|
||||
|
||||
$content = $response->getOriginalContent();
|
||||
$this->assertInternalType('array', $content);
|
||||
$this->assertIsArray($content);
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
$this->assertCount(1, $content);
|
||||
$this->assertArrayHasKey('ajax-result', $content);
|
||||
|
|
@ -272,7 +266,7 @@ class ControllerTest extends TestCase
|
|||
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Response', $response);
|
||||
|
||||
$content = $response->getOriginalContent();
|
||||
$this->assertInternalType('array', $content);
|
||||
$this->assertIsArray($content);
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
$this->assertCount(1, $content);
|
||||
$this->assertArrayHasKey('ajax-result', $content);
|
||||
|
|
@ -289,7 +283,7 @@ class ControllerTest extends TestCase
|
|||
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Response', $response);
|
||||
|
||||
$content = $response->getOriginalContent();
|
||||
$this->assertInternalType('array', $content);
|
||||
$this->assertIsArray($content);
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
$this->assertCount(2, $content);
|
||||
$this->assertArrayHasKey('ajax-result', $content);
|
||||
|
|
@ -303,7 +297,7 @@ class ControllerTest extends TestCase
|
|||
$theme = Theme::load('test');
|
||||
$controller = new Controller($theme);
|
||||
$response = $controller->run('/with-component')->getContent();
|
||||
$page = $this->readAttribute($controller, 'page');
|
||||
$page = self::getProtectedProperty($controller, 'page');
|
||||
$this->assertArrayHasKey('testArchive', $page->components);
|
||||
|
||||
$component = $page->components['testArchive'];
|
||||
|
|
@ -331,7 +325,7 @@ ESC;
|
|||
$theme = Theme::load('test');
|
||||
$controller = new Controller($theme);
|
||||
$response = $controller->run('/with-components')->getContent();
|
||||
$page = $this->readAttribute($controller, 'page');
|
||||
$page = self::getProtectedProperty($controller, 'page');
|
||||
|
||||
$this->assertArrayHasKey('firstAlias', $page->components);
|
||||
$this->assertArrayHasKey('secondAlias', $page->components);
|
||||
|
|
@ -363,19 +357,18 @@ ESC;
|
|||
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Response', $response);
|
||||
|
||||
$content = $response->getOriginalContent();
|
||||
$this->assertInternalType('array', $content);
|
||||
$this->assertIsArray($content);
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
$this->assertCount(1, $content);
|
||||
$this->assertArrayHasKey('ajax-result', $content);
|
||||
$this->assertEquals('page', $content['ajax-result']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException October\Rain\Exception\SystemException
|
||||
* @expectedExceptionMessage is not registered for the component
|
||||
*/
|
||||
public function testComponentClassNotFound()
|
||||
{
|
||||
$this->expectException(\October\Rain\Exception\SystemException::class);
|
||||
$this->expectExceptionMessageMatches('/is\snot\sregistered\sfor\sthe\scomponent/');
|
||||
|
||||
$theme = Theme::load('test');
|
||||
$controller = new Controller($theme);
|
||||
$response = $controller->run('/no-component-class')->getContent();
|
||||
|
|
@ -395,7 +388,7 @@ ESC;
|
|||
$theme = Theme::load('test');
|
||||
$controller = new Controller($theme);
|
||||
$response = $controller->run('/with-soft-component-class')->getContent();
|
||||
$page = $this->readAttribute($controller, 'page');
|
||||
$page = $controller->getPage();
|
||||
$this->assertArrayHasKey('testArchive', $page->components);
|
||||
|
||||
$component = $page->components['testArchive'];
|
||||
|
|
@ -421,7 +414,7 @@ ESC;
|
|||
$theme = Theme::load('test');
|
||||
$controller = new Controller($theme);
|
||||
$response = $controller->run('/with-soft-component-class-alias')->getContent();
|
||||
$page = $this->readAttribute($controller, 'page');
|
||||
$page = $controller->getPage();
|
||||
$this->assertArrayHasKey('someAlias', $page->components);
|
||||
|
||||
$component = $page->components['someAlias'];
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ class RouterTest extends TestCase
|
|||
{
|
||||
protected static $theme = null;
|
||||
|
||||
public function setUp()
|
||||
public function setUp() : void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
|
|
@ -43,7 +43,7 @@ class RouterTest extends TestCase
|
|||
$this->assertFalse($value);
|
||||
$map = $property->getValue($router);
|
||||
|
||||
$this->assertInternalType('array', $map);
|
||||
$this->assertIsArray($map);
|
||||
$this->assertGreaterThanOrEqual(4, count($map));
|
||||
|
||||
/*
|
||||
|
|
@ -52,7 +52,7 @@ class RouterTest extends TestCase
|
|||
$value = $method->invoke($router);
|
||||
$this->assertTrue($value);
|
||||
$map = $property->getValue($router);
|
||||
$this->assertInternalType('array', $map);
|
||||
$this->assertIsArray($map);
|
||||
$this->assertGreaterThanOrEqual(4, count($map));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use Cms\Classes\Theme;
|
|||
|
||||
class ThemeTest extends TestCase
|
||||
{
|
||||
public function setUp()
|
||||
public function setUp() : void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
|
|
@ -44,7 +44,7 @@ class ThemeTest extends TestCase
|
|||
|
||||
$pageCollection = $theme->listPages();
|
||||
$pages = array_values($pageCollection->all());
|
||||
$this->assertInternalType('array', $pages);
|
||||
$this->assertIsArray($pages);
|
||||
|
||||
$expectedPageNum = $this->countThemePages(base_path().'/tests/fixtures/themes/test/pages');
|
||||
$this->assertCount($expectedPageNum, $pages);
|
||||
|
|
@ -63,12 +63,11 @@ class ThemeTest extends TestCase
|
|||
$this->assertEquals('test', $activeTheme->getDirName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \October\Rain\Exception\SystemException
|
||||
* @expectedExceptionMessage The active theme is not set.
|
||||
*/
|
||||
public function testNoActiveTheme()
|
||||
{
|
||||
$this->expectException(\October\Rain\Exception\SystemException::class);
|
||||
$this->expectExceptionMessage('The active theme is not set.');
|
||||
|
||||
Config::set('cms.activeTheme', null);
|
||||
Theme::getActiveTheme();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use Database\Tester\Models\User;
|
|||
|
||||
class AttachManyModelTest extends PluginTestCase
|
||||
{
|
||||
public function setUp()
|
||||
public function setUp() : void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use Symfony\Component\HttpFoundation\File\UploadedFile;
|
|||
|
||||
class AttachOneModelTest extends PluginTestCase
|
||||
{
|
||||
public function setUp()
|
||||
public function setUp() : void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use Database\Tester\Models\Author;
|
|||
|
||||
class BelongsToManyModelTest extends PluginTestCase
|
||||
{
|
||||
public function setUp()
|
||||
public function setUp() : void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use Database\Tester\Models\Author;
|
|||
|
||||
class BelongsToModelTest extends PluginTestCase
|
||||
{
|
||||
public function setUp()
|
||||
public function setUp() : void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use October\Rain\Database\Models\DeferredBinding;
|
|||
|
||||
class DeferredBindingTest extends PluginTestCase
|
||||
{
|
||||
public function setUp()
|
||||
public function setUp() : void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use October\Rain\Database\Collection;
|
|||
|
||||
class HasManyModelTest extends PluginTestCase
|
||||
{
|
||||
public function setUp()
|
||||
public function setUp() : void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
|
|
@ -63,8 +63,6 @@ class HasManyModelTest extends PluginTestCase
|
|||
|
||||
public function testGetRelationValue()
|
||||
{
|
||||
$this->markTestSkipped('Marked as \'skipped\' for further investigation');
|
||||
|
||||
Model::unguard();
|
||||
$author = Author::create(['name' => 'Stevie']);
|
||||
$post1 = Post::create(['title' => "First post", 'author_id' => $author->id]);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
|
||||
use Database\Tester\Models\Author;
|
||||
use Database\Tester\Models\Country;
|
||||
use Database\Tester\Models\Post;
|
||||
use October\Rain\Database\Collection;
|
||||
|
||||
class HasManyThroughModelTest extends PluginTestCase
|
||||
{
|
||||
public function setUp() : void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
include_once base_path().'/tests/fixtures/plugins/database/tester/models/Post.php';
|
||||
include_once base_path().'/tests/fixtures/plugins/database/tester/models/Author.php';
|
||||
include_once base_path().'/tests/fixtures/plugins/database/tester/models/Country.php';
|
||||
|
||||
$this->runPluginRefreshCommand('Database.Tester');
|
||||
}
|
||||
|
||||
public function testGet()
|
||||
{
|
||||
Model::unguard();
|
||||
$country = Country::create(['name' => 'Australia']);
|
||||
$author1 = Author::create(['name' => 'Stevie', 'email' => 'stevie@email.tld']);
|
||||
$author2 = Author::create(['name' => 'Louie', 'email' => 'louie@email.tld']);
|
||||
$post1 = Post::create(['title' => "First post", 'description' => "Yay!!"]);
|
||||
$post2 = Post::create(['title' => "Second post", 'description' => "Woohoo!!"]);
|
||||
$post3 = Post::create(['title' => "Third post", 'description' => "Yipiee!!"]);
|
||||
$post4 = Post::make(['title' => "Fourth post", 'description' => "Hooray!!"]);
|
||||
Model::reguard();
|
||||
|
||||
// Set data
|
||||
$author1->country = $country;
|
||||
$author2->country = $country;
|
||||
|
||||
$author1->posts = new Collection([$post1, $post2]);
|
||||
$author2->posts = new Collection([$post3, $post4]);
|
||||
|
||||
$author1->save();
|
||||
$author2->save();
|
||||
|
||||
$country = Country::with([
|
||||
'posts'
|
||||
])->find($country->id);
|
||||
|
||||
$this->assertEquals([
|
||||
$post1->id,
|
||||
$post2->id,
|
||||
$post3->id,
|
||||
$post4->id
|
||||
], $country->posts->pluck('id')->toArray());
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ use Database\Tester\Models\Phone;
|
|||
|
||||
class HasOneModelTest extends PluginTestCase
|
||||
{
|
||||
public function setUp()
|
||||
public function setUp() : void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
use Database\Tester\Models\Author;
|
||||
use Database\Tester\Models\Phone;
|
||||
use Database\Tester\Models\User;
|
||||
|
||||
class HasOneThroughModelTest extends PluginTestCase
|
||||
{
|
||||
public function setUp() : void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
include_once base_path().'/tests/fixtures/plugins/database/tester/models/User.php';
|
||||
include_once base_path().'/tests/fixtures/plugins/database/tester/models/Author.php';
|
||||
include_once base_path().'/tests/fixtures/plugins/database/tester/models/Phone.php';
|
||||
|
||||
$this->runPluginRefreshCommand('Database.Tester');
|
||||
}
|
||||
|
||||
public function testGet()
|
||||
{
|
||||
Model::unguard();
|
||||
$phone = Phone::create(['number' => '08 1234 5678']);
|
||||
$author = Author::create(['name' => 'Stevie', 'email' => 'stevie@email.tld']);
|
||||
$user = User::create(['name' => 'Stevie', 'email' => 'stevie@email.tld']);
|
||||
Model::reguard();
|
||||
|
||||
// Set data
|
||||
$author->phone = $phone;
|
||||
$author->user = $user;
|
||||
$author->save();
|
||||
|
||||
$user = User::with([
|
||||
'phone'
|
||||
])->find($user->id);
|
||||
|
||||
$this->assertEquals($phone->id, $user->phone->id);
|
||||
}
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@ use Database\Tester\Models\Post;
|
|||
|
||||
class ModelTest extends PluginTestCase
|
||||
{
|
||||
public function setUp()
|
||||
public function setUp() : void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
|
|
@ -23,12 +23,11 @@ class ModelTest extends PluginTestCase
|
|||
$this->assertEquals(1, $post->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Illuminate\Database\Eloquent\MassAssignmentException
|
||||
* @expectedExceptionMessage title
|
||||
*/
|
||||
public function testGuardedAttribute()
|
||||
{
|
||||
$this->expectException(\Illuminate\Database\Eloquent\MassAssignmentException::class);
|
||||
$this->expectExceptionMessageMatches('/title/');
|
||||
|
||||
Post::create(['title' => 'Hi!', 'slug' => 'authenticity']);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue