mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2026-03-21 12:42:10 +00:00
Compare commits
117 Commits
develop-20
...
develop-20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7c09278c8e | ||
|
|
21af34c65a | ||
|
|
594c04b121 | ||
|
|
c50408249b | ||
|
|
b05a38c0e2 | ||
|
|
0bb1afdf6c | ||
|
|
547b83b36e | ||
|
|
134d8c8cf6 | ||
|
|
94144a407d | ||
|
|
15e29d133a | ||
|
|
889ba9f3e6 | ||
|
|
32fe62df03 | ||
|
|
21f9be6504 | ||
|
|
d514792f4d | ||
|
|
5894695ad6 | ||
|
|
7004c9aaf5 | ||
|
|
1893a33d84 | ||
|
|
d345b31cd4 | ||
|
|
a27642024d | ||
|
|
c23ad831d0 | ||
|
|
d50c283973 | ||
|
|
9ea3519585 | ||
|
|
ddb5bc6038 | ||
|
|
b3d048eb67 | ||
|
|
caadef7c64 | ||
|
|
f7c01e6821 | ||
|
|
3a971d738c | ||
|
|
1eb4ae3a2c | ||
|
|
0f30eb59a4 | ||
|
|
9c10b01e8b | ||
|
|
7c4f80a360 | ||
|
|
e5c19f6088 | ||
|
|
b067215ba8 | ||
|
|
a17d10b064 | ||
|
|
859fea532d | ||
|
|
75261a46d9 | ||
|
|
a4a99310ea | ||
|
|
8de0844e55 | ||
|
|
e7a6dd792f | ||
|
|
395ccf8f75 | ||
|
|
dfbfdb6aa2 | ||
|
|
a367ee96bd | ||
|
|
b6b1261df5 | ||
|
|
52b611d7b3 | ||
|
|
bbc96f457b | ||
|
|
490c421ae5 | ||
|
|
48e5adbbfd | ||
|
|
b123f7e6f1 | ||
|
|
bff351bad2 | ||
|
|
2f0a3238c3 | ||
|
|
dc88781607 | ||
|
|
d6c2698eae | ||
|
|
aee804940b | ||
|
|
b53a756e5a | ||
|
|
ff5d83eba5 | ||
|
|
4c10c4a26f | ||
|
|
f75817b44d | ||
|
|
9ad5dfd45b | ||
|
|
9e3b8e6232 | ||
|
|
6c3b4a77b5 | ||
|
|
34b5d9fcf6 | ||
|
|
12bbc91dca | ||
|
|
a77ff6a51f | ||
|
|
62eb054c7f | ||
|
|
13536a2f65 | ||
|
|
19dece287e | ||
|
|
897e1f773e | ||
|
|
5788e18d6d | ||
|
|
c8c4816fe8 | ||
|
|
aa57252b11 | ||
|
|
58e4c26a87 | ||
|
|
ac323f11c4 | ||
|
|
a907f9b2f7 | ||
|
|
8abd2a6604 | ||
|
|
0780390ff6 | ||
|
|
b9d1ed28a5 | ||
|
|
b8ebcdf1a8 | ||
|
|
ac8dbbff6c | ||
|
|
fea89c5231 | ||
|
|
654f2ee489 | ||
|
|
5c18624cf9 | ||
|
|
27ba8e842a | ||
|
|
e504ee204a | ||
|
|
a3a332643c | ||
|
|
464a89f305 | ||
|
|
062c2323e3 | ||
|
|
a37f995872 | ||
|
|
a5b6315cb8 | ||
|
|
ff568653c8 | ||
|
|
21447a9b2f | ||
|
|
238bfc819e | ||
|
|
3fab4668fc | ||
|
|
190050d6cf | ||
|
|
45d623e0c1 | ||
|
|
93fe8dbf42 | ||
|
|
63c49f740f | ||
|
|
bc23bc0173 | ||
|
|
1611cb3819 | ||
|
|
c520e79b85 | ||
|
|
51e005f305 | ||
|
|
133449640d | ||
|
|
c5a126eb61 | ||
|
|
4222d8ffdd | ||
|
|
28ff0a8423 | ||
|
|
4c0e599b01 | ||
|
|
10d2137723 | ||
|
|
f9b7149fc7 | ||
|
|
7c3fb7a95a | ||
|
|
91b7ee06d8 | ||
|
|
84ea19d14c | ||
|
|
9950f79a6b | ||
|
|
e3df7675d3 | ||
|
|
15094097bc | ||
|
|
a07dc4dbc8 | ||
|
|
c86562554b | ||
|
|
19b548a417 | ||
|
|
71698b36e2 |
@@ -33,29 +33,14 @@ parameters:
|
||||
- Illuminate\Database\Eloquent\Model
|
||||
reportUnmatchedIgnoredErrors: true
|
||||
ignoreErrors:
|
||||
# these are actually interesting but not right now:
|
||||
- identifier: larastan.noUnnecessaryCollectionCall
|
||||
- identifier: varTag.differentVariable
|
||||
- identifier: identical.alwaysTrue
|
||||
- identifier: assign.propertyReadOnly
|
||||
- identifier: varTag.nativeType
|
||||
- identifier: property.onlyWritten
|
||||
- identifier: parameter.phpDocType
|
||||
- identifier: property.dynamicName
|
||||
- identifier: property.unusedType
|
||||
- identifier: staticMethod.deprecated
|
||||
# ignore everything but things that BREAK
|
||||
- identifier: property.deprecated
|
||||
- identifier: method.deprecated
|
||||
- identifier: cast.useless
|
||||
- identifier: parameter.deprecatedClass
|
||||
- identifier: method.deprecatedClass
|
||||
- identifier: argument.type
|
||||
- identifier: return.type
|
||||
- identifier: assign.propertyType
|
||||
- identifier: return.unusedType
|
||||
- identifier: return.phpDocType
|
||||
# all errors below I will (probably) never fix.
|
||||
- identifier: property.unusedType # one false positive
|
||||
- identifier: varTag.nativeType # dont even know what im supposed to fix.
|
||||
- identifier: method.notFound # way too many false positives
|
||||
- identifier: catch.neverThrown # plenty of errors that are thrown undocumented
|
||||
- identifier: staticMethod.dynamicName # dont care
|
||||
@@ -68,9 +53,6 @@ parameters:
|
||||
# - '#expects view-string, string given#'
|
||||
# - "#Parameter \\#[1-2] \\$num[1-2] of function bc[a-z]+ expects numeric-string, [a-z\\-|&]+ given#"
|
||||
- identifier: missingType.generics # not interesting enough to fix.
|
||||
-
|
||||
identifier: larastan.noEnvCallsOutsideOfConfig
|
||||
path: ../app/Console/Commands/System/CreatesDatabase.php
|
||||
- identifier: missingType.iterableValue # not interesting enough to fix.
|
||||
- identifier: varTag.type # needs a custom extension for every repository, not gonna happen.
|
||||
# - '#Dynamic call to static method Illuminate#'
|
||||
|
||||
@@ -173,7 +173,7 @@ MAIL_ENCRYPTION=null
|
||||
MAIL_SENDMAIL_COMMAND=
|
||||
|
||||
#
|
||||
# If you use self-signed certificates for your STMP server, you can use the following settings.
|
||||
# If you use self-signed certificates for your SMTP server, you can use the following settings.
|
||||
#
|
||||
MAIL_ALLOW_SELF_SIGNED=false
|
||||
MAIL_VERIFY_PEER=true
|
||||
|
||||
55
.github/pull_request_template.md
vendored
55
.github/pull_request_template.md
vendored
@@ -1,25 +1,50 @@
|
||||
<!--
|
||||
|
||||
Please TALK TO ME FIRST before you open a PR.
|
||||
🙌 Thanks for contributing a pull request. Before you continue:
|
||||
|
||||
1. If you fix a problem that has no ticket, talk to me FIRST.
|
||||
2. If you introduce new financial solutions or concepts, talk to me FIRST.
|
||||
3. If your PR is more than 25 lines, talk to me FIRST.
|
||||
4. If you used AI to write your PR, talk to me FIRST.
|
||||
5. If you fix spelling or code comments, talk to me FIRST.
|
||||
1. If you introduce new financial solutions or concepts, talk to me FIRST.
|
||||
2. If your PR is more than 25 lines, talk to me FIRST.
|
||||
3. If you fix spelling or code comments, talk to me FIRST.
|
||||
|
||||
Wanna talk to me? Open a GitHub Issue, Discussion, or send me an email: james@firefly-iii.org
|
||||
Wanna talk to me? Open a GitHub Issue, Discussion, or email me: james@firefly-iii.org
|
||||
|
||||
See also: https://docs.firefly-iii.org/explanation/support/#contributing-code
|
||||
👀 Please ensure you have taken a look at the contribution guidelines:
|
||||
https://docs.firefly-iii.org/explanation/support/#contributing-code
|
||||
|
||||
Remember that your PR may be CLOSED:
|
||||
|
||||
1. If you do not refer to an existing issue, your PR will be CLOSED.
|
||||
2. If you open a PR on the main branch, your PR will be CLOSED.
|
||||
3. If you only fix a spelling error or code comment, your PR will be CLOSED.
|
||||
|
||||
Thanks again, and happy developing!
|
||||
|
||||
-->
|
||||
|
||||
@JC5
|
||||
|
||||
This PR fixes issue # <!-- mandatory field! -->.
|
||||
#### Reference issues and PRs
|
||||
<!--
|
||||
Example: Fixes #1234. See also #3456.
|
||||
-->
|
||||
|
||||
Changes in this pull request:
|
||||
#### What does this implement/fix? Explain your changes.
|
||||
|
||||
-
|
||||
-
|
||||
-
|
||||
|
||||
|
||||
#### AI usage disclosure
|
||||
<!--
|
||||
If AI tools were involved in creating this PR, please check all boxes that apply
|
||||
below and make sure that you adhere to our Automated Contributions Policy:
|
||||
https://docs.firefly-iii.org/explanation/support/#automated-contributions-policy
|
||||
-->
|
||||
I used AI assistance for:
|
||||
- [ ] Code generation (e.g., when writing an implementation or fixing a bug)
|
||||
- [ ] Test/benchmark generation
|
||||
- [ ] Documentation (including examples)
|
||||
- [ ] Research and understanding
|
||||
|
||||
|
||||
#### Any other comments?
|
||||
|
||||
<!--
|
||||
Thanks for contributing!
|
||||
-->
|
||||
|
||||
25
.github/security.md
vendored
25
.github/security.md
vendored
@@ -3,13 +3,12 @@
|
||||
Firefly III is an application to manage your personal finances. As such, the developer has adopted this security
|
||||
disclosure and response policy to ensure that critical issues are responsibly handled.
|
||||
|
||||
## Supported Versions
|
||||
## Supported versions
|
||||
|
||||
Only the latest Firefly III release is maintained. Applicable fixes, including security fixes, will not backported to
|
||||
older release branches. Please refer to [releases.md](https://github.com/firefly-iii/firefly-iii/blob/main/releases.md)
|
||||
for details.
|
||||
older release branches. Please refer to [releases.md](https://github.com/firefly-iii/firefly-iii/blob/main/releases.md) for details.
|
||||
|
||||
## Reporting a Vulnerability - Private Disclosure Process
|
||||
## Reporting a vulnerability - private disclosure process
|
||||
|
||||
Security is of the highest importance and all security vulnerabilities or suspected security vulnerabilities should be
|
||||
reported to Firefly III privately, to minimize attacks against current users of Firefly III before they are fixed.
|
||||
@@ -28,7 +27,7 @@ within 3 business days, including a detailed plan to investigate the issue and a
|
||||
the meantime. Do not report non-security-impacting bugs through this channel.
|
||||
Use [GitHub issues](https://github.com/firefly-iii/firefly-iii/issues/new/choose) instead.
|
||||
|
||||
### Proposed Email Content
|
||||
### Proposed email content
|
||||
|
||||
Provide a descriptive subject line and in the body of the email include the following information:
|
||||
|
||||
@@ -47,7 +46,7 @@ Provide a descriptive subject line and in the body of the email include the foll
|
||||
* When you know of or suspect a potential vulnerability on another project that is used by Firefly III. For example
|
||||
Firefly III has a dependency on Docker, MySQL, etc.
|
||||
|
||||
## Patch, Release, and Disclosure
|
||||
## Patch, release, and disclosure
|
||||
|
||||
The Firefly III developer will respond to vulnerability reports as follows:
|
||||
|
||||
@@ -75,7 +74,7 @@ The Firefly III developer will respond to vulnerability reports as follows:
|
||||
8. Once the fix is confirmed, the developer will patch the vulnerability in the next patch or minor release. Upon
|
||||
release of the patched version of Firefly III, we will follow the **Public Disclosure Process**.
|
||||
|
||||
### Public Disclosure Process
|
||||
### Public disclosure process
|
||||
|
||||
The developer publishes a public [advisory](https://github.com/firefly-iii/firefly-iii/security/advisories) to the
|
||||
Firefly III community via GitHub. In most cases, additional communication via Mastodon, Gitter and other channels will
|
||||
@@ -97,6 +96,18 @@ III to provide a hardened Firefly III environment. We will not act on any securi
|
||||
safe defaults. Over time, we will work towards improved safe-by-default configuration, taking into account backwards
|
||||
compatibility.
|
||||
|
||||
## Security scanning through automated means
|
||||
|
||||
There is some additional guidance for security vulnerabilities or suspected security vulnerabilities that have been
|
||||
found with the full or partial support of AI coding agents, large language models and other code-scanning tools. These reports are often not applicable, not actually a vulnerability, or just plain wrong. This takes time away from responding to
|
||||
*actual* security vulnerabilities or suspected security vulnerabilities. If you use automated means to search for security vulnerabilities in the Firefly III code base, please take care to:
|
||||
|
||||
1. manually validate the results before you submit a report,
|
||||
2. explain how the vulnerability can actually be abused by a nefarious third party, and
|
||||
3. try to limit the verbosity of your report.
|
||||
|
||||
At the discretion of the maintainer of the developer, your report may be closed without resolve.
|
||||
|
||||
## Credits
|
||||
|
||||
This security policy is based on [Harbor](https://github.com/goharbor/harbor)'s security policy.
|
||||
|
||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -33,7 +33,7 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Import GPG key
|
||||
uses: crazy-max/ghaction-import-gpg@v6
|
||||
uses: crazy-max/ghaction-import-gpg@v7
|
||||
with:
|
||||
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||
passphrase: ${{ secrets.PASSPHRASE }}
|
||||
|
||||
@@ -4,6 +4,7 @@ Over time, many people have contributed to Firefly III. Their efforts are not al
|
||||
Please find below all the people who contributed to the Firefly III code. Their names are mentioned in the year of their first contribution.
|
||||
|
||||
## 2026
|
||||
- Daniel Holøien
|
||||
- Matthew Grove
|
||||
- Cinnamon Pyro
|
||||
- R1DEN
|
||||
|
||||
@@ -80,23 +80,23 @@ final class AccountController extends Controller
|
||||
public function accounts(AutocompleteApiRequest $request): JsonResponse
|
||||
{
|
||||
// Log::debug('Before All.');
|
||||
['types' => $types, 'query' => $query, 'date' => $date, 'limit' => $limit] = $request->attributes->all();
|
||||
['types' => $types, 'query' => $query, 'date' => $date, 'limit' => $limit] = $request->attributes->all();
|
||||
|
||||
$date ??= today(config('app.timezone'));
|
||||
|
||||
// set date to end-of-day for account balance. so it is at $date 23:59:59
|
||||
$date->endOfDay();
|
||||
|
||||
$return = [];
|
||||
$result = $this->repository->searchAccount((string) $query, $types, $limit);
|
||||
$allBalances = Steam::accountsBalancesOptimized($result, $date, $this->primaryCurrency, $this->convertToPrimary);
|
||||
$return = [];
|
||||
$result = $this->repository->searchAccount((string) $query, $types, $limit);
|
||||
$allBalances = Steam::accountsBalancesOptimized($result, $date, $this->primaryCurrency, $this->convertToPrimary);
|
||||
|
||||
/** @var Account $account */
|
||||
foreach ($result as $account) {
|
||||
$nameWithBalance = $account->name;
|
||||
$currency = $this->repository->getAccountCurrency($account) ?? $this->primaryCurrency;
|
||||
$useCurrency = $currency;
|
||||
if (in_array($account->accountType->type, $this->balanceTypes, true)) {
|
||||
if (in_array($account->accountType->type, $this->balanceTypes, strict: true)) {
|
||||
// this one is correct.
|
||||
Log::debug(sprintf('accounts: Call finalAccountBalance with date/time "%s"', $date->toIso8601String()));
|
||||
$balance = $allBalances[$account->id] ?? [];
|
||||
|
||||
@@ -63,7 +63,7 @@ final class BillController extends Controller
|
||||
public function bills(AutocompleteApiRequest $request): JsonResponse
|
||||
{
|
||||
$result = $this->repository->searchBill($request->attributes->get('query'), $request->attributes->get('limit'));
|
||||
$filtered = $result->map(static fn (Bill $item): array => ['id' => (string) $item->id, 'name' => $item->name, 'active' => $item->active]);
|
||||
$filtered = $result->map(static fn (Bill $item): array => ['id' => (string) $item->id, 'name' => $item->name, 'active' => $item->active]);
|
||||
|
||||
return response()->api($filtered->toArray());
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ final class BudgetController extends Controller
|
||||
public function budgets(AutocompleteApiRequest $request): JsonResponse
|
||||
{
|
||||
$result = $this->repository->searchBudget($request->attributes->get('query'), $request->attributes->get('limit'));
|
||||
$filtered = $result->map(static fn (Budget $item): array => ['id' => (string) $item->id, 'name' => $item->name, 'active' => $item->active]);
|
||||
$filtered = $result->map(static fn (Budget $item): array => ['id' => (string) $item->id, 'name' => $item->name, 'active' => $item->active]);
|
||||
|
||||
return response()->api($filtered->toArray());
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ final class CategoryController extends Controller
|
||||
public function categories(AutocompleteApiRequest $request): JsonResponse
|
||||
{
|
||||
$result = $this->repository->searchCategory($request->attributes->get('query'), $request->attributes->get('limit'));
|
||||
$filtered = $result->map(static fn (Category $item): array => ['id' => (string) $item->id, 'name' => $item->name]);
|
||||
$filtered = $result->map(static fn (Category $item): array => ['id' => (string) $item->id, 'name' => $item->name]);
|
||||
|
||||
return response()->api($filtered->toArray());
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ final class ObjectGroupController extends Controller
|
||||
|
||||
/** @var ObjectGroup $objectGroup */
|
||||
foreach ($result as $objectGroup) {
|
||||
$return[] = ['id' => (string) $objectGroup->id, 'name' => $objectGroup->title, 'title' => $objectGroup->title];
|
||||
$return[] = ['id' => (string) $objectGroup->id, 'name' => $objectGroup->title, 'title' => $objectGroup->title];
|
||||
}
|
||||
|
||||
return response()->api($return);
|
||||
|
||||
@@ -63,7 +63,7 @@ final class TagController extends Controller
|
||||
|
||||
/** @var Tag $tag */
|
||||
foreach ($result as $tag) {
|
||||
$array[] = ['id' => (string) $tag->id, 'name' => $tag->tag, 'tag' => $tag->tag];
|
||||
$array[] = ['id' => (string) $tag->id, 'name' => $tag->tag, 'tag' => $tag->tag];
|
||||
}
|
||||
|
||||
return response()->api($array);
|
||||
|
||||
@@ -62,7 +62,7 @@ final class TransactionTypeController extends Controller
|
||||
/** @var TransactionType $type */
|
||||
foreach ($types as $type) {
|
||||
// different key for consistency.
|
||||
$array[] = ['id' => (string) $type->id, 'name' => $type->type, 'type' => $type->type];
|
||||
$array[] = ['id' => (string) $type->id, 'name' => $type->type, 'type' => $type->type];
|
||||
}
|
||||
|
||||
return response()->api($array);
|
||||
|
||||
@@ -220,7 +220,7 @@ final class BudgetController extends Controller
|
||||
'end_date' => $row['end'],
|
||||
'yAxisID' => 0,
|
||||
'type' => 'bar',
|
||||
'entries' => ['budgeted' => $row['budgeted'], 'spent' => $row['spent'], 'left' => $row['left'], 'overspent' => $row['overspent']],
|
||||
'entries' => ['budgeted' => $row['budgeted'], 'spent' => $row['spent'], 'left' => $row['left'], 'overspent' => $row['overspent']],
|
||||
'pc_entries' => [
|
||||
'budgeted' => $row['pc_budgeted'],
|
||||
'spent' => $row['pc_spent'],
|
||||
|
||||
@@ -153,8 +153,8 @@ final class CategoryController extends Controller
|
||||
'end_date' => $end->toAtomString(),
|
||||
'yAxisID' => 0,
|
||||
'type' => 'bar',
|
||||
'entries' => ['spent' => '0', 'earned' => '0'],
|
||||
'pc_entries' => ['spent' => '0', 'earned' => '0'],
|
||||
'entries' => ['spent' => '0', 'earned' => '0'],
|
||||
'pc_entries' => ['spent' => '0', 'earned' => '0'],
|
||||
];
|
||||
|
||||
// add monies
|
||||
|
||||
@@ -171,6 +171,9 @@ abstract class Controller extends BaseController
|
||||
return $manager->createData($resource)->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
#[Deprecated(message: <<<'TXT'
|
||||
use Request classes
|
||||
Method to grab all parameters from the URL
|
||||
@@ -224,7 +227,8 @@ abstract class Controller extends BaseController
|
||||
$value = min(max(1, $value), 2 ** 16);
|
||||
$bag->set($integer, $value);
|
||||
}
|
||||
if (null === $value && 'limit' === $integer && auth()->check()) {
|
||||
// && 'limit' === $integer
|
||||
if (null === $value && auth()->check()) {
|
||||
// set default for user:
|
||||
/** @var User $user */
|
||||
$user = auth()->user();
|
||||
|
||||
@@ -185,6 +185,8 @@ final class DestroyController extends Controller
|
||||
/** @var BudgetRepositoryInterface $budgetRepository */
|
||||
$budgetRepository = app(BudgetRepositoryInterface::class);
|
||||
$budgetRepository->destroyAll();
|
||||
|
||||
$abRepository->cleanup();
|
||||
}
|
||||
|
||||
private function destroyCategories(): void
|
||||
|
||||
@@ -70,21 +70,21 @@ final class ListController extends Controller
|
||||
|
||||
public function attachments(PaginationRequest $request, Account $account): JsonResponse
|
||||
{
|
||||
$manager = $this->getManager();
|
||||
['limit' => $limit, 'offset' => $offset, 'page' => $page] = $request->attributes->all();
|
||||
$collection = $this->repository->getAttachments($account);
|
||||
$manager = $this->getManager();
|
||||
['limit' => $limit, 'offset' => $offset, 'page' => $page] = $request->attributes->all();
|
||||
$collection = $this->repository->getAttachments($account);
|
||||
|
||||
$count = $collection->count();
|
||||
$attachments = $collection->slice($offset, $limit);
|
||||
$count = $collection->count();
|
||||
$attachments = $collection->slice($offset, $limit);
|
||||
|
||||
// make paginator:
|
||||
$paginator = new LengthAwarePaginator($attachments, $count, $limit, $page);
|
||||
$paginator = new LengthAwarePaginator($attachments, $count, $limit, $page);
|
||||
$paginator->setPath(route('api.v1.accounts.attachments', [$account->id]).$this->buildParams());
|
||||
|
||||
/** @var AttachmentTransformer $transformer */
|
||||
$transformer = app(AttachmentTransformer::class);
|
||||
$transformer = app(AttachmentTransformer::class);
|
||||
|
||||
$resource = new FractalCollection($attachments, $transformer, 'attachments');
|
||||
$resource = new FractalCollection($attachments, $transformer, 'attachments');
|
||||
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||
@@ -93,31 +93,31 @@ final class ListController extends Controller
|
||||
public function piggyBanks(PaginationRequest $request, Account $account): JsonResponse
|
||||
{
|
||||
// create some objects:
|
||||
$manager = $this->getManager();
|
||||
$manager = $this->getManager();
|
||||
|
||||
['limit' => $limit, 'offset' => $offset, 'page' => $page] = $request->attributes->all();
|
||||
['limit' => $limit, 'offset' => $offset, 'page' => $page] = $request->attributes->all();
|
||||
|
||||
// get list of piggy banks. Count it and split it.
|
||||
$collection = $this->repository->getPiggyBanks($account);
|
||||
$count = $collection->count();
|
||||
$piggyBanks = $collection->slice($offset, $limit);
|
||||
$collection = $this->repository->getPiggyBanks($account);
|
||||
$count = $collection->count();
|
||||
$piggyBanks = $collection->slice($offset, $limit);
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new PiggyBankEnrichment();
|
||||
$admin = auth()->user();
|
||||
$enrichment = new PiggyBankEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$piggyBanks = $enrichment->enrich($piggyBanks);
|
||||
$piggyBanks = $enrichment->enrich($piggyBanks);
|
||||
|
||||
// make paginator:
|
||||
$paginator = new LengthAwarePaginator($piggyBanks, $count, $limit, $page);
|
||||
$paginator = new LengthAwarePaginator($piggyBanks, $count, $limit, $page);
|
||||
$paginator->setPath(route('api.v1.accounts.piggy-banks', [$account->id]).$this->buildParams());
|
||||
|
||||
/** @var PiggyBankTransformer $transformer */
|
||||
$transformer = app(PiggyBankTransformer::class);
|
||||
$transformer = app(PiggyBankTransformer::class);
|
||||
// $transformer->setParameters($this->parameters);
|
||||
|
||||
$resource = new FractalCollection($piggyBanks, $transformer, 'piggy-banks');
|
||||
$resource = new FractalCollection($piggyBanks, $transformer, 'piggy-banks');
|
||||
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||
@@ -128,16 +128,16 @@ final class ListController extends Controller
|
||||
*/
|
||||
public function transactions(PaginationDateRangeRequest $request, Account $account): JsonResponse
|
||||
{
|
||||
['limit' => $limit, 'page' => $page, 'start' => $start, 'end' => $end, 'type' => $type] = $request->attributes->all();
|
||||
$types = $this->mapTransactionTypes($type ?? 'default');
|
||||
$manager = $this->getManager();
|
||||
['limit' => $limit, 'page' => $page, 'start' => $start, 'end' => $end, 'type' => $type] = $request->attributes->all();
|
||||
$types = $this->mapTransactionTypes($type ?? 'default');
|
||||
$manager = $this->getManager();
|
||||
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$admin = auth()->user();
|
||||
|
||||
// use new group collector:
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setUser($admin)->setAccounts(new Collection()->push($account))->withAPIInformation()->setLimit($limit)->setPage($page)->setTypes($types);
|
||||
if (null !== $start) {
|
||||
$collector->setStart($start);
|
||||
@@ -146,18 +146,18 @@ final class ListController extends Controller
|
||||
$collector->setEnd($end);
|
||||
}
|
||||
|
||||
$paginator = $collector->getPaginatedGroups();
|
||||
$paginator = $collector->getPaginatedGroups();
|
||||
$paginator->setPath(route('api.v1.accounts.transactions', [$account->id]).$this->buildParams());
|
||||
|
||||
// enrich
|
||||
$enrichment = new TransactionGroupEnrichment();
|
||||
$enrichment = new TransactionGroupEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$transactions = $enrichment->enrich($paginator->getCollection());
|
||||
$transactions = $enrichment->enrich($paginator->getCollection());
|
||||
|
||||
/** @var TransactionGroupTransformer $transformer */
|
||||
$transformer = app(TransactionGroupTransformer::class);
|
||||
$transformer = app(TransactionGroupTransformer::class);
|
||||
|
||||
$resource = new FractalCollection($transactions, $transformer, 'transactions');
|
||||
$resource = new FractalCollection($transactions, $transformer, 'transactions');
|
||||
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||
|
||||
@@ -124,22 +124,22 @@ final class ShowController extends Controller
|
||||
// get list of accounts. Count it and split it.
|
||||
$this->repository->resetAccountOrder();
|
||||
$account->refresh();
|
||||
$manager = $this->getManager();
|
||||
['start' => $start, 'end' => $end, 'date' => $date] = $request->attributes->all();
|
||||
$manager = $this->getManager();
|
||||
['start' => $start, 'end' => $end, 'date' => $date] = $request->attributes->all();
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new AccountEnrichment();
|
||||
$admin = auth()->user();
|
||||
$enrichment = new AccountEnrichment();
|
||||
$enrichment->setDate($date);
|
||||
$enrichment->setStart($start);
|
||||
$enrichment->setEnd($end);
|
||||
$enrichment->setUser($admin);
|
||||
$account = $enrichment->enrichSingle($account);
|
||||
$account = $enrichment->enrichSingle($account);
|
||||
|
||||
/** @var AccountTransformer $transformer */
|
||||
$transformer = app(AccountTransformer::class);
|
||||
$resource = new Item($account, $transformer, self::RESOURCE_KEY);
|
||||
$transformer = app(AccountTransformer::class);
|
||||
$resource = new Item($account, $transformer, self::RESOURCE_KEY);
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ final class ShowController extends Controller
|
||||
*/
|
||||
public function index(PaginationRequest $request): JsonResponse
|
||||
{
|
||||
['limit' => $limit, 'offset' => $offset, 'page' => $page] = $request->attributes->all();
|
||||
['limit' => $limit, 'offset' => $offset, 'page' => $page] = $request->attributes->all();
|
||||
|
||||
if (true === auth()->user()->hasRole('demo')) {
|
||||
Log::channel('audit')->warning(sprintf('Demo user tries to access attachment API in %s', __METHOD__));
|
||||
@@ -129,21 +129,21 @@ final class ShowController extends Controller
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
|
||||
$manager = $this->getManager();
|
||||
$manager = $this->getManager();
|
||||
|
||||
// get list of attachments. Count it and split it.
|
||||
$collection = $this->repository->get();
|
||||
$count = $collection->count();
|
||||
$attachments = $collection->slice($offset, $limit);
|
||||
$collection = $this->repository->get();
|
||||
$count = $collection->count();
|
||||
$attachments = $collection->slice($offset, $limit);
|
||||
|
||||
// make paginator:
|
||||
$paginator = new LengthAwarePaginator($attachments, $count, $limit, $page);
|
||||
$paginator = new LengthAwarePaginator($attachments, $count, $limit, $page);
|
||||
$paginator->setPath(route('api.v1.attachments.index').$this->buildParams());
|
||||
|
||||
/** @var AttachmentTransformer $transformer */
|
||||
$transformer = app(AttachmentTransformer::class);
|
||||
$transformer = app(AttachmentTransformer::class);
|
||||
|
||||
$resource = new FractalCollection($attachments, $transformer, 'attachments');
|
||||
$resource = new FractalCollection($attachments, $transformer, 'attachments');
|
||||
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||
|
||||
@@ -68,29 +68,29 @@ final class ShowController extends Controller
|
||||
*/
|
||||
public function index(PaginationDateRangeRequest $request): JsonResponse
|
||||
{
|
||||
$manager = $this->getManager();
|
||||
['limit' => $limit, 'offset' => $offset, 'page' => $page, 'start' => $start, 'end' => $end] = $request->attributes->all();
|
||||
$manager = $this->getManager();
|
||||
['limit' => $limit, 'offset' => $offset, 'page' => $page, 'start' => $start, 'end' => $end] = $request->attributes->all();
|
||||
|
||||
// get list of available budgets. Count it and split it.
|
||||
$collection = $this->abRepository->getAvailableBudgetsByDate($start, $end);
|
||||
$count = $collection->count();
|
||||
$availableBudgets = $collection->slice($offset, $limit);
|
||||
$collection = $this->abRepository->getAvailableBudgetsByDate($start, $end);
|
||||
$count = $collection->count();
|
||||
$availableBudgets = $collection->slice($offset, $limit);
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new AvailableBudgetEnrichment();
|
||||
$admin = auth()->user();
|
||||
$enrichment = new AvailableBudgetEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$availableBudgets = $enrichment->enrich($availableBudgets);
|
||||
$availableBudgets = $enrichment->enrich($availableBudgets);
|
||||
|
||||
// make paginator:
|
||||
$paginator = new LengthAwarePaginator($availableBudgets, $count, $limit, $page);
|
||||
$paginator = new LengthAwarePaginator($availableBudgets, $count, $limit, $page);
|
||||
$paginator->setPath(route('api.v1.available-budgets.index').$this->buildParams());
|
||||
|
||||
/** @var AvailableBudgetTransformer $transformer */
|
||||
$transformer = app(AvailableBudgetTransformer::class);
|
||||
$transformer = app(AvailableBudgetTransformer::class);
|
||||
|
||||
$resource = new FractalCollection($availableBudgets, $transformer, 'available_budgets');
|
||||
$resource = new FractalCollection($availableBudgets, $transformer, 'available_budgets');
|
||||
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||
|
||||
@@ -72,21 +72,21 @@ final class ListController extends Controller
|
||||
*/
|
||||
public function attachments(PaginationRequest $request, Bill $bill): JsonResponse
|
||||
{
|
||||
['limit' => $limit, 'offset' => $offset, 'page' => $page] = $request->attributes->all();
|
||||
$manager = $this->getManager();
|
||||
$collection = $this->repository->getAttachments($bill);
|
||||
['limit' => $limit, 'offset' => $offset, 'page' => $page] = $request->attributes->all();
|
||||
$manager = $this->getManager();
|
||||
$collection = $this->repository->getAttachments($bill);
|
||||
|
||||
$count = $collection->count();
|
||||
$attachments = $collection->slice($offset, $limit);
|
||||
$count = $collection->count();
|
||||
$attachments = $collection->slice($offset, $limit);
|
||||
|
||||
// make paginator:
|
||||
$paginator = new LengthAwarePaginator($attachments, $count, $limit, $page);
|
||||
$paginator = new LengthAwarePaginator($attachments, $count, $limit, $page);
|
||||
$paginator->setPath(route('api.v1.bills.attachments', [$bill->id]).$this->buildParams());
|
||||
|
||||
/** @var AttachmentTransformer $transformer */
|
||||
$transformer = app(AttachmentTransformer::class);
|
||||
$transformer = app(AttachmentTransformer::class);
|
||||
|
||||
$resource = new FractalCollection($attachments, $transformer, 'attachments');
|
||||
$resource = new FractalCollection($attachments, $transformer, 'attachments');
|
||||
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||
@@ -100,20 +100,20 @@ final class ListController extends Controller
|
||||
*/
|
||||
public function rules(PaginationRequest $request, Bill $bill): JsonResponse
|
||||
{
|
||||
['limit' => $limit, 'offset' => $offset, 'page' => $page] = $request->attributes->all();
|
||||
['limit' => $limit, 'offset' => $offset, 'page' => $page] = $request->attributes->all();
|
||||
|
||||
$manager = $this->getManager();
|
||||
$collection = $this->repository->getRulesForBill($bill);
|
||||
$count = $collection->count();
|
||||
$rules = $collection->slice($offset, $limit);
|
||||
$manager = $this->getManager();
|
||||
$collection = $this->repository->getRulesForBill($bill);
|
||||
$count = $collection->count();
|
||||
$rules = $collection->slice($offset, $limit);
|
||||
|
||||
// make paginator:
|
||||
$paginator = new LengthAwarePaginator($rules, $count, $limit, $page);
|
||||
$paginator = new LengthAwarePaginator($rules, $count, $limit, $page);
|
||||
$paginator->setPath(route('api.v1.bills.rules', [$bill->id]).$this->buildParams());
|
||||
|
||||
/** @var RuleTransformer $transformer */
|
||||
$transformer = app(RuleTransformer::class);
|
||||
$resource = new FractalCollection($rules, $transformer, 'rules');
|
||||
$transformer = app(RuleTransformer::class);
|
||||
$resource = new FractalCollection($rules, $transformer, 'rules');
|
||||
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||
@@ -127,16 +127,16 @@ final class ListController extends Controller
|
||||
*/
|
||||
public function transactions(PaginationDateRangeRequest $request, Bill $bill): JsonResponse
|
||||
{
|
||||
['limit' => $limit, 'page' => $page, 'types' => $types, 'start' => $start, 'end' => $end] = $request->attributes->all();
|
||||
['limit' => $limit, 'page' => $page, 'types' => $types, 'start' => $start, 'end' => $end] = $request->attributes->all();
|
||||
|
||||
$manager = $this->getManager();
|
||||
$manager = $this->getManager();
|
||||
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$admin = auth()->user();
|
||||
|
||||
// use new group collector:
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector
|
||||
->setUser($admin)
|
||||
// include source + destination account name and type.
|
||||
@@ -159,18 +159,18 @@ final class ListController extends Controller
|
||||
}
|
||||
|
||||
// get paginator.
|
||||
$paginator = $collector->getPaginatedGroups();
|
||||
$paginator = $collector->getPaginatedGroups();
|
||||
$paginator->setPath(route('api.v1.bills.transactions', [$bill->id]).$this->buildParams());
|
||||
|
||||
// enrich
|
||||
$enrichment = new TransactionGroupEnrichment();
|
||||
$enrichment = new TransactionGroupEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$transactions = $enrichment->enrich($paginator->getCollection());
|
||||
$transactions = $enrichment->enrich($paginator->getCollection());
|
||||
|
||||
/** @var TransactionGroupTransformer $transformer */
|
||||
$transformer = app(TransactionGroupTransformer::class);
|
||||
$transformer = app(TransactionGroupTransformer::class);
|
||||
|
||||
$resource = new FractalCollection($transactions, $transformer, 'transactions');
|
||||
$resource = new FractalCollection($transactions, $transformer, 'transactions');
|
||||
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||
|
||||
@@ -67,28 +67,28 @@ final class ShowController extends Controller
|
||||
*/
|
||||
public function index(PaginationDateRangeRequest $request): JsonResponse
|
||||
{
|
||||
['limit' => $limit, 'offset' => $offset, 'start' => $start, 'end' => $end, 'page' => $page] = $request->attributes->all();
|
||||
['limit' => $limit, 'offset' => $offset, 'start' => $start, 'end' => $end, 'page' => $page] = $request->attributes->all();
|
||||
|
||||
$this->repository->correctOrder();
|
||||
$bills = $this->repository->getBills();
|
||||
$manager = $this->getManager();
|
||||
$count = $bills->count();
|
||||
$bills = $bills->slice($offset, $limit);
|
||||
$paginator = new LengthAwarePaginator($bills, $count, $limit, $page);
|
||||
$bills = $this->repository->getBills();
|
||||
$manager = $this->getManager();
|
||||
$count = $bills->count();
|
||||
$bills = $bills->slice($offset, $limit);
|
||||
$paginator = new LengthAwarePaginator($bills, $count, $limit, $page);
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new SubscriptionEnrichment();
|
||||
$admin = auth()->user();
|
||||
$enrichment = new SubscriptionEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$enrichment->setStart($start);
|
||||
$enrichment->setEnd($end);
|
||||
$bills = $enrichment->enrich($bills);
|
||||
$bills = $enrichment->enrich($bills);
|
||||
|
||||
/** @var BillTransformer $transformer */
|
||||
$transformer = app(BillTransformer::class);
|
||||
$transformer = app(BillTransformer::class);
|
||||
|
||||
$resource = new FractalCollection($bills, $transformer, 'bills');
|
||||
$resource = new FractalCollection($bills, $transformer, 'bills');
|
||||
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||
@@ -102,23 +102,23 @@ final class ShowController extends Controller
|
||||
*/
|
||||
public function show(DateRangeRequest $request, Bill $bill): JsonResponse
|
||||
{
|
||||
['start' => $start, 'end' => $end] = $request->attributes->all();
|
||||
['start' => $start, 'end' => $end] = $request->attributes->all();
|
||||
|
||||
$manager = $this->getManager();
|
||||
$manager = $this->getManager();
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new SubscriptionEnrichment();
|
||||
$admin = auth()->user();
|
||||
$enrichment = new SubscriptionEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$enrichment->setStart($start);
|
||||
$enrichment->setEnd($end);
|
||||
$bill = $enrichment->enrichSingle($bill);
|
||||
$bill = $enrichment->enrichSingle($bill);
|
||||
|
||||
/** @var BillTransformer $transformer */
|
||||
$transformer = app(BillTransformer::class);
|
||||
$transformer = app(BillTransformer::class);
|
||||
|
||||
$resource = new Item($bill, $transformer, 'bills');
|
||||
$resource = new Item($bill, $transformer, 'bills');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||
}
|
||||
|
||||
@@ -83,7 +83,6 @@ final class StoreController extends Controller
|
||||
|
||||
/** @var BillTransformer $transformer */
|
||||
$transformer = app(BillTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
$resource = new Item($bill, $transformer, 'bills');
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Api\V1\Controllers\Models\BudgetLimit;
|
||||
|
||||
use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Api\V1\Requests\Data\SameDateRequest;
|
||||
use FireflyIII\Api\V1\Requests\DateRangeRequest;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
@@ -118,12 +118,12 @@ final class ShowController extends Controller
|
||||
*
|
||||
* @SuppressWarnings("PHPMD.UnusedFormalParameter")
|
||||
*/
|
||||
public function indexAll(SameDateRequest $request): JsonResponse
|
||||
public function indexAll(DateRangeRequest $request): JsonResponse
|
||||
{
|
||||
$manager = $this->getManager();
|
||||
$manager->parseIncludes('budget');
|
||||
$pageSize = $this->parameters->get('limit');
|
||||
$collection = $this->blRepository->getAllBudgetLimits($this->parameters->get('start'), $this->parameters->get('end'));
|
||||
$collection = $this->blRepository->getAllBudgetLimits($request->attributes->get('start'), $request->attributes->get('end'));
|
||||
$count = $collection->count();
|
||||
$budgetLimits = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
|
||||
$paginator = new LengthAwarePaginator($budgetLimits, $count, $pageSize, $this->parameters->get('page'));
|
||||
|
||||
@@ -28,6 +28,7 @@ use Carbon\Carbon;
|
||||
use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Api\V1\Requests\Models\CurrencyExchangeRate\DestroyRequest;
|
||||
use FireflyIII\Enums\UserRoleEnum;
|
||||
use FireflyIII\Events\Model\CurrencyExchangeRate\DestroyedCurrencyExchangeRate;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\CurrencyExchangeRate;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
@@ -59,11 +60,12 @@ final class DestroyController extends Controller
|
||||
public function destroy(DestroyRequest $request, TransactionCurrency $from, TransactionCurrency $to): JsonResponse
|
||||
{
|
||||
$this->repository->deleteRates($from, $to);
|
||||
event(new DestroyedCurrencyExchangeRate($from, $to, $this->validateUserGroup($request)));
|
||||
|
||||
return response()->json([], 204);
|
||||
}
|
||||
|
||||
public function destroySingleByDate(TransactionCurrency $from, TransactionCurrency $to, Carbon $date): JsonResponse
|
||||
public function destroySingleByDate(Request $request, TransactionCurrency $from, TransactionCurrency $to, Carbon $date): JsonResponse
|
||||
{
|
||||
$exchangeRate = $this->repository->getSpecificRateOnDate($from, $to, $date);
|
||||
if ($exchangeRate instanceof CurrencyExchangeRate) {
|
||||
@@ -72,14 +74,19 @@ final class DestroyController extends Controller
|
||||
if (!$exchangeRate instanceof CurrencyExchangeRate) {
|
||||
throw new FireflyException('Bla');
|
||||
}
|
||||
event(new DestroyedCurrencyExchangeRate($from, $to, $this->validateUserGroup($request)));
|
||||
|
||||
return response()->json([], 204);
|
||||
}
|
||||
|
||||
public function destroySingleById(CurrencyExchangeRate $exchangeRate): JsonResponse
|
||||
public function destroySingleById(Request $request, CurrencyExchangeRate $exchangeRate): JsonResponse
|
||||
{
|
||||
$from = $exchangeRate->fromCurrency;
|
||||
$to = $exchangeRate->toCurrency;
|
||||
$this->repository->deleteRate($exchangeRate);
|
||||
|
||||
event(new DestroyedCurrencyExchangeRate($from, $to, $this->validateUserGroup($request)));
|
||||
|
||||
return response()->json([], 204);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@ use FireflyIII\Api\V1\Requests\Models\CurrencyExchangeRate\StoreByCurrenciesRequ
|
||||
use FireflyIII\Api\V1\Requests\Models\CurrencyExchangeRate\StoreByDateRequest;
|
||||
use FireflyIII\Api\V1\Requests\Models\CurrencyExchangeRate\StoreRequest;
|
||||
use FireflyIII\Enums\UserRoleEnum;
|
||||
use FireflyIII\Events\Model\CurrencyExchangeRate\CreatedCurrencyExchangeRate;
|
||||
use FireflyIII\Events\Model\CurrencyExchangeRate\UpdatedCurrencyExchangeRate;
|
||||
use FireflyIII\Models\CurrencyExchangeRate;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Repositories\ExchangeRate\ExchangeRateRepositoryInterface;
|
||||
@@ -73,10 +75,12 @@ final class StoreController extends Controller
|
||||
if ($object instanceof CurrencyExchangeRate) {
|
||||
// just update it, no matter.
|
||||
$rate = $this->repository->updateExchangeRate($object, $rate, $date);
|
||||
event(new UpdatedCurrencyExchangeRate($rate));
|
||||
}
|
||||
if (!$object instanceof CurrencyExchangeRate) {
|
||||
// store new
|
||||
$rate = $this->repository->storeExchangeRate($from, $to, $rate, $date);
|
||||
event(new CreatedCurrencyExchangeRate($rate));
|
||||
}
|
||||
|
||||
$transformer = new ExchangeRateTransformer();
|
||||
@@ -97,10 +101,12 @@ final class StoreController extends Controller
|
||||
// update existing rate.
|
||||
$existing = $this->repository->updateExchangeRate($existing, $rate);
|
||||
$collection->push($existing);
|
||||
event(new UpdatedCurrencyExchangeRate($existing));
|
||||
|
||||
continue;
|
||||
}
|
||||
$new = $this->repository->storeExchangeRate($from, $to, $rate, $date);
|
||||
event(new CreatedCurrencyExchangeRate($new));
|
||||
$collection->push($new);
|
||||
}
|
||||
|
||||
@@ -124,11 +130,13 @@ final class StoreController extends Controller
|
||||
// update existing rate.
|
||||
$existing = $this->repository->updateExchangeRate($existing, $rate);
|
||||
$collection->push($existing);
|
||||
event(new UpdatedCurrencyExchangeRate($existing));
|
||||
|
||||
continue;
|
||||
}
|
||||
$new = $this->repository->storeExchangeRate($from, $to, $rate, $date);
|
||||
$collection->push($new);
|
||||
event(new CreatedCurrencyExchangeRate($new));
|
||||
}
|
||||
|
||||
$count = $collection->count();
|
||||
|
||||
@@ -28,6 +28,7 @@ use Carbon\Carbon;
|
||||
use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Api\V1\Requests\Models\CurrencyExchangeRate\UpdateRequest;
|
||||
use FireflyIII\Enums\UserRoleEnum;
|
||||
use FireflyIII\Events\Model\CurrencyExchangeRate\UpdatedCurrencyExchangeRate;
|
||||
use FireflyIII\Models\CurrencyExchangeRate;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Repositories\ExchangeRate\ExchangeRateRepositoryInterface;
|
||||
@@ -66,7 +67,7 @@ final class UpdateController extends Controller
|
||||
$date = $request->getDate();
|
||||
$rate = $request->getRate();
|
||||
$exchangeRate = $this->repository->updateExchangeRate($exchangeRate, $rate, $date);
|
||||
|
||||
event(new UpdatedCurrencyExchangeRate($exchangeRate));
|
||||
$transformer = new ExchangeRateTransformer();
|
||||
|
||||
return response()->api($this->jsonApiObject(self::RESOURCE_KEY, $exchangeRate, $transformer))->header('Content-Type', self::CONTENT_TYPE);
|
||||
@@ -77,6 +78,7 @@ final class UpdateController extends Controller
|
||||
$date = $request->getDate();
|
||||
$rate = $request->getRate();
|
||||
$exchangeRate = $this->repository->updateExchangeRate($exchangeRate, $rate, $date);
|
||||
event(new UpdatedCurrencyExchangeRate($exchangeRate));
|
||||
$transformer = new ExchangeRateTransformer();
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
|
||||
@@ -83,6 +83,9 @@ final class ListController extends Controller
|
||||
// use new group collector:
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
if (0 === count($journalIds)) {
|
||||
$collector->findNothing();
|
||||
}
|
||||
$collector
|
||||
->setUser($admin)
|
||||
// filter on journal IDs.
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* TriggerController.php
|
||||
* Copyright (c) 2025 james@firefly-iii.org
|
||||
* Copyright (c) 2026 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -22,10 +20,12 @@ declare(strict_types=1);
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V1\Controllers\Models\Recurrence;
|
||||
|
||||
use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Api\V1\Requests\Generic\SingleDateRequest;
|
||||
use FireflyIII\Api\V1\Requests\DateRequest;
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
use FireflyIII\Jobs\CreateRecurringTransactions;
|
||||
use FireflyIII\Models\Recurrence;
|
||||
@@ -59,12 +59,12 @@ final class TriggerController extends Controller
|
||||
});
|
||||
}
|
||||
|
||||
public function trigger(SingleDateRequest $request, Recurrence $recurrence): JsonResponse
|
||||
public function trigger(DateRequest $request, Recurrence $recurrence): JsonResponse
|
||||
{
|
||||
// find recurrence occurrence for this date and trigger it.
|
||||
// grab the date from the last time the recurrence fired:
|
||||
$backupDate = $recurrence->latest_date;
|
||||
$date = $request->getDate();
|
||||
$date = $request->attributes->get('date');
|
||||
|
||||
// fire the recurring cron job on the given date, then post-date the created transaction.
|
||||
Log::info(sprintf('Trigger: will now fire recurring cron job task for date "%s".', $date->format('Y-m-d H:i:s')));
|
||||
|
||||
@@ -78,15 +78,15 @@ final class TriggerController extends Controller
|
||||
// overrule the rule(s) if necessary.
|
||||
if (array_key_exists('start', $parameters) && null !== $parameters['start']) {
|
||||
// add a range:
|
||||
$ruleEngine->addOperator(['type' => 'date_after', 'value' => $parameters['start']->format('Y-m-d')]);
|
||||
$ruleEngine->addOperator(['type' => 'date_after', 'value' => $parameters['start']->format('Y-m-d')]);
|
||||
}
|
||||
|
||||
if (array_key_exists('end', $parameters) && null !== $parameters['end']) {
|
||||
// add a range:
|
||||
$ruleEngine->addOperator(['type' => 'date_before', 'value' => $parameters['end']->format('Y-m-d')]);
|
||||
$ruleEngine->addOperator(['type' => 'date_before', 'value' => $parameters['end']->format('Y-m-d')]);
|
||||
}
|
||||
if (array_key_exists('accounts', $parameters) && '' !== $parameters['accounts']) {
|
||||
$ruleEngine->addOperator(['type' => 'account_id', 'value' => implode(',', $parameters['accounts'])]);
|
||||
$ruleEngine->addOperator(['type' => 'account_id', 'value' => implode(',', $parameters['accounts'])]);
|
||||
}
|
||||
|
||||
// file the rule(s)
|
||||
@@ -98,7 +98,7 @@ final class TriggerController extends Controller
|
||||
$enrichment->setUser($rule->user);
|
||||
$transactions = $enrichment->enrich($transactions);
|
||||
|
||||
$paginator = new LengthAwarePaginator($transactions, $count, 31337, $this->parameters->get('page'));
|
||||
$paginator = new LengthAwarePaginator($transactions, $count, 31_337, $this->parameters->get('page'));
|
||||
$paginator->setPath(route('api.v1.rules.test', [$rule->id]).$this->buildParams());
|
||||
|
||||
// resulting list is presented as JSON thing.
|
||||
@@ -132,15 +132,15 @@ final class TriggerController extends Controller
|
||||
// overrule the rule(s) if necessary.
|
||||
if (array_key_exists('start', $parameters) && null !== $parameters['start']) {
|
||||
// add a range:
|
||||
$ruleEngine->addOperator(['type' => 'date_after', 'value' => $parameters['start']->format('Y-m-d')]);
|
||||
$ruleEngine->addOperator(['type' => 'date_after', 'value' => $parameters['start']->format('Y-m-d')]);
|
||||
}
|
||||
|
||||
if (array_key_exists('end', $parameters) && null !== $parameters['end']) {
|
||||
// add a range:
|
||||
$ruleEngine->addOperator(['type' => 'date_before', 'value' => $parameters['end']->format('Y-m-d')]);
|
||||
$ruleEngine->addOperator(['type' => 'date_before', 'value' => $parameters['end']->format('Y-m-d')]);
|
||||
}
|
||||
if (array_key_exists('accounts', $parameters) && is_array($parameters['accounts']) && count($parameters['accounts']) > 0) {
|
||||
$ruleEngine->addOperator(['type' => 'account_id', 'value' => implode(',', $parameters['accounts'])]);
|
||||
$ruleEngine->addOperator(['type' => 'account_id', 'value' => implode(',', $parameters['accounts'])]);
|
||||
}
|
||||
|
||||
// fire the rule(s)
|
||||
|
||||
@@ -85,15 +85,15 @@ final class TriggerController extends Controller
|
||||
// overrule the rule(s) if necessary.
|
||||
if (array_key_exists('start', $parameters) && null !== $parameters['start']) {
|
||||
// add a range:
|
||||
$ruleEngine->addOperator(['type' => 'date_after', 'value' => $parameters['start']->format('Y-m-d')]);
|
||||
$ruleEngine->addOperator(['type' => 'date_after', 'value' => $parameters['start']->format('Y-m-d')]);
|
||||
}
|
||||
|
||||
if (array_key_exists('end', $parameters) && null !== $parameters['end']) {
|
||||
// add a range:
|
||||
$ruleEngine->addOperator(['type' => 'date_before', 'value' => $parameters['end']->format('Y-m-d')]);
|
||||
$ruleEngine->addOperator(['type' => 'date_before', 'value' => $parameters['end']->format('Y-m-d')]);
|
||||
}
|
||||
if (array_key_exists('accounts', $parameters) && '' !== $parameters['accounts']) {
|
||||
$ruleEngine->addOperator(['type' => 'account_id', 'value' => implode(',', $parameters['accounts'])]);
|
||||
$ruleEngine->addOperator(['type' => 'account_id', 'value' => implode(',', $parameters['accounts'])]);
|
||||
}
|
||||
|
||||
// file the rule(s)
|
||||
@@ -105,7 +105,7 @@ final class TriggerController extends Controller
|
||||
$enrichment->setUser($group->user);
|
||||
$transactions = $enrichment->enrich($transactions);
|
||||
|
||||
$paginator = new LengthAwarePaginator($transactions, $count, 31337, $this->parameters->get('page'));
|
||||
$paginator = new LengthAwarePaginator($transactions, $count, 31_337, $this->parameters->get('page'));
|
||||
$paginator->setPath(route('api.v1.rule-groups.test', [$group->id]).$this->buildParams());
|
||||
|
||||
// resulting list is presented as JSON thing.
|
||||
@@ -146,15 +146,15 @@ final class TriggerController extends Controller
|
||||
// overrule the rule(s) if necessary.
|
||||
if (array_key_exists('start', $parameters) && null !== $parameters['start']) {
|
||||
// add a range:
|
||||
$ruleEngine->addOperator(['type' => 'date_after', 'value' => $parameters['start']->format('Y-m-d')]);
|
||||
$ruleEngine->addOperator(['type' => 'date_after', 'value' => $parameters['start']->format('Y-m-d')]);
|
||||
}
|
||||
|
||||
if (array_key_exists('end', $parameters) && null !== $parameters['end']) {
|
||||
// add a range:
|
||||
$ruleEngine->addOperator(['type' => 'date_before', 'value' => $parameters['end']->format('Y-m-d')]);
|
||||
$ruleEngine->addOperator(['type' => 'date_before', 'value' => $parameters['end']->format('Y-m-d')]);
|
||||
}
|
||||
if (array_key_exists('accounts', $parameters) && is_array($parameters['accounts']) && count($parameters['accounts']) > 0) {
|
||||
$ruleEngine->addOperator(['type' => 'account_id', 'value' => implode(',', $parameters['accounts'])]);
|
||||
$ruleEngine->addOperator(['type' => 'account_id', 'value' => implode(',', $parameters['accounts'])]);
|
||||
}
|
||||
|
||||
// file the rule(s)
|
||||
|
||||
@@ -48,6 +48,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
final class UpdateController extends Controller
|
||||
{
|
||||
private TransactionGroupRepositoryInterface $groupRepository;
|
||||
protected array $acceptedRoles = [];
|
||||
|
||||
/**
|
||||
* TransactionController constructor.
|
||||
|
||||
@@ -32,6 +32,7 @@ use FireflyIII\Support\Facades\Preferences;
|
||||
use FireflyIII\Support\Http\Api\TransactionFilter;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Class DestroyController
|
||||
@@ -71,6 +72,12 @@ final class DestroyController extends Controller
|
||||
if (false === $linkType->editable) {
|
||||
throw new FireflyException('200020: Link type cannot be changed.');
|
||||
}
|
||||
if (false === auth()->user()->hasRole('owner')) {
|
||||
Log::channel('audit')->warning('Non-owner user tries to delete a link type.');
|
||||
|
||||
return response()->json([], 401);
|
||||
}
|
||||
|
||||
$this->repository->destroy($linkType);
|
||||
Preferences::mark();
|
||||
|
||||
|
||||
@@ -84,6 +84,9 @@ final class ListController extends Controller
|
||||
// use new group collector:
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
if (0 === count($journalIds)) {
|
||||
$collector->findNothing();
|
||||
}
|
||||
$collector
|
||||
->setUser($admin)
|
||||
// filter on journal IDs.
|
||||
|
||||
@@ -52,12 +52,12 @@ final class IndexController extends Controller
|
||||
|
||||
public function index(PaginationRequest $request): JsonResponse
|
||||
{
|
||||
$administrations = $this->repository->get();
|
||||
['page' => $page, 'limit' => $limit, 'offset' => $offset] = $request->attributes->all();
|
||||
$count = $administrations->count();
|
||||
$administrations = $administrations->slice($offset, $limit);
|
||||
$paginator = new LengthAwarePaginator($administrations, $count, $limit, $page);
|
||||
$transformer = new UserGroupTransformer();
|
||||
$administrations = $this->repository->get();
|
||||
['page' => $page, 'limit' => $limit, 'offset' => $offset] = $request->attributes->all();
|
||||
$count = $administrations->count();
|
||||
$administrations = $administrations->slice($offset, $limit);
|
||||
$paginator = new LengthAwarePaginator($administrations, $count, $limit, $page);
|
||||
$transformer = new UserGroupTransformer();
|
||||
|
||||
return response()->json($this->jsonApiList(self::RESOURCE_KEY, $paginator, $transformer))->header('Content-Type', self::CONTENT_TYPE);
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ final class AccountController extends Controller
|
||||
$query = trim((string) $request->get('query'));
|
||||
$field = trim((string) $request->get('field'));
|
||||
$type = $request->get('type') ?? 'all';
|
||||
if ('' === $query || !in_array($field, $this->validFields, true)) {
|
||||
if ('' === $query || !in_array($field, $this->validFields, strict: true)) {
|
||||
return response(null, 422);
|
||||
}
|
||||
Log::debug(sprintf('Now in account search("%s", "%s")', $field, $query));
|
||||
|
||||
@@ -66,7 +66,7 @@ final class TransactionController extends Controller
|
||||
$internalRef = (string) $request->attributes->get('internal_reference');
|
||||
$notes = (string) $request->attributes->get('notes');
|
||||
$description = (string) $request->attributes->get('description');
|
||||
Log::debug(sprintf('Include deleted? %s', var_export($includeDeleted, true)));
|
||||
Log::debug(sprintf('Include deleted? %s', var_export(value: $includeDeleted, return: true)));
|
||||
if ('' !== $externalId) {
|
||||
$count += $this->repository->countByMeta('external_id', $externalId, $includeDeleted);
|
||||
Log::debug(sprintf('Search for transactions with external_identifier "%s", count is now %d', $externalId, $count));
|
||||
|
||||
@@ -81,6 +81,7 @@ final class BasicController extends Controller
|
||||
$this->accountRepository->setUser($user);
|
||||
$this->abRepository->setUser($user);
|
||||
$this->opsRepository->setUser($user);
|
||||
$this->abRepository->cleanup();
|
||||
|
||||
return $next($request);
|
||||
});
|
||||
@@ -89,20 +90,20 @@ final class BasicController extends Controller
|
||||
public function basic(BasicRequest $request): JsonResponse
|
||||
{
|
||||
// parameters for boxes:
|
||||
['start' => $start, 'end' => $end, 'code' => $code] = $request->attributes->all();
|
||||
['start' => $start, 'end' => $end, 'code' => $code] = $request->attributes->all();
|
||||
// balance information:
|
||||
$balanceData = $this->getBalanceInformation($start, $end);
|
||||
$billData = $this->getSubscriptionInformation($start, $end);
|
||||
$spentData = $this->getLeftToSpendInfo($start, $end);
|
||||
$netWorthData = $this->getNetWorthInfo($end);
|
||||
$balanceData = $this->getBalanceInformation($start, $end);
|
||||
$billData = $this->getSubscriptionInformation($start, $end);
|
||||
$spentData = $this->getLeftToSpendInfo($start, $end);
|
||||
$netWorthData = $this->getNetWorthInfo($end);
|
||||
// $balanceData = [];
|
||||
// $billData = [];
|
||||
// $spentData = [];
|
||||
// $netWorthData = [];
|
||||
$total = array_merge($balanceData, $billData, $spentData, $netWorthData);
|
||||
$total = array_merge($balanceData, $billData, $spentData, $netWorthData);
|
||||
|
||||
// give new keys
|
||||
$return = [];
|
||||
$return = [];
|
||||
foreach ($total as $entry) {
|
||||
if ('' === $code || $code === $entry['currency_code']) {
|
||||
$return[$entry['key']] = $entry;
|
||||
@@ -322,7 +323,7 @@ final class BasicController extends Controller
|
||||
$today = today(config('app.timezone'));
|
||||
$available = $this->abRepository->getAvailableBudgetWithCurrency($start, $end);
|
||||
$budgets = $this->budgetRepository->getActiveBudgets();
|
||||
$spent = $this->opsRepository->sumExpenses($start, $end, null, $budgets);
|
||||
$spent = $this->opsRepository->sumExpenses($start, $end, null, $budgets, null, true);
|
||||
$days = (int) $today->diffInDays($end, true) + 1;
|
||||
$currencies = [];
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* BatchController.php
|
||||
* Copyright (c) 2026 james@firefly-iii.org
|
||||
@@ -22,6 +20,8 @@ declare(strict_types=1);
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V1\Controllers\System;
|
||||
|
||||
use FireflyIII\Api\V1\Controllers\Controller;
|
||||
|
||||
@@ -32,7 +32,7 @@ use RuntimeException;
|
||||
abstract class AggregateFormRequest extends ApiRequest
|
||||
{
|
||||
/**
|
||||
* @var ApiRequest[]
|
||||
* @var Request[]
|
||||
*/
|
||||
protected array $requests = [];
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ class ApiRequest extends FormRequest
|
||||
|
||||
public function handleConfig(array $config): void
|
||||
{
|
||||
if (in_array('required', $config, true)) {
|
||||
if (in_array('required', $config, strict: true)) {
|
||||
$this->required = 'required';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* AutocompleteApiRequest.php
|
||||
* Copyright (c) 2025 james@firefly-iii.org
|
||||
* Copyright (c) 2026 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -22,6 +20,8 @@ declare(strict_types=1);
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V1\Requests\Autocomplete;
|
||||
|
||||
use FireflyIII\Api\V1\Requests\AggregateFormRequest;
|
||||
|
||||
@@ -54,7 +54,7 @@ class AutocompleteRequest extends FormRequest
|
||||
|
||||
$date = $this->getCarbonDate('date') ?? today(config('app.timezone'));
|
||||
|
||||
return ['types' => $array, 'query' => $this->convertString('query'), 'date' => $date->endOfDay()];
|
||||
return ['types' => $array, 'query' => $this->convertString('query'), 'date' => $date->endOfDay()];
|
||||
}
|
||||
|
||||
public function rules(): array
|
||||
|
||||
@@ -28,7 +28,7 @@ use FireflyIII\Enums\UserRoleEnum;
|
||||
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
|
||||
use FireflyIII\Support\Request\ChecksLogin;
|
||||
use FireflyIII\Support\Request\ConvertsDataTypes;
|
||||
use Illuminate\Contracts\Validation\Validator;
|
||||
use FireflyIII\Validation\FireflyValidator;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
@@ -69,9 +69,9 @@ class ChartRequest extends FormRequest
|
||||
];
|
||||
}
|
||||
|
||||
public function withValidator(Validator $validator): void
|
||||
public function withValidator(FireflyValidator $validator): void
|
||||
{
|
||||
$validator->after(static function (Validator $validator): void {
|
||||
$validator->after(static function (FireflyValidator $validator): void {
|
||||
// validate transaction query data.
|
||||
$data = $validator->getData();
|
||||
if (!array_key_exists('accounts', $data)) {
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace FireflyIII\Api\V1\Requests\Data\Bulk;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Support\Request\ChecksLogin;
|
||||
use FireflyIII\Support\Request\ConvertsDataTypes;
|
||||
use Illuminate\Contracts\Validation\Validator;
|
||||
use FireflyIII\Validation\FireflyValidator;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
@@ -43,7 +43,7 @@ class MoveTransactionsRequest extends FormRequest
|
||||
|
||||
public function getAll(): array
|
||||
{
|
||||
return ['original_account' => $this->convertInteger('original_account'), 'destination_account' => $this->convertInteger('destination_account')];
|
||||
return ['original_account' => $this->convertInteger('original_account'), 'destination_account' => $this->convertInteger('destination_account')];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,9 +61,9 @@ class MoveTransactionsRequest extends FormRequest
|
||||
* Configure the validator instance with special rules for after the basic validation rules.
|
||||
* TODO this is duplicate.
|
||||
*/
|
||||
public function withValidator(Validator $validator): void
|
||||
public function withValidator(FireflyValidator $validator): void
|
||||
{
|
||||
$validator->after(function (Validator $validator): void {
|
||||
$validator->after(function (FireflyValidator $validator): void {
|
||||
// validate start before end only if both are there.
|
||||
$data = $validator->getData();
|
||||
if (array_key_exists('original_account', $data) && array_key_exists('destination_account', $data)) {
|
||||
@@ -75,7 +75,7 @@ class MoveTransactionsRequest extends FormRequest
|
||||
}
|
||||
}
|
||||
|
||||
private function validateMove(Validator $validator): void
|
||||
private function validateMove(FireflyValidator $validator): void
|
||||
{
|
||||
$data = $validator->getData();
|
||||
$repository = app(AccountRepositoryInterface::class);
|
||||
|
||||
@@ -56,6 +56,6 @@ class DestroyRequest extends FormRequest
|
||||
.',accounts,asset_accounts,expense_accounts,revenue_accounts,liabilities,transactions,withdrawals,deposits,transfers'
|
||||
.',not_assets_liabilities';
|
||||
|
||||
return ['objects' => sprintf('required|max:255|min:1|string|in:%s', $valid), 'unused' => 'in:true,false'];
|
||||
return ['objects' => sprintf('required|max:255|min:1|string|in:%s', $valid), 'unused' => 'in:true,false'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,6 +72,6 @@ class ExportRequest extends FormRequest
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return ['type' => 'in:csv', 'accounts' => 'min:1|max:32768', 'start' => 'date|before:end', 'end' => 'date|after:start'];
|
||||
return ['type' => 'in:csv', 'accounts' => 'min:1|max:32768', 'start' => 'date|before:end', 'end' => 'date|after:start'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ class SameDateRequest extends FormRequest
|
||||
*/
|
||||
public function getAll(): array
|
||||
{
|
||||
return ['start' => $this->getCarbonDate('start'), 'end' => $this->getCarbonDate('end')];
|
||||
return ['start' => $this->getCarbonDate('start'), 'end' => $this->getCarbonDate('end')];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -55,6 +55,6 @@ class SameDateRequest extends FormRequest
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return ['start' => 'required|date', 'end' => 'required|date|after_or_equal:start'];
|
||||
return ['start' => 'required|date', 'end' => 'required|date|after_or_equal:start'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ class GenericRequest extends FormRequest
|
||||
*/
|
||||
public function getAll(): array
|
||||
{
|
||||
return ['start' => $this->getCarbonDate('start'), 'end' => $this->getCarbonDate('end')];
|
||||
return ['start' => $this->getCarbonDate('start'), 'end' => $this->getCarbonDate('end')];
|
||||
}
|
||||
|
||||
public function getAssetAccounts(): Collection
|
||||
@@ -72,7 +72,7 @@ class GenericRequest extends FormRequest
|
||||
if (in_array(
|
||||
$type,
|
||||
[AccountTypeEnum::ASSET->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value],
|
||||
true
|
||||
strict: true
|
||||
)) {
|
||||
$return->push($account);
|
||||
}
|
||||
@@ -169,7 +169,7 @@ class GenericRequest extends FormRequest
|
||||
$this->bills = new Collection();
|
||||
$this->tags = new Collection();
|
||||
|
||||
return ['start' => 'required|date', 'end' => 'required|date|after_or_equal:start'];
|
||||
return ['start' => 'required|date', 'end' => 'required|date|after_or_equal:start'];
|
||||
}
|
||||
|
||||
private function parseAccounts(): void
|
||||
|
||||
@@ -45,7 +45,7 @@ class AccountTypeApiRequest extends ApiRequest
|
||||
}
|
||||
|
||||
$type = $this->convertString('type', 'all');
|
||||
$this->attributes->add(['type' => $type, 'types' => $this->mapAccountTypes($type)]);
|
||||
$this->attributes->add(['type' => $type, 'types' => $this->mapAccountTypes($type)]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ use FireflyIII\Rules\UniqueIban;
|
||||
use FireflyIII\Support\Request\AppendsLocationData;
|
||||
use FireflyIII\Support\Request\ChecksLogin;
|
||||
use FireflyIII\Support\Request\ConvertsDataTypes;
|
||||
use Illuminate\Contracts\Validation\Validator;
|
||||
use FireflyIII\Validation\FireflyValidator;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
@@ -121,9 +121,9 @@ class UpdateRequest extends FormRequest
|
||||
/**
|
||||
* Configure the validator instance with special rules for after the basic validation rules.
|
||||
*/
|
||||
public function withValidator(Validator $validator): void
|
||||
public function withValidator(FireflyValidator $validator): void
|
||||
{
|
||||
$validator->after(function (Validator $validator): void {
|
||||
$validator->after(function (FireflyValidator $validator): void {
|
||||
// validate start before end only if both are there.
|
||||
$data = $validator->getData();
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ class UpdateRequest extends FormRequest
|
||||
];
|
||||
$allData = $this->getAllData($fields);
|
||||
if (array_key_exists('auto_budget_type', $allData)) {
|
||||
$types = ['none' => 0, 'reset' => 1, 'rollover' => 2, 'adjusted' => 3];
|
||||
$types = ['none' => 0, 'reset' => 1, 'rollover' => 2, 'adjusted' => 3];
|
||||
$allData['auto_budget_type'] = $types[$allData['auto_budget_type']] ?? 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ class StoreRequest extends FormRequest
|
||||
*/
|
||||
public function getAll(): array
|
||||
{
|
||||
return ['name' => $this->convertString('name'), 'notes' => $this->stringWithNewlines('notes')];
|
||||
return ['name' => $this->convertString('name'), 'notes' => $this->stringWithNewlines('notes')];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -44,7 +44,7 @@ class UpdateRequest extends FormRequest
|
||||
*/
|
||||
public function getAll(): array
|
||||
{
|
||||
$fields = ['name' => ['name', 'convertString'], 'notes' => ['notes', 'stringWithNewlines']];
|
||||
$fields = ['name' => ['name', 'convertString'], 'notes' => ['notes', 'stringWithNewlines']];
|
||||
|
||||
return $this->getAllData($fields);
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ class StoreByDateRequest extends FormRequest
|
||||
*/
|
||||
public function getAll(): array
|
||||
{
|
||||
return ['from' => $this->get('from'), 'rates' => $this->get('rates', [])];
|
||||
return ['from' => $this->get('from'), 'rates' => $this->get('rates', [])];
|
||||
}
|
||||
|
||||
public function getFromCurrency(): TransactionCurrency
|
||||
@@ -59,7 +59,7 @@ class StoreByDateRequest extends FormRequest
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return ['from' => 'required|exists:transaction_currencies,code', 'rates' => 'required|array', 'rates.*' => 'required|numeric|min:0.0000000001'];
|
||||
return ['from' => 'required|exists:transaction_currencies,code', 'rates' => 'required|array', 'rates.*' => 'required|numeric|min:0.0000000001'];
|
||||
}
|
||||
|
||||
public function withValidator(Validator $validator): void
|
||||
|
||||
@@ -116,7 +116,7 @@ class StoreRequest extends FormRequest
|
||||
$validator->errors()->add(sprintf('accounts.%d', $index), trans('validation.invalid_account_currency'));
|
||||
}
|
||||
$type = $account->accountType->type;
|
||||
if (!in_array($type, $types, true)) {
|
||||
if (!in_array($type, $types, strict: true)) {
|
||||
$validator->errors()->add(sprintf('accounts.%d', $index), trans('validation.invalid_account_type'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ class StoreRequest extends FormRequest
|
||||
];
|
||||
$recurrence = $this->getAllData($fields);
|
||||
|
||||
return ['recurrence' => $recurrence, 'transactions' => $this->getTransactionData(), 'repetitions' => $this->getRepetitionData()];
|
||||
return ['recurrence' => $recurrence, 'transactions' => $this->getTransactionData(), 'repetitions' => $this->getRepetitionData()];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -51,7 +51,7 @@ class StoreRequest extends FormRequest
|
||||
{
|
||||
$fields = [
|
||||
'title' => ['title', 'convertString'],
|
||||
'description' => ['description', 'convertString'],
|
||||
'description' => ['description', 'stringWithNewlines'],
|
||||
'rule_group_id' => ['rule_group_id', 'convertInteger'],
|
||||
'order' => ['order', 'convertInteger'],
|
||||
'rule_group_title' => ['rule_group_title', 'convertString'],
|
||||
|
||||
@@ -41,7 +41,7 @@ class TestRequest extends FormRequest
|
||||
|
||||
public function getTestParameters(): array
|
||||
{
|
||||
return ['page' => $this->getPage(), 'start' => $this->getDate('start'), 'end' => $this->getDate('end'), 'accounts' => $this->getAccounts()];
|
||||
return ['page' => $this->getPage(), 'start' => $this->getDate('start'), 'end' => $this->getDate('end'), 'accounts' => $this->getAccounts()];
|
||||
}
|
||||
|
||||
public function rules(): array
|
||||
|
||||
@@ -41,7 +41,7 @@ class TriggerRequest extends FormRequest
|
||||
|
||||
public function getTriggerParameters(): array
|
||||
{
|
||||
return ['start' => $this->getDate('start'), 'end' => $this->getDate('end'), 'accounts' => $this->getAccounts()];
|
||||
return ['start' => $this->getDate('start'), 'end' => $this->getDate('end'), 'accounts' => $this->getAccounts()];
|
||||
}
|
||||
|
||||
public function rules(): array
|
||||
|
||||
@@ -45,7 +45,7 @@ class StoreRequest extends FormRequest
|
||||
public function getAll(): array
|
||||
{
|
||||
$active = true;
|
||||
$order = 31337;
|
||||
$order = 31_337;
|
||||
if (null !== $this->get('active')) {
|
||||
$active = $this->boolean('active');
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ class TestRequest extends FormRequest
|
||||
|
||||
public function getTestParameters(): array
|
||||
{
|
||||
return ['start' => $this->getDate('start'), 'end' => $this->getDate('end'), 'accounts' => $this->getAccounts()];
|
||||
return ['start' => $this->getDate('start'), 'end' => $this->getDate('end'), 'accounts' => $this->getAccounts()];
|
||||
}
|
||||
|
||||
public function rules(): array
|
||||
|
||||
@@ -41,12 +41,12 @@ class TriggerRequest extends FormRequest
|
||||
|
||||
public function getTriggerParameters(): array
|
||||
{
|
||||
return ['start' => $this->getDate('start'), 'end' => $this->getDate('end'), 'accounts' => $this->getAccounts()];
|
||||
return ['start' => $this->getDate('start'), 'end' => $this->getDate('end'), 'accounts' => $this->getAccounts()];
|
||||
}
|
||||
|
||||
public function rules(): array
|
||||
{
|
||||
return ['start' => 'date|after:1970-01-02|before:2038-01-17', 'end' => 'date|after_or_equal:start|after:1970-01-02|before:2038-01-17'];
|
||||
return ['start' => 'date|after:1970-01-02|before:2038-01-17', 'end' => 'date|after_or_equal:start|after:1970-01-02|before:2038-01-17'];
|
||||
}
|
||||
|
||||
private function getAccounts(): array
|
||||
|
||||
@@ -48,7 +48,7 @@ class UpdateRequest extends FormRequest
|
||||
public function getAll(): array
|
||||
{
|
||||
// This is the way.
|
||||
$fields = ['tag' => ['tag', 'convertString'], 'date' => ['date', 'date'], 'description' => ['description', 'convertString']];
|
||||
$fields = ['tag' => ['tag', 'convertString'], 'date' => ['date', 'date'], 'description' => ['description', 'convertString']];
|
||||
$data = $this->getAllData($fields);
|
||||
|
||||
return $this->appendLocationData($data, null);
|
||||
|
||||
@@ -25,7 +25,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Api\V1\Requests\Models\TransactionCurrency;
|
||||
|
||||
use FireflyIII\Api\V1\Requests\ApiRequest;
|
||||
use Illuminate\Contracts\Validation\Validator;
|
||||
use FireflyIII\Validation\FireflyValidator;
|
||||
|
||||
class CurrencyCodeRequest extends ApiRequest
|
||||
{
|
||||
@@ -34,10 +34,10 @@ class CurrencyCodeRequest extends ApiRequest
|
||||
return ['code' => sprintf('exists:transaction_currencies,code|%s', $this->required)];
|
||||
}
|
||||
|
||||
public function withValidator(Validator $validator): void
|
||||
public function withValidator(FireflyValidator $validator): void
|
||||
{
|
||||
$validator->after(function (Validator $validator): void {
|
||||
if (!$validator->valid()) {
|
||||
$validator->after(function (FireflyValidator $validator): void {
|
||||
if (0 === count($validator->valid())) {
|
||||
return;
|
||||
}
|
||||
$code = $this->convertString('code', '');
|
||||
|
||||
@@ -43,7 +43,7 @@ class StoreRequest extends FormRequest
|
||||
*/
|
||||
public function getAll(): array
|
||||
{
|
||||
return ['name' => $this->convertString('name'), 'outward' => $this->convertString('outward'), 'inward' => $this->convertString('inward')];
|
||||
return ['name' => $this->convertString('name'), 'outward' => $this->convertString('outward'), 'inward' => $this->convertString('inward')];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -45,7 +45,7 @@ class UpdateRequest extends FormRequest
|
||||
*/
|
||||
public function getAll(): array
|
||||
{
|
||||
return ['name' => $this->convertString('name'), 'outward' => $this->convertString('outward'), 'inward' => $this->convertString('inward')];
|
||||
return ['name' => $this->convertString('name'), 'outward' => $this->convertString('outward'), 'inward' => $this->convertString('inward')];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -47,12 +47,12 @@ class CreateRequest extends FormRequest
|
||||
|
||||
public function getData(): array
|
||||
{
|
||||
$fields = ['title' => ['title', 'convertString'], 'active' => ['active', 'boolean'], 'url' => ['url', 'convertString']];
|
||||
$fields = ['title' => ['title', 'convertString'], 'active' => ['active', 'boolean'], 'url' => ['url', 'convertString']];
|
||||
$triggers = $this->get('triggers', []);
|
||||
$responses = $this->get('responses', []);
|
||||
$deliveries = $this->get('deliveries', []);
|
||||
|
||||
if (in_array(0, [count($triggers), count($responses), count($deliveries)], true)) {
|
||||
if (in_array(0, [count($triggers), count($responses), count($deliveries)], strict: true)) {
|
||||
throw new FireflyException('Unexpectedly got no responses, triggers or deliveries.');
|
||||
}
|
||||
|
||||
|
||||
@@ -47,13 +47,13 @@ class UpdateRequest extends FormRequest
|
||||
|
||||
public function getData(): array
|
||||
{
|
||||
$fields = ['title' => ['title', 'convertString'], 'active' => ['active', 'boolean'], 'url' => ['url', 'convertString']];
|
||||
$fields = ['title' => ['title', 'convertString'], 'active' => ['active', 'boolean'], 'url' => ['url', 'convertString']];
|
||||
|
||||
$triggers = $this->get('triggers', []);
|
||||
$responses = $this->get('responses', []);
|
||||
$deliveries = $this->get('deliveries', []);
|
||||
|
||||
if (in_array(0, [count($triggers), count($responses), count($deliveries)], true)) {
|
||||
if (in_array(0, [count($triggers), count($responses), count($deliveries)], strict: true)) {
|
||||
throw new FireflyException('Unexpectedly got no responses, triggers or deliveries.');
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ class CronRequest extends FormRequest
|
||||
*/
|
||||
public function getAll(): array
|
||||
{
|
||||
$data = ['force' => false, 'date' => today(config('app.timezone'))];
|
||||
$data = ['force' => false, 'date' => today(config('app.timezone'))];
|
||||
if ($this->has('force')) {
|
||||
$data['force'] = $this->boolean('force');
|
||||
}
|
||||
@@ -68,6 +68,6 @@ class CronRequest extends FormRequest
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return ['force' => 'in:true,false', 'date' => 'nullable|date|after:1970-01-02|before:2038-01-17'];
|
||||
return ['force' => 'in:true,false', 'date' => 'nullable|date|after:1970-01-02|before:2038-01-17'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,10 +56,10 @@ class UpdateRequest extends FormRequest
|
||||
public function getAll(): array
|
||||
{
|
||||
$name = $this->route()->parameter('dynamicConfigKey');
|
||||
if (in_array($name, $this->booleans, true)) {
|
||||
if (in_array($name, $this->booleans, strict: true)) {
|
||||
return ['value' => $this->boolean('value')];
|
||||
}
|
||||
if (in_array($name, $this->integers, true)) {
|
||||
if (in_array($name, $this->integers, strict: true)) {
|
||||
return ['value' => $this->convertInteger('value')];
|
||||
}
|
||||
|
||||
@@ -73,13 +73,13 @@ class UpdateRequest extends FormRequest
|
||||
{
|
||||
$name = $this->route()->parameter('configName');
|
||||
|
||||
if (in_array($name, $this->booleans, true)) {
|
||||
if (in_array($name, $this->booleans, strict: true)) {
|
||||
return ['value' => ['required', new IsBoolean()]];
|
||||
}
|
||||
if ('configuration.permission_update_check' === $name) {
|
||||
return ['value' => 'required|numeric|min:-1|max:1'];
|
||||
}
|
||||
if (in_array($name, $this->integers, true)) {
|
||||
if (in_array($name, $this->integers, strict: true)) {
|
||||
return ['value' => 'required|numeric|min:464272080'];
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ use Carbon\Carbon;
|
||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
|
||||
use FireflyIII\Support\Facades\FireflyConfig;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
@@ -82,7 +83,7 @@ class ConvertsDatesToUTC extends Command
|
||||
return;
|
||||
}
|
||||
$this->friendlyInfo(sprintf('Converting field "%s" of model "%s" to UTC.', $field, $shortModel));
|
||||
$items->each(static function ($item) use ($field, $timezoneField): void {
|
||||
$items->each(static function (Model $item) use ($field, $timezoneField): void {
|
||||
$date = Carbon::parse($item->{$field}, $item->{$timezoneField});
|
||||
$date->setTimezone('UTC');
|
||||
$item->{$field} = $date->format('Y-m-d H:i:s');
|
||||
|
||||
@@ -125,7 +125,7 @@ class CorrectsAccountTypes extends Command
|
||||
|
||||
private function canCreateDestination(array $validDestinations): bool
|
||||
{
|
||||
return in_array(AccountTypeEnum::EXPENSE->value, $validDestinations, true);
|
||||
return in_array(AccountTypeEnum::EXPENSE->value, $validDestinations, strict: true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -133,7 +133,7 @@ class CorrectsAccountTypes extends Command
|
||||
*/
|
||||
private function canCreateSource(array $validSources): bool
|
||||
{
|
||||
return in_array(AccountTypeEnum::REVENUE->value, $validSources, true);
|
||||
return in_array(AccountTypeEnum::REVENUE->value, $validSources, strict: true);
|
||||
}
|
||||
|
||||
private function fixJournal(TransactionJournal $journal, string $transactionType, Transaction $source, Transaction $dest): void
|
||||
@@ -229,12 +229,24 @@ class CorrectsAccountTypes extends Command
|
||||
|
||||
private function getDestinationTransaction(TransactionJournal $journal): Transaction
|
||||
{
|
||||
return $journal->transactions->firstWhere('amount', '>', 0);
|
||||
/** @var null|Transaction $res */
|
||||
$res = $journal->transactions->firstWhere('amount', '>', 0);
|
||||
if (null === $res) {
|
||||
throw new FireflyException('Could not find transaction.');
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
private function getSourceTransaction(TransactionJournal $journal): Transaction
|
||||
{
|
||||
return $journal->transactions->firstWhere('amount', '<', 0);
|
||||
/** @var null|Transaction $res */
|
||||
$res = $journal->transactions->firstWhere('amount', '<', 0);
|
||||
if (null === $res) {
|
||||
throw new FireflyException('Could not find transaction.');
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
private function giveNewDestinationAccount(TransactionJournal $journal, Account $newDestination): void
|
||||
@@ -296,7 +308,7 @@ class CorrectsAccountTypes extends Command
|
||||
|
||||
private function hasValidAccountType(array $validTypes, string $accountType): bool
|
||||
{
|
||||
return in_array($accountType, $validTypes, true);
|
||||
return in_array($accountType, $validTypes, strict: true);
|
||||
}
|
||||
|
||||
private function inspectJournal(TransactionJournal $journal): void
|
||||
@@ -330,7 +342,7 @@ class CorrectsAccountTypes extends Command
|
||||
return;
|
||||
}
|
||||
$expectedTypes = $this->expected[$type][$sourceAccountType];
|
||||
if (!in_array($destAccountType, $expectedTypes, true)) {
|
||||
if (!in_array($destAccountType, $expectedTypes, strict: true)) {
|
||||
Log::debug(sprintf('[b] Going to fix journal #%d', $journal->id));
|
||||
$this->fixJournal($journal, $type, $sourceTransaction, $destTransaction);
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ class CreatesGroupMemberships extends Command
|
||||
->first()
|
||||
;
|
||||
if (null === $membership) {
|
||||
GroupMembership::create(['user_id' => $user->id, 'user_role_id' => $userRole->id, 'user_group_id' => $userGroup->id]);
|
||||
GroupMembership::create(['user_id' => $user->id, 'user_role_id' => $userRole->id, 'user_group_id' => $userGroup->id]);
|
||||
}
|
||||
if (null === $user->user_group_id) {
|
||||
$user->user_group_id = $userGroup->id;
|
||||
|
||||
@@ -29,6 +29,8 @@ use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Models\Tag;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Repositories\Budget\AvailableBudgetRepositoryInterface;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
@@ -92,6 +94,18 @@ class RemovesLinksToDeletedObjects extends Command
|
||||
if (count($deletedCategories) > 0) {
|
||||
$this->cleanupCategories($deletedCategories);
|
||||
}
|
||||
|
||||
// count and clean up available budgets in currencies with no budget limits.
|
||||
// this is not entirely the place for it but OK.
|
||||
/** @var AvailableBudgetRepositoryInterface $repository */
|
||||
$repository = app(AvailableBudgetRepositoryInterface::class);
|
||||
|
||||
/** @var User $user */
|
||||
foreach (User::get() as $user) {
|
||||
$repository->setUser($user);
|
||||
$repository->cleanup();
|
||||
}
|
||||
|
||||
$this->friendlyNeutral('Validated links to deleted objects.');
|
||||
}
|
||||
|
||||
|
||||
@@ -75,7 +75,10 @@ class RollbacksSingleMigration extends Command
|
||||
}
|
||||
|
||||
if ($res) {
|
||||
DB::table('migrations')->where('id', (int) $entry->id)->delete();
|
||||
DB::table('migrations')
|
||||
->where('id', (int) $entry->id)
|
||||
->delete()
|
||||
;
|
||||
$this->friendlyInfo(sprintf('Database migration #%d ("%s") is deleted.', $entry->id, $entry->migration));
|
||||
$this->friendlyLine('');
|
||||
$this->friendlyLine('Try running "php artisan migrate" now.');
|
||||
|
||||
79
app/Console/Commands/SendTestEmail.php
Normal file
79
app/Console/Commands/SendTestEmail.php
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* SendTestEmail.php
|
||||
* Copyright (c) 2026 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Console\Commands;
|
||||
|
||||
use FireflyIII\Events\Test\OwnerTestsNotificationChannel;
|
||||
use FireflyIII\Notifications\Notifiables\OwnerNotifiable;
|
||||
use FireflyIII\Support\Facades\FireflyConfig;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class SendTestEmail extends Command
|
||||
{
|
||||
use ShowsFriendlyMessages;
|
||||
use VerifiesAccessToken;
|
||||
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'firefly-iii:send-test-email
|
||||
{--user=1 : The user ID.}
|
||||
{--token= : The user\'s access token.}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Send test email';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle(): int
|
||||
{
|
||||
$user = $this->getUser();
|
||||
if (!$user->hasRole('owner')) {
|
||||
$this->friendlyError((string) trans('firefly.must_be_owner'));
|
||||
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
/** @var int $lastNotification */
|
||||
$lastNotification = FireflyConfig::get('last_test_notification', 123)->data;
|
||||
if ((time() - $lastNotification) < 120) {
|
||||
$this->friendlyError((string) trans('firefly.test_rate_limited'));
|
||||
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$owner = new OwnerNotifiable();
|
||||
event(new OwnerTestsNotificationChannel('email', $owner));
|
||||
FireflyConfig::set('last_test_notification', time());
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -54,10 +54,10 @@ class CreatesDatabase extends Command
|
||||
}
|
||||
// try to set up a raw connection:
|
||||
$exists = false;
|
||||
$dsn = sprintf('mysql:host=%s;port=%d;charset=utf8mb4', env('DB_HOST'), env('DB_PORT'));
|
||||
$dsn = sprintf('mysql:host=%s;port=%d;charset=utf8mb4', config('database.connections.mysql.host'), config('database.connections.mysql.port'));
|
||||
|
||||
if ('' !== (string) env('DB_SOCKET')) {
|
||||
$dsn = sprintf('mysql:unix_socket=%s;charset=utf8mb4', env('DB_SOCKET'));
|
||||
if ('' !== (string) config('database.connections.mysql.unix_socket')) {
|
||||
$dsn = sprintf('mysql:unix_socket=%s;charset=utf8mb4', config('database.connections.mysql.unix_socket'));
|
||||
}
|
||||
$this->friendlyLine(sprintf('DSN is %s', $dsn));
|
||||
|
||||
@@ -69,7 +69,7 @@ class CreatesDatabase extends Command
|
||||
|
||||
// when it fails, display error
|
||||
try {
|
||||
$pdo = new PDO($dsn, (string) env('DB_USERNAME'), (string) env('DB_PASSWORD'), $options);
|
||||
$pdo = new PDO($dsn, (string) config('database.connections.mysql.username'), (string) config('database.connections.mysql.password'), $options);
|
||||
} catch (PDOException $e) {
|
||||
$this->friendlyError(sprintf('Error when connecting to DB: %s', $e->getMessage()));
|
||||
|
||||
@@ -83,19 +83,19 @@ class CreatesDatabase extends Command
|
||||
// slightly more complex but less error-prone.
|
||||
foreach ($stmt as $row) {
|
||||
$name = $row['Database'] ?? false;
|
||||
if ($name === env('DB_DATABASE')) {
|
||||
if ($name === config('database.connections.mysql.database')) {
|
||||
$exists = true;
|
||||
}
|
||||
}
|
||||
if (false === $exists) {
|
||||
$this->friendlyError(sprintf('Database "%s" does not exist.', env('DB_DATABASE')));
|
||||
$this->friendlyError(sprintf('Database "%s" does not exist.', config('database.connections.mysql.database')));
|
||||
|
||||
// try to create it.
|
||||
$pdo->exec(sprintf('CREATE DATABASE `%s` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;', env('DB_DATABASE')));
|
||||
$this->friendlyInfo(sprintf('Created database "%s"', env('DB_DATABASE')));
|
||||
$pdo->exec(sprintf('CREATE DATABASE `%s` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;', config('database.connections.mysql.database')));
|
||||
$this->friendlyInfo(sprintf('Created database "%s"', config('database.connections.mysql.database')));
|
||||
}
|
||||
if ($exists) {
|
||||
$this->friendlyInfo(sprintf('Database "%s" exists.', env('DB_DATABASE')));
|
||||
$this->friendlyInfo(sprintf('Database "%s" exists.', config('database.connections.mysql.database')));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -56,7 +56,7 @@ class CreatesFirstUser extends Command
|
||||
|
||||
return 1;
|
||||
}
|
||||
$data = ['blocked' => false, 'blocked_code' => null, 'email' => $this->argument('email'), 'role' => 'owner'];
|
||||
$data = ['blocked' => false, 'blocked_code' => null, 'email' => $this->argument('email'), 'role' => 'owner'];
|
||||
$password = Str::random(24);
|
||||
$user = $this->repository->store($data);
|
||||
$user->password = Hash::make($password);
|
||||
|
||||
@@ -78,7 +78,7 @@ class ForcesMigrations extends Command
|
||||
sleep(2);
|
||||
Schema::dropIfExists('migrations');
|
||||
$this->friendlyLine('Re-run all migrations...');
|
||||
Artisan::call('migrate', ['--seed' => true, '--force' => true]);
|
||||
Artisan::call('migrate', ['--seed' => true, '--force' => true]);
|
||||
sleep(2);
|
||||
$this->friendlyLine('');
|
||||
$this->friendlyWarning('There is a good chance you just saw a lot of error messages.');
|
||||
|
||||
@@ -121,11 +121,11 @@ class ApplyRules extends Command
|
||||
$filterAccountList[] = $account->id;
|
||||
}
|
||||
$list = implode(',', $filterAccountList);
|
||||
$ruleEngine->addOperator(['type' => 'account_id', 'value' => $list]);
|
||||
$ruleEngine->addOperator(['type' => 'account_id', 'value' => $list]);
|
||||
|
||||
// add the date as a filter:
|
||||
$ruleEngine->addOperator(['type' => 'date_after', 'value' => $this->startDate->format('Y-m-d')]);
|
||||
$ruleEngine->addOperator(['type' => 'date_before', 'value' => $this->endDate->format('Y-m-d')]);
|
||||
$ruleEngine->addOperator(['type' => 'date_after', 'value' => $this->startDate->format('Y-m-d')]);
|
||||
$ruleEngine->addOperator(['type' => 'date_before', 'value' => $this->endDate->format('Y-m-d')]);
|
||||
|
||||
// start running rules.
|
||||
$this->friendlyLine(sprintf('Will apply %d rule(s) to your transaction(s).', $count));
|
||||
|
||||
@@ -84,7 +84,7 @@ class ChecksForUpdates extends Command
|
||||
}
|
||||
// if running develop, slightly different message.
|
||||
if (str_contains($version, 'develop')) {
|
||||
$this->friendlyInfo(trans('firefly.update_current_dev_older', ['version' => $version, 'new_version' => $info->getNewVersion()]));
|
||||
$this->friendlyInfo(trans('firefly.update_current_dev_older', ['version' => $version, 'new_version' => $info->getNewVersion()]));
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ trait VerifiesDatabaseConnectionTrait
|
||||
{
|
||||
$loops = 30;
|
||||
$loop = 0;
|
||||
$queries = ['pgsql' => 'SELECT * FROM pg_catalog.pg_tables;', 'sqlite' => 'SELECT name FROM sqlite_schema;', 'mysql' => 'SHOW TABLES;'];
|
||||
$queries = ['pgsql' => 'SELECT * FROM pg_catalog.pg_tables;', 'sqlite' => 'SELECT name FROM sqlite_schema;', 'mysql' => 'SHOW TABLES;'];
|
||||
$default = config('database.default');
|
||||
if (!array_key_exists($default, $queries)) {
|
||||
$this->friendlyWarning(sprintf('Cannot validate database connection for "%s"', $default));
|
||||
|
||||
@@ -64,10 +64,6 @@ class RemovesDatabaseDecryption extends Command
|
||||
'journal_links' => ['comment'],
|
||||
];
|
||||
|
||||
/**
|
||||
* @var string $table
|
||||
* @var array $fields
|
||||
*/
|
||||
foreach ($tables as $table => $fields) {
|
||||
$this->decryptTable($table, $fields);
|
||||
}
|
||||
|
||||
@@ -107,7 +107,10 @@ class RepairsPostgresSequences extends Command
|
||||
$this->friendlyLine(sprintf('Checking the next id sequence for table "%s".', $tableToCheck));
|
||||
|
||||
$highestId = DB::table($tableToCheck)->select(DB::raw('MAX(id)'))->first();
|
||||
$nextId = DB::table($tableToCheck)->select(DB::raw(sprintf('nextval(\'%s_id_seq\')', $tableToCheck)))->first();
|
||||
$nextId = DB::table($tableToCheck)
|
||||
->select(DB::raw(sprintf('nextval(\'%s_id_seq\')', $tableToCheck)))
|
||||
->first()
|
||||
;
|
||||
if (null === $nextId) {
|
||||
$this->friendlyInfo(sprintf('nextval is NULL for table "%s", go to next table.', $tableToCheck));
|
||||
|
||||
@@ -117,7 +120,10 @@ class RepairsPostgresSequences extends Command
|
||||
if ($nextId->nextval < $highestId->max) {
|
||||
DB::select(sprintf('SELECT setval(\'%s_id_seq\', %d)', $tableToCheck, $highestId->max));
|
||||
$highestId = DB::table($tableToCheck)->select(DB::raw('MAX(id)'))->first();
|
||||
$nextId = DB::table($tableToCheck)->select(DB::raw(sprintf('nextval(\'%s_id_seq\')', $tableToCheck)))->first();
|
||||
$nextId = DB::table($tableToCheck)
|
||||
->select(DB::raw(sprintf('nextval(\'%s_id_seq\')', $tableToCheck)))
|
||||
->first()
|
||||
;
|
||||
if ($nextId->nextval > $highestId->max) {
|
||||
$this->friendlyInfo(sprintf('Table "%s" autoincrement corrected.', $tableToCheck));
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ class UpgradesAccountCurrencies extends Command
|
||||
// both 0? set to default currency:
|
||||
if (0 === $accountCurrency && 0 === $obCurrency) {
|
||||
AccountMeta::where('account_id', $account->id)->where('name', 'currency_id')->forceDelete();
|
||||
AccountMeta::create(['account_id' => $account->id, 'name' => 'currency_id', 'data' => $currency->id]);
|
||||
AccountMeta::create(['account_id' => $account->id, 'name' => 'currency_id', 'data' => $currency->id]);
|
||||
$this->friendlyInfo(sprintf('Account #%d ("%s") now has a currency setting (%s).', $account->id, $account->name, $currency->code));
|
||||
++$this->count;
|
||||
|
||||
@@ -116,7 +116,7 @@ class UpgradesAccountCurrencies extends Command
|
||||
|
||||
// account is set to 0, opening balance is not?
|
||||
if (0 === $accountCurrency && $obCurrency > 0) {
|
||||
AccountMeta::create(['account_id' => $account->id, 'name' => 'currency_id', 'data' => $obCurrency]);
|
||||
AccountMeta::create(['account_id' => $account->id, 'name' => 'currency_id', 'data' => $obCurrency]);
|
||||
$this->friendlyInfo(sprintf('Account #%d ("%s") now has a currency setting (#%d).', $account->id, $account->name, $obCurrency));
|
||||
++$this->count;
|
||||
|
||||
|
||||
@@ -113,17 +113,17 @@ class UpgradesBillsToRules extends Command
|
||||
'title' => (string) trans('firefly.rule_for_bill_title', ['name' => $bill->name], $languageString),
|
||||
'description' => (string) trans('firefly.rule_for_bill_description', ['name' => $bill->name], $languageString),
|
||||
'trigger' => 'store-journal',
|
||||
'triggers' => [['type' => 'description_contains', 'value' => $match]],
|
||||
'actions' => [['type' => 'link_to_bill', 'value' => $bill->name]],
|
||||
'triggers' => [['type' => 'description_contains', 'value' => $match]],
|
||||
'actions' => [['type' => 'link_to_bill', 'value' => $bill->name]],
|
||||
];
|
||||
|
||||
// two triggers or one, depends on bill content:
|
||||
if ($bill->amount_max === $bill->amount_min) {
|
||||
$newRule['triggers'][] = ['type' => 'amount_exactly', 'value' => $bill->amount_min];
|
||||
$newRule['triggers'][] = ['type' => 'amount_exactly', 'value' => $bill->amount_min];
|
||||
}
|
||||
if ($bill->amount_max !== $bill->amount_min) {
|
||||
$newRule['triggers'][] = ['type' => 'amount_less', 'value' => $bill->amount_max];
|
||||
$newRule['triggers'][] = ['type' => 'amount_more', 'value' => $bill->amount_min];
|
||||
$newRule['triggers'][] = ['type' => 'amount_less', 'value' => $bill->amount_max];
|
||||
$newRule['triggers'][] = ['type' => 'amount_more', 'value' => $bill->amount_min];
|
||||
}
|
||||
|
||||
$this->ruleRepository->store($newRule);
|
||||
|
||||
@@ -95,7 +95,7 @@ class UpgradesDatabase extends Command
|
||||
private function callInitialCommands(): void
|
||||
{
|
||||
$this->call('firefly-iii:verify-database-connection');
|
||||
$this->call('migrate', ['--seed' => true, '--force' => true, '--no-interaction' => true]);
|
||||
$this->call('migrate', ['--seed' => true, '--force' => true, '--no-interaction' => true]);
|
||||
$this->call('upgrade:600-pgsql-sequences');
|
||||
$this->call('upgrade:480-decrypt-all');
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ class UpgradesRecurrenceMetaData extends Command
|
||||
$value = json_encode($array, JSON_THROW_ON_ERROR);
|
||||
}
|
||||
|
||||
RecurrenceTransactionMeta::create(['rt_id' => $firstTransaction->id, 'name' => $meta->name, 'value' => $value]);
|
||||
RecurrenceTransactionMeta::create(['rt_id' => $firstTransaction->id, 'name' => $meta->name, 'value' => $value]);
|
||||
$meta->forceDelete();
|
||||
|
||||
return 1;
|
||||
|
||||
@@ -86,14 +86,15 @@ class UpgradesToGroups extends Command
|
||||
private function findOpposingTransaction(TransactionJournal $journal, Transaction $transaction): ?Transaction
|
||||
{
|
||||
$set = $journal->transactions->filter(static function (Transaction $subject) use ($transaction): bool {
|
||||
$amount = ((float) $transaction->amount * -1) === (float) $subject->amount; // intentional float
|
||||
$amount = -(float) $transaction->amount === (float) $subject->amount; // intentional float
|
||||
$identifier = $transaction->identifier === $subject->identifier;
|
||||
Log::debug(sprintf('Amount the same? %s', var_export($amount, true)));
|
||||
Log::debug(sprintf('ID the same? %s', var_export($identifier, true)));
|
||||
Log::debug(sprintf('Amount the same? %s', var_export($amount, return: true)));
|
||||
Log::debug(sprintf('ID the same? %s', var_export($identifier, return: true)));
|
||||
|
||||
return $amount && $identifier;
|
||||
});
|
||||
|
||||
/** @var null|Transaction */
|
||||
return $set->first();
|
||||
}
|
||||
|
||||
|
||||
@@ -106,17 +106,20 @@ class UpgradesVariousCurrencyInformation extends Command
|
||||
break;
|
||||
|
||||
case TransactionTypeEnum::WITHDRAWAL->value:
|
||||
/** @var null|Transaction $lead */
|
||||
$lead = $journal->transactions()->where('amount', '<', 0)->first();
|
||||
|
||||
break;
|
||||
|
||||
case TransactionTypeEnum::DEPOSIT->value:
|
||||
/** @var null|Transaction $lead */
|
||||
$lead = $journal->transactions()->where('amount', '>', 0)->first();
|
||||
|
||||
break;
|
||||
|
||||
case TransactionTypeEnum::OPENING_BALANCE->value:
|
||||
// whichever isn't an initial balance account:
|
||||
/** @var null|Transaction $lead */
|
||||
$lead = $journal
|
||||
->transactions()
|
||||
->leftJoin('accounts', 'transactions.account_id', '=', 'accounts.id')
|
||||
@@ -129,6 +132,7 @@ class UpgradesVariousCurrencyInformation extends Command
|
||||
|
||||
case TransactionTypeEnum::RECONCILIATION->value:
|
||||
// whichever isn't the reconciliation account:
|
||||
/** @var null|Transaction $lead */
|
||||
$lead = $journal
|
||||
->transactions()
|
||||
->leftJoin('accounts', 'transactions.account_id', '=', 'accounts.id')
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* CreatedCurrencyExchangeRate.php
|
||||
* Copyright (c) 2026 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace FireflyIII\Events\Model\CurrencyExchangeRate;
|
||||
|
||||
use FireflyIII\Events\Event;
|
||||
use FireflyIII\Models\CurrencyExchangeRate;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class CreatedCurrencyExchangeRate extends Event
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
public function __construct(
|
||||
public CurrencyExchangeRate $rate
|
||||
) {
|
||||
Log::debug(sprintf('CreatedCurrencyExchangeRate(#%d) Event', $rate->id));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* DestroyedCurrencyExchangeRate.php
|
||||
* Copyright (c) 2026 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace FireflyIII\Events\Model\CurrencyExchangeRate;
|
||||
|
||||
use FireflyIII\Events\Event;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Models\UserGroup;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class DestroyedCurrencyExchangeRate extends Event
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
public function __construct(
|
||||
public TransactionCurrency $from,
|
||||
public TransactionCurrency $to,
|
||||
public UserGroup $userGroup
|
||||
) {
|
||||
Log::debug(sprintf('DestroyedCurrencyExchangeRate(%s, %s) Event', $from->code, $to->code));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* UpdatedCurrencyExchangeRate.php
|
||||
* Copyright (c) 2026 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace FireflyIII\Events\Model\CurrencyExchangeRate;
|
||||
|
||||
use FireflyIII\Events\Event;
|
||||
use FireflyIII\Models\CurrencyExchangeRate;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class UpdatedCurrencyExchangeRate extends Event
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
public function __construct(
|
||||
public CurrencyExchangeRate $rate
|
||||
) {
|
||||
Log::debug(sprintf('UpdatedCurrencyExchangeRate(#%d) Event', $rate->id));
|
||||
}
|
||||
}
|
||||
@@ -117,40 +117,40 @@ class Handler extends ExceptionHandler
|
||||
// JSON error:
|
||||
Log::debug('Return JSON not found error.');
|
||||
|
||||
return response()->json(['message' => 'Resource not found', 'exception' => 'NotFoundHttpException'], 404);
|
||||
return response()->json(['message' => 'Resource not found', 'exception' => 'NotFoundHttpException'], 404);
|
||||
}
|
||||
|
||||
if ($e instanceof AuthorizationException && $expectsJson) {
|
||||
// somehow Laravel handler does not catch this:
|
||||
Log::debug('Return JSON unauthorized error.');
|
||||
|
||||
return response()->json(['message' => $e->getMessage(), 'exception' => 'AuthorizationException'], 401);
|
||||
return response()->json(['message' => $e->getMessage(), 'exception' => 'AuthorizationException'], 401);
|
||||
}
|
||||
|
||||
if ($e instanceof AuthenticationException && $expectsJson) {
|
||||
// somehow Laravel handler does not catch this:
|
||||
Log::debug('Return JSON unauthenticated error.');
|
||||
|
||||
return response()->json(['message' => $e->getMessage(), 'exception' => 'AuthenticationException'], 401);
|
||||
return response()->json(['message' => $e->getMessage(), 'exception' => 'AuthenticationException'], 401);
|
||||
}
|
||||
|
||||
if ($e instanceof OAuthServerException && $expectsJson) {
|
||||
Log::debug('Return JSON OAuthServerException.');
|
||||
|
||||
// somehow Laravel handler does not catch this:
|
||||
return response()->json(['message' => $e->getMessage(), 'exception' => 'OAuthServerException'], 401);
|
||||
return response()->json(['message' => $e->getMessage(), 'exception' => 'OAuthServerException'], 401);
|
||||
}
|
||||
if ($e instanceof BadRequestHttpException) {
|
||||
Log::debug('Return JSON BadRequestHttpException.');
|
||||
|
||||
return response()->json(['message' => $e->getMessage(), 'exception' => 'HttpException'], 400);
|
||||
return response()->json(['message' => $e->getMessage(), 'exception' => 'HttpException'], 400);
|
||||
}
|
||||
|
||||
if ($e instanceof BadHttpHeaderException) {
|
||||
// is always API exception.
|
||||
Log::debug('Return JSON BadHttpHeaderException.');
|
||||
|
||||
return response()->json(['message' => $e->getMessage(), 'exception' => 'BadHttpHeaderException'], $e->statusCode);
|
||||
return response()->json(['message' => $e->getMessage(), 'exception' => 'BadHttpHeaderException'], $e->statusCode);
|
||||
}
|
||||
if (($e instanceof ValidationException || $e instanceof NumberFormatException) && $expectsJson) {
|
||||
$errorCode = 422;
|
||||
@@ -197,14 +197,14 @@ class Handler extends ExceptionHandler
|
||||
Log::debug('Return Firefly III database exception view.');
|
||||
$isDebug = config('app.debug');
|
||||
|
||||
return response()->view('errors.DatabaseException', ['exception' => $e, 'debug' => $isDebug], 500);
|
||||
return response()->view('errors.DatabaseException', ['exception' => $e, 'debug' => $isDebug], 500);
|
||||
}
|
||||
|
||||
if ($e instanceof FireflyException || $e instanceof ErrorException || $e instanceof OAuthServerException) {
|
||||
Log::debug('Return Firefly III error view.');
|
||||
$isDebug = config('app.debug');
|
||||
|
||||
return response()->view('errors.FireflyException', ['exception' => $e, 'debug' => $isDebug], 500);
|
||||
return response()->view('errors.FireflyException', ['exception' => $e, 'debug' => $isDebug], 500);
|
||||
}
|
||||
|
||||
Log::debug(sprintf('Error "%s" has no Firefly III treatment, parent will handle.', $e::class));
|
||||
@@ -228,7 +228,7 @@ class Handler extends ExceptionHandler
|
||||
|
||||
return;
|
||||
}
|
||||
$userData = ['id' => 0, 'email' => 'unknown@example.com'];
|
||||
$userData = ['id' => 0, 'email' => 'unknown@example.com'];
|
||||
if (auth()->check()) {
|
||||
$userData['id'] = auth()->user()->id;
|
||||
$userData['email'] = auth()->user()->email;
|
||||
@@ -250,6 +250,7 @@ class Handler extends ExceptionHandler
|
||||
'json' => request()->acceptsJson(),
|
||||
'method' => request()->method(),
|
||||
'headers' => $headers,
|
||||
// @mago-expect lint:no-request-all
|
||||
'post' => 'POST' === request()->method() ? json_encode(request()->all()) : '',
|
||||
];
|
||||
|
||||
|
||||
@@ -219,7 +219,7 @@ class AccountFactory
|
||||
'user_group_id' => $this->user->user_group_id,
|
||||
'account_type_id' => $type->id,
|
||||
'name' => $data['name'],
|
||||
'order' => 25000,
|
||||
'order' => 25_000,
|
||||
'virtual_balance' => $virtualBalance,
|
||||
'active' => $active,
|
||||
'iban' => $data['iban'],
|
||||
|
||||
@@ -53,7 +53,7 @@ class AccountMetaFactory
|
||||
}
|
||||
// if $data has field and $entry is null, create new one:
|
||||
if (null === $entry) {
|
||||
return $this->create(['account_id' => $account->id, 'name' => $field, 'data' => $value]);
|
||||
return $this->create(['account_id' => $account->id, 'name' => $field, 'data' => $value]);
|
||||
}
|
||||
|
||||
// if $data has field and $entry is not null, update $entry:
|
||||
|
||||
@@ -75,7 +75,7 @@ class CategoryFactory
|
||||
}
|
||||
|
||||
try {
|
||||
return Category::create(['user_id' => $this->user->id, 'user_group_id' => $this->user->user_group_id, 'name' => $categoryName]);
|
||||
return Category::create(['user_id' => $this->user->id, 'user_group_id' => $this->user->user_group_id, 'name' => $categoryName]);
|
||||
} catch (QueryException $e) {
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
|
||||
@@ -159,7 +159,7 @@ class PiggyBankFactory
|
||||
}
|
||||
|
||||
// no amount set, use previous amount
|
||||
$toBeLinked[$account->id] = ['current_amount' => $toBeLinked[$account->id]['current_amount']];
|
||||
$toBeLinked[$account->id] = ['current_amount' => $toBeLinked[$account->id]['current_amount'] ?? '0'];
|
||||
Log::debug(sprintf('[b] Will link account #%d with amount %s', $account->id, $toBeLinked[$account->id]['current_amount']));
|
||||
|
||||
// create event:
|
||||
@@ -246,7 +246,7 @@ class PiggyBankFactory
|
||||
$piggyBankData['target_date_tz'] = $piggyBankData['target_date']?->format('e');
|
||||
$piggyBankData['account_id'] = null;
|
||||
$piggyBankData['transaction_currency_id'] = $this->getCurrency($data)->id;
|
||||
$piggyBankData['order'] = 131337;
|
||||
$piggyBankData['order'] = 131_337;
|
||||
|
||||
try {
|
||||
/** @var PiggyBank $piggyBank */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user