Compare commits

..

26 Commits

Author SHA1 Message Date
github-actions[bot]
52abe3bbc2 Merge pull request #10765 from firefly-iii/develop
🤖 Automatically merge the PR into the main branch.
2025-08-16 19:54:36 +02:00
github-actions[bot]
34db9f41c2 Merge pull request #10764 from firefly-iii/release-1755366862
🤖 Automatically merge the PR into the develop branch.
2025-08-16 19:54:31 +02:00
JC5
72c31fbe6a 🤖 Auto commit for release 'v6.3.0' on 2025-08-16 2025-08-16 19:54:22 +02:00
github-actions[bot]
1d8dd41564 Merge pull request #10763 from firefly-iii/release-1755365805
🤖 Automatically merge the PR into the develop branch.
2025-08-16 19:36:56 +02:00
JC5
3409240a19 🤖 Auto commit for release 'develop' on 2025-08-16 2025-08-16 19:36:45 +02:00
James Cole
eccc58e75a Add piggy bank tests. 2025-08-16 19:31:59 +02:00
James Cole
24098f35bb Fix some commands. 2025-08-16 15:04:15 +02:00
James Cole
e7d9dc57d8 Add some tests. 2025-08-16 14:52:29 +02:00
James Cole
f04ed5b8f0 Restore and fix API tests 2025-08-16 14:10:24 +02:00
James Cole
8bd44f429b Merge pull request #10762 from firefly-iii/JC5-patch-1
Update lock.yml
2025-08-16 10:26:21 +02:00
James Cole
fb7866b165 Update lock.yml
Signed-off-by: James Cole <james@firefly-iii.org>
2025-08-16 10:26:09 +02:00
James Cole
98db6db1eb Fix references to charts. 2025-08-16 08:28:10 +02:00
James Cole
0a235ec523 Optimize category chart. 2025-08-16 06:34:28 +02:00
github-actions[bot]
cb4f7ad0a8 Merge pull request #10761 from firefly-iii/release-1755317595
🤖 Automatically merge the PR into the develop branch.
2025-08-16 06:13:25 +02:00
JC5
91ce1d3b88 🤖 Auto commit for release 'develop' on 2025-08-16 2025-08-16 06:13:15 +02:00
James Cole
8f9ab150ee Add command to reset rate limit for error emails. 2025-08-16 06:08:01 +02:00
James Cole
8d52f83b4f Fix nulls. 2025-08-16 06:02:26 +02:00
James Cole
fb19739b54 Fix missing enrichment. 2025-08-16 05:58:58 +02:00
James Cole
acd4f28ae3 Restore "default" API endpoint so data importer does not fail. 2025-08-15 21:37:49 +02:00
James Cole
e4d443db50 Remove some unused comments. 2025-08-15 21:10:30 +02:00
James Cole
fe9d36cd27 Clean up a variety of end points. 2025-08-15 20:06:28 +02:00
James Cole
a916cc7e78 Rename command. 2025-08-15 20:00:29 +02:00
James Cole
77d15f884b Extend acceptedRoles to chart controllers. 2025-08-15 19:57:32 +02:00
James Cole
ab773c9052 Extend acceptedRoles array in AC controllers. 2025-08-15 19:50:12 +02:00
James Cole
87d292ca27 Rename method from default to primary. 2025-08-15 14:33:14 +02:00
James Cole
946e272d1c Update changelog and templates. 2025-08-15 13:46:41 +02:00
93 changed files with 798 additions and 535 deletions

View File

@@ -1,6 +1,6 @@
parameters:
scanFiles:
- ../_ide_helper
- ../_ide_helper.php
paths:
- ../app
- ../database

View File

@@ -1,6 +1,7 @@
Welcome to release %version of Firefly III. This **alpha** release contains the latest fixes, translations and features. It is probably buggy and may not work as expected. You can download the release below, and adventurous Docker users can find this release under the `alpha` tag.
:warning: Please be careful with this alpha release, as it may not work as expected.
> [!WARNING]
> Please be careful with this alpha release, as it may not work as expected.
Alpha releases are created to test new features and fixes before they are included in a stable release. They are not recommended for production use. This release was created on %date and may contain unexpected bugs. Data loss is rare but possible.

View File

@@ -1,6 +1,7 @@
Welcome to release %version of Firefly III. This **beta** release contains the latest fixes, translations and features. It may be buggy, nor work as expected. You can download the release below, and adventurous Docker users can find this release under the `beta` tag.
:warning: Please be careful with this beta release, as it may not work as expected.
> [!WARNING]
> Please be careful with this beta release, as it may not work as expected.
Alpha releases are created to test new features and fixes before they are included in a stable release. They are not recommended for production use. This release was created on %date and may contain unexpected bugs. Data loss is rare but possible.

View File

@@ -1,6 +1,7 @@
Welcome to release %version of Firefly III. This branch-related release contains the latest fixes, translations and features. It is probably buggy and may not work as expected. You can download the release below, and adventurous Docker users can find this release under the `branch-*` tag.
:warning: Please be careful with this branch release, as it may not work as expected.
> [!WARNING]
> Please be careful with this branch release, as it may not work as expected.
Branch releases are created to test large new features that are developed alongside the normal release flow. They are not recommended for production use. This release was created on %date and may contain unexpected bugs. Data loss is rare but possible.

View File

@@ -1,6 +1,7 @@
Welcome to the latest development release of Firefly III. This test release contains the absolute latest fixes, translations and features. It is probably buggy and may not work as expected. You can download the release below, and adventurous Docker users can find this release under the `develop` tag.
:warning: Please be careful with this pre-release, as it may not work as expected.
> [!WARNING]
> Please be careful with this pre-release, as it may not work as expected.
This release was created on %date and may contain unexpected bugs. Data loss is rare but possible.

View File

@@ -21,7 +21,7 @@ jobs:
discussions: write
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v5
- uses: JC5/lock-threads@v6.0.2
with:
issue-inactive-days: 21
pr-inactive-days: 21

View File

@@ -27,6 +27,7 @@ namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
@@ -34,7 +35,6 @@ use FireflyIII\Support\Debug\Timer;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Http\Api\AccountFilter;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
@@ -46,7 +46,8 @@ class AccountController extends Controller
use AccountFilter;
// this array only exists to test if the constructor will use it properly.
protected array $accepts = ['application/json', 'application/vnd.api+json'];
protected array $accepts = ['application/json', 'application/vnd.api+json'];
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY];
/** @var array<int, string> */
private array $balanceTypes;
@@ -60,10 +61,10 @@ class AccountController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
$this->validateUserGroup($request);
$this->repository = app(AccountRepositoryInterface::class);
$this->repository->setUser($user);
$this->repository->setUser($this->user);
$this->repository->setUserGroup($this->userGroup);
return $next($request);
}

View File

