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.
|
# Maximum file size, in megabytes, that can be uploaded to the system.
|
||||||
FILE_UPLOAD_SIZE_LIMIT=50
|
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
|
# Allow <script> tags in page content
|
||||||
# Note, if set to 'true' the page editor may still escape scripts.
|
# Note, if set to 'true' the page editor may still escape scripts.
|
||||||
ALLOW_CONTENT_SCRIPTS=false
|
ALLOW_CONTENT_SCRIPTS=false
|
||||||
|
|
|
@ -3,10 +3,10 @@ name: phpstan
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches-ignore:
|
branches-ignore:
|
||||||
- l10n_master
|
- l10n_development
|
||||||
pull_request:
|
pull_request:
|
||||||
branches-ignore:
|
branches-ignore:
|
||||||
- l10n_master
|
- l10n_development
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
|
|
@ -3,10 +3,10 @@ name: phpunit
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches-ignore:
|
branches-ignore:
|
||||||
- l10n_master
|
- l10n_development
|
||||||
pull_request:
|
pull_request:
|
||||||
branches-ignore:
|
branches-ignore:
|
||||||
- l10n_master
|
- l10n_development
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
|
|
@ -3,10 +3,10 @@ name: test-migrations
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches-ignore:
|
branches-ignore:
|
||||||
- l10n_master
|
- l10n_development
|
||||||
pull_request:
|
pull_request:
|
||||||
branches-ignore:
|
branches-ignore:
|
||||||
- l10n_master
|
- l10n_development
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
|
|
@ -60,8 +60,11 @@ class OidcJwtSigningKey
|
||||||
*/
|
*/
|
||||||
protected function loadFromJwkArray(array $jwk)
|
protected function loadFromJwkArray(array $jwk)
|
||||||
{
|
{
|
||||||
if ($jwk['alg'] !== 'RS256') {
|
// 'alg' is optional for a JWK, but we will still attempt to validate if
|
||||||
throw new OidcInvalidKeyException("Only RS256 keys are currently supported. Found key using {$jwk['alg']}");
|
// 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'])) {
|
if (empty($jwk['use'])) {
|
||||||
|
|
|
@ -164,7 +164,9 @@ class OidcProviderSettings
|
||||||
protected function filterKeys(array $keys): array
|
protected function filterKeys(array $keys): array
|
||||||
{
|
{
|
||||||
return array_filter($keys, function (array $key) {
|
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
|
public function attachDefaultRole(): void
|
||||||
{
|
{
|
||||||
$roleId = setting('registration-role');
|
$roleId = intval(setting('registration-role'));
|
||||||
if ($roleId && $this->roles()->where('id', '=', $roleId)->count() === 0) {
|
if ($roleId && $this->roles()->where('id', '=', $roleId)->count() === 0) {
|
||||||
$this->roles()->attach($roleId);
|
$this->roles()->attach($roleId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,10 @@
|
||||||
* Configuration should be altered via the `.env` file or environment variables.
|
* 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.
|
* Do not edit this file unless you're happy to maintain any changes yourself.
|
||||||
*/
|
*/
|
||||||
|
$dompdfPaperSizeMap = [
|
||||||
|
'a4' => 'a4',
|
||||||
|
'letter' => 'letter',
|
||||||
|
];
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
||||||
|
@ -150,7 +154,7 @@ return [
|
||||||
*
|
*
|
||||||
* @see CPDF_Adapter::PAPER_SIZES for valid sizes ('letter', 'legal', 'A4', etc.)
|
* @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.
|
* The default font family.
|
||||||
|
|
|
@ -7,6 +7,10 @@
|
||||||
* Configuration should be altered via the `.env` file or environment variables.
|
* 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.
|
* Do not edit this file unless you're happy to maintain any changes yourself.
|
||||||
*/
|
*/
|
||||||
|
$snappyPaperSizeMap = [
|
||||||
|
'a4' => 'A4',
|
||||||
|
'letter' => 'Letter',
|
||||||
|
];
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'pdf' => [
|
'pdf' => [
|
||||||
|
@ -14,7 +18,8 @@ return [
|
||||||
'binary' => file_exists(base_path('wkhtmltopdf')) ? base_path('wkhtmltopdf') : env('WKHTMLTOPDF', false),
|
'binary' => file_exists(base_path('wkhtmltopdf')) ? base_path('wkhtmltopdf') : env('WKHTMLTOPDF', false),
|
||||||
'timeout' => false,
|
'timeout' => false,
|
||||||
'options' => [
|
'options' => [
|
||||||
'outline' => true,
|
'outline' => true,
|
||||||
|
'page-size' => $snappyPaperSizeMap[env('EXPORT_PAGE_SIZE', 'a4')] ?? 'A4',
|
||||||
],
|
],
|
||||||
'env' => [],
|
'env' => [],
|
||||||
],
|
],
|
||||||
|
|
|
@ -3,8 +3,10 @@
|
||||||
namespace BookStack\Console\Commands;
|
namespace BookStack\Console\Commands;
|
||||||
|
|
||||||
use BookStack\Auth\UserRepo;
|
use BookStack\Auth\UserRepo;
|
||||||
|
use BookStack\Exceptions\NotFoundException;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
use Illuminate\Validation\Rules\Password;
|
use Illuminate\Validation\Rules\Password;
|
||||||
use Illuminate\Validation\Rules\Unique;
|
use Illuminate\Validation\Rules\Unique;
|
||||||
use Symfony\Component\Console\Command\Command as SymfonyCommand;
|
use Symfony\Component\Console\Command\Command as SymfonyCommand;
|
||||||
|
@ -19,7 +21,8 @@ class CreateAdmin extends Command
|
||||||
protected $signature = 'bookstack:create-admin
|
protected $signature = 'bookstack:create-admin
|
||||||
{--email= : The email address for the new admin user}
|
{--email= : The email address for the new admin user}
|
||||||
{--name= : The name of 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.
|
* The console command description.
|
||||||
|
@ -42,28 +45,35 @@ class CreateAdmin extends Command
|
||||||
/**
|
/**
|
||||||
* Execute the console command.
|
* Execute the console command.
|
||||||
*
|
*
|
||||||
* @throws \BookStack\Exceptions\NotFoundException
|
* @throws NotFoundException
|
||||||
*
|
*
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
$details = $this->options();
|
$details = $this->snakeCaseOptions();
|
||||||
|
|
||||||
if (empty($details['email'])) {
|
if (empty($details['email'])) {
|
||||||
$details['email'] = $this->ask('Please specify an email address for the new admin user');
|
$details['email'] = $this->ask('Please specify an email address for the new admin user');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($details['name'])) {
|
if (empty($details['name'])) {
|
||||||
$details['name'] = $this->ask('Please specify a name for the new admin user');
|
$details['name'] = $this->ask('Please specify a name for the new admin user');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($details['password'])) {
|
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, [
|
$validator = Validator::make($details, [
|
||||||
'email' => ['required', 'email', 'min:5', new Unique('users', 'email')],
|
'email' => ['required', 'email', 'min:5', new Unique('users', 'email')],
|
||||||
'name' => ['required', 'min:2'],
|
'name' => ['required', 'min:2'],
|
||||||
'password' => ['required', Password::default()],
|
'password' => ['required_without:external_auth_id', Password::default()],
|
||||||
|
'external_auth_id' => ['required_without:password'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if ($validator->fails()) {
|
if ($validator->fails()) {
|
||||||
|
@ -84,4 +94,14 @@ class CreateAdmin extends Command
|
||||||
|
|
||||||
return SymfonyCommand::SUCCESS;
|
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');
|
$this->checkPermission('users-manage');
|
||||||
$authMethod = config('auth.method');
|
$authMethod = config('auth.method');
|
||||||
$roles = $this->userRepo->getAllRoles();
|
$roles = $this->userRepo->getAllRoles();
|
||||||
|
$this->setPageTitle(trans('settings.users_add_new'));
|
||||||
|
|
||||||
return view('users.create', ['authMethod' => $authMethod, 'roles' => $roles]);
|
return view('users.create', ['authMethod' => $authMethod, 'roles' => $roles]);
|
||||||
}
|
}
|
||||||
|
@ -76,8 +77,9 @@ class UserController extends Controller
|
||||||
{
|
{
|
||||||
$this->checkPermission('users-manage');
|
$this->checkPermission('users-manage');
|
||||||
$validationRules = [
|
$validationRules = [
|
||||||
'name' => ['required'],
|
'name' => ['required'],
|
||||||
'email' => ['required', 'email', 'unique:users,email'],
|
'email' => ['required', 'email', 'unique:users,email'],
|
||||||
|
'setting' => ['array'],
|
||||||
];
|
];
|
||||||
|
|
||||||
$authMethod = config('auth.method');
|
$authMethod = config('auth.method');
|
||||||
|
@ -104,6 +106,13 @@ class UserController extends Controller
|
||||||
DB::transaction(function () use ($user, $sendInvite, $request) {
|
DB::transaction(function () use ($user, $sendInvite, $request) {
|
||||||
$user->save();
|
$user->save();
|
||||||
|
|
||||||
|
// Save user-specific settings
|
||||||
|
if ($request->filled('setting')) {
|
||||||
|
foreach ($request->get('setting') as $key => $value) {
|
||||||
|
setting()->putUser($user, $key, $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($sendInvite) {
|
if ($sendInvite) {
|
||||||
$this->inviteService->sendInvitation($user);
|
$this->inviteService->sendInvitation($user);
|
||||||
}
|
}
|
||||||
|
@ -198,7 +207,7 @@ class UserController extends Controller
|
||||||
$user->external_auth_id = $request->get('external_auth_id');
|
$user->external_auth_id = $request->get('external_auth_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save an user-specific settings
|
// Save user-specific settings
|
||||||
if ($request->filled('setting')) {
|
if ($request->filled('setting')) {
|
||||||
foreach ($request->get('setting') as $key => $value) {
|
foreach ($request->get('setting') as $key => $value) {
|
||||||
setting()->putUser($user, $key, $value);
|
setting()->putUser($user, $key, $value);
|
||||||
|
|
|
@ -2,35 +2,33 @@
|
||||||
|
|
||||||
namespace BookStack\Notifications;
|
namespace BookStack\Notifications;
|
||||||
|
|
||||||
|
use BookStack\Auth\User;
|
||||||
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
|
|
||||||
class UserInvite extends MailNotification
|
class UserInvite extends MailNotification
|
||||||
{
|
{
|
||||||
public $token;
|
public $token;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new notification instance.
|
* Create a new notification instance.
|
||||||
*
|
|
||||||
* @param string $token
|
|
||||||
*/
|
*/
|
||||||
public function __construct($token)
|
public function __construct(string $token)
|
||||||
{
|
{
|
||||||
$this->token = $token;
|
$this->token = $token;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the mail representation of the notification.
|
* 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')];
|
$appName = ['appName' => setting('app-name')];
|
||||||
|
$language = setting()->getUser($notifiable, 'language');
|
||||||
|
|
||||||
return $this->newMailMessage()
|
return $this->newMailMessage()
|
||||||
->subject(trans('auth.user_invite_email_subject', $appName))
|
->subject(trans('auth.user_invite_email_subject', $appName, $language))
|
||||||
->greeting(trans('auth.user_invite_email_greeting', $appName))
|
->greeting(trans('auth.user_invite_email_greeting', $appName, $language))
|
||||||
->line(trans('auth.user_invite_email_text'))
|
->line(trans('auth.user_invite_email_text', [], $language))
|
||||||
->action(trans('auth.user_invite_email_action'), url('/register/invite/' . $this->token));
|
->action(trans('auth.user_invite_email_action', [], $language), url('/register/invite/' . $this->token));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
19
readme.md
19
readme.md
|
@ -1,7 +1,7 @@
|
||||||
# BookStack
|
# BookStack
|
||||||
|
|
||||||
[](https://github.com/BookStackApp/BookStack/releases/latest)
|
[](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://crowdin.com/project/bookstack)
|
||||||
[](https://discord.gg/ztkBqR2)
|
[](https://discord.gg/ztkBqR2)
|
||||||
[](https://gh-stats.bookstackapp.com/)
|
[](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.
|
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).
|
[View all sponsors](https://github.com/sponsors/ssddanbrown).
|
||||||
|
|
||||||
#### Silver Sponsor
|
#### Silver Sponsors
|
||||||
|
|
||||||
<table><tbody><tr>
|
<table><tbody><tr>
|
||||||
<td><a href="https://www.diagrams.net/" target="_blank">
|
<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>
|
</a></td>
|
||||||
</tr></tbody></table>
|
</tr></tbody></table>
|
||||||
|
|
||||||
|
@ -79,7 +82,7 @@ Feature releases, and some patch releases, will be accompanied by a post on the
|
||||||
|
|
||||||
## 🛠️ Development & Testing
|
## 🛠️ 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+
|
* [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 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
|
## 🔒 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'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
|
## ♿ 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 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:
|
These are the great open-source projects used to help build BookStack:
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,7 @@ return [
|
||||||
'status_active' => 'Active',
|
'status_active' => 'Active',
|
||||||
'status_inactive' => 'Inactive',
|
'status_inactive' => 'Inactive',
|
||||||
'never' => 'Never',
|
'never' => 'Never',
|
||||||
|
'none' => 'None',
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
'header_menu_expand' => 'عرض القائمة',
|
'header_menu_expand' => 'عرض القائمة',
|
||||||
|
|
|
@ -75,6 +75,7 @@ return [
|
||||||
'status_active' => 'Active',
|
'status_active' => 'Active',
|
||||||
'status_inactive' => 'Inactive',
|
'status_inactive' => 'Inactive',
|
||||||
'never' => 'Never',
|
'never' => 'Never',
|
||||||
|
'none' => 'None',
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
'header_menu_expand' => 'Expand Header Menu',
|
'header_menu_expand' => 'Expand Header Menu',
|
||||||
|
|
|
@ -75,6 +75,7 @@ return [
|
||||||
'status_active' => 'Active',
|
'status_active' => 'Active',
|
||||||
'status_inactive' => 'Inactive',
|
'status_inactive' => 'Inactive',
|
||||||
'never' => 'Never',
|
'never' => 'Never',
|
||||||
|
'none' => 'None',
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
'header_menu_expand' => 'Otvori meni u zaglavlju',
|
'header_menu_expand' => 'Otvori meni u zaglavlju',
|
||||||
|
|
|
@ -75,6 +75,7 @@ return [
|
||||||
'status_active' => 'Active',
|
'status_active' => 'Active',
|
||||||
'status_inactive' => 'Inactive',
|
'status_inactive' => 'Inactive',
|
||||||
'never' => 'Never',
|
'never' => 'Never',
|
||||||
|
'none' => 'None',
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
'header_menu_expand' => 'Expand Header Menu',
|
'header_menu_expand' => 'Expand Header Menu',
|
||||||
|
|
|
@ -75,6 +75,7 @@ return [
|
||||||
'status_active' => 'Aktivní',
|
'status_active' => 'Aktivní',
|
||||||
'status_inactive' => 'Neaktivní',
|
'status_inactive' => 'Neaktivní',
|
||||||
'never' => 'Nikdy',
|
'never' => 'Nikdy',
|
||||||
|
'none' => 'None',
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
'header_menu_expand' => 'Rozbalit menu v záhlaví',
|
'header_menu_expand' => 'Rozbalit menu v záhlaví',
|
||||||
|
|
|
@ -75,6 +75,7 @@ return [
|
||||||
'status_active' => 'Active',
|
'status_active' => 'Active',
|
||||||
'status_inactive' => 'Inactive',
|
'status_inactive' => 'Inactive',
|
||||||
'never' => 'Never',
|
'never' => 'Never',
|
||||||
|
'none' => 'None',
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
'header_menu_expand' => 'Udvid header menu',
|
'header_menu_expand' => 'Udvid header menu',
|
||||||
|
|
|
@ -75,6 +75,7 @@ return [
|
||||||
'status_active' => 'Aktiv',
|
'status_active' => 'Aktiv',
|
||||||
'status_inactive' => 'Inaktiv',
|
'status_inactive' => 'Inaktiv',
|
||||||
'never' => 'Never',
|
'never' => 'Never',
|
||||||
|
'none' => 'None',
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
'header_menu_expand' => 'Header-Menü erweitern',
|
'header_menu_expand' => 'Header-Menü erweitern',
|
||||||
|
|
|
@ -75,6 +75,7 @@ return [
|
||||||
'status_active' => 'Aktiv',
|
'status_active' => 'Aktiv',
|
||||||
'status_inactive' => 'Inaktiv',
|
'status_inactive' => 'Inaktiv',
|
||||||
'never' => 'Never',
|
'never' => 'Never',
|
||||||
|
'none' => 'None',
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
'header_menu_expand' => 'Header-Menü erweitern',
|
'header_menu_expand' => 'Header-Menü erweitern',
|
||||||
|
|
|
@ -75,6 +75,7 @@ return [
|
||||||
'status_active' => 'Active',
|
'status_active' => 'Active',
|
||||||
'status_inactive' => 'Inactive',
|
'status_inactive' => 'Inactive',
|
||||||
'never' => 'Never',
|
'never' => 'Never',
|
||||||
|
'none' => 'None',
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
'header_menu_expand' => 'Expand Header Menu',
|
'header_menu_expand' => 'Expand Header Menu',
|
||||||
|
|
|
@ -64,7 +64,7 @@ return [
|
||||||
'email_not_confirmed_resend_button' => 'Reenviar Correo Electrónico de confirmación',
|
'email_not_confirmed_resend_button' => 'Reenviar Correo Electrónico de confirmación',
|
||||||
|
|
||||||
// User Invite
|
// 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_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_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',
|
'user_invite_email_action' => 'Ajustar la Contraseña de la Cuenta',
|
||||||
|
|
|
@ -75,6 +75,7 @@ return [
|
||||||
'status_active' => 'Activo',
|
'status_active' => 'Activo',
|
||||||
'status_inactive' => 'Inactive',
|
'status_inactive' => 'Inactive',
|
||||||
'never' => 'Nunca',
|
'never' => 'Nunca',
|
||||||
|
'none' => 'Ninguno',
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
'header_menu_expand' => 'Expandir el Menú de la Cabecera',
|
'header_menu_expand' => 'Expandir el Menú de la Cabecera',
|
||||||
|
|
|
@ -75,6 +75,7 @@ return [
|
||||||
'status_active' => 'Activo',
|
'status_active' => 'Activo',
|
||||||
'status_inactive' => 'Inactivo',
|
'status_inactive' => 'Inactivo',
|
||||||
'never' => 'Nunca',
|
'never' => 'Nunca',
|
||||||
|
'none' => 'Ninguno',
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
'header_menu_expand' => 'Expandir el Menú de Cabecera',
|
'header_menu_expand' => 'Expandir el Menú de Cabecera',
|
||||||
|
|
|
@ -28,8 +28,8 @@ return [
|
||||||
'create_account' => 'Loo konto',
|
'create_account' => 'Loo konto',
|
||||||
'already_have_account' => 'Kasutajakonto juba olemas?',
|
'already_have_account' => 'Kasutajakonto juba olemas?',
|
||||||
'dont_have_account' => 'Sul ei ole veel kontot?',
|
'dont_have_account' => 'Sul ei ole veel kontot?',
|
||||||
'social_login' => 'Social Login',
|
'social_login' => 'Sisene läbi sotsiaalmeedia',
|
||||||
'social_registration' => 'Social Registration',
|
'social_registration' => 'Registreeru läbi sotsiaalmeedia',
|
||||||
'social_registration_text' => 'Registreeru ja logi sisse välise teenuse kaudu.',
|
'social_registration_text' => 'Registreeru ja logi sisse välise teenuse kaudu.',
|
||||||
|
|
||||||
'register_thanks' => 'Aitäh, et registreerusid!',
|
'register_thanks' => 'Aitäh, et registreerusid!',
|
||||||
|
|
|
@ -75,6 +75,7 @@ return [
|
||||||
'status_active' => 'Aktiivne',
|
'status_active' => 'Aktiivne',
|
||||||
'status_inactive' => 'Mitteaktiivne',
|
'status_inactive' => 'Mitteaktiivne',
|
||||||
'never' => 'Mitte kunagi',
|
'never' => 'Mitte kunagi',
|
||||||
|
'none' => 'None',
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
'header_menu_expand' => 'Laienda päisemenüü',
|
'header_menu_expand' => 'Laienda päisemenüü',
|
||||||
|
|
|
@ -23,7 +23,7 @@ return [
|
||||||
'meta_updated' => 'Muudetud :timeLength',
|
'meta_updated' => 'Muudetud :timeLength',
|
||||||
'meta_updated_name' => 'Muudetud :timeLength kasutaja :user poolt',
|
'meta_updated_name' => 'Muudetud :timeLength kasutaja :user poolt',
|
||||||
'meta_owned_name' => 'Kuulub kasutajale :user',
|
'meta_owned_name' => 'Kuulub kasutajale :user',
|
||||||
'entity_select' => 'Entity Select',
|
'entity_select' => 'Objekti valik',
|
||||||
'images' => 'Pildid',
|
'images' => 'Pildid',
|
||||||
'my_recent_drafts' => 'Minu hiljutised mustandid',
|
'my_recent_drafts' => 'Minu hiljutised mustandid',
|
||||||
'my_recently_viewed' => 'Minu viimati vaadatud',
|
'my_recently_viewed' => 'Minu viimati vaadatud',
|
||||||
|
|
|
@ -75,6 +75,7 @@ return [
|
||||||
'status_active' => 'فعال',
|
'status_active' => 'فعال',
|
||||||
'status_inactive' => 'غیر فعال',
|
'status_inactive' => 'غیر فعال',
|
||||||
'never' => 'هرگز',
|
'never' => 'هرگز',
|
||||||
|
'none' => 'None',
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
'header_menu_expand' => 'گسترش منو',
|
'header_menu_expand' => 'گسترش منو',
|
||||||
|
|
|
@ -75,6 +75,7 @@ return [
|
||||||
'status_active' => 'Actif',
|
'status_active' => 'Actif',
|
||||||
'status_inactive' => 'Inactif',
|
'status_inactive' => 'Inactif',
|
||||||
'never' => 'Jamais',
|
'never' => 'Jamais',
|
||||||
|
'none' => 'None',
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
'header_menu_expand' => 'Développer le menu',
|
'header_menu_expand' => 'Développer le menu',
|
||||||
|
|
|
@ -75,6 +75,7 @@ return [
|
||||||
'status_active' => 'Active',
|
'status_active' => 'Active',
|
||||||
'status_inactive' => 'Inactive',
|
'status_inactive' => 'Inactive',
|
||||||
'never' => 'Never',
|
'never' => 'Never',
|
||||||
|
'none' => 'None',
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
'header_menu_expand' => 'Expand Header Menu',
|
'header_menu_expand' => 'Expand Header Menu',
|
||||||
|
|
|
@ -75,6 +75,7 @@ return [
|
||||||
'status_active' => 'Active',
|
'status_active' => 'Active',
|
||||||
'status_inactive' => 'Inactive',
|
'status_inactive' => 'Inactive',
|
||||||
'never' => 'Never',
|
'never' => 'Never',
|
||||||
|
'none' => 'None',
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
'header_menu_expand' => 'Proširi izbornik',
|
'header_menu_expand' => 'Proširi izbornik',
|
||||||
|
|
|
@ -75,6 +75,7 @@ return [
|
||||||
'status_active' => 'Active',
|
'status_active' => 'Active',
|
||||||
'status_inactive' => 'Inactive',
|
'status_inactive' => 'Inactive',
|
||||||
'never' => 'Never',
|
'never' => 'Never',
|
||||||
|
'none' => 'None',
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
'header_menu_expand' => 'Expand Header Menu',
|
'header_menu_expand' => 'Expand Header Menu',
|
||||||
|
|
|
@ -75,6 +75,7 @@ return [
|
||||||
'status_active' => 'Active',
|
'status_active' => 'Active',
|
||||||
'status_inactive' => 'Inactive',
|
'status_inactive' => 'Inactive',
|
||||||
'never' => 'Never',
|
'never' => 'Never',
|
||||||
|
'none' => 'None',
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
'header_menu_expand' => 'Perluas Menu Tajuk',
|
'header_menu_expand' => 'Perluas Menu Tajuk',
|
||||||
|
|
|
@ -74,7 +74,8 @@ return [
|
||||||
'status' => 'Stato',
|
'status' => 'Stato',
|
||||||
'status_active' => 'Attivo',
|
'status_active' => 'Attivo',
|
||||||
'status_inactive' => 'Inattivo',
|
'status_inactive' => 'Inattivo',
|
||||||
'never' => 'Never',
|
'never' => 'Mai',
|
||||||
|
'none' => 'None',
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
'header_menu_expand' => 'Espandi Menù Intestazione',
|
'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_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_events_all' => 'Tutti gli eventi di sistema',
|
||||||
'webhooks_name' => 'Nome Webhook',
|
'webhooks_name' => 'Nome Webhook',
|
||||||
'webhooks_timeout' => 'Webhook Request Timeout (Seconds)',
|
'webhooks_timeout' => 'Timeout Richiesta Webhook (Secondi)',
|
||||||
'webhooks_endpoint' => 'Endpoint Webhook',
|
'webhooks_endpoint' => 'Endpoint Webhook',
|
||||||
'webhooks_active' => 'Webhook Attivo',
|
'webhooks_active' => 'Webhook Attivo',
|
||||||
'webhook_events_table_header' => 'Eventi',
|
'webhook_events_table_header' => 'Eventi',
|
||||||
|
@ -255,10 +255,10 @@ return [
|
||||||
'webhooks_delete_confirm' => 'Sei sicuro di voler eliminare questo webhook?',
|
'webhooks_delete_confirm' => 'Sei sicuro di voler eliminare questo webhook?',
|
||||||
'webhooks_format_example' => 'Esempio Di Formato 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_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_status' => 'Stato Webhook',
|
||||||
'webhooks_last_called' => 'Last Called:',
|
'webhooks_last_called' => 'Ultima Chiamata:',
|
||||||
'webhooks_last_errored' => 'Last Errored:',
|
'webhooks_last_errored' => 'Ultimo Errore:',
|
||||||
'webhooks_last_error_message' => 'Last Error Message:',
|
'webhooks_last_error_message' => 'Ultimo Messaggio Di Errore:',
|
||||||
|
|
||||||
|
|
||||||
//! If editing translations files directly please ignore this in all
|
//! If editing translations files directly please ignore this in all
|
||||||
|
|
|
@ -75,6 +75,7 @@ return [
|
||||||
'status_active' => '有効',
|
'status_active' => '有効',
|
||||||
'status_inactive' => '無効',
|
'status_inactive' => '無効',
|
||||||
'never' => '該当なし',
|
'never' => '該当なし',
|
||||||
|
'none' => 'None',
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
'header_menu_expand' => 'ヘッダーメニューを展開',
|
'header_menu_expand' => 'ヘッダーメニューを展開',
|
||||||
|
|
|
@ -75,6 +75,7 @@ return [
|
||||||
'status_active' => 'Active',
|
'status_active' => 'Active',
|
||||||
'status_inactive' => 'Inactive',
|
'status_inactive' => 'Inactive',
|
||||||
'never' => 'Never',
|
'never' => 'Never',
|
||||||
|
'none' => 'None',
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
'header_menu_expand' => 'Expand Header Menu',
|
'header_menu_expand' => 'Expand Header Menu',
|
||||||
|
|
|
@ -75,6 +75,7 @@ return [
|
||||||
'status_active' => 'Active',
|
'status_active' => 'Active',
|
||||||
'status_inactive' => 'Inactive',
|
'status_inactive' => 'Inactive',
|
||||||
'never' => 'Never',
|
'never' => 'Never',
|
||||||
|
'none' => 'None',
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
'header_menu_expand' => 'Plėsti antraštės meniu',
|
'header_menu_expand' => 'Plėsti antraštės meniu',
|
||||||
|
|
|
@ -75,6 +75,7 @@ return [
|
||||||
'status_active' => 'Aktīvs',
|
'status_active' => 'Aktīvs',
|
||||||
'status_inactive' => 'Neaktīvs',
|
'status_inactive' => 'Neaktīvs',
|
||||||
'never' => 'Never',
|
'never' => 'Never',
|
||||||
|
'none' => 'None',
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
'header_menu_expand' => 'Izvērst galvenes izvēlni',
|
'header_menu_expand' => 'Izvērst galvenes izvēlni',
|
||||||
|
|
|
@ -75,6 +75,7 @@ return [
|
||||||
'status_active' => 'Active',
|
'status_active' => 'Active',
|
||||||
'status_inactive' => 'Inactive',
|
'status_inactive' => 'Inactive',
|
||||||
'never' => 'Never',
|
'never' => 'Never',
|
||||||
|
'none' => 'None',
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
'header_menu_expand' => 'Utvid toppmeny',
|
'header_menu_expand' => 'Utvid toppmeny',
|
||||||
|
|
|
@ -75,6 +75,7 @@ return [
|
||||||
'status_active' => 'Active',
|
'status_active' => 'Active',
|
||||||
'status_inactive' => 'Inactive',
|
'status_inactive' => 'Inactive',
|
||||||
'never' => 'Never',
|
'never' => 'Never',
|
||||||
|
'none' => 'None',
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
'header_menu_expand' => 'Header menu uitvouwen',
|
'header_menu_expand' => 'Header menu uitvouwen',
|
||||||
|
|
|
@ -75,6 +75,7 @@ return [
|
||||||
'status_active' => 'Active',
|
'status_active' => 'Active',
|
||||||
'status_inactive' => 'Inactive',
|
'status_inactive' => 'Inactive',
|
||||||
'never' => 'Never',
|
'never' => 'Never',
|
||||||
|
'none' => 'None',
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
'header_menu_expand' => 'Rozwiń menu nagłówka',
|
'header_menu_expand' => 'Rozwiń menu nagłówka',
|
||||||
|
|
|
@ -75,6 +75,7 @@ return [
|
||||||
'status_active' => 'Ativo',
|
'status_active' => 'Ativo',
|
||||||
'status_inactive' => 'Inativo',
|
'status_inactive' => 'Inativo',
|
||||||
'never' => 'Never',
|
'never' => 'Never',
|
||||||
|
'none' => 'None',
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
'header_menu_expand' => 'Expandir Menu de Cabeçalho',
|
'header_menu_expand' => 'Expandir Menu de Cabeçalho',
|
||||||
|
|
|
@ -75,6 +75,7 @@ return [
|
||||||
'status_active' => 'Ativo',
|
'status_active' => 'Ativo',
|
||||||
'status_inactive' => 'Inativo',
|
'status_inactive' => 'Inativo',
|
||||||
'never' => 'Nunca',
|
'never' => 'Nunca',
|
||||||
|
'none' => 'None',
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
'header_menu_expand' => 'Expandir Cabeçalho do Menu',
|
'header_menu_expand' => 'Expandir Cabeçalho do Menu',
|
||||||
|
|
|
@ -75,6 +75,7 @@ return [
|
||||||
'status_active' => 'Активен',
|
'status_active' => 'Активен',
|
||||||
'status_inactive' => 'Неактивен',
|
'status_inactive' => 'Неактивен',
|
||||||
'never' => 'Никогда',
|
'never' => 'Никогда',
|
||||||
|
'none' => 'None',
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
'header_menu_expand' => 'Развернуть меню заголовка',
|
'header_menu_expand' => 'Развернуть меню заголовка',
|
||||||
|
|
|
@ -75,6 +75,7 @@ return [
|
||||||
'status_active' => 'Active',
|
'status_active' => 'Active',
|
||||||
'status_inactive' => 'Inactive',
|
'status_inactive' => 'Inactive',
|
||||||
'never' => 'Never',
|
'never' => 'Never',
|
||||||
|
'none' => 'None',
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
'header_menu_expand' => 'Rozbaliť menu v záhlaví',
|
'header_menu_expand' => 'Rozbaliť menu v záhlaví',
|
||||||
|
|
|
@ -75,6 +75,7 @@ return [
|
||||||
'status_active' => 'Active',
|
'status_active' => 'Active',
|
||||||
'status_inactive' => 'Inactive',
|
'status_inactive' => 'Inactive',
|
||||||
'never' => 'Never',
|
'never' => 'Never',
|
||||||
|
'none' => 'None',
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
'header_menu_expand' => 'Expand Header Menu',
|
'header_menu_expand' => 'Expand Header Menu',
|
||||||
|
|
|
@ -75,6 +75,7 @@ return [
|
||||||
'status_active' => 'Active',
|
'status_active' => 'Active',
|
||||||
'status_inactive' => 'Inactive',
|
'status_inactive' => 'Inactive',
|
||||||
'never' => 'Never',
|
'never' => 'Never',
|
||||||
|
'none' => 'None',
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
'header_menu_expand' => 'Expandera sidhuvudsmenyn',
|
'header_menu_expand' => 'Expandera sidhuvudsmenyn',
|
||||||
|
|
|
@ -75,6 +75,7 @@ return [
|
||||||
'status_active' => 'Active',
|
'status_active' => 'Active',
|
||||||
'status_inactive' => 'Inactive',
|
'status_inactive' => 'Inactive',
|
||||||
'never' => 'Never',
|
'never' => 'Never',
|
||||||
|
'none' => 'None',
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
'header_menu_expand' => 'Expand Header Menu',
|
'header_menu_expand' => 'Expand Header Menu',
|
||||||
|
|
|
@ -75,6 +75,7 @@ return [
|
||||||
'status_active' => 'Active',
|
'status_active' => 'Active',
|
||||||
'status_inactive' => 'Inactive',
|
'status_inactive' => 'Inactive',
|
||||||
'never' => 'Never',
|
'never' => 'Never',
|
||||||
|
'none' => 'None',
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
'header_menu_expand' => 'Розгорнути меню заголовка',
|
'header_menu_expand' => 'Розгорнути меню заголовка',
|
||||||
|
|
|
@ -75,6 +75,7 @@ return [
|
||||||
'status_active' => 'Active',
|
'status_active' => 'Active',
|
||||||
'status_inactive' => 'Inactive',
|
'status_inactive' => 'Inactive',
|
||||||
'never' => 'Never',
|
'never' => 'Never',
|
||||||
|
'none' => 'None',
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
'header_menu_expand' => 'Expand Header Menu',
|
'header_menu_expand' => 'Expand Header Menu',
|
||||||
|
|
|
@ -75,6 +75,7 @@ return [
|
||||||
'status_active' => '已激活',
|
'status_active' => '已激活',
|
||||||
'status_inactive' => '未激活',
|
'status_inactive' => '未激活',
|
||||||
'never' => '从未',
|
'never' => '从未',
|
||||||
|
'none' => 'None',
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
'header_menu_expand' => '展开标头菜单',
|
'header_menu_expand' => '展开标头菜单',
|
||||||
|
|
|
@ -75,6 +75,7 @@ return [
|
||||||
'status_active' => 'Active',
|
'status_active' => 'Active',
|
||||||
'status_inactive' => 'Inactive',
|
'status_inactive' => 'Inactive',
|
||||||
'never' => 'Never',
|
'never' => 'Never',
|
||||||
|
'none' => 'None',
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
'header_menu_expand' => '展開選單',
|
'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">
|
<!-- Styles and Fonts -->
|
||||||
<div class="card content-wrap auto-height">
|
<link rel="stylesheet" href="{{ versioned_asset('dist/styles.css') }}">
|
||||||
<h1 class="list-heading">{{ trans('errors.app_down', ['appName' => setting('app-name')]) }}</h1>
|
<link rel="stylesheet" media="print" href="{{ versioned_asset('dist/print-styles.css') }}">
|
||||||
<p>{{ trans('errors.back_soon') }}</p>
|
|
||||||
|
<!-- 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>
|
||||||
</div>
|
</div>
|
||||||
|
</body>
|
||||||
@stop
|
</html>
|
||||||
|
|
|
@ -227,10 +227,11 @@
|
||||||
|
|
||||||
<label for="setting-registration-role">{{ trans('settings.reg_default_role') }}</label>
|
<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>
|
<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)
|
@foreach(\BookStack\Auth\Role::all() as $role)
|
||||||
<option value="{{$role->id}}"
|
<option value="{{$role->id}}"
|
||||||
data-system-role-name="{{ $role->system_name ?? '' }}"
|
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 }}
|
{{ $role->display_name }}
|
||||||
</option>
|
</option>
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
<div class="setting-list">
|
<div class="setting-list">
|
||||||
@include('users.parts.form')
|
@include('users.parts.form')
|
||||||
|
@include('users.parts.language-option-row', ['value' => old('setting.language') ?? config('app.default_locale')])
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group text-right">
|
<div class="form-group text-right">
|
||||||
|
|
|
@ -35,22 +35,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid half gap-xl v-center">
|
@include('users.parts.language-option-row', ['value' => setting()->getUser($user, 'language', config('app.default_locale'))])
|
||||||
<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>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="text-right">
|
<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;
|
namespace Tests\Auth;
|
||||||
|
|
||||||
use BookStack\Auth\Access\Mfa\MfaSession;
|
use BookStack\Auth\Access\Mfa\MfaSession;
|
||||||
|
use BookStack\Auth\Role;
|
||||||
use BookStack\Auth\User;
|
use BookStack\Auth\User;
|
||||||
use BookStack\Entities\Models\Page;
|
use BookStack\Entities\Models\Page;
|
||||||
use BookStack\Notifications\ConfirmEmail;
|
use BookStack\Notifications\ConfirmEmail;
|
||||||
|
@ -43,7 +44,10 @@ class AuthTest extends TestCase
|
||||||
public function test_normal_registration()
|
public function test_normal_registration()
|
||||||
{
|
{
|
||||||
// Set settings and get user instance
|
// 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();
|
$user = User::factory()->make();
|
||||||
|
|
||||||
// Test form and ensure user is created
|
// Test form and ensure user is created
|
||||||
|
@ -57,7 +61,12 @@ class AuthTest extends TestCase
|
||||||
$resp = $this->get('/');
|
$resp = $this->get('/');
|
||||||
$resp->assertOk();
|
$resp->assertOk();
|
||||||
$resp->assertSee($user->name);
|
$resp->assertSee($user->name);
|
||||||
|
|
||||||
$this->assertDatabaseHas('users', ['name' => $user->name, 'email' => $user->email]);
|
$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()
|
public function test_empty_registration_redirects_back_with_errors()
|
||||||
|
@ -189,6 +198,14 @@ class AuthTest extends TestCase
|
||||||
$this->assertNull(auth()->user());
|
$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()
|
public function test_logout()
|
||||||
{
|
{
|
||||||
$this->asAdmin()->get('/')->assertOk();
|
$this->asAdmin()->get('/')->assertOk();
|
||||||
|
|
|
@ -318,6 +318,31 @@ class OidcTest extends TestCase
|
||||||
$this->assertCount(4, $transactions);
|
$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()
|
protected function withAutodiscovery()
|
||||||
{
|
{
|
||||||
config()->set([
|
config()->set([
|
||||||
|
|
|
@ -6,6 +6,7 @@ use BookStack\Auth\Access\UserInviteService;
|
||||||
use BookStack\Auth\User;
|
use BookStack\Auth\User;
|
||||||
use BookStack\Notifications\UserInvite;
|
use BookStack\Notifications\UserInvite;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Facades\Notification;
|
use Illuminate\Support\Facades\Notification;
|
||||||
use Illuminate\Support\Str;
|
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()
|
public function test_invite_set_password()
|
||||||
{
|
{
|
||||||
Notification::fake();
|
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);
|
$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
|
* Set an environment variable of the given name and value
|
||||||
* then check the given config key to see if it matches the given result.
|
* 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');
|
$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()
|
public function test_user_creation_is_not_performed_if_the_invitation_sending_fails()
|
||||||
{
|
{
|
||||||
/** @var User $user */
|
/** @var User $user */
|
||||||
|
|
Loading…
Reference in New Issue