Expand API with better user group management.

This commit is contained in:
James Cole
2023-09-20 06:17:56 +02:00
parent 549f3c038a
commit 1c41b6753d
31 changed files with 853 additions and 146 deletions

View File

@@ -32,6 +32,10 @@ use Illuminate\Http\JsonResponse;
class StoreController extends Controller class StoreController extends Controller
{ {
/** /**
* TODO this method is practically the same as the V1 method and borrows as much code as possible.
* TODO still it duplicates a lot.
* TODO the v1 endpoints will never support separate administrations, this is an important distinction.
*
* @return JsonResponse * @return JsonResponse
*/ */
public function post(): JsonResponse public function post(): JsonResponse

View File

@@ -2,7 +2,7 @@
/* /*
* NetWorthController.php * NetWorthController.php
* Copyright (c) 2022 james@firefly-iii.org * Copyright (c) 2023 james@firefly-iii.org
* *
* This file is part of Firefly III (https://github.com/firefly-iii). * This file is part of Firefly III (https://github.com/firefly-iii).
* *
@@ -22,8 +22,9 @@
declare(strict_types=1); declare(strict_types=1);
namespace FireflyIII\Api\V2\Controllers; namespace FireflyIII\Api\V2\Controllers\Summary;
use FireflyIII\Api\V2\Controllers\Controller;
use FireflyIII\Api\V2\Request\Generic\SingleDateRequest; use FireflyIII\Api\V2\Request\Generic\SingleDateRequest;
use FireflyIII\Helpers\Report\NetWorthInterface; use FireflyIII\Helpers\Report\NetWorthInterface;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;

View File

@@ -2,7 +2,7 @@
/* /*
* VersionUpdateController.php * VersionUpdateController.php
* Copyright (c) 2022 james@firefly-iii.org * Copyright (c) 2023 james@firefly-iii.org
* *
* This file is part of Firefly III (https://github.com/firefly-iii). * This file is part of Firefly III (https://github.com/firefly-iii).
* *
@@ -22,7 +22,9 @@
declare(strict_types=1); declare(strict_types=1);
namespace FireflyIII\Api\V2\Controllers; namespace FireflyIII\Api\V2\Controllers\System;
use FireflyIII\Api\V2\Controllers\Controller;
/** /**
* Class VersionUpdateController * Class VersionUpdateController

View File

@@ -2,7 +2,7 @@
/* /*
* AccountController.php * AccountController.php
* Copyright (c) 2022 james@firefly-iii.org * Copyright (c) 2023 james@firefly-iii.org
* *
* This file is part of Firefly III (https://github.com/firefly-iii). * This file is part of Firefly III (https://github.com/firefly-iii).
* *

View File

@@ -1,6 +1,4 @@
<?php <?php
declare(strict_types=1);
/* /*
* TransactionController.php * TransactionController.php
* Copyright (c) 2023 james@firefly-iii.org * Copyright (c) 2023 james@firefly-iii.org
@@ -21,6 +19,8 @@ declare(strict_types=1);
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
declare(strict_types=1);
namespace FireflyIII\Api\V2\Controllers\Transaction\List; namespace FireflyIII\Api\V2\Controllers\Transaction\List;
use FireflyIII\Api\V2\Controllers\Controller; use FireflyIII\Api\V2\Controllers\Controller;

View File

@@ -2,7 +2,7 @@
/* /*
* BillController.php * BillController.php
* Copyright (c) 2022 james@firefly-iii.org * Copyright (c) 2023 james@firefly-iii.org
* *
* This file is part of Firefly III (https://github.com/firefly-iii). * This file is part of Firefly III (https://github.com/firefly-iii).
* *

View File

@@ -0,0 +1,32 @@
<?php
/*
* DestroyController.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\Api\V2\Controllers\UserGroup;
use FireflyIII\Api\V2\Controllers\Controller;
/**
* Class DestroyController
*/
class DestroyController extends Controller
{
}

View File

@@ -0,0 +1,97 @@
<?php
/*
* ShowController.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\Api\V2\Controllers\UserGroup;
use FireflyIII\Api\V2\Controllers\Controller;
use FireflyIII\Models\UserGroup;
use FireflyIII\Repositories\UserGroup\UserGroupRepositoryInterface;
use FireflyIII\Transformers\V2\UserGroupTransformer;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
/**
* Class ShowController
*/
class ShowController extends Controller
{
private UserGroupRepositoryInterface $repository;
/**
*
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
$this->repository = app(UserGroupRepositoryInterface::class);
return $next($request);
}
);
}
/**
* @param Request $request
*
* @return JsonResponse
*/
public function index(Request $request): JsonResponse
{
$collection = new Collection();
// if the user has the system owner role, get all. Otherwise, get only the users' groups.
if (!auth()->user()->hasRole('owner')) {
$collection = $this->repository->get();
}
if (auth()->user()->hasRole('owner')) {
$collection = $this->repository->getAll();
}
$count = $collection->count();
$userGroups = $collection->slice(($this->parameters->get('page') - 1) * $this->pageSize, $this->pageSize);
$paginator = new LengthAwarePaginator($userGroups, $count, $this->pageSize, $this->parameters->get('page'));
$transformer = new UserGroupTransformer();
$transformer->setParameters($this->parameters); // give params to transformer
return response()
->json($this->jsonApiList('user-groups', $paginator, $transformer))
->header('Content-Type', self::CONTENT_TYPE);
}
/**
* @param Request $request
* @param UserGroup $userGroup
*
* @return JsonResponse
*/
public function show(Request $request, UserGroup $userGroup): JsonResponse
{
$transformer = new UserGroupTransformer();
$transformer->setParameters($this->parameters);
return response()
->api($this->jsonApiObject('user-groups', $userGroup, $transformer))
->header('Content-Type', self::CONTENT_TYPE);
}
}

View File

@@ -0,0 +1,67 @@
<?php
/*
* StoreController.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\Api\V2\Controllers\UserGroup;
use FireflyIII\Api\V2\Controllers\Controller;
use FireflyIII\Api\V2\Request\UserGroup\StoreRequest;
use FireflyIII\Repositories\UserGroup\UserGroupRepositoryInterface;
use FireflyIII\Transformers\V2\UserGroupTransformer;
use Illuminate\Http\JsonResponse;
/**
* Class StoreController
*/
class StoreController extends Controller
{
private UserGroupRepositoryInterface $repository;
/**
*
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
$this->repository = app(UserGroupRepositoryInterface::class);
return $next($request);
}
);
}
/**
* @return JsonResponse
*/
public function store(StoreRequest $request): JsonResponse
{
$all = $request->getAll();
$userGroup = $this->repository->store($all);
$transformer = new UserGroupTransformer();
$transformer->setParameters($this->parameters);
return response()
->api($this->jsonApiObject('user-groups', $userGroup, $transformer))
->header('Content-Type', self::CONTENT_TYPE);
}
}

View File

@@ -0,0 +1,31 @@
<?php
/*
* UpdateController.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\Api\V2\Controllers\UserGroup;
use FireflyIII\Api\V2\Controllers\Controller;
class UpdateController extends Controller
{
// basic edit van group
// add user, add rights, remove user, remove rights.
}

View File

@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V2\Request\Autocomplete; namespace FireflyIII\Api\V2\Request\Autocomplete;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\AccountType; use FireflyIII\Models\AccountType;
use FireflyIII\Models\UserRole; use FireflyIII\Models\UserRole;
@@ -92,7 +93,7 @@ class AutocompleteRequest extends FormRequest
$validator->after( $validator->after(
function (Validator $validator) { function (Validator $validator) {
// validate if the account can access this administration // validate if the account can access this administration
$this->validateAdministration($validator, [UserRole::CHANGE_TRANSACTIONS]); $this->validateAdministration($validator, [UserRoleEnum::MANAGE_TRANSACTIONS]);
} }
); );
} }

View File

@@ -0,0 +1,52 @@
<?php
/*
* StoreRequest.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\Api\V2\Request\UserGroup;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Foundation\Http\FormRequest;
class StoreRequest extends FormRequest
{
use ChecksLogin;
use ConvertsDataTypes;
/**
* @return array
*/
public function getAll(): array
{
return [
'title' => $this->convertString('title'),
];
}
/**
* @return array
*/
public function rules(): array
{
return [
'title' => 'unique:user_groups,title|required|min:2|max:255',
];
}
}

View File

@@ -25,6 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Console\Commands\Integrity; namespace FireflyIII\Console\Commands\Integrity;
use FireflyIII\Console\Commands\ShowsFriendlyMessages; use FireflyIII\Console\Commands\ShowsFriendlyMessages;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\GroupMembership; use FireflyIII\Models\GroupMembership;
use FireflyIII\Models\UserGroup; use FireflyIII\Models\UserGroup;
@@ -85,7 +86,7 @@ class CreateGroupMemberships extends Command
$userGroup = UserGroup::create(['title' => $user->email]); $userGroup = UserGroup::create(['title' => $user->email]);
} }
$userRole = UserRole::where('title', UserRole::OWNER)->first(); $userRole = UserRole::where('title', UserRoleEnum::OWNER->value)->first();
if (null === $userRole) { if (null === $userRole) {
throw new FireflyException('Firefly III could not find a user role. Please make sure all migrations have run.'); throw new FireflyException('Firefly III could not find a user role. Please make sure all migrations have run.');

View File

@@ -29,12 +29,34 @@ namespace FireflyIII\Enums;
*/ */
enum UserRoleEnum: string enum UserRoleEnum: string
{ {
case CHANGE_PIGGY_BANKS = 'change_piggies'; // most basic rights, cannot see other members, can see everything else.
case CHANGE_REPETITIONS = 'change_reps';
case CHANGE_RULES = 'change_rules';
case CHANGE_TRANSACTIONS = 'change_tx';
case FULL = 'full';
case OWNER = 'owner';
case READ_ONLY = 'ro'; case READ_ONLY = 'ro';
// required to even USE the group properly (in this order)
case MANAGE_TRANSACTIONS = 'mng_trx';
// required to edit, add or change categories/tags/object-groups
case MANAGE_META = 'mng_meta';
// manage other financial objects:
case MANAGE_BUDGETS = 'mng_budgets';
case MANAGE_PIGGY_BANKS = 'mng_piggies';
case MANAGE_REPETITIONS = 'mng_reps';
case MANAGE_SUBSCRIPTIONS = 'mng_subscriptions';
case MANAGE_RULES = 'mng_rules';
case MANAGE_RECURRING = 'mng_recurring';
case MANAGE_WEBHOOKS = 'mng_webhooks';
case MANAGE_CURRENCIES = 'mng_currencies';
// view and generate reports
case VIEW_REPORTS = 'view_reports'; case VIEW_REPORTS = 'view_reports';
// view memberships. needs FULL to manage them.
case VIEW_MEMBERSHIPS = 'view_memberships';
// everything the creator can, except remove/change original creator and delete group
case FULL = 'full';
// reserved for original creator
case OWNER = 'owner';
} }

View File

@@ -0,0 +1,62 @@
<?php
/*
* UserGroupFactory.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\Factory;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\GroupMembership;
use FireflyIII\Models\UserGroup;
use FireflyIII\Models\UserRole;
/**
* Class UserGroupFactory
*/
class UserGroupFactory
{
/**
* @param array $data
*
* @return UserGroup
* @throws FireflyException
*/
public function create(array $data): UserGroup
{
$userGroup = new UserGroup();
$userGroup->title = $data['title'];
$userGroup->save();
// grab the OWNER role:
$role = UserRole::whereTitle(UserRoleEnum::OWNER->value)->first();
if (null === $role) {
throw new FireflyException('Role "owner" does not exist.');
}
// make user member:
$groupMembership = new GroupMembership();
$groupMembership->user_group_id = $userGroup->id;
$groupMembership->user_id = $data['user']->id;
$groupMembership->user_role_id = $role->id;
$groupMembership->save();
return $userGroup;
}
}

View File

@@ -48,18 +48,23 @@ class AutomationHandler
public function reportJournals(RequestedReportOnJournals $event): void public function reportJournals(RequestedReportOnJournals $event): void
{ {
Log::debug('In reportJournals.'); Log::debug('In reportJournals.');
$sendReport = config('firefly.send_report_journals');
if (false === $sendReport) {
return;
}
/** @var UserRepositoryInterface $repository */ /** @var UserRepositoryInterface $repository */
$repository = app(UserRepositoryInterface::class); $repository = app(UserRepositoryInterface::class);
$user = $repository->find($event->userId); $user = $repository->find($event->userId);
if (null === $user || 0 === $event->groups->count()) { $sendReport = app('preferences')->getForUser($user, 'notification_transaction_creation', false)->data;
if (false === $sendReport) {
Log::debug('Not sending report, because config says so.');
return; return;
} }
if (null === $user || 0 === $event->groups->count()) {
Log::debug('No transaction groups in event, nothing to email about.');
return;
}
Log::debug('Continue with message!');
// transform groups into array: // transform groups into array:
/** @var TransactionGroupTransformer $transformer */ /** @var TransactionGroupTransformer $transformer */
$transformer = app(TransactionGroupTransformer::class); $transformer = app(TransactionGroupTransformer::class);
@@ -83,5 +88,6 @@ class AutomationHandler
Log::error($e->getMessage()); Log::error($e->getMessage());
Log::error($e->getTraceAsString()); Log::error($e->getTraceAsString());
} }
Log::debug('If there is no error above this line, message was sent.');
} }
} }