@@ -26,9 +26,9 @@ namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\Bill;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
/**
@@ -37,6 +37,7 @@ use Illuminate\Http\JsonResponse;
class BillController extends Controller
{
private BillRepositoryInterface $repository;
protected array $acceptedRoles = [UserRoleEnum::READ_SUBSCRIPTIONS];
/**
* BillController constructor.
@@ -46,10 +47,10 @@ class BillController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
$this->validateUserGroup($request);
$this->repository = app(BillRepositoryInterface::class);
$this->repository->setUser($user);
$this->repository->setUser($this->user);
$this->repository->setUserGroup($this->userGroup);
return $next($request);
}

View File

@@ -26,9 +26,9 @@ namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\Budget;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
/**
@@ -37,6 +37,7 @@ use Illuminate\Http\JsonResponse;
class BudgetController extends Controller
{
private BudgetRepositoryInterface $repository;
protected array $acceptedRoles = [UserRoleEnum::READ_BUDGETS];
/**
* BudgetController constructor.
@@ -46,10 +47,10 @@ class BudgetController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
$this->validateUserGroup($request);
$this->repository = app(BudgetRepositoryInterface::class);
$this->repository->setUser($user);
$this->repository->setUser($this->user);
$this->repository->setUserGroup($this->userGroup);
return $next($request);
}

View File

@@ -26,9 +26,9 @@ namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\Category;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
/**
@@ -37,6 +37,7 @@ use Illuminate\Http\JsonResponse;
class CategoryController extends Controller
{
private CategoryRepositoryInterface $repository;
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY];
/**
* CategoryController constructor.
@@ -46,10 +47,10 @@ class CategoryController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
$this->validateUserGroup($request);
$this->repository = app(CategoryRepositoryInterface::class);
$this->repository->setUser($user);
$this->repository->setUser($this->user);
$this->repository->setUserGroup($this->userGroup);
return $next($request);
}

View File

@@ -27,9 +27,9 @@ namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use Deprecated;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
/**
@@ -38,6 +38,7 @@ use Illuminate\Http\JsonResponse;
class CurrencyController extends Controller
{
private CurrencyRepositoryInterface $repository;
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY];
/**
* CurrencyController constructor.
@@ -47,10 +48,10 @@ class CurrencyController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
$this->validateUserGroup($request);
$this->repository = app(CurrencyRepositoryInterface::class);
$this->repository->setUser($user);
$this->repository->setUser($this->user);
$this->repository->setUserGroup($this->userGroup);
return $next($request);
}

View File

@@ -26,9 +26,9 @@ namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\ObjectGroup;
use FireflyIII\Repositories\ObjectGroup\ObjectGroupRepositoryInterface;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
/**
@@ -37,6 +37,7 @@ use Illuminate\Http\JsonResponse;
class ObjectGroupController extends Controller
{
private ObjectGroupRepositoryInterface $repository;
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY];
/**
* CurrencyController constructor.
@@ -46,10 +47,10 @@ class ObjectGroupController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
$this->validateUserGroup($request);
$this->repository = app(ObjectGroupRepositoryInterface::class);
$this->repository->setUser($user);
$this->repository->setUser($this->user);
$this->repository->setUserGroup($this->userGroup);
return $next($request);
}

View File

@@ -26,10 +26,10 @@ namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
/**
@@ -39,6 +39,7 @@ class PiggyBankController extends Controller
{
private AccountRepositoryInterface $accountRepository;
private PiggyBankRepositoryInterface $piggyRepository;
protected array $acceptedRoles = [UserRoleEnum::READ_PIGGY_BANKS];
/**
* PiggyBankController constructor.
@@ -48,22 +49,19 @@ class PiggyBankController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
$this->validateUserGroup($request);
$this->piggyRepository = app(PiggyBankRepositoryInterface::class);
$this->accountRepository = app(AccountRepositoryInterface::class);
$this->piggyRepository->setUser($user);
$this->accountRepository->setUser($user);
$this->piggyRepository->setUser($this->user);
$this->piggyRepository->setUserGroup($this->userGroup);
$this->accountRepository->setUser($this->user);
$this->accountRepository->setUserGroup($this->userGroup);
return $next($request);
}
);
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/autocomplete/getPiggiesAC
*/
public function piggyBanks(AutocompleteRequest $request): JsonResponse
{
$data = $request->getData();
@@ -90,10 +88,6 @@ class PiggyBankController extends Controller
return response()->api($response);
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/autocomplete/getPiggiesBalanceAC
*/
public function piggyBanksWithBalance(AutocompleteRequest $request): JsonResponse
{
$data = $request->getData();

View File

@@ -26,6 +26,7 @@ namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\Recurrence;
use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface;
use Illuminate\Http\JsonResponse;
@@ -36,6 +37,7 @@ use Illuminate\Http\JsonResponse;
class RecurrenceController extends Controller
{
private RecurringRepositoryInterface $repository;
protected array $acceptedRoles = [UserRoleEnum::READ_RECURRING];
/**
* RecurrenceController constructor.
@@ -45,19 +47,16 @@ class RecurrenceController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
$this->validateUserGroup($request);
$this->repository = app(RecurringRepositoryInterface::class);
$this->repository->setUser(auth()->user());
$this->repository->setUser($this->user);
$this->repository->setUserGroup($this->userGroup);
return $next($request);
}
);
}
/**
* This endpoint is documented at:
* * https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/autocomplete/getRecurringAC
*/
public function recurring(AutocompleteRequest $request): JsonResponse
{
$data = $request->getData();

View File

@@ -26,6 +26,7 @@ namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\Rule;
use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
use Illuminate\Http\JsonResponse;
@@ -36,6 +37,7 @@ use Illuminate\Http\JsonResponse;
class RuleController extends Controller
{
private RuleRepositoryInterface $repository;
protected array $acceptedRoles = [UserRoleEnum::READ_RULES];
/**
* RuleController constructor.
@@ -45,18 +47,16 @@ class RuleController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
$this->validateUserGroup($request);
$this->repository = app(RuleRepositoryInterface::class);
$this->repository->setUser(auth()->user());
$this->repository->setUser($this->user);
$this->repository->setUserGroup($this->userGroup);
return $next($request);
}
);
}
/**
* This endpoint is documented at:
* * https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/autocomplete/getRulesAC
*/
public function rules(AutocompleteRequest $request): JsonResponse
{
$data = $request->getData();

View File

@@ -26,6 +26,7 @@ namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\RuleGroup;
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
use Illuminate\Http\JsonResponse;
@@ -36,6 +37,7 @@ use Illuminate\Http\JsonResponse;
class RuleGroupController extends Controller
{
private RuleGroupRepositoryInterface $repository;
protected array $acceptedRoles = [UserRoleEnum::READ_RULES];
/**
* RuleGroupController constructor.
@@ -45,18 +47,16 @@ class RuleGroupController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
$this->validateUserGroup($request);
$this->repository = app(RuleGroupRepositoryInterface::class);
$this->repository->setUser(auth()->user());
$this->repository->setUser($this->user);
$this->repository->setUserGroup($this->userGroup);
return $next($request);
}
);
}
/**
* This endpoint is documented at:
* * https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/autocomplete/getRuleGroupsAC
*/
public function ruleGroups(AutocompleteRequest $request): JsonResponse
{
$data = $request->getData();

View File

@@ -26,9 +26,9 @@ namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\Tag;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
/**
@@ -37,6 +37,7 @@ use Illuminate\Http\JsonResponse;
class TagController extends Controller
{
private TagRepositoryInterface $repository;
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY];
/**
* TagController constructor.
@@ -46,20 +47,16 @@ class TagController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
$this->validateUserGroup($request);
$this->repository = app(TagRepositoryInterface::class);
$this->repository->setUser($user);
$this->repository->setUser($this->user);
$this->repository->setUserGroup($this->userGroup);
return $next($request);
}
);
}
/**
* This endpoint is documented at:
* * https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/autocomplete/getTagAC
*/
public function tags(AutocompleteRequest $request): JsonResponse
{
$data = $request->getData();

View File

@@ -31,7 +31,6 @@ use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Collection;
@@ -52,24 +51,19 @@ class TransactionController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
$userGroup = $this->validateUserGroup($request);
$this->validateUserGroup($request);
$this->repository = app(JournalRepositoryInterface::class);
$this->groupRepository = app(TransactionGroupRepositoryInterface::class);
$this->repository->setUser($user);
$this->groupRepository->setUser($user);
$this->groupRepository->setUserGroup($userGroup);
$this->repository->setUser($this->user);
$this->repository->setUserGroup($this->userGroup);
$this->groupRepository->setUser($this->user);
$this->groupRepository->setUserGroup($this->userGroup);
return $next($request);
}
);
}
/**
* This endpoint is documented at:
* * https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/autocomplete/getTransactionsAC
*/
public function transactions(AutocompleteRequest $request): JsonResponse
{
$data = $request->getData();
@@ -92,10 +86,6 @@ class TransactionController extends Controller
return response()->api($array);
}
/**
* This endpoint is documented at:
* * https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/autocomplete/getTransactionsIDAC
*/
public function transactionsWithID(AutocompleteRequest $request): JsonResponse
{
$data = $request->getData();

View File

@@ -26,6 +26,7 @@ namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\TransactionType\TransactionTypeRepositoryInterface;
use Illuminate\Http\JsonResponse;
@@ -36,6 +37,7 @@ use Illuminate\Http\JsonResponse;
class TransactionTypeController extends Controller
{
private TransactionTypeRepositoryInterface $repository;
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY];
/**
* TransactionTypeController constructor.
@@ -45,17 +47,16 @@ class TransactionTypeController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
$this->validateUserGroup($request);
$this->repository = app(TransactionTypeRepositoryInterface::class);
$this->repository->setUser($this->user);
$this->repository->setUserGroup($this->userGroup);
return $next($request);
}
);
}
/**
* This endpoint is documented at
* * https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/autocomplete/getTransactionTypesAC
*/
public function transactionTypes(AutocompleteRequest $request): JsonResponse
{
$data = $request->getData();

View File

@@ -26,17 +26,14 @@ namespace FireflyIII\Api\V1\Controllers\Chart;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Chart\ChartRequest;
use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account;
use FireflyIII\Models\Preference;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Chart\ChartData;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Http\Api\ApiSupport;
use FireflyIII\Support\Http\Api\CleansChartData;
use FireflyIII\Support\Http\Api\CollectsAccountsFromFilter;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
@@ -47,11 +44,12 @@ use Illuminate\Support\Facades\Log;
class AccountController extends Controller
{
use ApiSupport;
use CleansChartData;
use CollectsAccountsFromFilter;
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY];
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY];
private ChartData $chartData;
private array $chartData = [];
private AccountRepositoryInterface $repository;
/**
@@ -62,11 +60,10 @@ class AccountController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
$this->chartData = new ChartData();
$this->repository = app(AccountRepositoryInterface::class);
$userGroup = $this->validateUserGroup($request);
$this->repository->setUserGroup($userGroup);
$this->validateUserGroup($request);
$this->repository->setUserGroup($this->userGroup);
$this->repository->setUser($this->user);
return $next($request);
}
@@ -84,7 +81,7 @@ class AccountController extends Controller
// move date to end of day
$queryParameters['start']->startOfDay();
$queryParameters['end']->endOfDay();
Log::debug(sprintf('dashboard(), convert to primary: %s', var_export($this->convertToPrimary, true)));
// Log::debug(sprintf('dashboard(), convert to primary: %s', var_export($this->convertToPrimary, true)));
// loop each account, and collect info:
/** @var Account $account */
@@ -93,7 +90,7 @@ class AccountController extends Controller
$this->renderAccountData($queryParameters, $account);
}
return response()->json($this->chartData->render());
return response()->json($this->clean($this->chartData));
}
/**
@@ -102,17 +99,17 @@ class AccountController extends Controller
private function renderAccountData(array $params, Account $account): void
{
Log::debug(sprintf('Now in %s(array, #%d)', __METHOD__, $account->id));
$currency = $this->repository->getAccountCurrency($account);
$currentStart = clone $params['start'];
$range = Steam::finalAccountBalanceInRange($account, $params['start'], clone $params['end'], $this->convertToPrimary);
$currency = $this->repository->getAccountCurrency($account);
$currentStart = clone $params['start'];
$range = Steam::finalAccountBalanceInRange($account, $params['start'], clone $params['end'], $this->convertToPrimary);
$previous = array_values($range)[0]['balance'];
$pcPrevious = null;
$previous = array_values($range)[0]['balance'];
$pcPrevious = null;
if (!$currency instanceof TransactionCurrency) {
$currency = $this->default;
$currency = $this->primaryCurrency;
}
$currentSet = [
$currentSet = [
'label' => $account->name,
// the currency that belongs to the account.
@@ -162,21 +159,6 @@ class AccountController extends Controller
$currentStart->addDay();
}
$this->chartData->add($currentSet);
}
private function getFrontPageAccountIds(): array
{
$defaultSet = $this->repository->getAccountsByType([AccountTypeEnum::ASSET->value])->pluck('id')->toArray();
/** @var Preference $frontpage */
$frontpage = Preferences::get('frontpageAccounts', $defaultSet);
if (!(is_array($frontpage->data) && count($frontpage->data) > 0)) {
$frontpage->data = $defaultSet;
$frontpage->save();
}
return $frontpage->data ?? $defaultSet;
$this->chartData[] = $currentSet;
}
}

View File

@@ -25,9 +25,9 @@ class BalanceController extends Controller
{
use CleansChartData;
use CollectsAccountsFromFilter;
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY];
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY];
private array $chartData;
private array $chartData = [];
private GroupCollectorInterface $collector;
private AccountRepositoryInterface $repository;
@@ -38,13 +38,13 @@ class BalanceController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
$this->validateUserGroup($request);
$this->repository = app(AccountRepositoryInterface::class);
$this->collector = app(GroupCollectorInterface::class);
$userGroup = $this->validateUserGroup($request);
$this->repository->setUserGroup($userGroup);
$this->collector->setUserGroup($userGroup);
$this->chartData = [];
// $this->default = app('amount')->getPrimaryCurrency();
$this->repository->setUserGroup($this->userGroup);
$this->collector->setUserGroup($this->userGroup);
$this->repository->setUser($this->user);
$this->collector->setUser($this->user);
return $next($request);
}

View File

@@ -26,7 +26,7 @@ namespace FireflyIII\Api\V1\Controllers\Chart;
use Carbon\Carbon;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Data\DateRequest;
use FireflyIII\Api\V1\Requests\Data\SameDateRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Budget;
@@ -63,13 +63,16 @@ class BudgetController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
$this->validateUserGroup($request);
$this->repository = app(BudgetRepositoryInterface::class);
$this->blRepository = app(BudgetLimitRepositoryInterface::class);
$this->opsRepository = app(OperationsRepositoryInterface::class);
$userGroup = $this->validateUserGroup($request);
$this->repository->setUserGroup($userGroup);
$this->opsRepository->setUserGroup($userGroup);
$this->blRepository->setUserGroup($userGroup);
$this->repository->setUserGroup($this->userGroup);
$this->opsRepository->setUserGroup($this->userGroup);
$this->blRepository->setUserGroup($this->userGroup);
$this->repository->setUser($this->user);
$this->opsRepository->setUser($this->user);
$this->blRepository->setUser($this->user);
return $next($request);
}
@@ -81,7 +84,7 @@ class BudgetController extends Controller
*
* @throws FireflyException
*/
public function overview(DateRequest $request): JsonResponse
public function overview(SameDateRequest $request): JsonResponse
{
$params = $request->getAll();
@@ -157,12 +160,6 @@ class BudgetController extends Controller
}
// if no limits
// if (0 === $limits->count()) {
// return as a single item in an array
// $rows = $this->noBudgetLimits($budget, $start, $end);
// }
// is always an array
$return = [];
foreach ($rows as $row) {
@@ -193,9 +190,9 @@ class BudgetController extends Controller
],
'pc_entries' => [
'budgeted' => $row['pc_budgeted'],
'spent' => '0',
'left' => '0',
'overspent' => '0',
'spent' => $row['pc_spent'],
'left' => $row['pc_left'],
'overspent' => $row['pc_overspent'],
],
];
$return[] = $current;

