mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-09-29 18:20:01 +00:00
Basic check for user's administration ID
This commit is contained in:
@@ -25,11 +25,14 @@ namespace FireflyIII\Http\Requests;
|
|||||||
|
|
||||||
use FireflyIII\Models\Account;
|
use FireflyIII\Models\Account;
|
||||||
use FireflyIII\Models\Location;
|
use FireflyIII\Models\Location;
|
||||||
|
use FireflyIII\Models\UserRole;
|
||||||
use FireflyIII\Rules\UniqueIban;
|
use FireflyIII\Rules\UniqueIban;
|
||||||
use FireflyIII\Support\Request\AppendsLocationData;
|
use FireflyIII\Support\Request\AppendsLocationData;
|
||||||
use FireflyIII\Support\Request\ChecksLogin;
|
use FireflyIII\Support\Request\ChecksLogin;
|
||||||
use FireflyIII\Support\Request\ConvertsDataTypes;
|
use FireflyIII\Support\Request\ConvertsDataTypes;
|
||||||
|
use FireflyIII\Validation\Administration\ValidatesAdministrationAccess;
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
use Illuminate\Validation\Validator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class AccountFormRequest.
|
* Class AccountFormRequest.
|
||||||
@@ -39,6 +42,7 @@ class AccountFormRequest extends FormRequest
|
|||||||
use ConvertsDataTypes;
|
use ConvertsDataTypes;
|
||||||
use AppendsLocationData;
|
use AppendsLocationData;
|
||||||
use ChecksLogin;
|
use ChecksLogin;
|
||||||
|
use ValidatesAdministrationAccess;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all data.
|
* Get all data.
|
||||||
@@ -48,6 +52,7 @@ class AccountFormRequest extends FormRequest
|
|||||||
public function getAccountData(): array
|
public function getAccountData(): array
|
||||||
{
|
{
|
||||||
$data = [
|
$data = [
|
||||||
|
'administration_id' => $this->convertInteger('administration_id'),
|
||||||
'name' => $this->convertString('name'),
|
'name' => $this->convertString('name'),
|
||||||
'active' => $this->boolean('active'),
|
'active' => $this->boolean('active'),
|
||||||
'account_type_name' => $this->convertString('objectType'),
|
'account_type_name' => $this->convertString('objectType'),
|
||||||
@@ -67,6 +72,9 @@ class AccountFormRequest extends FormRequest
|
|||||||
'include_net_worth' => '1',
|
'include_net_worth' => '1',
|
||||||
'liability_direction' => $this->convertString('liability_direction'),
|
'liability_direction' => $this->convertString('liability_direction'),
|
||||||
];
|
];
|
||||||
|
if (0 === $data['administration_id']) {
|
||||||
|
$data['administration_id'] = auth()->user()->getAdministrationId();
|
||||||
|
}
|
||||||
|
|
||||||
$data = $this->appendLocationData($data, 'location');
|
$data = $this->appendLocationData($data, 'location');
|
||||||
if (false === $this->boolean('include_net_worth')) {
|
if (false === $this->boolean('include_net_worth')) {
|
||||||
@@ -101,6 +109,7 @@ class AccountFormRequest extends FormRequest
|
|||||||
$types = implode(',', array_keys(config('firefly.subTitlesByIdentifier')));
|
$types = implode(',', array_keys(config('firefly.subTitlesByIdentifier')));
|
||||||
$ccPaymentTypes = implode(',', array_keys(config('firefly.ccTypes')));
|
$ccPaymentTypes = implode(',', array_keys(config('firefly.ccTypes')));
|
||||||
$rules = [
|
$rules = [
|
||||||
|
'administration_id' => 'min:1|max:16777216|numeric',
|
||||||
'name' => 'required|min:1|uniqueAccountForUser',
|
'name' => 'required|min:1|uniqueAccountForUser',
|
||||||
'opening_balance' => 'numeric|nullable|max:1000000000',
|
'opening_balance' => 'numeric|nullable|max:1000000000',
|
||||||
'opening_balance_date' => 'date|required_with:opening_balance|nullable',
|
'opening_balance_date' => 'date|required_with:opening_balance|nullable',
|
||||||
@@ -130,4 +139,20 @@ class AccountFormRequest extends FormRequest
|
|||||||
|
|
||||||
return $rules;
|
return $rules;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Configure the validator instance with special rules for after the basic validation rules.
|
||||||
|
*
|
||||||
|
* @param Validator $validator
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function withValidator(Validator $validator): void
|
||||||
|
{
|
||||||
|
$validator->after(
|
||||||
|
function (Validator $validator) {
|
||||||
|
// validate if the account can access this administration
|
||||||
|
$this->validateAdministration($validator, [UserRole::CHANGE_TRANSACTIONS]);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -27,6 +27,7 @@ use Carbon\Carbon;
|
|||||||
use Exception;
|
use Exception;
|
||||||
use FireflyIII\Exceptions\FireflyException;
|
use FireflyIII\Exceptions\FireflyException;
|
||||||
use FireflyIII\Models\BudgetLimit;
|
use FireflyIII\Models\BudgetLimit;
|
||||||
|
use FireflyIII\Models\GroupMembership;
|
||||||
use FireflyIII\Models\InvitedUser;
|
use FireflyIII\Models\InvitedUser;
|
||||||
use FireflyIII\Models\Role;
|
use FireflyIII\Models\Role;
|
||||||
use FireflyIII\Models\UserGroup;
|
use FireflyIII\Models\UserGroup;
|
||||||
@@ -466,4 +467,25 @@ class UserRepository implements UserRepositoryInterface
|
|||||||
$invitee = InvitedUser::where('invite_code', $code)->where('expires', '>', $now->format('Y-m-d H:i:s'))->where('redeemed', 0)->first();
|
$invitee = InvitedUser::where('invite_code', $code)->where('expires', '>', $now->format('Y-m-d H:i:s'))->where('redeemed', 0)->first();
|
||||||
return null !== $invitee;
|
return null !== $invitee;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
* @throws FireflyException
|
||||||
|
*/
|
||||||
|
public function getRolesInGroup(User $user, int $groupId): array
|
||||||
|
{
|
||||||
|
/** @var UserGroup $group */
|
||||||
|
$group = UserGroup::find($groupId);
|
||||||
|
if (null === $group) {
|
||||||
|
throw new FireflyException(sprintf('Could not find group #%d', $groupId));
|
||||||
|
}
|
||||||
|
$memberships = $group->groupMemberships()->where('user_id', $user->id)->get();
|
||||||
|
$roles = [];
|
||||||
|
/** @var GroupMembership $membership */
|
||||||
|
foreach ($memberships as $membership) {
|
||||||
|
$role = $membership->userRole;
|
||||||
|
$roles[] = $role->title;
|
||||||
|
}
|
||||||
|
return $roles;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -40,6 +40,13 @@ interface UserRepositoryInterface
|
|||||||
*/
|
*/
|
||||||
public function all(): Collection;
|
public function all(): Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param User $user
|
||||||
|
* @param int $groupId
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getRolesInGroup(User $user, int $groupId): array;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gives a user a role.
|
* Gives a user a role.
|
||||||
*
|
*
|
||||||
|
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace FireflyIII\Transformers;
|
namespace FireflyIII\Transformers;
|
||||||
|
|
||||||
|
use FireflyIII\Exceptions\FireflyException;
|
||||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
|
|
||||||
@@ -40,20 +41,22 @@ class UserTransformer extends AbstractTransformer
|
|||||||
* @param User $user
|
* @param User $user
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
|
* @throws FireflyException
|
||||||
*/
|
*/
|
||||||
public function transform(User $user): array
|
public function transform(User $user): array
|
||||||
{
|
{
|
||||||
$this->repository = $this->repository ?? app(UserRepositoryInterface::class);
|
$this->repository = $this->repository ?? app(UserRepositoryInterface::class);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'id' => (int)$user->id,
|
'id' => (int)$user->id,
|
||||||
'created_at' => $user->created_at->toAtomString(),
|
'administration_id' => (string)$user->getAdministrationId(),
|
||||||
'updated_at' => $user->updated_at->toAtomString(),
|
'created_at' => $user->created_at->toAtomString(),
|
||||||
'email' => $user->email,
|
'updated_at' => $user->updated_at->toAtomString(),
|
||||||
'blocked' => 1 === (int)$user->blocked,
|
'email' => $user->email,
|
||||||
'blocked_code' => '' === $user->blocked_code ? null : $user->blocked_code,
|
'blocked' => 1 === (int)$user->blocked,
|
||||||
'role' => $this->repository->getRoleByUser($user),
|
'blocked_code' => '' === $user->blocked_code ? null : $user->blocked_code,
|
||||||
'links' => [
|
'role' => $this->repository->getRoleByUser($user),
|
||||||
|
'links' => [
|
||||||
[
|
[
|
||||||
'rel' => 'self',
|
'rel' => 'self',
|
||||||
'uri' => '/users/'.$user->id,
|
'uri' => '/users/'.$user->id,
|
||||||
|
15
app/User.php
15
app/User.php
@@ -27,6 +27,7 @@ namespace FireflyIII;
|
|||||||
use Eloquent;
|
use Eloquent;
|
||||||
use Exception;
|
use Exception;
|
||||||
use FireflyIII\Events\RequestedNewPassword;
|
use FireflyIII\Events\RequestedNewPassword;
|
||||||
|
use FireflyIII\Exceptions\FireflyException;
|
||||||
use FireflyIII\Models\Account;
|
use FireflyIII\Models\Account;
|
||||||
use FireflyIII\Models\Attachment;
|
use FireflyIII\Models\Attachment;
|
||||||
use FireflyIII\Models\AvailableBudget;
|
use FireflyIII\Models\AvailableBudget;
|
||||||
@@ -361,6 +362,20 @@ class User extends Authenticatable
|
|||||||
return $this->hasMany(GroupMembership::class)->with(['userGroup', 'userRole']);
|
return $this->hasMany(GroupMembership::class)->with(['userGroup', 'userRole']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A safe method that returns the user's current administration ID (group ID).
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
* @throws FireflyException
|
||||||
|
*/
|
||||||
|
public function getAdministrationId(): int {
|
||||||
|
$groupId = (int)$this->user_group_id;
|
||||||
|
if(0 === $groupId) {
|
||||||
|
throw new FireflyException('User has no administration ID.');
|
||||||
|
}
|
||||||
|
return $groupId;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @codeCoverageIgnore
|
* @codeCoverageIgnore
|
||||||
* Link to object groups.
|
* Link to object groups.
|
||||||
|
@@ -0,0 +1,98 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* ValidatesAdministrationAccess.php
|
||||||
|
* Copyright (c) 2023 james@firefly-iii.org
|
||||||
|
*
|
||||||
|
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace FireflyIII\Validation\Administration;
|
||||||
|
|
||||||
|
use FireflyIII\Models\UserRole;
|
||||||
|
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||||
|
use FireflyIII\User;
|
||||||
|
use Illuminate\Auth\AuthenticationException;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Validation\Validator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trait ValidatesAdministrationAccess
|
||||||
|
*/
|
||||||
|
trait ValidatesAdministrationAccess
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param Validator $validator
|
||||||
|
* @param array $allowedRoles
|
||||||
|
* @return void
|
||||||
|
* @throws AuthenticationException
|
||||||
|
*/
|
||||||
|
protected function validateAdministration(Validator $validator, array $allowedRoles): void
|
||||||
|
{
|
||||||
|
Log::debug('Now in validateAdministration()');
|
||||||
|
if (!auth()->check()) {
|
||||||
|
Log::error('User is not authenticated.');
|
||||||
|
throw new AuthenticationException('No access to validateAdministration() method.');
|
||||||
|
}
|
||||||
|
/** @var User $user */
|
||||||
|
$user = auth()->user();
|
||||||
|
// get data from request:
|
||||||
|
$data = $validator->getData();
|
||||||
|
// check if user is part of this administration
|
||||||
|
$administrationId = (int)($data['administration_id'] ?? $user->getAdministrationId());
|
||||||
|
// safety catch:
|
||||||
|
if (0 === $administrationId) {
|
||||||
|
Log::error('validateAdministration ran into empty administration ID.');
|
||||||
|
throw new AuthenticationException('Cannot validate administration.');
|
||||||
|
}
|
||||||
|
// grab the group:
|
||||||
|
$repository = app(UserRepositoryInterface::class);
|
||||||
|
|
||||||
|
// collect the user's roles in this group:
|
||||||
|
$administrationId = 2;
|
||||||
|
$array = $repository->getRolesInGroup($user, $administrationId);
|
||||||
|
if (0 === count($array)) {
|
||||||
|
Log::error(sprintf('User #%d ("%s") has no membership in group #%d.', $user->id, $user->email, $administrationId));
|
||||||
|
$validator->errors()->add('administration', (string)trans('validation.no_access_user_group'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (in_array(UserRole::OWNER, $array, true)) {
|
||||||
|
Log::debug('User is owner of this administration.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (in_array(UserRole::FULL, $array, true)) {
|
||||||
|
Log::debug('User has full access to this administration.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$access = true;
|
||||||
|
foreach ($allowedRoles as $allowedRole) {
|
||||||
|
if (!in_array($allowedRole, $array, true)) {
|
||||||
|
$access = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (false === $access) {
|
||||||
|
Log::error(
|
||||||
|
sprintf(
|
||||||
|
'User #%d has memberships [%s] to group #%d but needs [%s].',
|
||||||
|
$user->id,
|
||||||
|
join(', ', $array),
|
||||||
|
$administrationId,
|
||||||
|
join(', ', $allowedRoles)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$validator->errors()->add('administration', (string)trans('validation.no_access_user_group'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -83,73 +83,73 @@ return [
|
|||||||
|
|
||||||
// Ignore this comment
|
// Ignore this comment
|
||||||
|
|
||||||
'between.numeric' => 'The :attribute must be between :min and :max.',
|
'between.numeric' => 'The :attribute must be between :min and :max.',
|
||||||
'between.file' => 'The :attribute must be between :min and :max kilobytes.',
|
'between.file' => 'The :attribute must be between :min and :max kilobytes.',
|
||||||
'between.string' => 'The :attribute must be between :min and :max characters.',
|
'between.string' => 'The :attribute must be between :min and :max characters.',
|
||||||
'between.array' => 'The :attribute must have between :min and :max items.',
|
'between.array' => 'The :attribute must have between :min and :max items.',
|
||||||
'boolean' => 'The :attribute field must be true or false.',
|
'boolean' => 'The :attribute field must be true or false.',
|
||||||
'confirmed' => 'The :attribute confirmation does not match.',
|
'confirmed' => 'The :attribute confirmation does not match.',
|
||||||
'date' => 'The :attribute is not a valid date.',
|
'date' => 'The :attribute is not a valid date.',
|
||||||
'date_format' => 'The :attribute does not match the format :format.',
|
'date_format' => 'The :attribute does not match the format :format.',
|
||||||
'different' => 'The :attribute and :other must be different.',
|
'different' => 'The :attribute and :other must be different.',
|
||||||
'digits' => 'The :attribute must be :digits digits.',
|
'digits' => 'The :attribute must be :digits digits.',
|
||||||
'digits_between' => 'The :attribute must be between :min and :max digits.',
|
'digits_between' => 'The :attribute must be between :min and :max digits.',
|
||||||
'email' => 'The :attribute must be a valid email address.',
|
'email' => 'The :attribute must be a valid email address.',
|
||||||
'filled' => 'The :attribute field is required.',
|
'filled' => 'The :attribute field is required.',
|
||||||
'exists' => 'The selected :attribute is invalid.',
|
'exists' => 'The selected :attribute is invalid.',
|
||||||
'image' => 'The :attribute must be an image.',
|
'image' => 'The :attribute must be an image.',
|
||||||
'in' => 'The selected :attribute is invalid.',
|
'in' => 'The selected :attribute is invalid.',
|
||||||
'integer' => 'The :attribute must be an integer.',
|
'integer' => 'The :attribute must be an integer.',
|
||||||
'ip' => 'The :attribute must be a valid IP address.',
|
'ip' => 'The :attribute must be a valid IP address.',
|
||||||
'json' => 'The :attribute must be a valid JSON string.',
|
'json' => 'The :attribute must be a valid JSON string.',
|
||||||
'max.numeric' => 'The :attribute may not be greater than :max.',
|
'max.numeric' => 'The :attribute may not be greater than :max.',
|
||||||
'max.file' => 'The :attribute may not be greater than :max kilobytes.',
|
'max.file' => 'The :attribute may not be greater than :max kilobytes.',
|
||||||
'max.string' => 'The :attribute may not be greater than :max characters.',
|
'max.string' => 'The :attribute may not be greater than :max characters.',
|
||||||
'max.array' => 'The :attribute may not have more than :max items.',
|
'max.array' => 'The :attribute may not have more than :max items.',
|
||||||
'mimes' => 'The :attribute must be a file of type: :values.',
|
'mimes' => 'The :attribute must be a file of type: :values.',
|
||||||
'min.numeric' => 'The :attribute must be at least :min.',
|
'min.numeric' => 'The :attribute must be at least :min.',
|
||||||
'lte.numeric' => 'The :attribute must be less than or equal :value.',
|
'lte.numeric' => 'The :attribute must be less than or equal :value.',
|
||||||
'min.file' => 'The :attribute must be at least :min kilobytes.',
|
'min.file' => 'The :attribute must be at least :min kilobytes.',
|
||||||
'min.string' => 'The :attribute must be at least :min characters.',
|
'min.string' => 'The :attribute must be at least :min characters.',
|
||||||
'min.array' => 'The :attribute must have at least :min items.',
|
'min.array' => 'The :attribute must have at least :min items.',
|
||||||
'not_in' => 'The selected :attribute is invalid.',
|
'not_in' => 'The selected :attribute is invalid.',
|
||||||
'numeric' => 'The :attribute must be a number.',
|
'numeric' => 'The :attribute must be a number.',
|
||||||
'numeric_native' => 'The native amount must be a number.',
|
'numeric_native' => 'The native amount must be a number.',
|
||||||
'numeric_destination' => 'The destination amount must be a number.',
|
'numeric_destination' => 'The destination amount must be a number.',
|
||||||
'numeric_source' => 'The source amount must be a number.',
|
'numeric_source' => 'The source amount must be a number.',
|
||||||
'regex' => 'The :attribute format is invalid.',
|
'regex' => 'The :attribute format is invalid.',
|
||||||
'required' => 'The :attribute field is required.',
|
'required' => 'The :attribute field is required.',
|
||||||
'required_if' => 'The :attribute field is required when :other is :value.',
|
'required_if' => 'The :attribute field is required when :other is :value.',
|
||||||
'required_unless' => 'The :attribute field is required unless :other is in :values.',
|
'required_unless' => 'The :attribute field is required unless :other is in :values.',
|
||||||
'required_with' => 'The :attribute field is required when :values is present.',
|
'required_with' => 'The :attribute field is required when :values is present.',
|
||||||
'required_with_all' => 'The :attribute field is required when :values is present.',
|
'required_with_all' => 'The :attribute field is required when :values is present.',
|
||||||
'required_without' => 'The :attribute field is required when :values is not present.',
|
'required_without' => 'The :attribute field is required when :values is not present.',
|
||||||
'required_without_all' => 'The :attribute field is required when none of :values are present.',
|
'required_without_all' => 'The :attribute field is required when none of :values are present.',
|
||||||
'same' => 'The :attribute and :other must match.',
|
'same' => 'The :attribute and :other must match.',
|
||||||
'size.numeric' => 'The :attribute must be :size.',
|
'size.numeric' => 'The :attribute must be :size.',
|
||||||
'amount_min_over_max' => 'The minimum amount cannot be larger than the maximum amount.',
|
'amount_min_over_max' => 'The minimum amount cannot be larger than the maximum amount.',
|
||||||
'size.file' => 'The :attribute must be :size kilobytes.',
|
'size.file' => 'The :attribute must be :size kilobytes.',
|
||||||
'size.string' => 'The :attribute must be :size characters.',
|
'size.string' => 'The :attribute must be :size characters.',
|
||||||
'size.array' => 'The :attribute must contain :size items.',
|
'size.array' => 'The :attribute must contain :size items.',
|
||||||
'unique' => 'The :attribute has already been taken.',
|
'unique' => 'The :attribute has already been taken.',
|
||||||
'string' => 'The :attribute must be a string.',
|
'string' => 'The :attribute must be a string.',
|
||||||
'url' => 'The :attribute format is invalid.',
|
'url' => 'The :attribute format is invalid.',
|
||||||
'timezone' => 'The :attribute must be a valid zone.',
|
'timezone' => 'The :attribute must be a valid zone.',
|
||||||
'2fa_code' => 'The :attribute field is invalid.',
|
'2fa_code' => 'The :attribute field is invalid.',
|
||||||
'dimensions' => 'The :attribute has invalid image dimensions.',
|
'dimensions' => 'The :attribute has invalid image dimensions.',
|
||||||
'distinct' => 'The :attribute field has a duplicate value.',
|
'distinct' => 'The :attribute field has a duplicate value.',
|
||||||
'file' => 'The :attribute must be a file.',
|
'file' => 'The :attribute must be a file.',
|
||||||
'in_array' => 'The :attribute field does not exist in :other.',
|
'in_array' => 'The :attribute field does not exist in :other.',
|
||||||
'present' => 'The :attribute field must be present.',
|
'present' => 'The :attribute field must be present.',
|
||||||
'amount_zero' => 'The total amount cannot be zero.',
|
'amount_zero' => 'The total amount cannot be zero.',
|
||||||
'current_target_amount' => 'The current amount must be less than the target amount.',
|
'current_target_amount' => 'The current amount must be less than the target amount.',
|
||||||
'unique_piggy_bank_for_user' => 'The name of the piggy bank must be unique.',
|
'unique_piggy_bank_for_user' => 'The name of the piggy bank must be unique.',
|
||||||
'unique_object_group' => 'The group name must be unique',
|
'unique_object_group' => 'The group name must be unique',
|
||||||
'starts_with' => 'The value must start with :values.',
|
'starts_with' => 'The value must start with :values.',
|
||||||
'unique_webhook' => 'You already have a webhook with this combination of URL, trigger, response and delivery.',
|
'unique_webhook' => 'You already have a webhook with this combination of URL, trigger, response and delivery.',
|
||||||
'unique_existing_webhook' => 'You already have another webhook with this combination of URL, trigger, response and delivery.',
|
'unique_existing_webhook' => 'You already have another webhook with this combination of URL, trigger, response and delivery.',
|
||||||
'same_account_type' => 'Both accounts must be of the same account type',
|
'same_account_type' => 'Both accounts must be of the same account type',
|
||||||
'same_account_currency' => 'Both accounts must have the same currency setting',
|
'same_account_currency' => 'Both accounts must have the same currency setting',
|
||||||
|
|
||||||
// Ignore this comment
|
// Ignore this comment
|
||||||
|
|
||||||
@@ -240,6 +240,9 @@ return [
|
|||||||
'amount_required_for_auto_budget' => 'The amount is required.',
|
'amount_required_for_auto_budget' => 'The amount is required.',
|
||||||
'auto_budget_amount_positive' => 'The amount must be more than zero.',
|
'auto_budget_amount_positive' => 'The amount must be more than zero.',
|
||||||
'auto_budget_period_mandatory' => 'The auto budget period is a mandatory field.',
|
'auto_budget_period_mandatory' => 'The auto budget period is a mandatory field.',
|
||||||
|
|
||||||
|
// no access to administration:
|
||||||
|
'no_access_user_group' => 'You do not have the correct access rights for this administration.',
|
||||||
];
|
];
|
||||||
|
|
||||||
// Ignore this comment
|
// Ignore this comment
|
||||||
|
Reference in New Issue
Block a user