View File

@@ -26,6 +26,7 @@ namespace FireflyIII\Handlers\Events;
use Carbon\Carbon; use Carbon\Carbon;
use Database\Seeders\ExchangeRateSeeder; use Database\Seeders\ExchangeRateSeeder;
use Exception; use Exception;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Events\ActuallyLoggedIn; use FireflyIII\Events\ActuallyLoggedIn;
use FireflyIII\Events\Admin\InvitationCreated; use FireflyIII\Events\Admin\InvitationCreated;
use FireflyIII\Events\DetectedNewIPAddress; use FireflyIII\Events\DetectedNewIPAddress;
@@ -144,7 +145,7 @@ class UserEventHandler
} }
} }
/** @var UserRole|null $role */ /** @var UserRole|null $role */
$role = UserRole::where('title', UserRole::OWNER)->first(); $role = UserRole::where('title', UserRoleEnum::OWNER->value)->first();
if (null === $role) { if (null === $role) {
throw new FireflyException('The user role is unexpectedly empty. Did you run all migrations?'); throw new FireflyException('The user role is unexpectedly empty. Did you run all migrations?');
} }

View File

@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Http\Requests; namespace FireflyIII\Http\Requests;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\Location; use FireflyIII\Models\Location;
use FireflyIII\Models\UserRole; use FireflyIII\Models\UserRole;
@@ -152,7 +153,7 @@ class AccountFormRequest extends FormRequest
$validator->after( $validator->after(
function (Validator $validator) { function (Validator $validator) {
// validate if the account can access this administration // validate if the account can access this administration
$this->validateAdministration($validator, [UserRole::CHANGE_TRANSACTIONS]); $this->validateAdministration($validator, [UserRoleEnum::MANAGE_TRANSACTIONS->value]);
} }
); );
} }