View File

@@ -26,7 +26,7 @@ namespace FireflyIII\Api\V1\Controllers\Chart;
use Carbon\Carbon;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Data\DateRequest;
use FireflyIII\Api\V1\Requests\Data\SameDateRequest;
use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Enums\UserRoleEnum;
@@ -59,11 +59,13 @@ class CategoryController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
$this->validateUserGroup($request);
$this->accountRepos = app(AccountRepositoryInterface::class);
$this->currencyRepos = app(CurrencyRepositoryInterface::class);
$userGroup = $this->validateUserGroup($request);
$this->accountRepos->setUserGroup($userGroup);
$this->currencyRepos->setUserGroup($userGroup);
$this->accountRepos->setUserGroup($this->userGroup);
$this->currencyRepos->setUserGroup($this->userGroup);
$this->accountRepos->setUser($this->user);
$this->currencyRepos->setUser($this->user);
return $next($request);
}
@@ -78,7 +80,7 @@ class CategoryController extends Controller
*
* @SuppressWarnings("PHPMD.UnusedFormalParameter")
*/
public function overview(DateRequest $request): JsonResponse
public function overview(SameDateRequest $request): JsonResponse
{
/** @var Carbon $start */
$start = $this->parameters->get('start');

View File

@@ -64,7 +64,7 @@ abstract class Controller extends BaseController
protected const string CONTENT_TYPE = 'application/vnd.api+json';
protected const string JSON_CONTENT_TYPE = 'application/json';
protected array $accepts = ['application/json', 'application/vnd.api+json'];
protected array $accepts = ['application/json', 'application/vnd.api+json'];
/** @var array<int, string> */
protected array $allowedSort;
@@ -107,7 +107,7 @@ abstract class Controller extends BaseController
private function getParameters(): ParameterBag
{
$bag = new ParameterBag();
$page = (int) request()->get('page');
$page = (int)request()->get('page');
if ($page < 1) {
$page = 1;
}
@@ -131,13 +131,13 @@ abstract class Controller extends BaseController
$obj = null;
if (null !== $date) {
try {
$obj = Carbon::parse((string) $date);
$obj = Carbon::parse((string)$date);
} catch (InvalidFormatException $e) {
// don't care
Log::warning(
sprintf(
'Ignored invalid date "%s" in API controller parameter check: %s',
substr((string) $date, 0, 20),
substr((string)$date, 0, 20),
$e->getMessage()
)
);
@@ -158,7 +158,7 @@ abstract class Controller extends BaseController
$value = null;
}
if (null !== $value) {
$value = (int) $value;
$value = (int)$value;
if ($value < 1) {
$value = 1;
}
@@ -176,7 +176,7 @@ abstract class Controller extends BaseController
$user = auth()->user();
/** @var Preference $pageSize */
$pageSize = (int) app('preferences')->getForUser($user, 'listPageSize', 50)->data;
$pageSize = (int)app('preferences')->getForUser($user, 'listPageSize', 50)->data;
$bag->set($integer, $pageSize);
}
}
@@ -190,7 +190,7 @@ abstract class Controller extends BaseController
$sortParameters = [];
try {
$param = (string) request()->query->get('sort');
$param = (string)request()->query->get('sort');
} catch (BadRequestException $e) {
Log::error('Request field "sort" contains a non-scalar value. Value set to NULL.');
Log::error($e->getMessage());

View File

@@ -26,6 +26,7 @@ namespace FireflyIII\Api\V1\Controllers\Data\Bulk;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Data\Bulk\TransactionRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Services\Internal\Destroy\AccountDestroyService;
use Illuminate\Http\JsonResponse;
@@ -44,23 +45,23 @@ class TransactionController extends Controller
{
private AccountRepositoryInterface $repository;
protected array $acceptedRoles = [UserRoleEnum::MANAGE_TRANSACTIONS];
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
$this->validateUserGroup($request);
$this->repository = app(AccountRepositoryInterface::class);
$this->repository->setUser(auth()->user());
$this->repository->setUserGroup($this->userGroup);
$this->repository->setUser($this->user);
return $next($request);
}
);
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/data/bulkUpdateTransactions
*/
public function update(TransactionRequest $request): JsonResponse
{
$query = $request->getAll();

View File

@@ -28,6 +28,7 @@ use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Data\DestroyRequest;
use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account;
use FireflyIII\Models\TransactionJournal;
@@ -55,12 +56,20 @@ class DestroyController extends Controller
{
private bool $unused;
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/data/destroyData
*
* @throws FireflyException
*/
protected array $acceptedRoles = [UserRoleEnum::FULL];
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
$this->validateUserGroup($request);
return $next($request);
}
);
}
public function destroy(DestroyRequest $request): JsonResponse
{
$objects = $request->getObjects();

View File

@@ -26,6 +26,7 @@ namespace FireflyIII\Api\V1\Controllers\Data\Export;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Data\Export\ExportRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Support\Export\ExportDataGenerator;
use Illuminate\Http\Response as LaravelResponse;
@@ -39,6 +40,7 @@ use function Safe\date;
class ExportController extends Controller
{
private ExportDataGenerator $exporter;
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY];
/**
* ExportController constructor.
@@ -48,8 +50,10 @@ class ExportController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
$this->validateUserGroup($request);
$this->exporter = app(ExportDataGenerator::class);
$this->exporter->setUser(auth()->user());
$this->exporter->setUserGroup($this->userGroup);
$this->exporter->setUser($this->user);
return $next($request);
}
@@ -57,9 +61,6 @@ class ExportController extends Controller
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/data/exportAccounts
*
* @throws FireflyException
*
* @SuppressWarnings("PHPMD.UnusedFormalParameter")
@@ -99,9 +100,6 @@ class ExportController extends Controller
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/data/exportBills
*
* @throws FireflyException
*
* @SuppressWarnings("PHPMD.UnusedFormalParameter")
@@ -114,9 +112,6 @@ class ExportController extends Controller
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/data/exportBudgets
*
* @throws FireflyException
*
* @SuppressWarnings("PHPMD.UnusedFormalParameter")
@@ -129,9 +124,6 @@ class ExportController extends Controller
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/data/exportCategories
*
* @throws FireflyException
*
* @SuppressWarnings("PHPMD.UnusedFormalParameter")
@@ -144,9 +136,6 @@ class ExportController extends Controller
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/data/exportPiggies
*
* @throws FireflyException
*
* @SuppressWarnings("PHPMD.UnusedFormalParameter")
@@ -159,9 +148,6 @@ class ExportController extends Controller
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/data/exportRecurring
*
* @throws FireflyException
*
* @SuppressWarnings("PHPMD.UnusedFormalParameter")
@@ -174,9 +160,6 @@ class ExportController extends Controller
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/data/exportRules
*
* @throws FireflyException
*
* @SuppressWarnings("PHPMD.UnusedFormalParameter")
@@ -189,9 +172,6 @@ class ExportController extends Controller
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/data/exportTags
*
* @throws FireflyException
*
* @SuppressWarnings("PHPMD.UnusedFormalParameter")
@@ -204,9 +184,6 @@ class ExportController extends Controller
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/data/exportTransactions
*
* @throws FireflyException
*/
public function transactions(ExportRequest $request): LaravelResponse

View File

@@ -25,6 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Data;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\Account;
use FireflyIII\Models\Bill;
use FireflyIII\Models\Budget;
@@ -44,10 +45,22 @@ use Illuminate\Http\JsonResponse;
*/
class PurgeController extends Controller
{
protected array $acceptedRoles = [UserRoleEnum::FULL];
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
$this->validateUserGroup($request);
return $next($request);
}
);
}
/**
* TODO cleanup and use repositories.
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/data/purgeData
*/
public function purge(): JsonResponse
{
@@ -66,14 +79,6 @@ class PurgeController extends Controller
$repository = app(PiggyBankRepositoryInterface::class);
$repository->setUser($user);
$repository->purgeAll();
// $set = PiggyBank::leftJoin('accounts', 'accounts.id', 'piggy_banks.account_id')
// ->where('accounts.user_id', $user->id)->onlyTrashed()->get(['piggy_banks.*'])
// ;
//
// /** @var PiggyBank $piggy */
// foreach ($set as $piggy) {
// $piggy->forceDelete();
// }
// rule group
RuleGroup::whereUserId($user->id)->onlyTrashed()->forceDelete();

View File

@@ -64,10 +64,6 @@ class AccountController extends Controller
);
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/insight/insightExpenseAsset
*/
public function asset(GenericRequest $request): JsonResponse
{
$start = $request->getStart();
@@ -91,10 +87,6 @@ class AccountController extends Controller
return response()->json($result);
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/insight/insightExpenseExpense
*/
public function expense(GenericRequest $request): JsonResponse
{
$start = $request->getStart();

View File

@@ -58,9 +58,6 @@ class BillController extends Controller
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/insight/insightExpenseBill
*
* Expenses per bill, possibly filtered by bill and account.
*/
public function bill(GenericRequest $request): JsonResponse
@@ -122,9 +119,6 @@ class BillController extends Controller
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/insight/insightExpenseNoBill
*
* Expenses for no bill filtered by account.
*/
public function noBill(GenericRequest $request): JsonResponse

View File

@@ -63,10 +63,6 @@ class BudgetController extends Controller
);
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/insight/insightExpenseBudget
*/
public function budget(GenericRequest $request): JsonResponse
{
$start = $request->getStart();
@@ -98,10 +94,6 @@ class BudgetController extends Controller
return response()->json($result);
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/insight/insightExpenseNoBudget
*/
public function noBudget(GenericRequest $request): JsonResponse
{
$start = $request->getStart();

View File

@@ -63,10 +63,6 @@ class CategoryController extends Controller
);
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/insight/insightTransferCategory
*/
public function category(GenericRequest $request): JsonResponse
{
$start = $request->getStart();
@@ -98,10 +94,6 @@ class CategoryController extends Controller
return response()->json($result);
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/insight/insightTransferNoCategory
*/
public function noCategory(GenericRequest $request): JsonResponse
{
$start = $request->getStart();

View File

@@ -37,10 +37,6 @@ use Illuminate\Support\Facades\Log;
*/
class PeriodController extends Controller
{
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/insight/insightExpenseTotal
*/
public function total(GenericRequest $request): JsonResponse
{
$accounts = $request->getAssetAccounts();

View File

@@ -57,9 +57,6 @@ class TagController extends Controller
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/insight/insightExpenseNoTag
*
* Expenses for no tag filtered by account.
*/
public function noTag(GenericRequest $request): JsonResponse
@@ -115,9 +112,6 @@ class TagController extends Controller
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/insight/insightExpenseTag
*
* Expenses per tag, possibly filtered by tag and account.
*/
public function tag(GenericRequest $request): JsonResponse

View File

@@ -64,10 +64,6 @@ class AccountController extends Controller
);
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/insight/insightIncomeAsset
*/
public function asset(GenericRequest $request): JsonResponse
{
$start = $request->getStart();
@@ -92,10 +88,6 @@ class AccountController extends Controller
return response()->json($result);
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/insight/insightIncomeRevenue
*/
public function revenue(GenericRequest $request): JsonResponse
{
$start = $request->getStart();

View File

@@ -63,10 +63,6 @@ class CategoryController extends Controller
);
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/insight/insightIncomeCategory
*/
public function category(GenericRequest $request): JsonResponse
{
$start = $request->getStart();
@@ -98,10 +94,6 @@ class CategoryController extends Controller
return response()->json($result);
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/insight/insightIncomeNoCategory
*/
public function noCategory(GenericRequest $request): JsonResponse
{
$start = $request->getStart();

View File

@@ -36,10 +36,6 @@ use Illuminate\Http\JsonResponse;
*/
class PeriodController extends Controller
{
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/insight/insightIncomeTotal
*/
public function total(GenericRequest $request): JsonResponse
{
$accounts = $request->getAssetAccounts();

View File

@@ -57,9 +57,6 @@ class TagController extends Controller
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/insight/insightIncomeTag
*
* Expenses for no tag filtered by account.
*/
public function noTag(GenericRequest $request): JsonResponse
@@ -109,9 +106,6 @@ class TagController extends Controller
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/insight/insightIncomeNoTag
*
* Expenses per tag, possibly filtered by tag and account.
*/
public function tag(GenericRequest $request): JsonResponse

View File

@@ -56,10 +56,6 @@ class AccountController extends Controller
);
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/insight/insightTransfers
*/
public function asset(GenericRequest $request): JsonResponse
{
$start = $request->getStart();

View File

@@ -63,10 +63,6 @@ class CategoryController extends Controller
);
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/insight/insightTransferCategory
*/
public function category(GenericRequest $request): JsonResponse
{
$start = $request->getStart();
@@ -98,10 +94,6 @@ class CategoryController extends Controller
return response()->json($result);
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/insight/insightTransferNoCategory
*/
public function noCategory(GenericRequest $request): JsonResponse
{
$start = $request->getStart();

View File

@@ -36,10 +36,6 @@ use Illuminate\Http\JsonResponse;
*/
class PeriodController extends Controller
{
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/insight/insightTransferTotal
*/
public function total(GenericRequest $request): JsonResponse
{
$accounts = $request->getAssetAccounts();

View File

@@ -56,10 +56,6 @@ class TagController extends Controller
);
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/insight/insightTransferNoTag
*/
public function noTag(GenericRequest $request): JsonResponse
{
$accounts = $request->getAssetAccounts();
@@ -108,9 +104,6 @@ class TagController extends Controller
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/insight/insightTransferTag
*
* Transfers per tag, possibly filtered by tag and account.
*/
public function tag(GenericRequest $request): JsonResponse

View File

@@ -55,9 +55,6 @@ class DestroyController extends Controller
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/accounts/deleteAccount
*
* Remove the specified resource from storage.
*/
public function destroy(Account $account): JsonResponse

View File

@@ -71,9 +71,6 @@ class ListController extends Controller
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/accounts/listAttachmentByAccount
*
* @throws FireflyException
*/
public function attachments(Account $account): JsonResponse
@@ -100,9 +97,6 @@ class ListController extends Controller
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/accounts/listPiggyBankByAccount
*
* @throws FireflyException
*/
public function piggyBanks(Account $account): JsonResponse
@@ -140,9 +134,6 @@ class ListController extends Controller
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/accounts/listTransactionByAccount
*
* Show all transaction groups related to the account.
*
* @throws FireflyException

View File

@@ -67,9 +67,6 @@ class ShowController extends Controller
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/accounts/listAccount
*
* Display a listing of the resource.
*
* @throws FireflyException

View File

@@ -31,6 +31,7 @@ use FireflyIII\Models\Budget;
use FireflyIII\Models\BudgetLimit;
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Support\JsonApi\Enrichments\BudgetEnrichment;
use FireflyIII\Support\JsonApi\Enrichments\BudgetLimitEnrichment;
use FireflyIII\Transformers\BudgetLimitTransformer;
use FireflyIII\User;
@@ -76,6 +77,16 @@ class ShowController extends Controller
*/
public function index(Budget $budget): JsonResponse
{
/** @var User $admin */
$admin = auth()->user();
// enrich budget:
$enrichment = new BudgetEnrichment();
$enrichment->setUser($admin);
$enrichment->setStart($this->parameters->get('start'));
$enrichment->setEnd($this->parameters->get('end'));
$budget = $enrichment->enrichSingle($budget);
$manager = $this->getManager();
$manager->parseIncludes('budget');
$pageSize = $this->parameters->get('limit');
@@ -87,8 +98,6 @@ class ShowController extends Controller
// enrich
/** @var User $admin */
$admin = auth()->user();
$enrichment = new BudgetLimitEnrichment();
$enrichment->setUser($admin);
$budgetLimits = $enrichment->enrich($budgetLimits);

View File

@@ -126,7 +126,7 @@ class ShowController extends Controller
*
* @throws FireflyException
*/
public function showDefault(): JsonResponse
public function showPrimary(): JsonResponse
{
/** @var User $user */
$user = auth()->user();

View File

@@ -73,7 +73,7 @@ class StoreController extends Controller
{
$currency = $this->repository->store($request->getAll());
if (true === $request->boolean('default')) {
$this->repository->makeDefault($currency);
$this->repository->makePrimary($currency);
app('preferences')->mark();
}
$manager = $this->getManager();

View File

@@ -101,12 +101,12 @@ class UpdateController extends Controller
/**
* @throws FireflyException
*/
public function makeDefault(TransactionCurrency $currency): JsonResponse
public function makePrimary(TransactionCurrency $currency): JsonResponse
{
/** @var User $user */
$user = auth()->user();
$this->repository->enable($currency);
$this->repository->makeDefault($currency);
$this->repository->makePrimary($currency);
app('preferences')->mark();

View File

@@ -49,14 +49,23 @@ class ValidatesEnvironmentVariables extends Command
*/
public function handle(): int
{
$this->validateLanguage();
$this->validateGuard();
$this->validateStaticToken();
$result = $this->validateLanguage();
if (false === $result) {
return Command::FAILURE;
}
$result = $this->validateGuard();
if (false === $result) {
return Command::FAILURE;
}
$result = $this->validateStaticToken();
if (false === $result) {
return Command::FAILURE;
}
return Command::SUCCESS;
}
private function validateLanguage(): void
private function validateLanguage(): bool
{
$language = config('firefly.default_language');
$locale = config('firefly.default_locale');
@@ -67,7 +76,7 @@ class ValidatesEnvironmentVariables extends Command
$this->friendlyError('Please check your .env file and make sure you use a valid setting.');
$this->friendlyError(sprintf('Valid languages are: %s', implode(', ', $options)));
exit(1);
return false;
}
$options[] = 'equal';
if (!in_array($locale, $options, true)) {
@@ -75,11 +84,13 @@ class ValidatesEnvironmentVariables extends Command
$this->friendlyError('Please check your .env file and make sure you use a valid setting.');
$this->friendlyError(sprintf('Valid locales are: %s', implode(', ', $options)));
exit(1);
return false;
}
return true;
}
private function validateGuard(): void
private function validateGuard(): bool
{
$guard = config('auth.defaults.guard');
if ('web' !== $guard && 'remote_user_guard' !== $guard) {
@@ -87,18 +98,22 @@ class ValidatesEnvironmentVariables extends Command
$this->friendlyError('Please check your .env file and make sure you use a valid setting.');
$this->friendlyError('Valid guards are: web, remote_user_guard');
exit(1);
return false;
}
return true;
}
private function validateStaticToken(): void
private function validateStaticToken(): bool
{
$token = (string) config('firefly.static_cron_token');
$token = (string)config('firefly.static_cron_token');
if ('' !== $token && 32 !== strlen($token)) {
$this->friendlyError('STATIC_CRON_TOKEN must be empty or a 32-character string.');
$this->friendlyError('Please check your .env file and make sure you use a valid setting.');
exit(1);
return false;
}
return true;
}
}

View File

@@ -0,0 +1,60 @@
<?php
declare(strict_types=1);
namespace FireflyIII\Console\Commands\System;
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
use Illuminate\Console\Command;
use Symfony\Component\Console\Command\Command as CommandAlias;
class ResetsErrorMailLimit extends Command
{
use ShowsFriendlyMessages;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:reset-error-mail-limit';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Resets the number of error mails sent.';
/**
* Execute the console command.
*/
public function handle(): int
{
$file = storage_path('framework/cache/error-count.json');
$directory = storage_path('framework/cache');
$limits = [];
if (!is_writable($directory)) {
$this->friendlyError(sprintf('Cannot write to directory "%s", cannot rate limit errors.', $directory));
return CommandAlias::FAILURE;
}
if (!file_exists($file)) {
$this->friendlyInfo(sprintf('Created new limits file at "%s"', $file));
file_put_contents($file, json_encode($limits, JSON_PRETTY_PRINT));
return CommandAlias::SUCCESS;
}
if (!is_writable($file)) {
$this->friendlyError(sprintf('Cannot write to "%s", cannot rate limit errors.', $file));
return CommandAlias::FAILURE;
}
$this->friendlyInfo(sprintf('Successfully reset the error rate-limits file located at "%s"', $file));
file_put_contents($file, json_encode($limits, JSON_PRETTY_PRINT));
return CommandAlias::SUCCESS;
}
}

View File

@@ -29,12 +29,16 @@ use FireflyIII\Models\Attachment;
use Illuminate\Console\Command;
use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Safe\Exceptions\FileinfoException;
use Safe\Exceptions\FilesystemException;
use Safe\Exceptions\StringsException;
use function Safe\tempnam;
use function Safe\file_put_contents;
use function Safe\md5_file;
use function Safe\mime_content_type;
use function Safe\tempnam;
class ScansAttachments extends Command
{
@@ -46,6 +50,10 @@ class ScansAttachments extends Command
/**
* Execute the console command.
*
* @throws FilesystemException
* @throws StringsException
* @throws FileinfoException
*/
public function handle(): int
{
@@ -57,7 +65,7 @@ class ScansAttachments extends Command
$fileName = $attachment->fileName();
$encryptedContent = $disk->get($fileName);
if (null === $encryptedContent) {
app('log')->error(sprintf('No content for attachment #%d under filename "%s"', $attachment->id, $fileName));
Log::error(sprintf('No content for attachment #%d under filename "%s"', $attachment->id, $fileName));
continue;
}
@@ -65,18 +73,13 @@ class ScansAttachments extends Command
try {
$decryptedContent = Crypt::decrypt($encryptedContent); // verified
} catch (DecryptException $e) {
app('log')->error(sprintf('Could not decrypt data of attachment #%d: %s', $attachment->id, $e->getMessage()));
Log::error(sprintf('Could not decrypt data of attachment #%d: %s', $attachment->id, $e->getMessage()));
$decryptedContent = $encryptedContent;
}
$tempFileName = tempnam(sys_get_temp_dir(), 'FireflyIII');
if (false === $tempFileName) {
app('log')->error(sprintf('Could not create temporary file for attachment #%d', $attachment->id));
exit(1);
}
file_put_contents($tempFileName, $decryptedContent);
$attachment->md5 = (string) md5_file($tempFileName);
$attachment->mime = (string) mime_content_type($tempFileName);
$attachment->md5 = (string)md5_file($tempFileName);
$attachment->mime = (string)mime_content_type($tempFileName);
$attachment->save();
$this->friendlyInfo(sprintf('Fixed attachment #%d', $attachment->id));
}

View File

@@ -50,7 +50,7 @@ class Cron extends Command
{--download-cer : Download exchange rates. Other tasks will be skipped unless also requested.}
{--create-recurring : Create recurring transactions. Other tasks will be skipped unless also requested.}
{--create-auto-budgets : Create auto budgets. Other tasks will be skipped unless also requested.}
{--send-bill-warnings : Send bill warnings. Other tasks will be skipped unless also requested.}
{--send-subscription-warnings : Send subscription warnings. Other tasks will be skipped unless also requested.}
{--send-webhook-messages : Sends any stray webhook messages (with a maximum of 5).}
';
@@ -59,7 +59,7 @@ class Cron extends Command
$doAll = !$this->option('download-cer')
&& !$this->option('create-recurring')
&& !$this->option('create-auto-budgets')
&& !$this->option('send-bill-warnings')
&& !$this->option('send-subscription-warnings')
&& !$this->option('check-version')
&& !$this->option('send-webhook-messages');
$date = null;
@@ -116,9 +116,9 @@ class Cron extends Command
}
// Fire bill warning cron job
if ($doAll || $this->option('send-bill-warnings')) {
if ($doAll || $this->option('send-subscription-warnings')) {
try {
$this->billWarningCronJob($force, $date);
$this->subscriptionWarningCronJob($force, $date);
} catch (FireflyException $e) {
app('log')->error($e->getMessage());
app('log')->error($e->getTraceAsString());
@@ -231,25 +231,25 @@ class Cron extends Command
/**
* @throws FireflyException
*/
private function billWarningCronJob(bool $force, ?Carbon $date): void
private function subscriptionWarningCronJob(bool $force, ?Carbon $date): void
{
$autoBudget = new BillWarningCronjob();
$autoBudget->setForce($force);
$subscriptionWarningJob = new BillWarningCronjob();
$subscriptionWarningJob->setForce($force);
// set date in cron job:
if ($date instanceof Carbon) {
$autoBudget->setDate($date);
$subscriptionWarningJob->setDate($date);
}
$autoBudget->fire();
$subscriptionWarningJob->fire();
if ($autoBudget->jobErrored) {
$this->friendlyError(sprintf('Error in "bill warnings" cron: %s', $autoBudget->message));
if ($subscriptionWarningJob->jobErrored) {
$this->friendlyError(sprintf('Error in "subscription warnings" cron: %s', $subscriptionWarningJob->message));
}
if ($autoBudget->jobFired) {
$this->friendlyInfo(sprintf('"Send bill warnings" cron fired: %s', $autoBudget->message));
if ($subscriptionWarningJob->jobFired) {
$this->friendlyInfo(sprintf('"Send subscription warnings" cron fired: %s', $subscriptionWarningJob->message));
}
if ($autoBudget->jobSucceeded) {
$this->friendlyPositive(sprintf('"Send bill warnings" cron ran with success: %s', $autoBudget->message));
if ($subscriptionWarningJob->jobSucceeded) {
$this->friendlyPositive(sprintf('"Send subscription warnings" cron ran with success: %s', $subscriptionWarningJob->message));
}
}

View File

@@ -839,7 +839,7 @@ class GroupCollector implements GroupCollectorInterface
return 'zzz';
}
exit('here we are 2');
return 'zzz';
});
}

View File

@@ -36,6 +36,7 @@ use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Redirector;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\ValidationException;
use Illuminate\View\View;
use Psr\Container\ContainerExceptionInterface;
@@ -94,7 +95,7 @@ class RegisterController extends Controller
$this->validator($request->all())->validate();
$user = $this->createUser($request->all());
app('log')->info(sprintf('Registered new user %s', $user->email));
Log::info(sprintf('Registered new user %s', $user->email));
$owner = new OwnerNotifiable();
event(new RegisteredUser($owner, $user));

View File

@@ -112,7 +112,7 @@ class NewUserController extends Controller
$this->createCashWalletAccount($currency, $language); // create cash wallet account
// store currency preference:
$currencyRepository->makeDefault($currency);
$currencyRepository->makePrimary($currency);
// store frontpage preferences:
$accounts = $this->repository->getAccountsByType([AccountTypeEnum::ASSET->value])->pluck('id')->toArray();

View File

@@ -417,7 +417,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
// currency must be made default.
if (true === $default) {
$this->makeDefault($currency);
$this->makePrimary($currency);
}
/** @var CurrencyUpdateService $service */
@@ -426,7 +426,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
return $service->update($currency, $data);
}
public function makeDefault(TransactionCurrency $currency): void
public function makePrimary(TransactionCurrency $currency): void
{
$current = app('amount')->getPrimaryCurrencyByUserGroup($this->userGroup);
Log::debug(sprintf('Enabled + made default currency %s for user #%d', $currency->code, $this->userGroup->id));

View File

@@ -102,7 +102,7 @@ interface CurrencyRepositoryInterface
public function isFallbackCurrency(TransactionCurrency $currency): bool;
public function makeDefault(TransactionCurrency $currency): void;
public function makePrimary(TransactionCurrency $currency): void;
public function searchCurrency(string $search, int $limit): Collection;

View File

@@ -209,7 +209,7 @@ class UserGroupRepository implements UserGroupRepositoryInterface, UserGroupInte
$currency = $repository->find((int) $data['primary_currency_id']);
}
if (null !== $currency) {
$repository->makeDefault($currency);
$repository->makePrimary($currency);
}

View File

@@ -365,7 +365,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface
// currency must be made default.
if (true === $default) {
$this->makeDefault($currency);
$this->makePrimary($currency);
}
/** @var CurrencyUpdateService $service */
@@ -374,7 +374,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface
return $service->update($currency, $data);
}
public function makeDefault(TransactionCurrency $currency): void
public function makePrimary(TransactionCurrency $currency): void
{
$current = app('amount')->getPrimaryCurrencyByUserGroup($this->userGroup);
Log::debug(sprintf('Enabled + made default currency %s for user #%d', $currency->code, $this->userGroup->id));

View File

@@ -89,7 +89,7 @@ interface CurrencyRepositoryInterface
public function isFallbackCurrency(TransactionCurrency $currency): bool;
public function makeDefault(TransactionCurrency $currency): void;
public function makePrimary(TransactionCurrency $currency): void;
public function searchCurrency(string $search, int $limit): Collection;

View File

@@ -65,55 +65,27 @@ class FrontpageChartGenerator
public function generate(): array
{
Log::debug('Now in generate()');
Log::debug(sprintf('Now in %s', __METHOD__));
$categories = $this->repository->getCategories();
$accounts = $this->accountRepos->getAccountsByType([AccountTypeEnum::DEBT->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::MORTGAGE->value, AccountTypeEnum::ASSET->value, AccountTypeEnum::DEFAULT->value]);
// get expenses + income per category:
$collection = [];
/** @var Category $category */
foreach ($categories as $category) {
// get expenses
$collection[] = $this->collectExpenses($category, $accounts);
}
$collection = $this->collectExpensesAll($categories, $accounts);
// collect for no-category:
$collection[] = $this->collectNoCatExpenses($accounts);
$tempData = array_merge(...$collection);
$noCategory = $this->collectNoCatExpenses($accounts);
$collection = array_merge($collection, $noCategory);
// sort temp array by amount.
$amounts = array_column($tempData, 'sum_float');
array_multisort($amounts, SORT_ASC, $tempData);
$amounts = array_column($collection, 'sum_float');
array_multisort($amounts, SORT_ASC, $collection);
$currencyData = $this->createCurrencyGroups($tempData);
$currencyData = $this->createCurrencyGroups($collection);
return $this->insertValues($currencyData, $tempData);
}
private function collectExpenses(Category $category, Collection $accounts): array
{
Log::debug(sprintf('Collect expenses for category #%d ("%s")', $category->id, $category->name));
$spent = $this->opsRepos->sumExpenses($this->start, $this->end, $accounts, new Collection([$category]));
$tempData = [];
foreach ($spent as $currency) {
Log::debug(sprintf('Spent %s %s', $currency['currency_code'], $currency['sum']));
$this->addCurrency($currency);
$tempData[] = [
'name' => $category->name,
'sum' => $currency['sum'],
'sum_float' => round((float) $currency['sum'], $currency['currency_decimal_places']),
'currency_id' => (int) $currency['currency_id'],
];
}
return $tempData;
return $this->insertValues($currencyData, $collection);
}
private function addCurrency(array $currency): void
{
$currencyId = (int) $currency['currency_id'];
$currencyId = (int)$currency['currency_id'];
$this->currencies[$currencyId] ??= [
'currency_id' => $currencyId,
@@ -133,8 +105,8 @@ class FrontpageChartGenerator
$tempData[] = [
'name' => trans('firefly.no_category'),
'sum' => $currency['sum'],
'sum_float' => round((float) $currency['sum'], $currency['currency_decimal_places'] ?? 2), // intentional float
'currency_id' => (int) $currency['currency_id'],
'sum_float' => round((float)$currency['sum'], $currency['currency_decimal_places'] ?? 2), // intentional float
'currency_id' => (int)$currency['currency_id'],
];
}
@@ -152,7 +124,7 @@ class FrontpageChartGenerator
foreach ($this->currencies as $currencyId => $currency) {
$key = sprintf('spent-%d', $currencyId);
$return[$key] = [
'label' => sprintf('%s (%s)', (string) trans('firefly.spent'), $currency['currency_name']),
'label' => sprintf('%s (%s)', (string)trans('firefly.spent'), $currency['currency_name']),
'type' => 'bar',
'currency_symbol' => $currency['currency_symbol'],
'entries' => $names,
@@ -175,4 +147,28 @@ class FrontpageChartGenerator
return $currencyData;
}
private function collectExpensesAll(Collection $categories, Collection $accounts): array
{
Log::debug(sprintf('Collect expenses for %d category(ies).', count($categories)));
$spent = $this->opsRepos->collectExpenses($this->start, $this->end, $accounts, $categories);
$tempData = [];
foreach ($categories as $category) {
$sums = $this->opsRepos->sumCollectedTransactionsByCategory($spent, $category, 'negative', $this->convertToPrimary);
if (0 === count($sums)) {
continue;
}
foreach ($sums as $currency) {
$this->addCurrency($currency);
$tempData[] = [
'name' => $category->name,
'sum' => $currency['sum'],
'sum_float' => round((float)$currency['sum'], $currency['currency_decimal_places']),
'currency_id' => (int)$currency['currency_id'],
];
}
}
return $tempData;
}
}

View File

@@ -42,6 +42,7 @@ use FireflyIII\Models\Rule;
use FireflyIII\Models\RuleAction;
use FireflyIII\Models\RuleTrigger;
use FireflyIII\Models\Tag;
use FireflyIII\Models\UserGroup;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
@@ -84,6 +85,7 @@ class ExportDataGenerator
private bool $exportTransactions;
private Carbon $start;
private User $user;
private UserGroup $userGroup;
public function __construct()
{
@@ -906,4 +908,9 @@ class ExportDataGenerator
{
$this->start = $start;
}
public function setUserGroup(UserGroup $userGroup): void
{
$this->userGroup = $userGroup;
}
}

View File

@@ -39,6 +39,7 @@ use Illuminate\Support\Facades\Log;
trait ValidatesUserGroupTrait
{
protected ?UserGroup $userGroup = null;
protected ?User $user = null;
/**
* An "undocumented" filter
@@ -101,6 +102,7 @@ trait ValidatesUserGroupTrait
if ($user->hasRoleInGroupOrOwner($group, $role)) {
Log::debug(sprintf('validateUserGroup: User has role "%s" in group #%d, return the group.', $role->value, $groupId));
$this->userGroup = $group;
$this->user = $user;
return $group;
}

View File

@@ -74,8 +74,8 @@ class BudgetLimitEnrichment implements EnrichmentInterface
private function collectIds(): void
{
$this->start = $this->collection->min('start_date');
$this->end = $this->collection->max('end_date');
$this->start = $this->collection->min('start_date') ?? Carbon::now()->startOfMonth();
$this->end = $this->collection->max('end_date') ?? Carbon::now()->endOfMonth();
/** @var BudgetLimit $limit */
foreach ($this->collection as $limit) {

View File

@@ -464,7 +464,7 @@ class Navigation
$displayFormat = (string) trans('config.month_and_day_js', [], $locale);
$diff = $start->diffInMonths($end, true);
// increment by month (for year)
if ($diff >= 1.0001) {
if ($diff >= 1.0001 && $diff < 12.001) {
$increment = 'addMonth';
$displayFormat = (string) trans('config.month_js');
}
@@ -495,7 +495,7 @@ class Navigation
$format = 'Y-m-d';
$diff = $start->diffInMonths($end, true);
// Log::debug(sprintf('preferredCarbonFormat(%s, %s) = %f', $start->format('Y-m-d'), $end->format('Y-m-d'), $diff));
if ($diff >= 1.001) {
if ($diff >= 1.001 && $diff < 12.001) {
// Log::debug(sprintf('Return Y-m because %s', $diff));
$format = 'Y-m';
}
@@ -566,7 +566,7 @@ class Navigation
{
$locale = app('steam')->getLocale();
$diff = $start->diffInMonths($end, true);
if ($diff >= 1.001) {
if ($diff >= 1.001 && $diff < 12.001) {
return (string) trans('config.month_js', [], $locale);
}
@@ -584,7 +584,7 @@ class Navigation
public function preferredEndOfPeriod(Carbon $start, Carbon $end): string
{
$diff = $start->diffInMonths($end, true);
if ($diff >= 1.001) {
if ($diff >= 1.001 && $diff < 12.001) {
return 'endOfMonth';
}
@@ -602,7 +602,7 @@ class Navigation
public function preferredRangeFormat(Carbon $start, Carbon $end): string
{
$diff = $start->diffInMonths($end, true);
if ($diff >= 1.001) {
if ($diff >= 1.001 && $diff < 12.001) {
return '1M';
}
@@ -620,7 +620,7 @@ class Navigation
public function preferredSqlFormat(Carbon $start, Carbon $end): string
{
$diff = $start->diffInMonths($end, true);
if ($diff >= 1.001) {
if ($diff >= 1.001 && $diff < 12.001) {
return '%Y-%m';
}

View File

@@ -66,14 +66,15 @@ trait UserGroupTrait
if ($user instanceof User) {
$this->user = $user;
if (null === $user->userGroup) {
throw new FireflyException(sprintf('User #%d has no user group.', $user->id));
throw new FireflyException(sprintf('User #%d ("%s") has no user group.', $user->id, $user->email));
}
$this->userGroup = $user->userGroup;
return;
}
$class = null === $user ? 'NULL' : $user::class;
throw new FireflyException(sprintf('Object is of class %s, not User.', $user::class));
throw new FireflyException(sprintf('Object is %s, not User.', $class));
}
public function getUserGroup(): ?UserGroup

View File

@@ -24,10 +24,15 @@ declare(strict_types=1);
namespace FireflyIII\Support\Request;
use FireflyIII\Exceptions\FireflyException;
trait GetFilterInstructions
{
private const string INVALID_FILTER = '%INVALID_JAMES_%';
/**
* @throws FireflyException
*/
final public function getFilterInstructions(string $key): array
{
$config = config(sprintf('firefly.filters.allowed.%s', $key));
@@ -48,7 +53,7 @@ trait GetFilterInstructions
switch ($filterType) {
default:
exit(sprintf('Do not support filter type "%s"', $filterType));
throw new FireflyException(sprintf('Do not support filter type "%s"', $filterType));
case 'boolean':
$filterValue = $this->booleanInstruction($filterValue);

View File

@@ -79,8 +79,11 @@ class CategoryTransformer extends AbstractTransformer
];
}
private function beautify(array $array): array
private function beautify(?array $array): ?array
{
if (null === $array) {
return null;
}
$return = [];
foreach ($array as $data) {
$data['sum'] = Steam::bcround($data['sum'], (int)$data['currency_decimal_places']);

View File

@@ -74,7 +74,7 @@ class User extends Authenticatable
use HasApiTokens;
use Notifiable;
use ReturnsIntegerIdTrait;
protected $fillable = ['email', 'password', 'blocked', 'blocked_code'];
protected $fillable = ['email', 'password', 'blocked', 'blocked_code', 'user_group_id'];
protected $hidden = ['password', 'remember_token'];
protected $table = 'users';

View File

@@ -5,7 +5,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## 6.3.0 - 2025-08-xx
> ⚠️ Firefly III v6.3.0 introduces a lot of API changes that deal with multi-currency support. Make sure your beloved apps are updated to support this.
> [!WARNING]
> Firefly III v6.3.0 introduces a lot of API changes that deal with multi-currency support. Make sure your beloved apps are updated to support this.
### Added

26
composer.lock generated
View File

@@ -11771,16 +11771,16 @@
},
{
"name": "phpunit/phpunit",
"version": "12.3.4",
"version": "12.3.5",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "429095031bd38cb5070ca44166bd9dd5a9245dd6"
"reference": "f10ba5f12a256026ad3c7ee4894ffe47f60d7dc7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/429095031bd38cb5070ca44166bd9dd5a9245dd6",
"reference": "429095031bd38cb5070ca44166bd9dd5a9245dd6",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f10ba5f12a256026ad3c7ee4894ffe47f60d7dc7",
"reference": "f10ba5f12a256026ad3c7ee4894ffe47f60d7dc7",
"shasum": ""
},
"require": {
@@ -11802,7 +11802,7 @@
"sebastian/cli-parser": "^4.0.0",
"sebastian/comparator": "^7.1.2",
"sebastian/diff": "^7.0.0",
"sebastian/environment": "^8.0.2",
"sebastian/environment": "^8.0.3",
"sebastian/exporter": "^7.0.0",
"sebastian/global-state": "^8.0.0",
"sebastian/object-enumerator": "^7.0.0",
@@ -11848,7 +11848,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
"source": "https://github.com/sebastianbergmann/phpunit/tree/12.3.4"
"source": "https://github.com/sebastianbergmann/phpunit/tree/12.3.5"
},
"funding": [
{
@@ -11872,20 +11872,20 @@
"type": "tidelift"
}
],
"time": "2025-08-12T07:35:30+00:00"
"time": "2025-08-16T05:20:09+00:00"
},
{
"name": "rector/rector",
"version": "2.1.3",
"version": "2.1.4",
"source": {
"type": "git",
"url": "https://github.com/rectorphp/rector.git",
"reference": "dd430c869fddf4965049c8fd6f5ee49f155cfddf"
"reference": "fe613c528819222f8686a9a037a315ef9d4915b3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/rectorphp/rector/zipball/dd430c869fddf4965049c8fd6f5ee49f155cfddf",
"reference": "dd430c869fddf4965049c8fd6f5ee49f155cfddf",
"url": "https://api.github.com/repos/rectorphp/rector/zipball/fe613c528819222f8686a9a037a315ef9d4915b3",
"reference": "fe613c528819222f8686a9a037a315ef9d4915b3",
"shasum": ""
},
"require": {
@@ -11924,7 +11924,7 @@
],
"support": {
"issues": "https://github.com/rectorphp/rector/issues",
"source": "https://github.com/rectorphp/rector/tree/2.1.3"
"source": "https://github.com/rectorphp/rector/tree/2.1.4"
},
"funding": [
{
@@ -11932,7 +11932,7 @@
"type": "github"
}
],
"time": "2025-08-13T11:43:04+00:00"
"time": "2025-08-15T14:41:36+00:00"
},
{
"name": "sebastian/cli-parser",

View File

@@ -78,8 +78,8 @@ return [
'running_balance_column' => env('USE_RUNNING_BALANCE', false),
// see cer.php for exchange rates feature flag.
],
'version' => '6.3.0-beta.2',
'build_time' => 1755258109,
'version' => '6.3.0',
'build_time' => 1755366750,
'api_version' => '2.1.0', // field is no longer used.
'db_version' => 26,

6
package-lock.json generated
View File

@@ -5700,9 +5700,9 @@
"license": "MIT"
},
"node_modules/electron-to-chromium": {
"version": "1.5.202",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.202.tgz",
"integrity": "sha512-NxbYjRmiHcHXV1Ws3fWUW+SLb62isauajk45LUJ/HgIOkUA7jLZu/X2Iif+X9FBNK8QkF9Zb4Q2mcwXCcY30mg==",
"version": "1.5.203",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.203.tgz",
"integrity": "sha512-uz4i0vLhfm6dLZWbz/iH88KNDV+ivj5+2SA+utpgjKaj9Q0iDLuwk6Idhe9BTxciHudyx6IvTvijhkPvFGUQ0g==",
"dev": true,
"license": "ISC"
},

View File

@@ -31,12 +31,18 @@
failOnRisky="true"
failOnWarning="true"
processIsolation="false"
stopOnError="true"
stopOnFailure="true">
<php>
<env name="APP_ENV" value="testing"/>
<env name="DB_CONNECTION" value="sqlite"/>
<env name="APP_LOG_ENV" value="notice"/>
<env name="DB_DATABASE" value=""/>
<env name="APP_LOG_LEVEL" value="notice"/>
<env name="AUDIT_LOG_LEVEL" value="emergency" />
<env name="QUERY_PARSER_IMPLEMENTATION" value="new"/>
<ini name="xdebug.mode" value="coverage"/>
</php>
<testsuites>
<testsuite name="unit">

View File

@@ -25,7 +25,7 @@ export default class Dashboard {
dashboard(start, end) {
let startStr = format(start, 'y-MM-dd');
let endStr = format(end, 'y-MM-dd');
return api.get('/api/v1/chart/account/dashboard', {params: {start: startStr, end: endStr}});
return api.get('/api/v1/chart/account/overview', {params: {start: startStr, end: endStr}});
}
expense(start, end) {

View File

@@ -25,6 +25,6 @@ export default class Dashboard {
dashboard(start, end) {
let startStr = format(start, 'y-MM-dd');
let endStr = format(end, 'y-MM-dd');
return api.get('/api/v1/chart/budget/dashboard', {params: {start: startStr, end: endStr}});
return api.get('/api/v1/chart/budget/overview', {params: {start: startStr, end: endStr}});
}
}

View File

@@ -25,6 +25,6 @@ export default class Dashboard {
dashboard(start, end) {
let startStr = format(start, 'y-MM-dd');
let endStr = format(end, 'y-MM-dd');
return api.get('/api/v1/chart/category/dashboard', {params: {start: startStr, end: endStr}});
return api.get('/api/v1/chart/category/overview', {params: {start: startStr, end: endStr}});
}
}

View File

@@ -25,7 +25,7 @@ export default class Dashboard {
dashboard(start, end) {
let startStr = format(start, 'y-MM-dd');
let endStr = format(end, 'y-MM-dd');
return api.get('/api/v1/chart/account/dashboard', {params: {start: startStr, end: endStr}});
return api.get('/api/v1/chart/account/overview', {params: {start: startStr, end: endStr}});
}
expense(start, end) {

View File

@@ -25,6 +25,6 @@ export default class Dashboard {
dashboard(start, end) {
let startStr = format(start, 'y-MM-dd');
let endStr = format(end, 'y-MM-dd');
return api.get('/api/v1/chart/budget/dashboard', {params: {start: startStr, end: endStr}});
return api.get('/api/v1/chart/budget/overview', {params: {start: startStr, end: endStr}});
}
}

View File

@@ -25,6 +25,6 @@ export default class Dashboard {
dashboard(start, end) {
let startStr = format(start, 'y-MM-dd');
let endStr = format(end, 'y-MM-dd');
return api.get('/api/v1/chart/category/dashboard', {params: {start: startStr, end: endStr}});
return api.get('/api/v1/chart/category/overview', {params: {start: startStr, end: endStr}});
}
}

View File

@@ -102,10 +102,10 @@ Route::group(
[
'namespace' => 'FireflyIII\Api\V1\Controllers\Chart',
'prefix' => 'v1/chart/balance',
'as' => 'api.v1.chart.balance',
'as' => 'api.v1.chart.balance.',
],
static function (): void {
Route::get('balance', ['uses' => 'BalanceController@balance', 'as' => 'balance.balance']);
Route::get('balance', ['uses' => 'BalanceController@balance', 'as' => 'balance']);
}
);
@@ -617,15 +617,15 @@ Route::group(
static function (): void {
Route::get('', ['uses' => 'ShowController@index', 'as' => 'index']);
Route::post('', ['uses' => 'StoreController@store', 'as' => 'store']);
Route::get('default', ['uses' => 'ShowController@showDefault', 'as' => 'show.default']);
Route::get('native', ['uses' => 'ShowController@showDefault', 'as' => 'show.native']);
Route::get('primary', ['uses' => 'ShowController@showPrimary', 'as' => 'show.primary']);
Route::get('default', ['uses' => 'ShowController@showPrimary', 'as' => 'show.default']);
Route::get('{currency_code}', ['uses' => 'ShowController@show', 'as' => 'show']);
Route::put('{currency_code?}', ['uses' => 'UpdateController@update', 'as' => 'update']);
Route::delete('{currency_code}', ['uses' => 'DestroyController@destroy', 'as' => 'delete']);
Route::post('{currency_code}/enable', ['uses' => 'UpdateController@enable', 'as' => 'enable']);
Route::post('{currency_code}/disable', ['uses' => 'UpdateController@disable', 'as' => 'disable']);
Route::post('{currency_code}/default', ['uses' => 'UpdateController@makeDefault', 'as' => 'default']);
Route::post('{currency_code}/primary', ['uses' => 'UpdateController@makePrimary', 'as' => 'update.primary']);
Route::get('{currency_code}/accounts', ['uses' => 'ListController@accounts', 'as' => 'accounts']);
Route::get('{currency_code}/available-budgets', ['uses' => 'ListController@availableBudgets', 'as' => 'available-budgets']);

View File

@@ -28,8 +28,6 @@ use FireflyIII\Models\Bill;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\integration\TestCase;
use FireflyIII\User;
use FireflyIII\Models\UserGroup;
use Override;
/**
* Class BillControllerTest
@@ -45,21 +43,6 @@ final class BillControllerTest extends TestCase
*/
use RefreshDatabase;
#[Override]
protected function createAuthenticatedUser(): User
{
$userGroup = UserGroup::create(['title' => 'Test Group']);
$user = User::create([
'email' => 'test@email.com',
'password' => 'password',
]);
$user->user_group_id = $userGroup->id;
$user->save();
return $user;
}
private function createTestBills(int $count, User $user): void
{
for ($i = 1; $i <= $count; ++$i) {
@@ -96,7 +79,6 @@ final class BillControllerTest extends TestCase
$response = $this->get(route('api.v1.autocomplete.bills'), ['Accept' => 'application/json']);
$response->assertStatus(200);
$response->assertHeader('Content-Type', 'application/json');
}
public function testGivenAuthenticatedRequestWhenCallingTheBillsEndpointThenReturnsBills(): void

View File

@@ -25,11 +25,9 @@ declare(strict_types=1);
namespace Tests\integration\Api\Autocomplete;
use FireflyIII\Models\Budget;
use FireflyIII\Models\UserGroup;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\integration\TestCase;
use FireflyIII\User;
use Override;
/**
* Class BudgetControllerTest
@@ -45,21 +43,6 @@ final class BudgetControllerTest extends TestCase
*/
use RefreshDatabase;
#[Override]
protected function createAuthenticatedUser(): User
{
$userGroup = UserGroup::create(['title' => 'Test Group']);
$user = User::create([
'email' => 'test@email.com',
'password' => 'password',
]);
$user->user_group_id = $userGroup->id;
$user->save();
return $user;
}
private function createTestBudgets(int $count, User $user): void
{
for ($i = 1; $i <= $count; ++$i) {

View File

@@ -28,8 +28,6 @@ use FireflyIII\Models\Category;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\integration\TestCase;
use FireflyIII\User;
use FireflyIII\Models\UserGroup;
use Override;
/**
* Class CategoryControllerTest
@@ -45,21 +43,6 @@ final class CategoryControllerTest extends TestCase
*/
use RefreshDatabase;
#[Override]
protected function createAuthenticatedUser(): User
{
$userGroup = UserGroup::create(['title' => 'Test Group']);
$user = User::create([
'email' => 'test@email.com',
'password' => 'password',
]);
$user->user_group_id = $userGroup->id;
$user->save();
return $user;
}
private function createTestCategories(int $count, User $user): void
{
for ($i = 1; $i <= $count; ++$i) {

View File

@@ -28,8 +28,6 @@ use FireflyIII\Models\TransactionCurrency;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\integration\TestCase;
use FireflyIII\User;
use FireflyIII\Models\UserGroup;
use Override;
/**
* Class CurrencyControllerTest
@@ -45,22 +43,6 @@ final class CurrencyControllerTest extends TestCase
*/
use RefreshDatabase;
#[Override]
protected function createAuthenticatedUser(): User
{
$userGroup = UserGroup::create(['title' => 'Test Group']);
$user = User::create([
'email' => 'test@email.com',
'password' => 'password',
]);
$user->user_group_id = $userGroup->id;
$user->save();
return $user;
}
private function createTestCurrencies(int $count, bool $enabled): void
{
for ($i = 1; $i <= $count; ++$i) {

View File

@@ -28,8 +28,6 @@ use FireflyIII\Models\ObjectGroup;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\integration\TestCase;
use FireflyIII\User;
use FireflyIII\Models\UserGroup;
use Override;
/**
* Class ObjectGroupControllerTest
@@ -45,22 +43,6 @@ final class ObjectGroupControllerTest extends TestCase
*/
use RefreshDatabase;
#[Override]
protected function createAuthenticatedUser(): User
{
$userGroup = UserGroup::create(['title' => 'Test Group']);
$user = User::create([
'email' => 'test@email.com',
'password' => 'password',
]);
$user->user_group_id = $userGroup->id;
$user->save();
return $user;
}
private function createTestObjectGroups(int $count, User $user): void
{
for ($i = 1; $i <= $count; ++$i) {

View File

@@ -0,0 +1,164 @@
<?php
/*
* BudgetControllerTest.php
* Copyright (c) 2024 tasnim0tantawi
*
* 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/>.
*/
declare(strict_types=1);
namespace Tests\integration\Api\Autocomplete;
use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\integration\TestCase;
/**
* Class BudgetControllerTest
*
* @internal
*
* @coversNothing
*/
final class PiggyBankControllerTest extends TestCase
{
/**
* @covers \FireflyIII\Api\V1\Controllers\Autocomplete\BudgetController
*/
use RefreshDatabase;
private function createTestPiggyBanks(int $count, User $user): void
{
$type = AccountType::whereType(AccountTypeEnum::DEFAULT->value)->first();
if (null === $type) {
$type = AccountType::create(['type' => AccountTypeEnum::DEFAULT->value]);
}
$currency = TransactionCurrency::whereCode('EUR')->first();
if (null === $currency) {
$currency = TransactionCurrency::create(
[
'code' => 'EUR',
'name' => 'Euro',
'symbol' => '€',
]
);
}
for ($i = 1; $i <= $count; ++$i) {
$piggyBank = PiggyBank::create(
[
'user_id' => $user->id,
'name' => 'Piggy bank '.$i,
'target_amount' => 1000,
'transaction_currency_id' => $currency->id,
'target_date' => now()->addDays(30),
'user_group_id' => $user->user_group_id,
'active' => 1,
]
);
$account = Account::create(
[
'user_id' => $user->id,
'name' => 'Account '.$i,
'user_group_id' => $user->user_group_id,
'account_type_id' => $type->id,
'active' => 1,
]
);
$piggyBank->accounts()->save($account);
}
}
public function testGivenAnUnauthenticatedRequestWhenCallingTheBudgetsEndpointThenReturns401HttpCode(): void
{
// test API
$response = $this->get(route('api.v1.autocomplete.piggy-banks'), ['Accept' => 'application/json']);
$response->assertStatus(401);
$response->assertHeader('Content-Type', 'application/json');
$response->assertContent('{"message":"Unauthenticated.","exception":"AuthenticationException"}');
}
public function testGivenAuthenticatedRequestWhenCallingTheBudgetsEndpointThenReturns200HttpCode(): void
{
// act as a user
$user = $this->createAuthenticatedUser();
$this->actingAs($user);
$response = $this->get(route('api.v1.autocomplete.piggy-banks'), ['Accept' => 'application/json']);
$response->assertStatus(200);
$response->assertHeader('Content-Type', 'application/json');
}
public function testGivenAuthenticatedRequestWhenCallingTheBudgetsEndpointThenReturnsBudgets(): void
{
$user = $this->createAuthenticatedUser();
$this->actingAs($user);
$this->createTestPiggyBanks(5, $user);
$response = $this->get(route('api.v1.autocomplete.piggy-banks'), ['Accept' => 'application/json']);
$response->assertStatus(200);
$response->assertHeader('Content-Type', 'application/json');
$response->assertJsonCount(5);
$response->assertJsonFragment(['name' => 'Piggy bank 1']);
$response->assertJsonStructure([
'*' => [
'id',
'name',
],
]);
}
public function testGivenAuthenticatedRequestWhenCallingTheBudgetsEndpointWithQueryThenReturnsBudgetsWithLimit(): void
{
$user = $this->createAuthenticatedUser();
$this->actingAs($user);
$this->createTestPiggyBanks(5, $user);
$response = $this->get(route('api.v1.autocomplete.piggy-banks', [
'query' => 'Piggy',
'limit' => 3,
]), ['Accept' => 'application/json']);
$response->assertStatus(200);
$response->assertHeader('Content-Type', 'application/json');
$response->assertJsonCount(3);
}
public function testGivenAuthenticatedRequestWhenCallingTheBudgetsEndpointWithQueryThenReturnsBudgetsThatMatchQuery(): void
{
$user = $this->createAuthenticatedUser();
$this->actingAs($user);
$this->createTestPiggyBanks(20, $user);
$response = $this->get(route('api.v1.autocomplete.piggy-banks', [
'query' => 'Piggy bank 1',
'limit' => 20,
]), ['Accept' => 'application/json']);
$response->assertStatus(200);
$response->assertHeader('Content-Type', 'application/json');
// Budget 1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 (11)
$response->assertJsonCount(11);
$response->assertJsonMissing(['name' => 'Piggy bank 2']);
}
}

View File

@@ -0,0 +1,50 @@
<?php
declare(strict_types=1);
namespace Tests\integration\Api\Chart;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\integration\TestCase;
/**
* @internal
*
* @coversNothing
*/
final class AccountControllerTest extends TestCase
{
use RefreshDatabase;
private $user;
#[Override]
protected function setUp(): void
{
parent::setUp();
if (!isset($this->user)) {
$this->user = $this->createAuthenticatedUser();
}
$this->actingAs($this->user);
}
public function testGetOverviewChartFails(): void
{
$this->actingAs($this->user);
$response = $this->getJson(route('api.v1.chart.account.overview'));
$response->assertStatus(422);
}
public function testGetOverviewChart(): void
{
$this->actingAs($this->user);
$params = [
'start' => '2024-01-01',
'end' => '2024-01-31',
];
$response = $this->getJson(route('api.v1.chart.account.overview').'?'.http_build_query($params));
$response->assertStatus(200);
}
}

View File

@@ -0,0 +1,50 @@
<?php
declare(strict_types=1);
namespace Tests\integration\Api\Chart;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\integration\TestCase;
/**
* @internal
*
* @coversNothing
*/
final class BalanceControllerTest extends TestCase
{
use RefreshDatabase;
private $user;
#[Override]
protected function setUp(): void
{
parent::setUp();
if (!isset($this->user)) {
$this->user = $this->createAuthenticatedUser();
}
$this->actingAs($this->user);
}
public function testGetOverviewChartFails(): void
{
$this->actingAs($this->user);
$response = $this->getJson(route('api.v1.chart.balance.balance'));
$response->assertStatus(422);
}
public function testGetOverviewChart(): void
{
$this->actingAs($this->user);
$params = [
'start' => '2024-01-01',
'end' => '2024-01-31',
];
$response = $this->getJson(route('api.v1.chart.balance.balance').'?'.http_build_query($params));
$response->assertStatus(200);
}
}

View File

@@ -0,0 +1,50 @@
<?php
declare(strict_types=1);
namespace Tests\integration\Api\Chart;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\integration\TestCase;
/**
* @internal
*
* @coversNothing
*/
final class BudgetControllerTest extends TestCase
{
use RefreshDatabase;
private $user;
#[Override]
protected function setUp(): void
{
parent::setUp();
if (!isset($this->user)) {
$this->user = $this->createAuthenticatedUser();
}
$this->actingAs($this->user);
}
public function testGetOverviewChartFails(): void
{
$this->actingAs($this->user);
$response = $this->getJson(route('api.v1.chart.budget.overview'));
$response->assertStatus(422);
}
public function testGetOverviewChart(): void
{
$this->actingAs($this->user);
$params = [
'start' => '2024-01-01',
'end' => '2024-01-31',
];
$response = $this->getJson(route('api.v1.chart.budget.overview').'?'.http_build_query($params));
$response->assertStatus(200);
}
}

View File

@@ -0,0 +1,50 @@
<?php
declare(strict_types=1);
namespace Tests\integration\Api\Chart;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\integration\TestCase;
/**
* @internal
*
* @coversNothing
*/
final class CategoryControllerTest extends TestCase
{
use RefreshDatabase;
private $user;
#[Override]
protected function setUp(): void
{
parent::setUp();
if (!isset($this->user)) {
$this->user = $this->createAuthenticatedUser();
}
$this->actingAs($this->user);
}
public function testGetOverviewChartFails(): void
{
$this->actingAs($this->user);
$response = $this->getJson(route('api.v1.chart.category.overview'));
$response->assertStatus(422);
}
public function testGetOverviewChart(): void
{
$this->actingAs($this->user);
$params = [
'start' => '2024-01-01',
'end' => '2024-01-31',
];
$response = $this->getJson(route('api.v1.chart.category.overview').'?'.http_build_query($params));
$response->assertStatus(200);
}
}

View File

@@ -23,7 +23,9 @@ declare(strict_types=1);
namespace Tests\integration;
use FireflyIII\Models\GroupMembership;
use FireflyIII\Models\UserGroup;
use FireflyIII\Models\UserRole;
use FireflyIII\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
@@ -54,14 +56,30 @@ abstract class TestCase extends BaseTestCase
];
}
protected function getAuthenticatedUser(): User
{
return User::where('email', 'james@firefly')->first();
}
protected function createAuthenticatedUser(): User
{
$group = UserGroup::create(['title' => 'test@email.com']);
return User::create([
$role = UserRole::where('title', 'owner')->first();
$user = User::create([
'email' => 'test@email.com',
'password' => 'password',
'user_group_id' => $group->id,
]);
GroupMembership::create(
[
'user_id' => $user->id,
'user_group_id' => $group->id,
'user_role_id' => $role->id,
]
);
return $user;
}
}