Merge branch 'development' into release
This commit is contained in:
commit
b62dab32e0
|
@ -297,6 +297,11 @@ RECYCLE_BIN_LIFETIME=30
|
|||
# Maximum file size, in megabytes, that can be uploaded to the system.
|
||||
FILE_UPLOAD_SIZE_LIMIT=50
|
||||
|
||||
# Export Page Size
|
||||
# Primarily used to determine page size of PDF exports.
|
||||
# Can be 'a4' or 'letter'.
|
||||
EXPORT_PAGE_SIZE=a4
|
||||
|
||||
# Allow <script> tags in page content
|
||||
# Note, if set to 'true' the page editor may still escape scripts.
|
||||
ALLOW_CONTENT_SCRIPTS=false
|
||||
|
|
|
@ -3,10 +3,10 @@ name: phpstan
|
|||
on:
|
||||
push:
|
||||
branches-ignore:
|
||||
- l10n_master
|
||||
- l10n_development
|
||||
pull_request:
|
||||
branches-ignore:
|
||||
- l10n_master
|
||||
- l10n_development
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
|
|
@ -3,10 +3,10 @@ name: phpunit
|
|||
on:
|
||||
push:
|
||||
branches-ignore:
|
||||
- l10n_master
|
||||
- l10n_development
|
||||
pull_request:
|
||||
branches-ignore:
|
||||
- l10n_master
|
||||
- l10n_development
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
|
|
@ -3,10 +3,10 @@ name: test-migrations
|
|||
on:
|
||||
push:
|
||||
branches-ignore:
|
||||
- l10n_master
|
||||
- l10n_development
|
||||
pull_request:
|
||||
branches-ignore:
|
||||
- l10n_master
|
||||
- l10n_development
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
|
|
@ -60,8 +60,11 @@ class OidcJwtSigningKey
|
|||
*/
|
||||
protected function loadFromJwkArray(array $jwk)
|
||||
{
|
||||
if ($jwk['alg'] !== 'RS256') {
|
||||
throw new OidcInvalidKeyException("Only RS256 keys are currently supported. Found key using {$jwk['alg']}");
|
||||
// 'alg' is optional for a JWK, but we will still attempt to validate if
|
||||
// it exists otherwise presume it will be compatible.
|
||||
$alg = $jwk['alg'] ?? null;
|
||||
if ($jwk['kty'] !== 'RSA' || !(is_null($alg) || $alg === 'RS256')) {
|
||||
throw new OidcInvalidKeyException("Only RS256 keys are currently supported. Found key using {$alg}");
|
||||
}
|
||||
|
||||
if (empty($jwk['use'])) {
|
||||
|
|
|
@ -164,7 +164,9 @@ class OidcProviderSettings
|
|||
protected function filterKeys(array $keys): array
|
||||
{
|
||||
return array_filter($keys, function (array $key) {
|
||||
return $key['kty'] === 'RSA' && $key['use'] === 'sig' && $key['alg'] === 'RS256';
|
||||
$alg = $key['alg'] ?? null;
|
||||
|
||||
return $key['kty'] === 'RSA' && $key['use'] === 'sig' && (is_null($alg) || $alg === 'RS256');
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -146,7 +146,7 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
|
|||
*/
|
||||
public function attachDefaultRole(): void
|
||||
{
|
||||
$roleId = setting('registration-role');
|
||||
$roleId = intval(setting('registration-role'));
|
||||
if ($roleId && $this->roles()->where('id', '=', $roleId)->count() === 0) {
|
||||
$this->roles()->attach($roleId);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,10 @@
|
|||
* Configuration should be altered via the `.env` file or environment variables.
|
||||
* Do not edit this file unless you're happy to maintain any changes yourself.
|
||||
*/
|
||||
$dompdfPaperSizeMap = [
|
||||
'a4' => 'a4',
|
||||
'letter' => 'letter',
|
||||
];
|
||||
|
||||
return [
|
||||
|
||||
|
@ -150,7 +154,7 @@ return [
|
|||
*
|
||||
* @see CPDF_Adapter::PAPER_SIZES for valid sizes ('letter', 'legal', 'A4', etc.)
|
||||
*/
|
||||
'default_paper_size' => 'a4',
|
||||
'default_paper_size' => $dompdfPaperSizeMap[env('EXPORT_PAGE_SIZE', 'a4')] ?? 'a4',
|
||||
|
||||
/**
|
||||
* The default font family.
|
||||
|
|
|
@ -7,6 +7,10 @@
|
|||
* Configuration should be altered via the `.env` file or environment variables.
|
||||
* Do not edit this file unless you're happy to maintain any changes yourself.
|
||||
*/
|
||||
$snappyPaperSizeMap = [
|
||||
'a4' => 'A4',
|
||||
'letter' => 'Letter',
|
||||
];
|
||||
|
||||
return [
|
||||
'pdf' => [
|
||||
|
@ -14,7 +18,8 @@ return [
|
|||
'binary' => file_exists(base_path('wkhtmltopdf')) ? base_path('wkhtmltopdf') : env('WKHTMLTOPDF', false),
|
||||
'timeout' => false,
|
||||
'options' => [
|
||||
'outline' => true,
|
||||
'outline' => true,
|
||||
'page-size' => $snappyPaperSizeMap[env('EXPORT_PAGE_SIZE', 'a4')] ?? 'A4',
|
||||
],
|
||||
'env' => [],
|
||||
],
|
||||
|
|
|
@ -3,8 +3,10 @@
|
|||
namespace BookStack\Console\Commands;
|
||||
|
||||
use BookStack\Auth\UserRepo;
|
||||
use BookStack\Exceptions\NotFoundException;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\Rules\Password;
|
||||
use Illuminate\Validation\Rules\Unique;
|
||||
use Symfony\Component\Console\Command\Command as SymfonyCommand;
|
||||
|
@ -19,7 +21,8 @@ class CreateAdmin extends Command
|
|||
protected $signature = 'bookstack:create-admin
|
||||
{--email= : The email address for the new admin user}
|
||||
{--name= : The name of the new admin user}
|
||||
{--password= : The password to assign to the new admin user}';
|
||||
{--password= : The password to assign to the new admin user}
|
||||
{--external-auth-id= : The external authentication system id for the new admin user (SAML2/LDAP/OIDC)}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
|
@ -42,28 +45,35 @@ class CreateAdmin extends Command
|
|||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @throws \BookStack\Exceptions\NotFoundException
|
||||
* @throws NotFoundException
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$details = $this->options();
|
||||
$details = $this->snakeCaseOptions();
|
||||
|
||||
if (empty($details['email'])) {
|
||||
$details['email'] = $this->ask('Please specify an email address for the new admin user');
|
||||
}
|
||||
|
||||
if (empty($details['name'])) {
|
||||
$details['name'] = $this->ask('Please specify a name for the new admin user');
|
||||
}
|
||||
|
||||
if (empty($details['password'])) {
|
||||
$details['password'] = $this->ask('Please specify a password for the new admin user (8 characters min)');
|
||||
if (empty($details['external_auth_id'])) {
|
||||
$details['password'] = $this->ask('Please specify a password for the new admin user (8 characters min)');
|
||||
} else {
|
||||
$details['password'] = Str::random(32);
|
||||
}
|
||||
}
|
||||
|
||||
$validator = Validator::make($details, [
|
||||
'email' => ['required', 'email', 'min:5', new Unique('users', 'email')],
|
||||
'name' => ['required', 'min:2'],
|
||||
'password' => ['required', Password::default()],
|
||||
'email' => ['required', 'email', 'min:5', new Unique('users', 'email')],
|
||||
'name' => ['required', 'min:2'],
|
||||
'password' => ['required_without:external_auth_id', Password::default()],
|
||||
'external_auth_id' => ['required_without:password'],
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
|
@ -84,4 +94,14 @@ class CreateAdmin extends Command
|
|||
|
||||
return SymfonyCommand::SUCCESS;
|
||||
}
|
||||
|
||||
protected function snakeCaseOptions(): array
|
||||
{
|
||||
$returnOpts = [];
|
||||
foreach ($this->options() as $key => $value) {
|
||||
$returnOpts[str_replace('-', '_', $key)] = $value;
|
||||
}
|
||||
|
||||
return $returnOpts;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,6 +62,7 @@ class UserController extends Controller
|
|||
$this->checkPermission('users-manage');
|
||||
$authMethod = config('auth.method');
|
||||
$roles = $this->userRepo->getAllRoles();
|
||||
$this->setPageTitle(trans('settings.users_add_new'));
|
||||
|
||||
return view('users.create', ['authMethod' => $authMethod, 'roles' => $roles]);
|
||||
}
|
||||
|
@ -76,8 +77,9 @@ class UserController extends Controller
|
|||
{
|
||||
$this->checkPermission('users-manage');
|
||||
$validationRules = [
|
||||
'name' => ['required'],
|
||||
'email' => ['required', 'email', 'unique:users,email'],
|
||||
'name' => ['required'],
|
||||
'email' => ['required', 'email', 'unique:users,email'],
|
||||
'setting' => ['array'],
|
||||
];
|
||||
|
||||
$authMethod = config('auth.method');
|
||||
|
@ -104,6 +106,13 @@ class UserController extends Controller
|
|||
DB::transaction(function () use ($user, $sendInvite, $request) {
|
||||
$user->save();
|
||||
|
||||
// Save user-specific settings
|
||||
if ($request->filled('setting')) {
|
||||
foreach ($request->get('setting') as $key => $value) {
|
||||
setting()->putUser($user, $key, $value);
|
||||
}
|
||||
}
|
||||
|
||||
if ($sendInvite) {
|
||||
$this->inviteService->sendInvitation($user);
|
||||
}
|
||||
|
@ -198,7 +207,7 @@ class UserController extends Controller
|
|||
$user->external_auth_id = $request->get('external_auth_id');
|
||||
}
|
||||
|
||||
// Save an user-specific settings
|
||||
// Save user-specific settings
|
||||
if ($request->filled('setting')) {
|
||||
foreach ($request->get('setting') as $key => $value) {
|
||||
setting()->putUser($user, $key, $value);
|
||||
|
|
|
@ -2,35 +2,33 @@
|
|||
|
||||
namespace BookStack\Notifications;
|
||||
|
||||
use BookStack\Auth\User;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
class UserInvite extends MailNotification
|
||||
{
|
||||
public $token;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*
|
||||
* @param string $token
|
||||
*/
|
||||
public function __construct($token)
|
||||
public function __construct(string $token)
|
||||
{
|
||||
$this->token = $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
*
|
||||
* @return \Illuminate\Notifications\Messages\MailMessage
|
||||
*/
|
||||
public function toMail($notifiable)
|
||||
public function toMail(User $notifiable): MailMessage
|
||||
{
|
||||
$appName = ['appName' => setting('app-name')];
|
||||
$language = setting()->getUser($notifiable, 'language');
|
||||
|
||||
return $this->newMailMessage()
|
||||
->subject(trans('auth.user_invite_email_subject', $appName))
|
||||
->greeting(trans('auth.user_invite_email_greeting', $appName))
|
||||
->line(trans('auth.user_invite_email_text'))
|
||||
->action(trans('auth.user_invite_email_action'), url('/register/invite/' . $this->token));
|
||||
->subject(trans('auth.user_invite_email_subject', $appName, $language))
|
||||
->greeting(trans('auth.user_invite_email_greeting', $appName, $language))
|
||||
->line(trans('auth.user_invite_email_text', [], $language))
|
||||
->action(trans('auth.user_invite_email_action', [], $language), url('/register/invite/' . $this->token));
|
||||
}
|
||||
}
|
||||
|
|
19
readme.md
19
readme.md
|
@ -1,7 +1,7 @@
|
|||
# BookStack
|
||||
|
||||
[](https://github.com/BookStackApp/BookStack/releases/latest)
|
||||
[](https://github.com/BookStackApp/BookStack/blob/master/LICENSE)
|
||||
[](https://github.com/BookStackApp/BookStack/blob/development/LICENSE)
|
||||
[](https://crowdin.com/project/bookstack)
|
||||
[](https://discord.gg/ztkBqR2)
|
||||
[](https://gh-stats.bookstackapp.com/)
|
||||
|
@ -34,11 +34,14 @@ Big thanks to these companies for supporting the project.
|
|||
Note: Listed services are not tested, vetted nor supported by the official BookStack project in any manner.
|
||||
[View all sponsors](https://github.com/sponsors/ssddanbrown).
|
||||
|
||||
#### Silver Sponsor
|
||||
#### Silver Sponsors
|
||||
|
||||
<table><tbody><tr>
|
||||
<td><a href="https://www.diagrams.net/" target="_blank">
|
||||
<img width="420" src="https://media.githubusercontent.com/media/BookStackApp/website/main/static/images/sponsors/diagramsnet.png" alt="Diagrams.net">
|
||||
<img width="400" src="https://media.githubusercontent.com/media/BookStackApp/website/main/static/images/sponsors/diagramsnet.png" alt="Diagrams.net">
|
||||
</a></td>
|
||||
<td><a href="https://cloudabove.com/hosting" target="_blank">
|
||||
<img height="100" src="https://raw.githubusercontent.com/BookStackApp/website/main/static/images/sponsors/cloudabove.svg" alt="Cloudabove">
|
||||
</a></td>
|
||||
</tr></tbody></table>
|
||||
|
||||
|
@ -79,7 +82,7 @@ Feature releases, and some patch releases, will be accompanied by a post on the
|
|||
|
||||
## 🛠️ Development & Testing
|
||||
|
||||
All development on BookStack is currently done on the master branch. When it's time for a release the master branch is merged into release with built & minified CSS & JS then tagged at its version. Here are the current development requirements:
|
||||
All development on BookStack is currently done on the `development` branch. When it's time for a release the `development` branch is merged into release with built & minified CSS & JS then tagged at its version. Here are the current development requirements:
|
||||
|
||||
* [Node.js](https://nodejs.org/en/) v14.0+
|
||||
|
||||
|
@ -175,9 +178,9 @@ Feel free to create issues to request new features or to report bugs & problems.
|
|||
|
||||
Pull requests are welcome. Unless a small tweak or language update, It may be best to open the pull request early or create an issue for your intended change to discuss how it will fit in to the project and plan out the merge. Just because a feature request exists, or is tagged, does not mean that feature would be accepted into the core project.
|
||||
|
||||
Pull requests should be created from the `master` branch since they will be merged back into `master` once done. Please do not build from or request a merge into the `release` branch as this is only for publishing releases. If you are looking to alter CSS or JavaScript content please edit the source files found in `resources/`. Any CSS or JS files within `public` are built from these source files and therefore should not be edited directly.
|
||||
Pull requests should be created from the `development` branch since they will be merged back into `development` once done. Please do not build from or request a merge into the `release` branch as this is only for publishing releases. If you are looking to alter CSS or JavaScript content please edit the source files found in `resources/`. Any CSS or JS files within `public` are built from these source files and therefore should not be edited directly.
|
||||
|
||||
The project's code of conduct [can be found here](https://github.com/BookStackApp/BookStack/blob/master/.github/CODE_OF_CONDUCT.md).
|
||||
The project's code of conduct [can be found here](https://github.com/BookStackApp/BookStack/blob/development/.github/CODE_OF_CONDUCT.md).
|
||||
|
||||
## 🔒 Security
|
||||
|
||||
|
@ -185,7 +188,7 @@ Security information for administering a BookStack instance can be found on the
|
|||
|
||||
If you'd like to be notified of new potential security concerns you can [sign-up to the BookStack security mailing list](https://updates.bookstackapp.com/signup/bookstack-security-updates).
|
||||
|
||||
If you would like to report a security concern, details of doing so can [can be found here](https://github.com/BookStackApp/BookStack/blob/master/.github/SECURITY.md).
|
||||
If you would like to report a security concern, details of doing so can [can be found here](https://github.com/BookStackApp/BookStack/blob/development/.github/SECURITY.md).
|
||||
|
||||
## ♿ Accessibility
|
||||
|
||||
|
@ -203,7 +206,7 @@ The BookStack source is provided under the MIT License. The libraries used by, a
|
|||
|
||||
The great people that have worked to build and improve BookStack can [be seen here](https://github.com/BookStackApp/BookStack/graphs/contributors).
|
||||
|
||||
The wonderful people that have provided translations, either through GitHub or via Crowdin [can be seen here](https://github.com/BookStackApp/BookStack/blob/master/.github/translators.txt).
|
||||
The wonderful people that have provided translations, either through GitHub or via Crowdin [can be seen here](https://github.com/BookStackApp/BookStack/blob/development/.github/translators.txt).
|
||||
|
||||
These are the great open-source projects used to help build BookStack:
|
||||
|
||||
|
|
|
@ -75,6 +75,7 @@ return [
|
|||
'status_active' => 'Active',
|
||||
'status_inactive' => 'Inactive',
|
||||
'never' => 'Never',
|
||||
'none' => 'None',
|
||||
|
||||
// Header
|
||||
'header_menu_expand' => 'عرض القائمة',
|
||||
|
|
|
@ -75,6 +75,7 @@ return [
|
|||
'status_active' => 'Active',
|
||||
'status_inactive' => 'Inactive',
|
||||
'never' => 'Never',
|
||||
'none' => 'None',
|
||||
|
||||
// Header
|
||||
'header_menu_expand' => 'Expand Header Menu',
|
||||
|
|
|
@ -75,6 +75,7 @@ return [
|
|||
'status_active' => 'Active',
|
||||
'status_inactive' => 'Inactive',
|
||||
'never' => 'Never',
|
||||
'none' => 'None',
|
||||
|
||||
// Header
|
||||
'header_menu_expand' => 'Otvori meni u zaglavlju',
|
||||
|
|
|
@ -75,6 +75,7 @@ return [
|
|||
'status_active' => 'Active',
|
||||
'status_inactive' => 'Inactive',
|
||||
'never' => 'Never',
|
||||
'none' => 'None',
|
||||
|
||||
// Header
|
||||
'header_menu_expand' => 'Expand Header Menu',
|
||||
|
|
|
@ -75,6 +75,7 @@ return [
|
|||
'status_active' => 'Aktivní',
|
||||
'status_inactive' => 'Neaktivní',
|
||||
'never' => 'Nikdy',
|
||||
'none' => 'None',
|
||||
|
||||
// Header
|
||||
'header_menu_expand' => 'Rozbalit menu v záhlaví',
|
||||
|
|
|
@ -75,6 +75,7 @@ return [
|
|||
'status_active' => 'Active',
|
||||
'status_inactive' => 'Inactive',
|
||||
'never' => 'Never',
|
||||
'none' => 'None',
|
||||
|
||||
// Header
|
||||
'header_menu_expand' => 'Udvid header menu',
|
||||
|
|
|
@ -75,6 +75,7 @@ return [
|
|||
'status_active' => 'Aktiv',
|
||||
'status_inactive' => 'Inaktiv',
|
||||
'never' => 'Never',
|
||||
'none' => 'None',
|
||||
|
||||
// Header
|
||||
'header_menu_expand' => 'Header-Menü erweitern',
|
||||
|
|
|
@ -75,6 +75,7 @@ return [
|
|||
'status_active' => 'Aktiv',
|
||||
'status_inactive' => 'Inaktiv',
|
||||
'never' => 'Never',
|
||||
'none' => 'None',
|
||||
|
||||
// Header
|
||||
'header_menu_expand' => 'Header-Menü erweitern',
|
||||
|
|
|
@ -75,6 +75,7 @@ return [
|
|||
'status_active' => 'Active',
|
||||
'status_inactive' => 'Inactive',
|
||||
'never' => 'Never',
|
||||
'none' => 'None',
|
||||
|
||||
// Header
|
||||
'header_menu_expand' => 'Expand Header Menu',
|
||||
|
|
|
@ -64,7 +64,7 @@ return [
|
|||
'email_not_confirmed_resend_button' => 'Reenviar Correo Electrónico de confirmación',
|
||||
|
||||
// User Invite
|
||||
'user_invite_email_subject' => 'Has sido invitado a unirte a :appName!',
|
||||
'user_invite_email_subject' => 'As sido invitado a unirte a :appName!',
|
||||
'user_invite_email_greeting' => 'Se ha creado una cuenta para usted en :appName.',
|
||||
'user_invite_email_text' => 'Clica en el botón a continuación para ajustar una contraseña y poder acceder:',
|
||||
'user_invite_email_action' => 'Ajustar la Contraseña de la Cuenta',
|
||||
|
|
|
@ -75,6 +75,7 @@ return [
|
|||
'status_active' => 'Activo',
|
||||
'status_inactive' => 'Inactive',
|
||||
'never' => 'Nunca',
|
||||
'none' => 'Ninguno',
|
||||
|
||||
// Header
|
||||
'header_menu_expand' => 'Expandir el Menú de la Cabecera',
|
||||
|
|
|
@ -75,6 +75,7 @@ return [
|
|||
'status_active' => 'Activo',
|
||||
'status_inactive' => 'Inactivo',
|
||||
'never' => 'Nunca',
|
||||
'none' => 'Ninguno',
|
||||
|
||||
// Header
|
||||
'header_menu_expand' => 'Expandir el Menú de Cabecera',
|
||||
|
|
|
@ -28,8 +28,8 @@ return [
|
|||
'create_account' => 'Loo konto',
|
||||
'already_have_account' => 'Kasutajakonto juba olemas?',
|
||||
'dont_have_account' => 'Sul ei ole veel kontot?',
|
||||
'social_login' => 'Social Login',
|
||||
'social_registration' => 'Social Registration',
|
||||
'social_login' => 'Sisene läbi sotsiaalmeedia',
|
||||
'social_registration' => 'Registreeru läbi sotsiaalmeedia',
|
||||
'social_registration_text' => 'Registreeru ja logi sisse välise teenuse kaudu.',
|
||||
|
||||
'register_thanks' => 'Aitäh, et registreerusid!',
|
||||
|
|
|
@ -75,6 +75,7 @@ return [
|
|||
'status_active' => 'Aktiivne',
|
||||
'status_inactive' => 'Mitteaktiivne',
|
||||
'never' => 'Mitte kunagi',
|
||||
'none' => 'None',
|
||||
|
||||
// Header
|
||||
'header_menu_expand' => 'Laienda päisemenüü',
|
||||
|
|
|
@ -23,7 +23,7 @@ return [
|
|||
'meta_updated' => 'Muudetud :timeLength',
|
||||
'meta_updated_name' => 'Muudetud :timeLength kasutaja :user poolt',
|
||||
'meta_owned_name' => 'Kuulub kasutajale :user',
|
||||
'entity_select' => 'Entity Select',
|
||||
'entity_select' => 'Objekti valik',
|
||||
'images' => 'Pildid',
|
||||
'my_recent_drafts' => 'Minu hiljutised mustandid',
|
||||
'my_recently_viewed' => 'Minu viimati vaadatud',
|
||||
|
|
|
@ -75,6 +75,7 @@ return [
|
|||
'status_active' => 'فعال',
|
||||
'status_inactive' => 'غیر فعال',
|
||||
'never' => 'هرگز',
|
||||
'none' => 'None',
|
||||
|
||||
// Header
|
||||
'header_menu_expand' => 'گسترش منو',
|
||||
|
|
|
@ -75,6 +75,7 @@ return [
|
|||
'status_active' => 'Actif',
|
||||
'status_inactive' => 'Inactif',
|
||||
'never' => 'Jamais',
|
||||
'none' => 'None',
|
||||
|
||||
// Header
|
||||
'header_menu_expand' => 'Développer le menu',
|
||||
|
|
|
@ -75,6 +75,7 @@ return [
|
|||
'status_active' => 'Active',
|
||||
'status_inactive' => 'Inactive',
|
||||
'never' => 'Never',
|
||||
'none' => 'None',
|
||||
|
||||
// Header
|
||||
'header_menu_expand' => 'Expand Header Menu',
|
||||
|
|
|
@ -75,6 +75,7 @@ return [
|
|||
'status_active' => 'Active',
|
||||
'status_inactive' => 'Inactive',
|
||||
'never' => 'Never',
|
||||
'none' => 'None',
|
||||
|
||||
// Header
|
||||
'header_menu_expand' => 'Proširi izbornik',
|
||||
|
|
|
@ -75,6 +75,7 @@ return [
|
|||
'status_active' => 'Active',
|
||||
'status_inactive' => 'Inactive',
|
||||
'never' => 'Never',
|
||||
'none' => 'None',
|
||||
|
||||
// Header
|
||||
'header_menu_expand' => 'Expand Header Menu',
|
||||
|
|
|
@ -75,6 +75,7 @@ return [
|
|||
'status_active' => 'Active',
|
||||
'status_inactive' => 'Inactive',
|
||||
'never' => 'Never',
|
||||
'none' => 'None',
|
||||
|
||||
// Header
|
||||
'header_menu_expand' => 'Perluas Menu Tajuk',
|
||||
|
|
|
@ -74,7 +74,8 @@ return [
|
|||
'status' => 'Stato',
|
||||
'status_active' => 'Attivo',
|
||||
'status_inactive' => 'Inattivo',
|
||||
'never' => 'Never',
|
||||
'never' => 'Mai',
|
||||
'none' => 'None',
|
||||
|
||||
// Header
|
||||
'header_menu_expand' => 'Espandi Menù Intestazione',
|
||||
|
|
|
@ -246,7 +246,7 @@ return [
|
|||
'webhooks_events_warning' => 'Tieni presente che questi eventi saranno attivati per tutti gli eventi selezionati, anche se vengono applicati permessi personalizzati. Assicurarsi che l\'uso di questo webhook non esporrà contenuti riservati.',
|
||||
'webhooks_events_all' => 'Tutti gli eventi di sistema',
|
||||
'webhooks_name' => 'Nome Webhook',
|
||||
'webhooks_timeout' => 'Webhook Request Timeout (Seconds)',
|
||||
'webhooks_timeout' => 'Timeout Richiesta Webhook (Secondi)',
|
||||
'webhooks_endpoint' => 'Endpoint Webhook',
|
||||
'webhooks_active' => 'Webhook Attivo',
|
||||
'webhook_events_table_header' => 'Eventi',
|
||||
|
@ -255,10 +255,10 @@ return [
|
|||
'webhooks_delete_confirm' => 'Sei sicuro di voler eliminare questo webhook?',
|
||||
'webhooks_format_example' => 'Esempio Di Formato Webhook',
|
||||
'webhooks_format_example_desc' => 'I dati Webhook vengono inviati come richiesta POST all\'endpoint configurato come JSON seguendo il formato sottostante. Le proprietà "related_item" e "url" sono opzionali e dipenderanno dal tipo di evento attivato.',
|
||||
'webhooks_status' => 'Webhook Status',
|
||||
'webhooks_last_called' => 'Last Called:',
|
||||
'webhooks_last_errored' => 'Last Errored:',
|
||||
'webhooks_last_error_message' => 'Last Error Message:',
|
||||
'webhooks_status' => 'Stato Webhook',
|
||||
'webhooks_last_called' => 'Ultima Chiamata:',
|
||||
'webhooks_last_errored' => 'Ultimo Errore:',
|
||||
'webhooks_last_error_message' => 'Ultimo Messaggio Di Errore:',
|
||||
|
||||
|
||||
//! If editing translations files directly please ignore this in all
|
||||
|
|
|
@ -75,6 +75,7 @@ return [
|
|||
'status_active' => '有効',
|
||||
'status_inactive' => '無効',
|
||||
'never' => '該当なし',
|
||||
'none' => 'None',
|
||||
|
||||
// Header
|
||||
'header_menu_expand' => 'ヘッダーメニューを展開',
|
||||
|
|
|
@ -75,6 +75,7 @@ return [
|
|||
'status_active' => 'Active',
|
||||
'status_inactive' => 'Inactive',
|
||||
'never' => 'Never',
|
||||
'none' => 'None',
|
||||
|
||||
// Header
|
||||
'header_menu_expand' => 'Expand Header Menu',
|
||||
|
|
|
@ -75,6 +75,7 @@ return [
|
|||
'status_active' => 'Active',
|
||||
'status_inactive' => 'Inactive',
|
||||
'never' => 'Never',
|
||||
'none' => 'None',
|
||||
|
||||
// Header
|
||||
'header_menu_expand' => 'Plėsti antraštės meniu',
|
||||
|
|
|
@ -75,6 +75,7 @@ return [
|
|||
'status_active' => 'Aktīvs',
|
||||
'status_inactive' => 'Neaktīvs',
|
||||
'never' => 'Never',
|
||||
'none' => 'None',
|
||||
|
||||
// Header
|
||||
'header_menu_expand' => 'Izvērst galvenes izvēlni',
|
||||
|
|
|
@ -75,6 +75,7 @@ return [
|
|||
'status_active' => 'Active',
|
||||
'status_inactive' => 'Inactive',
|
||||
'never' => 'Never',
|
||||
'none' => 'None',
|
||||
|
||||
// Header
|
||||
'header_menu_expand' => 'Utvid toppmeny',
|
||||
|
|
|
@ -75,6 +75,7 @@ return [
|
|||
'status_active' => 'Active',
|
||||
'status_inactive' => 'Inactive',
|
||||
'never' => 'Never',
|
||||
'none' => 'None',
|
||||
|
||||
// Header
|
||||
'header_menu_expand' => 'Header menu uitvouwen',
|
||||
|
|
|
@ -75,6 +75,7 @@ return [
|
|||
'status_active' => 'Active',
|
||||
'status_inactive' => 'Inactive',
|
||||
'never' => 'Never',
|
||||
'none' => 'None',
|
||||
|
||||
// Header
|
||||
'header_menu_expand' => 'Rozwiń menu nagłówka',
|
||||
|
|
|
@ -75,6 +75,7 @@ return [
|
|||
'status_active' => 'Ativo',
|
||||
'status_inactive' => 'Inativo',
|
||||
'never' => 'Never',
|
||||
'none' => 'None',
|
||||
|
||||
// Header
|
||||
'header_menu_expand' => 'Expandir Menu de Cabeçalho',
|
||||
|
|
|
@ -75,6 +75,7 @@ return [
|
|||
'status_active' => 'Ativo',
|
||||
'status_inactive' => 'Inativo',
|
||||
'never' => 'Nunca',
|
||||
'none' => 'None',
|
||||
|
||||
// Header
|
||||
'header_menu_expand' => 'Expandir Cabeçalho do Menu',
|
||||
|
|
|
@ -75,6 +75,7 @@ return [
|
|||
'status_active' => 'Активен',
|
||||
'status_inactive' => 'Неактивен',
|
||||
'never' => 'Никогда',
|
||||
'none' => 'None',
|
||||
|
||||
// Header
|
||||
'header_menu_expand' => 'Развернуть меню заголовка',
|
||||
|
|
|
@ -75,6 +75,7 @@ return [
|
|||
'status_active' => 'Active',
|
||||
'status_inactive' => 'Inactive',
|
||||
'never' => 'Never',
|
||||
'none' => 'None',
|
||||
|
||||
// Header
|
||||
'header_menu_expand' => 'Rozbaliť menu v záhlaví',
|
||||
|
|
|
@ -75,6 +75,7 @@ return [
|
|||
'status_active' => 'Active',
|
||||
'status_inactive' => 'Inactive',
|
||||
'never' => 'Never',
|
||||
'none' => 'None',
|
||||
|
||||
// Header
|
||||
'header_menu_expand' => 'Expand Header Menu',
|
||||
|
|
|
@ -75,6 +75,7 @@ return [
|
|||
'status_active' => 'Active',
|
||||
'status_inactive' => 'Inactive',
|
||||
'never' => 'Never',
|
||||
'none' => 'None',
|
||||
|
||||
// Header
|
||||
'header_menu_expand' => 'Expandera sidhuvudsmenyn',
|
||||
|
|
|
@ -75,6 +75,7 @@ return [
|
|||
'status_active' => 'Active',
|
||||
'status_inactive' => 'Inactive',
|
||||
'never' => 'Never',
|
||||
'none' => 'None',
|
||||
|
||||
// Header
|
||||
'header_menu_expand' => 'Expand Header Menu',
|
||||
|
|
|
@ -75,6 +75,7 @@ return [
|
|||
'status_active' => 'Active',
|
||||
'status_inactive' => 'Inactive',
|
||||
'never' => 'Never',
|
||||
'none' => 'None',
|
||||
|
||||
// Header
|
||||
'header_menu_expand' => 'Розгорнути меню заголовка',
|
||||
|
|
|
@ -75,6 +75,7 @@ return [
|
|||
'status_active' => 'Active',
|
||||
'status_inactive' => 'Inactive',
|
||||
'never' => 'Never',
|
||||
'none' => 'None',
|
||||
|
||||
// Header
|
||||
'header_menu_expand' => 'Expand Header Menu',
|
||||
|
|
|
@ -75,6 +75,7 @@ return [
|
|||
'status_active' => '已激活',
|
||||
'status_inactive' => '未激活',
|
||||
'never' => '从未',
|
||||
'none' => 'None',
|
||||
|
||||
// Header
|
||||
'header_menu_expand' => '展开标头菜单',
|
||||
|
|
|
@ -75,6 +75,7 @@ return [
|
|||
'status_active' => 'Active',
|
||||
'status_inactive' => 'Inactive',
|
||||
'never' => 'Never',
|
||||
'none' => 'None',
|
||||
|
||||
// Header
|
||||
'header_menu_expand' => '展開選單',
|
||||
|
|
|
@ -1,12 +1,29 @@
|
|||
@extends('layouts.simple')
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ config('app.lang') }}"
|
||||
dir="{{ config('app.rtl') ? 'rtl' : 'ltr' }}">
|
||||
<head>
|
||||
<title>{{ isset($pageTitle) ? $pageTitle . ' | ' : '' }}{{ setting('app-name') }}</title>
|
||||
|
||||
@section('content')
|
||||
<!-- Meta -->
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<meta charset="utf-8">
|
||||
|
||||
<div class="container small mt-xl">
|
||||
<div class="card content-wrap auto-height">
|
||||
<h1 class="list-heading">{{ trans('errors.app_down', ['appName' => setting('app-name')]) }}</h1>
|
||||
<p>{{ trans('errors.back_soon') }}</p>
|
||||
<!-- Styles and Fonts -->
|
||||
<link rel="stylesheet" href="{{ versioned_asset('dist/styles.css') }}">
|
||||
<link rel="stylesheet" media="print" href="{{ versioned_asset('dist/print-styles.css') }}">
|
||||
|
||||
<!-- Custom Styles & Head Content -->
|
||||
@include('common.custom-styles')
|
||||
@include('common.custom-head')
|
||||
</head>
|
||||
<body>
|
||||
<div id="content" class="block">
|
||||
<div class="container small mt-xl">
|
||||
<div class="card content-wrap auto-height">
|
||||
<h1 class="list-heading">{{ trans('errors.app_down', ['appName' => setting('app-name')]) }}</h1>
|
||||
<p>{{ trans('errors.back_soon') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@stop
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -227,10 +227,11 @@
|
|||
|
||||
<label for="setting-registration-role">{{ trans('settings.reg_default_role') }}</label>
|
||||
<select id="setting-registration-role" name="setting-registration-role" @if($errors->has('setting-registration-role')) class="neg" @endif>
|
||||
<option value="0" @if(intval(setting('registration-role', '0')) === 0) selected @endif>-- {{ trans('common.none') }} --</option>
|
||||
@foreach(\BookStack\Auth\Role::all() as $role)
|
||||
<option value="{{$role->id}}"
|
||||
data-system-role-name="{{ $role->system_name ?? '' }}"
|
||||
@if(setting('registration-role', \BookStack\Auth\Role::first()->id) == $role->id) selected @endif
|
||||
@if(intval(setting('registration-role', '0')) === $role->id) selected @endif
|
||||
>
|
||||
{{ $role->display_name }}
|
||||
</option>
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
<div class="setting-list">
|
||||
@include('users.parts.form')
|
||||
@include('users.parts.language-option-row', ['value' => old('setting.language') ?? config('app.default_locale')])
|
||||
</div>
|
||||
|
||||
<div class="form-group text-right">
|
||||
|
|
|
@ -35,22 +35,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid half gap-xl v-center">
|
||||
<div>
|
||||
<label for="user-language" class="setting-list-label">{{ trans('settings.users_preferred_language') }}</label>
|
||||
<p class="small">
|
||||
{{ trans('settings.users_preferred_language_desc') }}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<select name="setting[language]" id="user-language">
|
||||
@foreach(trans('settings.language_select') as $lang => $label)
|
||||
<option @if(setting()->getUser($user, 'language', config('app.default_locale')) === $lang) selected @endif value="{{ $lang }}">{{ $label }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@include('users.parts.language-option-row', ['value' => setting()->getUser($user, 'language', config('app.default_locale'))])
|
||||
</div>
|
||||
|
||||
<div class="text-right">
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
{{--
|
||||
$value - Currently selected lanuage value
|
||||
--}}
|
||||
<div class="grid half gap-xl v-center">
|
||||
<div>
|
||||
<label for="user-language" class="setting-list-label">{{ trans('settings.users_preferred_language') }}</label>
|
||||
<p class="small">
|
||||
{{ trans('settings.users_preferred_language_desc') }}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<select name="setting[language]" id="user-language">
|
||||
@foreach(trans('settings.language_select') as $lang => $label)
|
||||
<option @if($value === $lang) selected @endif value="{{ $lang }}">{{ $label }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
|
@ -3,6 +3,7 @@
|
|||
namespace Tests\Auth;
|
||||
|
||||
use BookStack\Auth\Access\Mfa\MfaSession;
|
||||
use BookStack\Auth\Role;
|
||||
use BookStack\Auth\User;
|
||||
use BookStack\Entities\Models\Page;
|
||||
use BookStack\Notifications\ConfirmEmail;
|
||||
|
@ -43,7 +44,10 @@ class AuthTest extends TestCase
|
|||
public function test_normal_registration()
|
||||
{
|
||||
// Set settings and get user instance
|
||||
$this->setSettings(['registration-enabled' => 'true']);
|
||||
/** @var Role $registrationRole */
|
||||
$registrationRole = Role::query()->first();
|
||||
$this->setSettings(['registration-enabled' => 'true', 'registration-role' => $registrationRole->id]);
|
||||
/** @var User $user */
|
||||
$user = User::factory()->make();
|
||||
|
||||
// Test form and ensure user is created
|
||||
|
@ -57,7 +61,12 @@ class AuthTest extends TestCase
|
|||
$resp = $this->get('/');
|
||||
$resp->assertOk();
|
||||
$resp->assertSee($user->name);
|
||||
|
||||
$this->assertDatabaseHas('users', ['name' => $user->name, 'email' => $user->email]);
|
||||
|
||||
$user = User::query()->where('email', '=', $user->email)->first();
|
||||
$this->assertEquals(1, $user->roles()->count());
|
||||
$this->assertEquals($registrationRole->id, $user->roles()->first()->id);
|
||||
}
|
||||
|
||||
public function test_empty_registration_redirects_back_with_errors()
|
||||
|
@ -189,6 +198,14 @@ class AuthTest extends TestCase
|
|||
$this->assertNull(auth()->user());
|
||||
}
|
||||
|
||||
public function test_registration_role_unset_by_default()
|
||||
{
|
||||
$this->assertFalse(setting('registration-role'));
|
||||
|
||||
$resp = $this->asAdmin()->get('/settings');
|
||||
$resp->assertElementContains('select[name="setting-registration-role"] option[value="0"][selected]', '-- None --');
|
||||
}
|
||||
|
||||
public function test_logout()
|
||||
{
|
||||
$this->asAdmin()->get('/')->assertOk();
|
||||
|
|
|
@ -318,6 +318,31 @@ class OidcTest extends TestCase
|
|||
$this->assertCount(4, $transactions);
|
||||
}
|
||||
|
||||
public function test_auth_login_with_autodiscovery_with_keys_that_do_not_have_alg_property()
|
||||
{
|
||||
$this->withAutodiscovery();
|
||||
|
||||
$keyArray = OidcJwtHelper::publicJwkKeyArray();
|
||||
unset($keyArray['alg']);
|
||||
|
||||
$this->mockHttpClient([
|
||||
$this->getAutoDiscoveryResponse(),
|
||||
new Response(200, [
|
||||
'Content-Type' => 'application/json',
|
||||
'Cache-Control' => 'no-cache, no-store',
|
||||
'Pragma' => 'no-cache',
|
||||
], json_encode([
|
||||
'keys' => [
|
||||
$keyArray,
|
||||
],
|
||||
])),
|
||||
]);
|
||||
|
||||
$this->assertFalse(auth()->check());
|
||||
$this->runLogin();
|
||||
$this->assertTrue(auth()->check());
|
||||
}
|
||||
|
||||
protected function withAutodiscovery()
|
||||
{
|
||||
config()->set([
|
||||
|
|
|
@ -6,6 +6,7 @@ use BookStack\Auth\Access\UserInviteService;
|
|||
use BookStack\Auth\User;
|
||||
use BookStack\Notifications\UserInvite;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Illuminate\Support\Str;
|
||||
|
@ -34,6 +35,32 @@ class UserInviteTest extends TestCase
|
|||
]);
|
||||
}
|
||||
|
||||
public function test_user_invite_sent_in_selected_language()
|
||||
{
|
||||
Notification::fake();
|
||||
$admin = $this->getAdmin();
|
||||
|
||||
$email = Str::random(16) . '@example.com';
|
||||
$resp = $this->actingAs($admin)->post('/settings/users/create', [
|
||||
'name' => 'Barry',
|
||||
'email' => $email,
|
||||
'send_invite' => 'true',
|
||||
'setting' => [
|
||||
'language' => 'de',
|
||||
],
|
||||
]);
|
||||
$resp->assertRedirect('/settings/users');
|
||||
|
||||
$newUser = User::query()->where('email', '=', $email)->orderBy('id', 'desc')->first();
|
||||
Notification::assertSentTo($newUser, UserInvite::class, function ($notification, $channels, $notifiable) {
|
||||
/** @var MailMessage $mail */
|
||||
$mail = $notification->toMail($notifiable);
|
||||
|
||||
return 'Du wurdest eingeladen BookStack beizutreten!' === $mail->subject &&
|
||||
'Ein Konto wurde für Sie auf BookStack erstellt.' === $mail->greeting;
|
||||
});
|
||||
}
|
||||
|
||||
public function test_invite_set_password()
|
||||
{
|
||||
Notification::fake();
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Commands;
|
||||
|
||||
use BookStack\Auth\User;
|
||||
use Tests\TestCase;
|
||||
|
||||
class AddAdminCommandTest extends TestCase
|
||||
{
|
||||
public function test_add_admin_command()
|
||||
{
|
||||
$exitCode = \Artisan::call('bookstack:create-admin', [
|
||||
'--email' => 'admintest@example.com',
|
||||
'--name' => 'Admin Test',
|
||||
'--password' => 'testing-4',
|
||||
]);
|
||||
$this->assertTrue($exitCode === 0, 'Command executed successfully');
|
||||
|
||||
$this->assertDatabaseHas('users', [
|
||||
'email' => 'admintest@example.com',
|
||||
'name' => 'Admin Test',
|
||||
]);
|
||||
|
||||
$this->assertTrue(User::query()->where('email', '=', 'admintest@example.com')->first()->hasSystemRole('admin'), 'User has admin role as expected');
|
||||
$this->assertTrue(\Auth::attempt(['email' => 'admintest@example.com', 'password' => 'testing-4']), 'Password stored as expected');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Commands;
|
||||
|
||||
use BookStack\Auth\User;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Tests\TestCase;
|
||||
|
||||
class CreateAdminCommandTest extends TestCase
|
||||
{
|
||||
public function test_standard_command_usage()
|
||||
{
|
||||
$this->artisan('bookstack:create-admin', [
|
||||
'--email' => 'admintest@example.com',
|
||||
'--name' => 'Admin Test',
|
||||
'--password' => 'testing-4',
|
||||
])->assertExitCode(0);
|
||||
|
||||
$this->assertDatabaseHas('users', [
|
||||
'email' => 'admintest@example.com',
|
||||
'name' => 'Admin Test',
|
||||
]);
|
||||
|
||||
/** @var User $user */
|
||||
$user = User::query()->where('email', '=', 'admintest@example.com')->first();
|
||||
$this->assertTrue($user->hasSystemRole('admin'));
|
||||
$this->assertTrue(Auth::attempt(['email' => 'admintest@example.com', 'password' => 'testing-4']));
|
||||
}
|
||||
|
||||
public function test_providing_external_auth_id()
|
||||
{
|
||||
$this->artisan('bookstack:create-admin', [
|
||||
'--email' => 'admintest@example.com',
|
||||
'--name' => 'Admin Test',
|
||||
'--external-auth-id' => 'xX_admin_Xx',
|
||||
])->assertExitCode(0);
|
||||
|
||||
$this->assertDatabaseHas('users', [
|
||||
'email' => 'admintest@example.com',
|
||||
'name' => 'Admin Test',
|
||||
'external_auth_id' => 'xX_admin_Xx',
|
||||
]);
|
||||
|
||||
/** @var User $user */
|
||||
$user = User::query()->where('email', '=', 'admintest@example.com')->first();
|
||||
$this->assertNotEmpty($user->password);
|
||||
}
|
||||
|
||||
public function test_password_required_if_external_auth_id_not_given()
|
||||
{
|
||||
$this->artisan('bookstack:create-admin', [
|
||||
'--email' => 'admintest@example.com',
|
||||
'--name' => 'Admin Test',
|
||||
])->expectsQuestion('Please specify a password for the new admin user (8 characters min)', 'hunter2000')
|
||||
->assertExitCode(0);
|
||||
|
||||
$this->assertDatabaseHas('users', [
|
||||
'email' => 'admintest@example.com',
|
||||
'name' => 'Admin Test',
|
||||
]);
|
||||
$this->assertTrue(Auth::attempt(['email' => 'admintest@example.com', 'password' => 'hunter2000']));
|
||||
}
|
||||
}
|
|
@ -82,6 +82,20 @@ class ConfigTest extends TestCase
|
|||
$this->checkEnvConfigResult('ALLOW_UNTRUSTED_SERVER_FETCHING', 'true', 'dompdf.defines.enable_remote', true);
|
||||
}
|
||||
|
||||
public function test_dompdf_paper_size_options_are_limited()
|
||||
{
|
||||
$this->checkEnvConfigResult('EXPORT_PAGE_SIZE', 'cat', 'dompdf.defines.default_paper_size', 'a4');
|
||||
$this->checkEnvConfigResult('EXPORT_PAGE_SIZE', 'letter', 'dompdf.defines.default_paper_size', 'letter');
|
||||
$this->checkEnvConfigResult('EXPORT_PAGE_SIZE', 'a4', 'dompdf.defines.default_paper_size', 'a4');
|
||||
}
|
||||
|
||||
public function test_snappy_paper_size_options_are_limited()
|
||||
{
|
||||
$this->checkEnvConfigResult('EXPORT_PAGE_SIZE', 'cat', 'snappy.pdf.options.page-size', 'A4');
|
||||
$this->checkEnvConfigResult('EXPORT_PAGE_SIZE', 'letter', 'snappy.pdf.options.page-size', 'Letter');
|
||||
$this->checkEnvConfigResult('EXPORT_PAGE_SIZE', 'a4', 'snappy.pdf.options.page-size', 'A4');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an environment variable of the given name and value
|
||||
* then check the given config key to see if it matches the given result.
|
||||
|
|
|
@ -183,6 +183,16 @@ class UserManagementTest extends TestCase
|
|||
$resp->assertSee('cannot delete the guest user');
|
||||
}
|
||||
|
||||
public function test_user_create_language_reflects_default_system_locale()
|
||||
{
|
||||
$langs = ['en', 'fr', 'hr'];
|
||||
foreach ($langs as $lang) {
|
||||
config()->set('app.locale', $lang);
|
||||
$resp = $this->asAdmin()->get('/settings/users/create');
|
||||
$resp->assertElementExists('select[name="setting[language]"] option[value="' . $lang . '"][selected]');
|
||||
}
|
||||
}
|
||||
|
||||
public function test_user_creation_is_not_performed_if_the_invitation_sending_fails()
|
||||
{
|
||||
/** @var User $user */
|
||||
|
|
Loading…
Reference in New Issue