View File

@@ -460,16 +460,18 @@ class CreateRecurringTransactions implements ShouldQueue
$total = $this->repository->totalTransactions($recurrence, $repetition); $total = $this->repository->totalTransactions($recurrence, $repetition);
$count = $this->repository->getJournalCount($recurrence) + 1; $count = $this->repository->getJournalCount($recurrence) + 1;
$transactions = $recurrence->recurrenceTransactions()->get(); $transactions = $recurrence->recurrenceTransactions()->get();
/** @var RecurrenceTransaction $first */
$first = $transactions->first();
$return = []; $return = [];
/** @var RecurrenceTransaction $transaction */ /** @var RecurrenceTransaction $transaction */
foreach ($transactions as $index => $transaction) { foreach ($transactions as $index => $transaction) {
$single = [ $single = [
'type' => strtolower($recurrence->transactionType->type), 'type' => null === $first->transactionType ? strtolower($recurrence->transactionType->type) : strtolower($first->transactionType->type),
'date' => $date, 'date' => $date,
'user' => $recurrence->user_id, 'user' => $recurrence->user_id,
'currency_id' => (int)$transaction->transaction_currency_id, 'currency_id' => (int)$transaction->transaction_currency_id,
'currency_code' => null, 'currency_code' => null,
'description' => $transactions->first()->description, 'description' => $first->description,
'amount' => $transaction->amount, 'amount' => $transaction->amount,
'budget_id' => $this->repository->getBudget($transaction), 'budget_id' => $this->repository->getBudget($transaction),
'budget_name' => null, 'budget_name' => null,

View File

@@ -25,12 +25,15 @@ declare(strict_types=1);
namespace FireflyIII\Models; namespace FireflyIII\Models;
use Eloquent; use Eloquent;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\User;
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasManyThrough; use Illuminate\Database\Eloquent\Relations\HasManyThrough;
use Illuminate\Support\Carbon; use Illuminate\Support\Carbon;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/** /**
* Class UserGroup * Class UserGroup
@@ -52,15 +55,15 @@ use Illuminate\Support\Carbon;
* @method static Builder|UserGroup whereUpdatedAt($value) * @method static Builder|UserGroup whereUpdatedAt($value)
* @property-read Collection<int, Account> $accounts * @property-read Collection<int, Account> $accounts
* @property-read int|null $accounts_count * @property-read int|null $accounts_count
* @property-read Collection<int, \FireflyIII\Models\AvailableBudget> $availableBudgets * @property-read Collection<int, AvailableBudget> $availableBudgets
* @property-read int|null $available_budgets_count * @property-read int|null $available_budgets_count
* @property-read Collection<int, \FireflyIII\Models\Bill> $bills * @property-read Collection<int, Bill> $bills
* @property-read int|null $bills_count * @property-read int|null $bills_count
* @property-read Collection<int, \FireflyIII\Models\Budget> $budgets * @property-read Collection<int, Budget> $budgets
* @property-read int|null $budgets_count * @property-read int|null $budgets_count
* @property-read Collection<int, \FireflyIII\Models\PiggyBank> $piggyBanks * @property-read Collection<int, PiggyBank> $piggyBanks
* @property-read int|null $piggy_banks_count * @property-read int|null $piggy_banks_count
* @property-read Collection<int, \FireflyIII\Models\TransactionJournal> $transactionJournals * @property-read Collection<int, TransactionJournal> $transactionJournals
* @property-read int|null $transaction_journals_count * @property-read int|null $transaction_journals_count
* @mixin Eloquent * @mixin Eloquent
*/ */
@@ -68,6 +71,34 @@ class UserGroup extends Model
{ {
protected $fillable = ['title']; protected $fillable = ['title'];
/**
* Route binder. Converts the key in the URL to the specified object (or throw 404).
*
* @param string $value
*
* @return UserGroup
* @throws NotFoundHttpException
*/
public static function routeBinder(string $value): UserGroup
{
if (auth()->check()) {
$userGroupId = (int)$value;
/** @var User $user */
$user = auth()->user();
/** @var UserGroup $userGroup */
$userGroup = UserGroup::find($userGroupId);
if (null === $userGroup) {
throw new NotFoundHttpException();
}
// need at least ready only to be aware of the user group's existence,
// but owner/full role (in the group) or global owner role may overrule this.
if ($user->hasRoleInGroup($userGroup, UserRoleEnum::READ_ONLY, true, true)) {
return $userGroup;
}
}
throw new NotFoundHttpException();
}
/** /**
* Link to accounts. * Link to accounts.
* *

View File

@@ -53,18 +53,6 @@ use Illuminate\Support\Carbon;
*/ */
class UserRole extends Model class UserRole extends Model
{ {
public const CHANGE_PIGGY_BANKS = 'change_piggies';
public const CHANGE_REPETITIONS = 'change_reps';
public const CHANGE_RULES = 'change_rules';
public const CHANGE_TRANSACTIONS = 'change_tx';
public const FULL = 'full';
public const MANAGE_CURRENCIES = 'manage_currencies';
public const MANAGE_WEBHOOKS = 'manage_webhooks';
public const OWNER = 'owner';
public const READ_ONLY = 'ro';
public const VIEW_REPORTS = 'view_reports';
protected $fillable = ['title']; protected $fillable = ['title'];
/** /**

View File

@@ -47,6 +47,8 @@ use FireflyIII\Repositories\TransactionType\TransactionTypeRepository;
use FireflyIII\Repositories\TransactionType\TransactionTypeRepositoryInterface; use FireflyIII\Repositories\TransactionType\TransactionTypeRepositoryInterface;
use FireflyIII\Repositories\User\UserRepository; use FireflyIII\Repositories\User\UserRepository;
use FireflyIII\Repositories\User\UserRepositoryInterface; use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Repositories\UserGroup\UserGroupRepository;
use FireflyIII\Repositories\UserGroup\UserGroupRepositoryInterface;
use FireflyIII\Repositories\Webhook\WebhookRepository; use FireflyIII\Repositories\Webhook\WebhookRepository;
use FireflyIII\Repositories\Webhook\WebhookRepositoryInterface; use FireflyIII\Repositories\Webhook\WebhookRepositoryInterface;
use FireflyIII\Services\FireflyIIIOrg\Update\UpdateRequest; use FireflyIII\Services\FireflyIIIOrg\Update\UpdateRequest;
@@ -212,6 +214,19 @@ class FireflyServiceProvider extends ServiceProvider
} }
); );
$this->app->bind(
UserGroupRepositoryInterface::class,
static function (Application $app) {
/** @var UserGroupRepository $repository */
$repository = app(UserGroupRepository::class);
if ($app->auth->check()) { // @phpstan-ignore-line (phpstan does not understand the reference to auth)
$repository->setUser(auth()->user());
}
return $repository;
}
);
// more generators: // more generators:
$this->app->bind(PopupReportInterface::class, PopupReport::class); $this->app->bind(PopupReportInterface::class, PopupReport::class);
$this->app->bind(ReportHelperInterface::class, ReportHelper::class); $this->app->bind(ReportHelperInterface::class, ReportHelper::class);

View File

@@ -0,0 +1,91 @@
<?php
/*
* UserGroupRepository.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\Repositories\UserGroup;
use FireflyIII\Factory\UserGroupFactory;
use FireflyIII\Models\GroupMembership;
use FireflyIII\Models\UserGroup;
use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Collection;
/**
* Class UserGroupRepository
*/
class UserGroupRepository implements UserGroupRepositoryInterface
{
private User $user;
/**
* Returns all groups the user is member in.
*
* @inheritDoc
*/
public function get(): Collection
{
$collection = new Collection();
$memberships = $this->user->groupMemberships()->get();
/** @var GroupMembership $membership */
foreach ($memberships as $membership) {
/** @var UserGroup $group */
$group = $membership->userGroup()->first();
if (null !== $group) {
$collection->push($group);
}
}
return $collection;
}
/**
* Returns all groups.
*
* @inheritDoc
*/
public function getAll(): Collection
{
return UserGroup::all();
}
/**
* @inheritDoc
*/
public function setUser(Authenticatable | User | null $user): void
{
app('log')->debug(sprintf('Now in %s', __METHOD__));
if (null !== $user) {
$this->user = $user;
}
}
/**
* @param array $data
*
* @return UserGroup
*/
public function store(array $data): UserGroup
{
$data['user'] = $this->user;
/** @var UserGroupFactory $factory */
$factory = app(UserGroupFactory::class);
return $factory->create($data);
}
}

View File

@@ -0,0 +1,49 @@
<?php
/*
* UserGroupRepositoryInterface.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\Repositories\UserGroup;
use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Collection;
/**
* Interface UserGroupRepositoryInterface
*/
interface UserGroupRepositoryInterface
{
/**
* @return Collection
*/
public function get(): Collection;
/**
* @return Collection
*/
public function getAll(): Collection;
/**
* @param User|Authenticatable|null $user
*
* @return void
*/
public function setUser(User | Authenticatable | null $user): void;
}

View File

@@ -0,0 +1,93 @@
<?php
/*
* UserGroupTransformer.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\Transformers\V2;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\GroupMembership;
use FireflyIII\Models\UserGroup;
use FireflyIII\User;
use Illuminate\Support\Collection;
/**
* Class UserGroupTransformer
*/
class UserGroupTransformer extends AbstractTransformer
{
private array $memberships;
/**
*
*/
public function __construct()
{
$this->memberships = [];
}
/**
* @inheritDoc
*/
public function collectMetaData(Collection $objects): void
{
if (auth()->check()) {
// collect memberships so they can be listed in the group.
/** @var User $user */
$user = auth()->user();
/** @var UserGroup $userGroup */
foreach ($objects as $userGroup) {
$userGroupId = (int)$userGroup->id;
$access = $user->hasRoleInGroup($userGroup, UserRoleEnum::VIEW_MEMBERSHIPS, true, true);
if ($access) {
$groupMemberships = $userGroup->groupMemberships()->get();
/** @var GroupMembership $groupMembership */
foreach ($groupMemberships as $groupMembership) {
$this->memberships[$userGroupId][] = [
'user_id' => (string)$groupMembership->user_id,
'user_email' => $groupMembership->user->email,
'role' => $groupMembership->userRole->title,
];
}
}
}
}
}
/**
* Transform the user group.
*
* @param UserGroup $userGroup
*
* @return array
*/
public function transform(UserGroup $userGroup): array
{
$return = [
'id' => (int)$userGroup->id,
'created_at' => $userGroup->created_at->toAtomString(),
'updated_at' => $userGroup->updated_at->toAtomString(),
'title' => $userGroup->title,
'members' => $this->memberships[(int)$userGroup->id] ?? [],
];
// if the user has a specific role in this group, then collect the memberships.
return $return;
}
}

View File

@@ -26,6 +26,7 @@ namespace FireflyIII;
use Eloquent; use Eloquent;
use Exception; use Exception;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Events\RequestedNewPassword; use FireflyIII\Events\RequestedNewPassword;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
@@ -48,6 +49,7 @@ use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionGroup; use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\UserGroup; use FireflyIII\Models\UserGroup;
use FireflyIII\Models\UserRole;
use FireflyIII\Models\Webhook; use FireflyIII\Models\Webhook;
use FireflyIII\Notifications\Admin\TestNotification; use FireflyIII\Notifications\Admin\TestNotification;
use FireflyIII\Notifications\Admin\UserInvitation; use FireflyIII\Notifications\Admin\UserInvitation;
@@ -365,6 +367,91 @@ class User extends Authenticatable
return 'objectguid'; return 'objectguid';
} }
/**
* Does the user have role X in group Y?
*
* If $allowOverride is set to true, then the roles FULL or OWNER will also be checked,
* which means that in most cases the user DOES have access, regardless of the original role submitted in $role.
*
* @param UserGroup $userGroup
* @param UserRoleEnum $role
* @param bool $allowOverride
*
* @return bool
*/
public function hasRoleInGroup(UserGroup $userGroup, UserRoleEnum $role, bool $allowGroupOverride = false, bool $allowSystemOverride = false): bool
{
if ($allowSystemOverride && $this->hasRole('owner')) {
app('log')->debug(sprintf('hasRoleInGroup: user "#%d %s" is system owner and allowSystemOverride = true, return true', $this->id, $this->email));
return true;
}
$roles = [$role->value];
if ($allowGroupOverride) {
$roles[] = UserRoleEnum::OWNER->value;
$roles[] = UserRoleEnum::FULL->value;
}
app('log')->debug(sprintf('in hasRoleInGroup(%s)', join(', ', $roles)));
/** @var Collection $dbRoles */
$dbRoles = UserRole::whereIn('title', $roles)->get();
if (0 === $dbRoles->count()) {
app('log')->error(sprintf('Could not find role(s): %s. Probably migration mishap.', join(', ', $roles)));
return false;
}
$dbRolesIds = $dbRoles->pluck('id')->toArray();
$dbRolesTitles = $dbRoles->pluck('title')->toArray();
/** @var Collection $groupMemberships */
$groupMemberships = $this->groupMemberships()
->whereIn('user_role_id', $dbRolesIds)
->where('user_group_id', $userGroup->id)->get();
if (0 === $groupMemberships->count()) {
app('log')->error(sprintf('User #%d "%s" does not have roles %s in user group #%d "%s"',
$this->id, $this->email,
join(', ', $roles), $userGroup->id, $userGroup->title));
return false;
}
foreach ($groupMemberships as $membership) {
app('log')->debug(sprintf('User #%d "%s" has role "%s" in user group #%d "%s"',
$this->id, $this->email,
$membership->userRole->title, $userGroup->id, $userGroup->title));
if (in_array($membership->userRole->title, $dbRolesTitles)) {
app('log')->debug(sprintf('Return true, found role "%s"', $membership->userRole->title));
return true;
}
}
app('log')->error(sprintf('User #%d "%s" does not have roles %s in user group #%d "%s"',
$this->id, $this->email,
join(', ', $roles), $userGroup->id, $userGroup->title));
return false;
// // not necessary, should always return true:
// $result = $groupMembership->userRole->title === $role->value;
// app('log')->error(sprintf('Does user #%d "%s" have role "%s" in user group #%d "%s"? %s',
// $this->id, $this->email,
// $role->value, $userGroup->id, $userGroup->title, var_export($result, true)));
// return $result;
}
/**
* @param string $role
*
* @return bool
*/
public function hasRole(string $role): bool
{
return $this->roles()->where('name', $role)->count() === 1;
}
/**
* Link to roles.
*
* @return BelongsToMany
*/
public function roles(): BelongsToMany
{
return $this->belongsToMany(Role::class);
}
/** /**
* *
* @return HasMany * @return HasMany
@@ -445,26 +532,6 @@ class User extends Authenticatable
}; };
} }
/**
* @param string $role
*
* @return bool
*/
public function hasRole(string $role): bool
{
return $this->roles()->where('name', $role)->count() === 1;
}
/**
* Link to roles.
*
* @return BelongsToMany
*/
public function roles(): BelongsToMany
{
return $this->belongsToMany(Role::class);
}
/** /**
* Route notifications for the Slack channel. * Route notifications for the Slack channel.
* *
@@ -513,6 +580,8 @@ class User extends Authenticatable
return $this->hasMany(Rule::class); return $this->hasMany(Rule::class);
} }
// start LDAP related code
/** /**
* Send the password reset notification. * Send the password reset notification.
* *
@@ -525,8 +594,6 @@ class User extends Authenticatable
event(new RequestedNewPassword($this, $token, $ipAddress)); event(new RequestedNewPassword($this, $token, $ipAddress));
} }
// start LDAP related code
/** /**
* Set the models LDAP domain. * Set the models LDAP domain.
* *

View File

@@ -25,6 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Validation\Administration; namespace FireflyIII\Validation\Administration;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\UserRole; use FireflyIII\Models\UserRole;
use FireflyIII\Repositories\User\UserRepositoryInterface; use FireflyIII\Repositories\User\UserRepositoryInterface;
@@ -48,6 +49,7 @@ trait ValidatesAdministrationAccess
*/ */
protected function validateAdministration(Validator $validator, array $allowedRoles): void protected function validateAdministration(Validator $validator, array $allowedRoles): void
{ {
die('deprecated method, must be done through user.');
Log::debug('Now in validateAdministration()'); Log::debug('Now in validateAdministration()');
if (!auth()->check()) { if (!auth()->check()) {
Log::error('User is not authenticated.'); Log::error('User is not authenticated.');
@@ -74,11 +76,11 @@ trait ValidatesAdministrationAccess
$validator->errors()->add('administration', (string)trans('validation.no_access_user_group')); $validator->errors()->add('administration', (string)trans('validation.no_access_user_group'));
return; return;
} }
if (in_array(UserRole::OWNER, $array, true)) { if (in_array(UserRoleEnum::OWNER->value, $array, true)) {
Log::debug('User is owner of this administration.'); Log::debug('User is owner of this administration.');
return; return;
} }
if (in_array(UserRole::FULL, $array, true)) { if (in_array(UserRoleEnum::OWNER->value, $array, true)) {
Log::debug('User has full access to this administration.'); Log::debug('User has full access to this administration.');
return; return;
} }

74
composer.lock generated
View File

@@ -4384,16 +4384,16 @@
}, },
{ {
"name": "phpseclib/phpseclib", "name": "phpseclib/phpseclib",
"version": "3.0.21", "version": "3.0.23",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpseclib/phpseclib.git", "url": "https://github.com/phpseclib/phpseclib.git",
"reference": "4580645d3fc05c189024eb3b834c6c1e4f0f30a1" "reference": "866cc78fbd82462ffd880e3f65692afe928bed50"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/4580645d3fc05c189024eb3b834c6c1e4f0f30a1", "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/866cc78fbd82462ffd880e3f65692afe928bed50",
"reference": "4580645d3fc05c189024eb3b834c6c1e4f0f30a1", "reference": "866cc78fbd82462ffd880e3f65692afe928bed50",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -4474,7 +4474,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/phpseclib/phpseclib/issues", "issues": "https://github.com/phpseclib/phpseclib/issues",
"source": "https://github.com/phpseclib/phpseclib/tree/3.0.21" "source": "https://github.com/phpseclib/phpseclib/tree/3.0.23"
}, },
"funding": [ "funding": [
{ {
@@ -4490,7 +4490,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-07-09T15:24:48+00:00" "time": "2023-09-18T17:22:01+00:00"
}, },
{ {
"name": "pragmarx/google2fa", "name": "pragmarx/google2fa",
@@ -9919,16 +9919,16 @@
}, },
{ {
"name": "phpmyadmin/sql-parser", "name": "phpmyadmin/sql-parser",
"version": "5.8.0", "version": "5.8.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpmyadmin/sql-parser.git", "url": "https://github.com/phpmyadmin/sql-parser.git",
"reference": "db1b3069b5dbc220d393d67ff911e0ae76732755" "reference": "b877ee6262a00f0f498da5e01335e8a5dc01d203"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpmyadmin/sql-parser/zipball/db1b3069b5dbc220d393d67ff911e0ae76732755", "url": "https://api.github.com/repos/phpmyadmin/sql-parser/zipball/b877ee6262a00f0f498da5e01335e8a5dc01d203",
"reference": "db1b3069b5dbc220d393d67ff911e0ae76732755", "reference": "b877ee6262a00f0f498da5e01335e8a5dc01d203",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -9950,7 +9950,7 @@
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
"psalm/plugin-phpunit": "^0.16.1", "psalm/plugin-phpunit": "^0.16.1",
"vimeo/psalm": "^4.11", "vimeo/psalm": "^4.11",
"zumba/json-serializer": "^3.0" "zumba/json-serializer": "~3.0.2"
}, },
"suggest": { "suggest": {
"ext-mbstring": "For best performance", "ext-mbstring": "For best performance",
@@ -10002,20 +10002,20 @@
"type": "other" "type": "other"
} }
], ],
"time": "2023-06-05T18:19:38+00:00" "time": "2023-09-15T18:21:22+00:00"
}, },
{ {
"name": "phpstan/phpdoc-parser", "name": "phpstan/phpdoc-parser",
"version": "1.24.0", "version": "1.24.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpdoc-parser.git", "url": "https://github.com/phpstan/phpdoc-parser.git",
"reference": "3510b0a6274cc42f7219367cb3abfc123ffa09d6" "reference": "9f854d275c2dbf84915a5c0ec9a2d17d2cd86b01"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/3510b0a6274cc42f7219367cb3abfc123ffa09d6", "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/9f854d275c2dbf84915a5c0ec9a2d17d2cd86b01",
"reference": "3510b0a6274cc42f7219367cb3abfc123ffa09d6", "reference": "9f854d275c2dbf84915a5c0ec9a2d17d2cd86b01",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -10047,9 +10047,9 @@
"description": "PHPDoc parser with support for nullable, intersection and generic types", "description": "PHPDoc parser with support for nullable, intersection and generic types",
"support": { "support": {
"issues": "https://github.com/phpstan/phpdoc-parser/issues", "issues": "https://github.com/phpstan/phpdoc-parser/issues",
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.24.0" "source": "https://github.com/phpstan/phpdoc-parser/tree/1.24.1"
}, },
"time": "2023-09-07T20:46:32+00:00" "time": "2023-09-18T12:18:02+00:00"
}, },
{ {
"name": "phpstan/phpstan", "name": "phpstan/phpstan",
@@ -10212,16 +10212,16 @@
}, },
{ {
"name": "phpunit/php-code-coverage", "name": "phpunit/php-code-coverage",
"version": "10.1.5", "version": "10.1.6",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "1df504e42a88044c27a90136910f0b3fe9e91939" "reference": "56f33548fe522c8d82da7ff3824b42829d324364"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/1df504e42a88044c27a90136910f0b3fe9e91939", "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/56f33548fe522c8d82da7ff3824b42829d324364",
"reference": "1df504e42a88044c27a90136910f0b3fe9e91939", "reference": "56f33548fe522c8d82da7ff3824b42829d324364",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -10278,7 +10278,7 @@
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.5" "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.6"
}, },
"funding": [ "funding": [
{ {
@@ -10286,7 +10286,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2023-09-12T14:37:22+00:00" "time": "2023-09-19T04:59:03+00:00"
}, },
{ {
"name": "phpunit/php-file-iterator", "name": "phpunit/php-file-iterator",
@@ -10533,16 +10533,16 @@
}, },
{ {
"name": "phpunit/phpunit", "name": "phpunit/phpunit",
"version": "10.3.4", "version": "10.3.5",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git", "url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "b8d59476f19115c9774b3b447f78131781c6c32b" "reference": "747c3b2038f1139e3dcd9886a3f5a948648b7503"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b8d59476f19115c9774b3b447f78131781c6c32b", "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/747c3b2038f1139e3dcd9886a3f5a948648b7503",
"reference": "b8d59476f19115c9774b3b447f78131781c6c32b", "reference": "747c3b2038f1139e3dcd9886a3f5a948648b7503",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -10566,7 +10566,7 @@
"sebastian/comparator": "^5.0", "sebastian/comparator": "^5.0",
"sebastian/diff": "^5.0", "sebastian/diff": "^5.0",
"sebastian/environment": "^6.0", "sebastian/environment": "^6.0",
"sebastian/exporter": "^5.0", "sebastian/exporter": "^5.1",
"sebastian/global-state": "^6.0.1", "sebastian/global-state": "^6.0.1",
"sebastian/object-enumerator": "^5.0", "sebastian/object-enumerator": "^5.0",
"sebastian/recursion-context": "^5.0", "sebastian/recursion-context": "^5.0",
@@ -10614,7 +10614,7 @@
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues", "issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy", "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
"source": "https://github.com/sebastianbergmann/phpunit/tree/10.3.4" "source": "https://github.com/sebastianbergmann/phpunit/tree/10.3.5"
}, },
"funding": [ "funding": [
{ {
@@ -10630,7 +10630,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-09-12T14:42:28+00:00" "time": "2023-09-19T05:42:37+00:00"
}, },
{ {
"name": "sebastian/cli-parser", "name": "sebastian/cli-parser",
@@ -11067,16 +11067,16 @@
}, },
{ {
"name": "sebastian/exporter", "name": "sebastian/exporter",
"version": "5.0.1", "version": "5.1.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/exporter.git", "url": "https://github.com/sebastianbergmann/exporter.git",
"reference": "32ff03d078fed1279c4ec9a407d08c5e9febb480" "reference": "c3fa8483f9539b190f7cd4bfc4a07631dd1df344"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/32ff03d078fed1279c4ec9a407d08c5e9febb480", "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/c3fa8483f9539b190f7cd4bfc4a07631dd1df344",
"reference": "32ff03d078fed1279c4ec9a407d08c5e9febb480", "reference": "c3fa8483f9539b190f7cd4bfc4a07631dd1df344",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -11133,7 +11133,7 @@
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/exporter/issues", "issues": "https://github.com/sebastianbergmann/exporter/issues",
"security": "https://github.com/sebastianbergmann/exporter/security/policy", "security": "https://github.com/sebastianbergmann/exporter/security/policy",
"source": "https://github.com/sebastianbergmann/exporter/tree/5.0.1" "source": "https://github.com/sebastianbergmann/exporter/tree/5.1.0"
}, },
"funding": [ "funding": [
{ {
@@ -11141,7 +11141,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2023-09-08T04:46:58+00:00" "time": "2023-09-18T07:15:37+00:00"
}, },
{ {
"name": "sebastian/global-state", "name": "sebastian/global-state",

View File

@@ -46,6 +46,7 @@ use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionJournalLink; use FireflyIII\Models\TransactionJournalLink;
use FireflyIII\Models\TransactionType as TransactionTypeModel; use FireflyIII\Models\TransactionType as TransactionTypeModel;
use FireflyIII\Models\UserGroup;
use FireflyIII\Models\Webhook; use FireflyIII\Models\Webhook;
use FireflyIII\Models\WebhookAttempt; use FireflyIII\Models\WebhookAttempt;
use FireflyIII\Models\WebhookMessage; use FireflyIII\Models\WebhookMessage;
@@ -482,6 +483,7 @@ return [
// V2 API endpoints: // V2 API endpoints:
'userGroupAccount' => UserGroupAccount::class, 'userGroupAccount' => UserGroupAccount::class,
'userGroupBill' => UserGroupBill::class, 'userGroupBill' => UserGroupBill::class,
'userGroup' => UserGroup::class,
], ],

View File

@@ -23,18 +23,12 @@
declare(strict_types=1); declare(strict_types=1);
use FireflyIII\Models\UserRole; use FireflyIII\Enums\UserRoleEnum;
return [ $result = [];
'roles' => [
UserRole::READ_ONLY => [], foreach (UserRoleEnum::cases() as $role) {
UserRole::CHANGE_TRANSACTIONS => [], $result[$role->value] = [];
UserRole::CHANGE_RULES => [], }
UserRole::CHANGE_PIGGY_BANKS => [], return $result;
UserRole::CHANGE_REPETITIONS => [],
UserRole::VIEW_REPORTS => [],
UserRole::FULL => [],
UserRole::OWNER => [],
],
];

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace Database\Seeders; namespace Database\Seeders;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\UserRole; use FireflyIII\Models\UserRole;
use Illuminate\Database\Seeder; use Illuminate\Database\Seeder;
use PDOException; use PDOException;
@@ -40,18 +41,10 @@ class UserRoleSeeder extends Seeder
*/ */
public function run() public function run()
{ {
$roles = [ $roles = [];
UserRole::READ_ONLY, foreach (UserRoleEnum::cases() as $role) {
UserRole::CHANGE_TRANSACTIONS, $roles[] = $role->value;
UserRole::CHANGE_RULES, }
UserRole::CHANGE_PIGGY_BANKS,
UserRole::CHANGE_REPETITIONS,
UserRole::VIEW_REPORTS,
UserRole::MANAGE_WEBHOOKS,
UserRole::MANAGE_CURRENCIES,
UserRole::FULL,
UserRole::OWNER,
];
/** @var string $role */ /** @var string $role */
foreach ($roles as $role) { foreach ($roles as $role) {