mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2026-03-21 12:42:10 +00:00
Compare commits
34 Commits
develop-20
...
v6.5.8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f5dea9ac09 | ||
|
|
4ef7944147 | ||
|
|
4e1c84944c | ||
|
|
f36da26cc3 | ||
|
|
5983a8eb6d | ||
|
|
b4a8a219ff | ||
|
|
4190c4d243 | ||
|
|
70cbbc1523 | ||
|
|
c724f13501 | ||
|
|
5f01a83b43 | ||
|
|
53c13d221d | ||
|
|
266cd7d8d0 | ||
|
|
7c09278c8e | ||
|
|
21af34c65a | ||
|
|
594c04b121 | ||
|
|
c50408249b | ||
|
|
b05a38c0e2 | ||
|
|
0bb1afdf6c | ||
|
|
547b83b36e | ||
|
|
134d8c8cf6 | ||
|
|
94144a407d | ||
|
|
15e29d133a | ||
|
|
21f9be6504 | ||
|
|
d514792f4d | ||
|
|
5894695ad6 | ||
|
|
7004c9aaf5 | ||
|
|
1893a33d84 | ||
|
|
d345b31cd4 | ||
|
|
a27642024d | ||
|
|
c23ad831d0 | ||
|
|
d50c283973 | ||
|
|
9ea3519585 | ||
|
|
ddb5bc6038 | ||
|
|
caadef7c64 |
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!
|
||||
-->
|
||||
|
||||
2
.github/security.md
vendored
2
.github/security.md
vendored
@@ -106,6 +106,8 @@ found with the full or partial support of AI coding agents, large language model
|
||||
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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -28,9 +28,7 @@ use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use FireflyIII\Support\Facades\Preferences;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
@@ -41,7 +39,6 @@ use Illuminate\Validation\ValidationException;
|
||||
final class DestroyController extends Controller
|
||||
{
|
||||
private CurrencyRepositoryInterface $repository;
|
||||
private UserRepositoryInterface $userRepository;
|
||||
|
||||
/**
|
||||
* CurrencyRepository constructor.
|
||||
@@ -50,8 +47,7 @@ final class DestroyController extends Controller
|
||||
{
|
||||
parent::__construct();
|
||||
$this->middleware(function ($request, $next) {
|
||||
$this->repository = app(CurrencyRepositoryInterface::class);
|
||||
$this->userRepository = app(UserRepositoryInterface::class);
|
||||
$this->repository = app(CurrencyRepositoryInterface::class);
|
||||
$this->repository->setUser(auth()->user());
|
||||
|
||||
return $next($request);
|
||||
@@ -69,15 +65,8 @@ final class DestroyController extends Controller
|
||||
*/
|
||||
public function destroy(TransactionCurrency $currency): JsonResponse
|
||||
{
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$rules = ['currency_code' => 'required'];
|
||||
|
||||
if (!$this->userRepository->hasRole($admin, 'owner')) {
|
||||
// access denied:
|
||||
$messages = ['currency_code' => '200005: You need the "owner" role to do this.'];
|
||||
Validator::make([], $rules, $messages)->validate();
|
||||
}
|
||||
if ($this->repository->currencyInUse($currency)) {
|
||||
$messages = ['currency_code' => '200006: Currency in use.'];
|
||||
Validator::make([], $rules, $messages)->validate();
|
||||
|
||||
@@ -32,7 +32,6 @@ 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
|
||||
@@ -72,11 +71,6 @@ 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.');
|
||||
|
||||
response()->json([], 401);
|
||||
}
|
||||
|
||||
$this->repository->destroy($linkType);
|
||||
Preferences::mark();
|
||||
|
||||
@@ -27,12 +27,10 @@ namespace FireflyIII\Api\V1\Controllers\Models\TransactionLinkType;
|
||||
use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Api\V1\Requests\Models\TransactionLinkType\StoreRequest;
|
||||
use FireflyIII\Repositories\LinkType\LinkTypeRepositoryInterface;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use FireflyIII\Support\Http\Api\TransactionFilter;
|
||||
use FireflyIII\Transformers\LinkTypeTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use League\Fractal\Resource\Item;
|
||||
|
||||
@@ -44,7 +42,6 @@ final class StoreController extends Controller
|
||||
use TransactionFilter;
|
||||
|
||||
private LinkTypeRepositoryInterface $repository;
|
||||
private UserRepositoryInterface $userRepository;
|
||||
|
||||
/**
|
||||
* LinkTypeController constructor.
|
||||
@@ -54,9 +51,8 @@ final class StoreController extends Controller
|
||||
parent::__construct();
|
||||
$this->middleware(function ($request, $next) {
|
||||
/** @var User $user */
|
||||
$user = auth()->user();
|
||||
$this->repository = app(LinkTypeRepositoryInterface::class);
|
||||
$this->userRepository = app(UserRepositoryInterface::class);
|
||||
$user = auth()->user();
|
||||
$this->repository = app(LinkTypeRepositoryInterface::class);
|
||||
$this->repository->setUser($user);
|
||||
|
||||
return $next($request);
|
||||
@@ -73,15 +69,6 @@ final class StoreController extends Controller
|
||||
*/
|
||||
public function store(StoreRequest $request): JsonResponse
|
||||
{
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$rules = ['name' => 'required'];
|
||||
|
||||
if (!$this->userRepository->hasRole($admin, 'owner')) {
|
||||
// access denied:
|
||||
$messages = ['name' => '200005: You need the "owner" role to do this.'];
|
||||
Validator::make([], $rules, $messages)->validate();
|
||||
}
|
||||
$data = $request->getAll();
|
||||
// if currency ID is 0, find the currency by the code:
|
||||
$linkType = $this->repository->store($data);
|
||||
|
||||
@@ -29,12 +29,10 @@ use FireflyIII\Api\V1\Requests\Models\TransactionLinkType\UpdateRequest;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\LinkType;
|
||||
use FireflyIII\Repositories\LinkType\LinkTypeRepositoryInterface;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use FireflyIII\Support\Http\Api\TransactionFilter;
|
||||
use FireflyIII\Transformers\LinkTypeTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use League\Fractal\Resource\Item;
|
||||
|
||||
@@ -46,7 +44,6 @@ final class UpdateController extends Controller
|
||||
use TransactionFilter;
|
||||
|
||||
private LinkTypeRepositoryInterface $repository;
|
||||
private UserRepositoryInterface $userRepository;
|
||||
|
||||
/**
|
||||
* LinkTypeController constructor.
|
||||
@@ -56,9 +53,8 @@ final class UpdateController extends Controller
|
||||
parent::__construct();
|
||||
$this->middleware(function ($request, $next) {
|
||||
/** @var User $user */
|
||||
$user = auth()->user();
|
||||
$this->repository = app(LinkTypeRepositoryInterface::class);
|
||||
$this->userRepository = app(UserRepositoryInterface::class);
|
||||
$user = auth()->user();
|
||||
$this->repository = app(LinkTypeRepositoryInterface::class);
|
||||
$this->repository->setUser($user);
|
||||
|
||||
return $next($request);
|
||||
@@ -80,15 +76,6 @@ final class UpdateController extends Controller
|
||||
throw new FireflyException('200020: Link type cannot be changed.');
|
||||
}
|
||||
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$rules = ['name' => 'required'];
|
||||
|
||||
if (!$this->userRepository->hasRole($admin, 'owner')) {
|
||||
$messages = ['name' => '200005: You need the "owner" role to do this.'];
|
||||
Validator::make([], $rules, $messages)->validate();
|
||||
}
|
||||
|
||||
$data = $request->getAll();
|
||||
$this->repository->update($linkType, $data);
|
||||
$manager = $this->getManager();
|
||||
|
||||
@@ -30,12 +30,10 @@ use FireflyIII\Enums\WebhookDelivery;
|
||||
use FireflyIII\Enums\WebhookResponse;
|
||||
use FireflyIII\Enums\WebhookTrigger;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use FireflyIII\Support\Binder\EitherConfigKey;
|
||||
use FireflyIII\Support\Facades\FireflyConfig;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
/**
|
||||
@@ -43,21 +41,6 @@ use Illuminate\Validation\ValidationException;
|
||||
*/
|
||||
final class ConfigurationController extends Controller
|
||||
{
|
||||
private UserRepositoryInterface $repository;
|
||||
|
||||
/**
|
||||
* ConfigurationController constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->middleware(function ($request, $next) {
|
||||
$this->repository = app(UserRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* This endpoint is documented at:
|
||||
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/configuration/getConfiguration
|
||||
@@ -142,11 +125,6 @@ final class ConfigurationController extends Controller
|
||||
*/
|
||||
public function update(UpdateRequest $request, string $name): JsonResponse
|
||||
{
|
||||
$rules = ['value' => 'required'];
|
||||
if (!$this->repository->hasRole(auth()->user(), 'owner')) {
|
||||
$messages = ['value' => '200005: You need the "owner" role to do this.'];
|
||||
Validator::make([], $rules, $messages)->validate();
|
||||
}
|
||||
$data = $request->getAll();
|
||||
$shortName = str_replace('configuration.', '', $name);
|
||||
|
||||
|
||||
@@ -74,13 +74,9 @@ final class UserController extends Controller
|
||||
return response()->json([], 500);
|
||||
}
|
||||
|
||||
if ($this->repository->hasRole($admin, 'owner')) {
|
||||
$this->repository->destroy($user);
|
||||
$this->repository->destroy($user);
|
||||
|
||||
return response()->json([], 204);
|
||||
}
|
||||
|
||||
throw new FireflyException('200025: No access to function.');
|
||||
return response()->json([], 204);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -83,7 +83,7 @@ final class RegisterController extends Controller
|
||||
throw new FireflyException('Registration is currently not available :(');
|
||||
}
|
||||
|
||||
$this->validator($request->only(['email', 'password']))->validate();
|
||||
$this->validator($request->only(['email', 'password', 'password_confirmation']))->validate();
|
||||
$user = $this->createUser($request->only(['email', 'password']));
|
||||
Log::info(sprintf('Registered new user %s', $user->email));
|
||||
$owner = new OwnerNotifiable();
|
||||
|
||||
@@ -44,6 +44,7 @@ use Illuminate\Contracts\View\Factory;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
@@ -108,7 +109,7 @@ final class DebugController extends Controller
|
||||
Preferences::mark();
|
||||
$request->session()->forget(['start', 'end', '_previous', 'viewRange', 'range', 'is_custom_range', 'temp-mfa-secret', 'temp-mfa-codes']);
|
||||
|
||||
Artisan::call('cache:clear');
|
||||
Cache::clear();
|
||||
Artisan::call('config:clear');
|
||||
Artisan::call('route:clear');
|
||||
Artisan::call('view:clear');
|
||||
|
||||
66
app/Http/Middleware/IsAdminApi.php
Normal file
66
app/Http/Middleware/IsAdminApi.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* IsAdmin.php
|
||||
* Copyright (c) 2019 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\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Auth\Access\AuthorizationException;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
/**
|
||||
* Class IsAdmin.
|
||||
*/
|
||||
class IsAdminApi
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request. Must be admin.
|
||||
*
|
||||
* @param null|string $guard
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle(Request $request, Closure $next, $guard = null)
|
||||
{
|
||||
if (Auth::guard($guard)->guest()) {
|
||||
if ($request->ajax()) {
|
||||
return response('Unauthorized.', 401);
|
||||
}
|
||||
|
||||
return response()->redirectTo(route('login'));
|
||||
}
|
||||
|
||||
/** @var User $user */
|
||||
$user = auth()->user();
|
||||
|
||||
/** @var UserRepositoryInterface $repository */
|
||||
$repository = app(UserRepositoryInterface::class);
|
||||
if (!$repository->hasRole($user, 'owner')) {
|
||||
throw new AuthorizationException();
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
@@ -59,7 +59,7 @@ class UpdatesAccountInformation implements ShouldQueue
|
||||
/** @var RuleAction $action */
|
||||
foreach ($rule->ruleActions as $action) {
|
||||
// fix name:
|
||||
if ($oldData['name'] === $action->action_value && in_array($action->action_type, $fields, true)) {
|
||||
if (array_key_exists('name', $oldData) && $oldData['name'] === $action->action_value && in_array($action->action_type, $fields, true)) {
|
||||
Log::debug(sprintf('Rule action #%d "%s" has old account name, replace with new.', $action->id, $action->action_type));
|
||||
$action->action_value = $account->name;
|
||||
$action->save();
|
||||
@@ -105,21 +105,25 @@ class UpdatesAccountInformation implements ShouldQueue
|
||||
/** @var RuleTrigger $trigger */
|
||||
foreach ($rule->ruleTriggers as $trigger) {
|
||||
// fix name:
|
||||
if ($oldData['name'] === $trigger->trigger_value && in_array($trigger->trigger_type, $nameFields, true)) {
|
||||
if (array_key_exists('name', $oldData) && $oldData['name'] === $trigger->trigger_value && in_array($trigger->trigger_type, $nameFields, true)) {
|
||||
Log::debug(sprintf('Rule trigger #%d "%s" has old account name, replace with new.', $trigger->id, $trigger->trigger_type));
|
||||
$trigger->trigger_value = $account->name;
|
||||
$trigger->save();
|
||||
++$fixed;
|
||||
}
|
||||
// fix IBAN:
|
||||
if ($oldData['iban'] === $trigger->trigger_value && in_array($trigger->trigger_type, $numberFields, true)) {
|
||||
if (array_key_exists('iban', $oldData) && $oldData['iban'] === $trigger->trigger_value && in_array($trigger->trigger_type, $numberFields, true)) {
|
||||
Log::debug(sprintf('Rule trigger #%d "%s" has old account IBAN, replace with new.', $trigger->id, $trigger->trigger_type));
|
||||
$trigger->trigger_value = $account->iban;
|
||||
$trigger->save();
|
||||
++$fixed;
|
||||
}
|
||||
// fix account number: // account_number
|
||||
if ($oldData['account_number'] === $trigger->trigger_value && in_array($trigger->trigger_type, $numberFields, true)) {
|
||||
if (
|
||||
array_key_exists('account_number', $oldData)
|
||||
&& $oldData['account_number'] === $trigger->trigger_value
|
||||
&& in_array($trigger->trigger_type, $numberFields, true)
|
||||
) {
|
||||
Log::debug(sprintf('Rule trigger #%d "%s" has old account account_number, replace with new.', $trigger->id, $trigger->trigger_type));
|
||||
$trigger->trigger_value = $account->iban;
|
||||
$trigger->save();
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* ProcessesExchangeRates.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\Listeners\Model\CurrencyExchangeRate;
|
||||
|
||||
use FireflyIII\Events\Model\CurrencyExchangeRate\CreatedCurrencyExchangeRate;
|
||||
use FireflyIII\Events\Model\CurrencyExchangeRate\DestroyedCurrencyExchangeRate;
|
||||
use FireflyIII\Events\Model\CurrencyExchangeRate\UpdatedCurrencyExchangeRate;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Models\UserGroup;
|
||||
use FireflyIII\Services\Internal\Recalculate\PrimaryAmountRecalculationService;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\Facades\Preferences;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class ProcessesExchangeRates
|
||||
{
|
||||
public function handle(CreatedCurrencyExchangeRate|DestroyedCurrencyExchangeRate|UpdatedCurrencyExchangeRate $event): void
|
||||
{
|
||||
Preferences::mark();
|
||||
Cache::clear();
|
||||
if ($event instanceof DestroyedCurrencyExchangeRate) {
|
||||
$this->handleCurrency($event->userGroup, $event->from);
|
||||
$this->handleCurrency($event->userGroup, $event->to);
|
||||
|
||||
return;
|
||||
}
|
||||
$this->handleCurrency($event->rate->userGroup, $event->rate->fromCurrency);
|
||||
$this->handleCurrency($event->rate->userGroup, $event->rate->toCurrency);
|
||||
}
|
||||
|
||||
private function handleCurrency(UserGroup $userGroup, TransactionCurrency $currency): void
|
||||
{
|
||||
$calculator = new PrimaryAmountRecalculationService();
|
||||
if (Amount::convertToPrimary()) {
|
||||
Log::debug(sprintf('Will now convert amounts to primary currency for currency %s.', $currency->code));
|
||||
|
||||
$calculator->recalculateForGroupAndCurrency($userGroup, $currency);
|
||||
// $calculator->recalculateForGroup($userGroup);
|
||||
|
||||
return;
|
||||
}
|
||||
Log::debug('Will NOT convert to primary currency.');
|
||||
}
|
||||
}
|
||||
@@ -25,46 +25,17 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Listeners\System;
|
||||
|
||||
use FireflyIII\Events\Preferences\UserGroupChangedPrimaryCurrency;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Models\UserGroup;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
|
||||
use FireflyIII\Services\Internal\Recalculate\PrimaryAmountRecalculationService;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use Illuminate\Database\Query\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class RecalculatesPrimaryCurrencyAmounts
|
||||
{
|
||||
public function handle(UserGroupChangedPrimaryCurrency $event): void
|
||||
{
|
||||
// Reset the primary currency amounts for all objects that have it.
|
||||
Log::debug('Resetting primary currency amounts for all objects.');
|
||||
|
||||
$tables = [
|
||||
// !!! this array is also in the migration
|
||||
'accounts' => ['native_virtual_balance'],
|
||||
'available_budgets' => ['native_amount'],
|
||||
'bills' => ['native_amount_min', 'native_amount_max'],
|
||||
];
|
||||
foreach ($tables as $table => $columns) {
|
||||
Log::debug(sprintf('Now processing table "%s"', $table));
|
||||
foreach ($columns as $column) {
|
||||
Log::debug(sprintf('Resetting column "%s" in table "%s".', $column, $table));
|
||||
DB::table($table)->where('user_group_id', $event->userGroup->id)->update([$column => null]);
|
||||
}
|
||||
}
|
||||
|
||||
$this->resetPiggyBanks($event->userGroup);
|
||||
$this->resetBudgets($event->userGroup);
|
||||
$this->resetTransactions($event->userGroup);
|
||||
Log::debug('Have now reset all primary amounts to NULL.');
|
||||
// fire laravel command to recalculate them all.
|
||||
if (Amount::convertToPrimary()) {
|
||||
Log::debug('Will now convert amounts to primary currency.');
|
||||
|
||||
$calculator = new PrimaryAmountRecalculationService();
|
||||
$calculator->recalculate();
|
||||
|
||||
@@ -72,87 +43,4 @@ class RecalculatesPrimaryCurrencyAmounts
|
||||
}
|
||||
Log::debug('Will NOT convert to primary currency.');
|
||||
}
|
||||
|
||||
private function resetBudget(Budget $budget): void
|
||||
{
|
||||
foreach ($budget->autoBudgets as $autoBudget) {
|
||||
if ('' === (string) $autoBudget->native_amount) {
|
||||
continue;
|
||||
}
|
||||
Log::debug(sprintf('Resetting native_amount for budget #%d and auto budget #%d.', $budget->id, $autoBudget->id));
|
||||
$autoBudget->native_amount = null;
|
||||
$autoBudget->saveQuietly();
|
||||
}
|
||||
foreach ($budget->budgetlimits as $limit) {
|
||||
if ('' !== (string) $limit->native_amount) {
|
||||
Log::debug(sprintf('Resetting native_amount for budget #%d and budget limit #%d.', $budget->id, $limit->id));
|
||||
$limit->native_amount = null;
|
||||
$limit->saveQuietly();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function resetBudgets(UserGroup $userGroup): void
|
||||
{
|
||||
$repository = app(BudgetRepositoryInterface::class);
|
||||
$repository->setUserGroup($userGroup);
|
||||
$set = $repository->getBudgets();
|
||||
|
||||
Log::debug(sprintf('Reset primary currency of %d budget(s).', $set->count()));
|
||||
|
||||
/** @var Budget $budget */
|
||||
foreach ($set as $budget) {
|
||||
$this->resetBudget($budget);
|
||||
}
|
||||
}
|
||||
|
||||
private function resetPiggyBank(PiggyBank $piggyBank): void
|
||||
{
|
||||
if ('' !== (string) $piggyBank->native_target_amount) {
|
||||
Log::debug(sprintf('Resetting native_target_amount for piggy bank #%d.', $piggyBank->id));
|
||||
$piggyBank->native_target_amount = null;
|
||||
$piggyBank->saveQuietly();
|
||||
}
|
||||
foreach ($piggyBank->accounts as $account) {
|
||||
if ('' !== (string) $account->pivot->native_current_amount) {
|
||||
Log::debug(sprintf('Resetting native_current_amount for piggy bank #%d and account #%d.', $piggyBank->id, $account->id));
|
||||
$account->pivot->native_current_amount = null;
|
||||
$account->pivot->save();
|
||||
}
|
||||
}
|
||||
foreach ($piggyBank->piggyBankEvents as $event) {
|
||||
if ('' !== (string) $event->native_amount) {
|
||||
Log::debug(sprintf('Resetting native_amount for piggy bank #%d and event #%d.', $piggyBank->id, $event->id));
|
||||
$event->native_amount = null;
|
||||
$event->saveQuietly();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function resetPiggyBanks(UserGroup $userGroup): void
|
||||
{
|
||||
$repository = app(PiggyBankRepositoryInterface::class);
|
||||
$repository->setUserGroup($userGroup);
|
||||
$piggyBanks = $repository->getPiggyBanks();
|
||||
Log::debug(sprintf('Reset primary currency of %d piggy bank(s).', $piggyBanks->count()));
|
||||
|
||||
/** @var PiggyBank $piggyBank */
|
||||
foreach ($piggyBanks as $piggyBank) {
|
||||
$this->resetPiggyBank($piggyBank);
|
||||
}
|
||||
}
|
||||
|
||||
private function resetTransactions(UserGroup $userGroup): void
|
||||
{
|
||||
// custom query because of the potential size of this update.
|
||||
$success = DB::table('transactions')
|
||||
->join('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||
->where('transaction_journals.user_group_id', $userGroup->id)
|
||||
->where(static function (Builder $q): void {
|
||||
$q->whereNotNull('native_amount')->orWhereNotNull('native_foreign_amount');
|
||||
})
|
||||
->update(['native_amount' => null, 'native_foreign_amount' => null])
|
||||
;
|
||||
Log::debug(sprintf('Reset %d transactions.', $success));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,11 @@ class CurrencyExchangeRate extends Model
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
public function userGroup(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(UserGroup::class);
|
||||
}
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
|
||||
@@ -368,6 +368,15 @@ class BudgetRepository implements BudgetRepositoryInterface, UserGroupInterface
|
||||
|
||||
public function getBudgets(): Collection
|
||||
{
|
||||
if (null === $this->user) {
|
||||
return $this->userGroup
|
||||
->budgets()
|
||||
->orderBy('order', 'ASC')
|
||||
->orderBy('name', 'ASC')
|
||||
->get()
|
||||
;
|
||||
}
|
||||
|
||||
return $this->user
|
||||
->budgets()
|
||||
->orderBy('order', 'ASC')
|
||||
|
||||
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Services\Internal\Recalculate;
|
||||
|
||||
use FireflyIII\Events\Model\Account\UpdatedExistingAccount;
|
||||
use FireflyIII\Handlers\Observer\TransactionObserver;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AutoBudget;
|
||||
@@ -36,14 +37,16 @@ use FireflyIII\Models\PiggyBankEvent;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Models\UserGroup;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
|
||||
use FireflyIII\Repositories\UserGroup\UserGroupRepositoryInterface;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\Facades\FireflyConfig;
|
||||
use FireflyIII\Support\Facades\Preferences;
|
||||
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
|
||||
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
|
||||
use Illuminate\Database\Query\Builder;
|
||||
use Illuminate\Database\Query\Builder as DatabaseBuilder;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
@@ -57,14 +60,52 @@ class PrimaryAmountRecalculationService
|
||||
|
||||
/** @var UserGroupRepositoryInterface $repository */
|
||||
$repository = app(UserGroupRepositoryInterface::class);
|
||||
Preferences::mark();
|
||||
|
||||
/** @var UserGroup $userGroup */
|
||||
foreach ($repository->getAll() as $userGroup) {
|
||||
Log::debug('Resetting primary currency amounts for all objects.');
|
||||
$this->resetGenericTables($userGroup);
|
||||
$this->resetPiggyBanks($userGroup);
|
||||
$this->resetBudgets($userGroup);
|
||||
$this->resetTransactions($userGroup);
|
||||
Log::debug('Have now reset all primary amounts to NULL.');
|
||||
$this->recalculateForGroup($userGroup);
|
||||
}
|
||||
}
|
||||
|
||||
public function recalculateForGroup(UserGroup $userGroup): void
|
||||
{
|
||||
Log::debug(sprintf('Now recalculating primary amounts for user group #%d', $userGroup->id));
|
||||
|
||||
// do a check with the group's currency so we can skip some stuff.
|
||||
$currency = Amount::getPrimaryCurrencyByUserGroup($userGroup);
|
||||
|
||||
$this->recalculateAccounts($userGroup, $currency);
|
||||
$this->recalculatePiggyBanks($userGroup, $currency);
|
||||
$this->recalculateBudgets($userGroup, $currency);
|
||||
$this->recalculateAvailableBudgets($userGroup, $currency);
|
||||
$this->recalculateBills($userGroup, $currency);
|
||||
$this->calculateTransactions($userGroup, $currency);
|
||||
}
|
||||
|
||||
public function recalculateForGroupAndCurrency(UserGroup $userGroup, TransactionCurrency $limitCurrency): void
|
||||
{
|
||||
// do a check with the group's currency so we can skip some stuff.
|
||||
$currency = Amount::getPrimaryCurrencyByUserGroup($userGroup);
|
||||
if ($limitCurrency->id === $currency->id) {
|
||||
Log::debug(sprintf('Can skip recalculation because user requested the same currencies (%s).', $limitCurrency->code));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->recalculateAccountsForCurrency($userGroup, $currency, $limitCurrency);
|
||||
$this->recalculatePiggyBanks($userGroup, $currency);
|
||||
$this->recalculateBudgets($userGroup, $currency);
|
||||
$this->recalculateAvailableBudgets($userGroup, $currency);
|
||||
$this->recalculateBills($userGroup, $currency);
|
||||
$this->calculateTransactionsForCurrency($userGroup, $currency, $limitCurrency);
|
||||
}
|
||||
|
||||
private function calculateTransactions(UserGroup $userGroup, TransactionCurrency $currency): void
|
||||
{
|
||||
// custom query because of the potential size of this update.
|
||||
@@ -86,7 +127,10 @@ class PrimaryAmountRecalculationService
|
||||
->get(['transactions.id'])
|
||||
;
|
||||
TransactionObserver::$recalculate = false;
|
||||
Log::debug(sprintf('Count of set is %d', $set->count()));
|
||||
foreach ($set as $item) {
|
||||
Log::debug(sprintf('Touch transaction #%d', $item->id));
|
||||
|
||||
// here we are.
|
||||
/** @var null|Transaction $transaction */
|
||||
$transaction = Transaction::find($item->id);
|
||||
@@ -96,13 +140,42 @@ class PrimaryAmountRecalculationService
|
||||
Log::debug(sprintf('Recalculated %d transactions.', $set->count()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Only recalculate accounts that have a virtual balance.
|
||||
* TODO this routine must filter on accounts that are NOT in the userGroup's currency.
|
||||
*/
|
||||
private function recalculateAccounts(UserGroup $userGroup): void
|
||||
private function calculateTransactionsForCurrency(UserGroup $userGroup, TransactionCurrency $currency, TransactionCurrency $limitCurrency): void
|
||||
{
|
||||
$set = $userGroup
|
||||
Log::debug(sprintf('Now in calculateTransactionsForCurrency(#%d, %s, %s)', $userGroup->id, $currency->code, $limitCurrency->code));
|
||||
// custom query because of the potential size of this update.
|
||||
$set = DB::table('transactions')
|
||||
->join('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||
->where('transaction_journals.user_group_id', $userGroup->id)
|
||||
->where(static function (DatabaseBuilder $q1) use ($currency): void {
|
||||
$q1->where(static function (DatabaseBuilder $q2) use ($currency): void {
|
||||
$q2->whereNot('transactions.transaction_currency_id', $currency->id)->whereNull('transactions.foreign_currency_id');
|
||||
})->orWhere(static function (DatabaseBuilder $q3) use ($currency): void {
|
||||
$q3->whereNot('transactions.transaction_currency_id', $currency->id)->whereNot('transactions.foreign_currency_id', $currency->id);
|
||||
});
|
||||
})
|
||||
// must be in the limit currency.
|
||||
->where('transactions.transaction_currency_id', $limitCurrency->id)
|
||||
->orWhere('transactions.foreign_currency_id', $limitCurrency->id)
|
||||
->get(['transactions.id'])
|
||||
;
|
||||
TransactionObserver::$recalculate = false;
|
||||
Log::debug(sprintf('Count of set is %d', $set->count()));
|
||||
foreach ($set as $item) {
|
||||
Log::debug(sprintf('Touch transaction #%d', $item->id));
|
||||
|
||||
// here we are.
|
||||
/** @var null|Transaction $transaction */
|
||||
$transaction = Transaction::find($item->id);
|
||||
$transaction?->touch();
|
||||
}
|
||||
TransactionObserver::$recalculate = true;
|
||||
Log::debug(sprintf('Recalculated %d transactions.', $set->count()));
|
||||
}
|
||||
|
||||
private function collectAccounts(UserGroup $userGroup): Collection
|
||||
{
|
||||
return $userGroup
|
||||
->accounts()
|
||||
->where(static function (EloquentBuilder $q): void {
|
||||
$q->whereNotNull('virtual_balance');
|
||||
@@ -117,14 +190,59 @@ class PrimaryAmountRecalculationService
|
||||
})
|
||||
->get()
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only recalculate accounts that have a virtual balance.
|
||||
*/
|
||||
private function recalculateAccounts(UserGroup $userGroup, TransactionCurrency $groupCurrency): void
|
||||
{
|
||||
Log::debug(sprintf('recalculateAccounts(#%d, %s)', $userGroup->id, $groupCurrency->code));
|
||||
$set = $this->collectAccounts($userGroup);
|
||||
|
||||
/** @var Account $account */
|
||||
foreach ($set as $account) {
|
||||
$currencyId = (int) $account->accountMeta()->where('name', 'currency_id')->first()->data;
|
||||
if ($groupCurrency->id === $currencyId) {
|
||||
Log::debug(sprintf('Account "%s" is in group currency %s. Skip.', $account->name, $groupCurrency->code));
|
||||
|
||||
continue;
|
||||
}
|
||||
Log::debug(sprintf('Account "%s" is NOT in group currency %s, so do it.', $account->name, $groupCurrency->code));
|
||||
$account->touch();
|
||||
}
|
||||
Log::debug(sprintf('Recalculated %d accounts for user group #%d.', $set->count(), $userGroup->id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Only recalculate accounts that have a virtual balance.
|
||||
*/
|
||||
private function recalculateAccountsForCurrency(UserGroup $userGroup, TransactionCurrency $groupCurrency, TransactionCurrency $limitCurrency): void
|
||||
{
|
||||
Log::debug(sprintf('recalculateAccountsForCurrency(#%d, %s, %s)', $userGroup->id, $groupCurrency->code, $limitCurrency->code));
|
||||
|
||||
$set = $this->collectAccounts($userGroup);
|
||||
|
||||
/** @var Account $account */
|
||||
foreach ($set as $account) {
|
||||
$currencyId = (int) $account->accountMeta()->where('name', 'currency_id')->first()->data;
|
||||
if ($groupCurrency->id === $currencyId) {
|
||||
Log::debug(sprintf('Account "%s" is in group currency %s. Skip.', $account->name, $groupCurrency->code));
|
||||
|
||||
continue;
|
||||
}
|
||||
if ($limitCurrency->id !== $currencyId) {
|
||||
Log::debug(sprintf('Account "%s" is NOT in limit currency %s, skip.', $account->name, $limitCurrency->code));
|
||||
|
||||
continue;
|
||||
}
|
||||
Log::debug(sprintf('Account "%s" is NOT in group currency %s, so do it.', $account->name, $groupCurrency->code));
|
||||
// TODO it is bad form to call an event from an event but OK.
|
||||
event(new UpdatedExistingAccount($account, []));
|
||||
}
|
||||
Log::debug(sprintf('Recalculated %d accounts for user group #%d.', $set->count(), $userGroup->id));
|
||||
}
|
||||
|
||||
private function recalculateAutoBudgets(Budget $budget, TransactionCurrency $currency): void
|
||||
{
|
||||
$set = $budget->autoBudgets()->where('transaction_currency_id', '!=', $currency->id)->get();
|
||||
@@ -184,21 +302,6 @@ class PrimaryAmountRecalculationService
|
||||
Log::debug(sprintf('Recalculated %d budgets.', $set->count()));
|
||||
}
|
||||
|
||||
private function recalculateForGroup(UserGroup $userGroup): void
|
||||
{
|
||||
Log::debug(sprintf('Now recalculating primary amounts for user group #%d', $userGroup->id));
|
||||
$this->recalculateAccounts($userGroup);
|
||||
|
||||
// do a check with the group's currency so we can skip some stuff.
|
||||
$currency = Amount::getPrimaryCurrencyByUserGroup($userGroup);
|
||||
|
||||
$this->recalculatePiggyBanks($userGroup, $currency);
|
||||
$this->recalculateBudgets($userGroup, $currency);
|
||||
$this->recalculateAvailableBudgets($userGroup, $currency);
|
||||
$this->recalculateBills($userGroup, $currency);
|
||||
$this->calculateTransactions($userGroup, $currency);
|
||||
}
|
||||
|
||||
private function recalculatePiggyBankEvents(PiggyBank $piggyBank): void
|
||||
{
|
||||
$set = $piggyBank->piggyBankEvents()->get();
|
||||
@@ -240,4 +343,104 @@ class PrimaryAmountRecalculationService
|
||||
}
|
||||
Log::debug(sprintf('Recalculated %d piggy banks for user group #%d.', $set->count(), $userGroup->id));
|
||||
}
|
||||
|
||||
private function resetBudget(Budget $budget): void
|
||||
{
|
||||
foreach ($budget->autoBudgets as $autoBudget) {
|
||||
if ('' === (string) $autoBudget->native_amount) {
|
||||
continue;
|
||||
}
|
||||
Log::debug(sprintf('Resetting native_amount for budget #%d and auto budget #%d.', $budget->id, $autoBudget->id));
|
||||
$autoBudget->native_amount = null;
|
||||
$autoBudget->saveQuietly();
|
||||
}
|
||||
foreach ($budget->budgetlimits as $limit) {
|
||||
if ('' !== (string) $limit->native_amount) {
|
||||
Log::debug(sprintf('Resetting native_amount for budget #%d and budget limit #%d.', $budget->id, $limit->id));
|
||||
$limit->native_amount = null;
|
||||
$limit->saveQuietly();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function resetBudgets(UserGroup $userGroup): void
|
||||
{
|
||||
$repository = app(BudgetRepositoryInterface::class);
|
||||
$repository->setUserGroup($userGroup);
|
||||
$set = $repository->getBudgets();
|
||||
|
||||
Log::debug(sprintf('Reset primary currency of %d budget(s).', $set->count()));
|
||||
|
||||
/** @var Budget $budget */
|
||||
foreach ($set as $budget) {
|
||||
$this->resetBudget($budget);
|
||||
}
|
||||
}
|
||||
|
||||
private function resetGenericTables(UserGroup $userGroup): void
|
||||
{
|
||||
$tables = [
|
||||
// !!! this array is also in the migration
|
||||
'accounts' => ['native_virtual_balance'],
|
||||
'available_budgets' => ['native_amount'],
|
||||
'bills' => ['native_amount_min', 'native_amount_max'],
|
||||
];
|
||||
foreach ($tables as $table => $columns) {
|
||||
Log::debug(sprintf('Now processing table "%s"', $table));
|
||||
foreach ($columns as $column) {
|
||||
Log::debug(sprintf('Resetting column "%s" in table "%s".', $column, $table));
|
||||
DB::table($table)->where('user_group_id', $userGroup->id)->update([$column => null]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function resetPiggyBank(PiggyBank $piggyBank): void
|
||||
{
|
||||
if ('' !== (string) $piggyBank->native_target_amount) {
|
||||
Log::debug(sprintf('Resetting native_target_amount for piggy bank #%d.', $piggyBank->id));
|
||||
$piggyBank->native_target_amount = null;
|
||||
$piggyBank->saveQuietly();
|
||||
}
|
||||
foreach ($piggyBank->accounts as $account) {
|
||||
if ('' !== (string) $account->pivot->native_current_amount) {
|
||||
Log::debug(sprintf('Resetting native_current_amount for piggy bank #%d and account #%d.', $piggyBank->id, $account->id));
|
||||
$account->pivot->native_current_amount = null;
|
||||
$account->pivot->save();
|
||||
}
|
||||
}
|
||||
foreach ($piggyBank->piggyBankEvents as $event) {
|
||||
if ('' !== (string) $event->native_amount) {
|
||||
Log::debug(sprintf('Resetting native_amount for piggy bank #%d and event #%d.', $piggyBank->id, $event->id));
|
||||
$event->native_amount = null;
|
||||
$event->saveQuietly();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function resetPiggyBanks(UserGroup $userGroup): void
|
||||
{
|
||||
$repository = app(PiggyBankRepositoryInterface::class);
|
||||
$repository->setUserGroup($userGroup);
|
||||
$piggyBanks = $repository->getPiggyBanks();
|
||||
Log::debug(sprintf('Reset primary currency of %d piggy bank(s).', $piggyBanks->count()));
|
||||
|
||||
/** @var PiggyBank $piggyBank */
|
||||
foreach ($piggyBanks as $piggyBank) {
|
||||
$this->resetPiggyBank($piggyBank);
|
||||
}
|
||||
}
|
||||
|
||||
private function resetTransactions(UserGroup $userGroup): void
|
||||
{
|
||||
// custom query because of the potential size of this update.
|
||||
$success = DB::table('transactions')
|
||||
->join('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||
->where('transaction_journals.user_group_id', $userGroup->id)
|
||||
->where(static function (Builder $q): void {
|
||||
$q->whereNotNull('native_amount')->orWhereNotNull('native_foreign_amount');
|
||||
})
|
||||
->update(['native_amount' => null, 'native_foreign_amount' => null])
|
||||
;
|
||||
Log::debug(sprintf('Reset %d transactions.', $success));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ use FireflyIII\Http\Middleware\EncryptCookies;
|
||||
use FireflyIII\Http\Middleware\Installer;
|
||||
use FireflyIII\Http\Middleware\InterestingMessage;
|
||||
use FireflyIII\Http\Middleware\IsAdmin;
|
||||
use FireflyIII\Http\Middleware\IsAdminApi;
|
||||
use FireflyIII\Http\Middleware\Range;
|
||||
use FireflyIII\Http\Middleware\RedirectIfAuthenticated;
|
||||
use FireflyIII\Http\Middleware\SecureHeaders;
|
||||
@@ -157,7 +158,7 @@ $app = Application::configure(basePath: dirname(__DIR__))
|
||||
// This middleware is added to ensure that the user is not only logged in and
|
||||
// authenticated (with MFA and everything), but also admin.
|
||||
$middleware->appendToGroup('api-admin', [
|
||||
IsAdmin::class,
|
||||
IsAdminApi::class,
|
||||
]);
|
||||
$middleware->appendToGroup('admin', [
|
||||
IsAdmin::class,
|
||||
|
||||
32
changelog.md
32
changelog.md
@@ -3,38 +3,32 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## v6.5.7 - 2026-03-xx
|
||||
### v6.5.8 - 2026-03-22
|
||||
|
||||
<!-- summary: If you can read this I forgot to update the summary! -->
|
||||
<!-- summary: This release fixes a regression bug in user registration. -->
|
||||
|
||||
### Added
|
||||
### Fixed
|
||||
|
||||
- Initial release.
|
||||
- [Issue 11995](https://github.com/firefly-iii/firefly-iii/issues/11995) (User registration breaks on password validation) reported by @mikaelhm
|
||||
|
||||
### Changed
|
||||
## v6.5.7 - 2026-03-21
|
||||
|
||||
- Initial release.
|
||||
|
||||
### Deprecated
|
||||
|
||||
- Initial release.
|
||||
|
||||
### Removed
|
||||
|
||||
- Initial release.
|
||||
<!-- summary: There is a new security policy for AI-generated security advisories and of course, some interesting but annoying bugs fixed. -->
|
||||
|
||||
### Fixed
|
||||
|
||||
- [Issue 11964](https://github.com/firefly-iii/firefly-iii/issues/11964) ("Left to spend" is not taking into account non-main currency withdrawals (when displaying in primary currency)) reported by @absdjfh
|
||||
- [Issue 11966](https://github.com/firefly-iii/firefly-iii/issues/11966) (Error when trying to export data in CSV (Export data via front end)) reported by @jgmm81
|
||||
|
||||
### Security
|
||||
|
||||
- Initial release.
|
||||
- [Issue 11969](https://github.com/firefly-iii/firefly-iii/issues/11969) (Problem found when editing a multi-currency record, as well as details in the "Audit log entries") reported by @jgmm81
|
||||
- [PR 11974](https://github.com/firefly-iii/firefly-iii/pull/11974) (Fix typo in SMTP server comment in .env.example) reported by @NorskNoobing
|
||||
- [Discussion 11977](https://github.com/orgs/firefly-iii/discussions/11977) (CSP header `form-action 'self'` prevents form submission because it's a redirect) started by @superrio0187
|
||||
- [Issue 11978](https://github.com/firefly-iii/firefly-iii/issues/11978) (Tags not associated with any record display incorrect information) reported by @jgmm81
|
||||
- [Issue 11982](https://github.com/firefly-iii/firefly-iii/issues/11982) (Foreign currency account value in primary currency does not update after changing exchange rates) reported by @gattacus
|
||||
- Remove old `zoomLevel` / `zoom_level` database references for tags, since they are no longer queries anyway.
|
||||
|
||||
### API
|
||||
|
||||
- Initial release.
|
||||
- [Issue 11976](https://github.com/firefly-iii/firefly-iii/issues/11976) (New lines are removed from rule description when created using API POST) reported by @AlexRNL
|
||||
|
||||
## v6.5.6 - 2026-03-16
|
||||
|
||||
|
||||
18
composer.lock
generated
18
composer.lock
generated
@@ -5781,27 +5781,27 @@
|
||||
},
|
||||
{
|
||||
"name": "rcrowe/twigbridge",
|
||||
"version": "v0.14.6",
|
||||
"version": "v0.14.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/rcrowe/TwigBridge.git",
|
||||
"reference": "0798ee4b5e5b943d0200850acaa87ccd82e2fe45"
|
||||
"reference": "03a767c8d5c1d74d5f14e9fc754619a271822663"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/rcrowe/TwigBridge/zipball/0798ee4b5e5b943d0200850acaa87ccd82e2fe45",
|
||||
"reference": "0798ee4b5e5b943d0200850acaa87ccd82e2fe45",
|
||||
"url": "https://api.github.com/repos/rcrowe/TwigBridge/zipball/03a767c8d5c1d74d5f14e9fc754619a271822663",
|
||||
"reference": "03a767c8d5c1d74d5f14e9fc754619a271822663",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/support": "^9|^10|^11|^12",
|
||||
"illuminate/view": "^9|^10|^11|^12",
|
||||
"illuminate/support": "^9|^10|^11|^12|^13",
|
||||
"illuminate/view": "^9|^10|^11|^12|^13",
|
||||
"php": "^8.1",
|
||||
"twig/twig": "~3.21"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-json": "*",
|
||||
"laravel/framework": "^9|^10|^11|^12",
|
||||
"laravel/framework": "^9|^10|^11|^12|^13",
|
||||
"mockery/mockery": "^1.3.1",
|
||||
"phpunit/phpunit": "^8.5.8 || ^9.3.7 || ^10.0 || ^11.0 || ^12.0",
|
||||
"squizlabs/php_codesniffer": "^3.6"
|
||||
@@ -5847,9 +5847,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/rcrowe/TwigBridge/issues",
|
||||
"source": "https://github.com/rcrowe/TwigBridge/tree/v0.14.6"
|
||||
"source": "https://github.com/rcrowe/TwigBridge/tree/v0.14.7"
|
||||
},
|
||||
"time": "2025-08-20T11:25:49+00:00"
|
||||
"time": "2026-03-20T16:59:18+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spatie/backtrace",
|
||||
|
||||
@@ -78,8 +78,8 @@ return [
|
||||
'running_balance_column' => (bool)envDefaultWhenEmpty(env('USE_RUNNING_BALANCE'), true), // this is only the default value, is not used.
|
||||
// see cer.php for exchange rates feature flag.
|
||||
],
|
||||
'version' => 'develop/2026-03-20',
|
||||
'build_time' => 1773991310,
|
||||
'version' => '6.5.8',
|
||||
'build_time' => 1774090288,
|
||||
'api_version' => '2.1.0', // field is no longer used.
|
||||
'db_version' => 28, // field is no longer used.
|
||||
|
||||
|
||||
236
package-lock.json
generated
236
package-lock.json
generated
@@ -2620,9 +2620,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz",
|
||||
"integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==",
|
||||
"version": "4.59.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.1.tgz",
|
||||
"integrity": "sha512-xB0b51TB7IfDEzAojXahmr+gfA00uYVInJGgNNkeQG6RPnCPGr7udsylFLTubuIUSRE6FkcI1NElyRt83PP5oQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -2634,9 +2634,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm64": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz",
|
||||
"integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==",
|
||||
"version": "4.59.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.1.tgz",
|
||||
"integrity": "sha512-XOjPId0qwSDKHaIsdzHJtKCxX0+nH8MhBwvrNsT7tVyKmdTx1jJ4XzN5RZXCdTzMpufLb+B8llTC0D8uCrLhcw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -2648,9 +2648,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz",
|
||||
"integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==",
|
||||
"version": "4.59.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.1.tgz",
|
||||
"integrity": "sha512-vQuRd28p0gQpPrS6kppd8IrWmFo42U8Pz1XLRjSZXq5zCqyMDYFABT7/sywL11mO1EL10Qhh7MVPEwkG8GiBeg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -2662,9 +2662,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-x64": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz",
|
||||
"integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==",
|
||||
"version": "4.59.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.1.tgz",
|
||||
"integrity": "sha512-x6VG6U29+Ivlnajrg1IHdzXeAwSoEHBFVO+CtC9Brugx6de712CUJobRUxsIA0KYrQvCmzNrMPFTT1A4CCqNTg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -2676,9 +2676,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-arm64": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz",
|
||||
"integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==",
|
||||
"version": "4.59.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.1.tgz",
|
||||
"integrity": "sha512-Sgi0Uo6t1YCHJMNO3Y8+bm+SvOanUGkoZKn/VJPwYUe2kp31X5KnXmzKd/NjW8iA3gFcfNZ64zh14uOGrIllCQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -2690,9 +2690,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-x64": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz",
|
||||
"integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==",
|
||||
"version": "4.59.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.1.tgz",
|
||||
"integrity": "sha512-AM4xnwEZwukdhk7laMWfzWu9JGSVnJd+Fowt6Fd7QW1nrf3h0Hp7Qx5881M4aqrUlKBCybOxz0jofvIIfl7C5g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -2704,9 +2704,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz",
|
||||
"integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==",
|
||||
"version": "4.59.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.1.tgz",
|
||||
"integrity": "sha512-KUizqxpwaR2AZdAUsMWfL/C94pUu7TKpoPd88c8yFVixJ+l9hejkrwoK5Zj3wiNh65UeyryKnJyxL1b7yNqFQA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -2718,9 +2718,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz",
|
||||
"integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==",
|
||||
"version": "4.59.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.1.tgz",
|
||||
"integrity": "sha512-MZoQ/am77ckJtZGFAtPucgUuJWiop3m2R3lw7tC0QCcbfl4DRhQUBUkHWCkcrT3pqy5Mzv5QQgY6Dmlba6iTWg==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -2732,9 +2732,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz",
|
||||
"integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==",
|
||||
"version": "4.59.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.1.tgz",
|
||||
"integrity": "sha512-Sez95TP6xGjkWB1608EfhCX1gdGrO5wzyN99VqzRtC17x/1bhw5VU1V0GfKUwbW/Xr1J8mSasoFoJa6Y7aGGSA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -2746,9 +2746,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz",
|
||||
"integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==",
|
||||
"version": "4.59.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.1.tgz",
|
||||
"integrity": "sha512-9Cs2Seq98LWNOJzR89EGTZoiP8EkZ9UbQhBlDgfAkM6asVna1xJ04W2CLYWDN/RpUgOjtQvcv8wQVi1t5oQazA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -2760,9 +2760,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-loong64-gnu": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz",
|
||||
"integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==",
|
||||
"version": "4.59.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.1.tgz",
|
||||
"integrity": "sha512-n9yqttftgFy7IrNEnHy1bOp6B4OSe8mJDiPkT7EqlM9FnKOwUMnCK62ixW0Kd9Clw0/wgvh8+SqaDXMFvw3KqQ==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
@@ -2774,9 +2774,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-loong64-musl": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz",
|
||||
"integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==",
|
||||
"version": "4.59.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.1.tgz",
|
||||
"integrity": "sha512-SfpNXDzVTqs/riak4xXcLpq5gIQWsqGWMhN1AGRQKB4qGSs4r0sEs3ervXPcE1O9RsQ5bm8Muz6zmQpQnPss1g==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
@@ -2788,9 +2788,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-ppc64-gnu": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz",
|
||||
"integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==",
|
||||
"version": "4.59.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.1.tgz",
|
||||
"integrity": "sha512-LjaChED0wQnjKZU+tsmGbN+9nN1XhaWUkAlSbTdhpEseCS4a15f/Q8xC2BN4GDKRzhhLZpYtJBZr2NZhR0jvNw==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
@@ -2802,9 +2802,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-ppc64-musl": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz",
|
||||
"integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==",
|
||||
"version": "4.59.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.1.tgz",
|
||||
"integrity": "sha512-ojW7iTJSIs4pwB2xV6QXGwNyDctvXOivYllttuPbXguuKDX5vwpqYJsHc6D2LZzjDGHML414Tuj3LvVPe1CT1A==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
@@ -2816,9 +2816,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz",
|
||||
"integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==",
|
||||
"version": "4.59.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.1.tgz",
|
||||
"integrity": "sha512-FP+Q6WTcxxvsr0wQczhSE+tOZvFPV8A/mUE6mhZYFW9/eea/y/XqAgRoLLMuE9Cz0hfX5bi7p116IWoB+P237A==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
@@ -2830,9 +2830,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-musl": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz",
|
||||
"integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==",
|
||||
"version": "4.59.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.1.tgz",
|
||||
"integrity": "sha512-L1uD9b/Ig8Z+rn1KttCJjwhN1FgjRMBKsPaBsDKkfUl7GfFq71pU4vWCnpOsGljycFEbkHWARZLf4lMYg3WOLw==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
@@ -2844,9 +2844,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz",
|
||||
"integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==",
|
||||
"version": "4.59.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.1.tgz",
|
||||
"integrity": "sha512-EZc9NGTk/oSUzzOD4nYY4gIjteo2M3CiozX6t1IXGCOdgxJTlVu/7EdPeiqeHPSIrxkLhavqpBAUCfvC6vBOug==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
@@ -2858,9 +2858,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz",
|
||||
"integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==",
|
||||
"version": "4.59.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.1.tgz",
|
||||
"integrity": "sha512-NQ9KyU1Anuy59L8+HHOKM++CoUxrQWrZWXRik4BJFm+7i5NP6q/SW43xIBr80zzt+PDBJ7LeNmloQGfa0JGk0w==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -2872,9 +2872,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz",
|
||||
"integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==",
|
||||
"version": "4.59.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.1.tgz",
|
||||
"integrity": "sha512-GZkLk2t6naywsveSFBsEb0PLU+JC9ggVjbndsbG20VPhar6D1gkMfCx4NfP9owpovBXTN+eRdqGSkDGIxPHhmQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -2886,9 +2886,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-openbsd-x64": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz",
|
||||
"integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==",
|
||||
"version": "4.59.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.1.tgz",
|
||||
"integrity": "sha512-1hjG9Jpl2KDOetr64iQd8AZAEjkDUUK5RbDkYWsViYLC1op1oNzdjMJeFiofcGhqbNTaY2kfgqowE7DILifsrA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -2900,9 +2900,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-openharmony-arm64": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz",
|
||||
"integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==",
|
||||
"version": "4.59.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.1.tgz",
|
||||
"integrity": "sha512-ARoKfflk0SiiYm3r1fmF73K/yB+PThmOwfWCk1sr7x/k9dc3uGLWuEE9if+Pw21el8MSpp3TMnG5vLNsJ/MMGQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -2914,9 +2914,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz",
|
||||
"integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==",
|
||||
"version": "4.59.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.1.tgz",
|
||||
"integrity": "sha512-oOST61G6VM45Mz2vdzWMr1s2slI7y9LqxEV5fCoWi2MDONmMvgsJVHSXxce/I2xOSZPTZ47nDPOl1tkwKWSHcw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -2928,9 +2928,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz",
|
||||
"integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==",
|
||||
"version": "4.59.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.1.tgz",
|
||||
"integrity": "sha512-x5WgLi5dWpRz7WclKBGEF15LcWTh0ewrHM6Cq4A+WUbkysUMZNeqt05bwPonOQ3ihPS/WMhAZV5zB1DfnI4Sxg==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@@ -2942,9 +2942,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-x64-gnu": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz",
|
||||
"integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==",
|
||||
"version": "4.59.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.1.tgz",
|
||||
"integrity": "sha512-wS+zHAJRVP5zOL0e+a3V3E/NTEwM2HEvvNKoDy5Xcfs0o8lljxn+EAFPkUsxihBdmDq1JWzXmmB9cbssCPdxxw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -2956,9 +2956,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz",
|
||||
"integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==",
|
||||
"version": "4.59.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.1.tgz",
|
||||
"integrity": "sha512-rhHyrMeLpErT/C7BxcEsU4COHQUzHyrPYW5tOZUeUhziNtRuYxmDWvqQqzpuUt8xpOgmbKa1btGXfnA/ANVO+g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -5066,9 +5066,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/cosmiconfig/node_modules/yaml": {
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
|
||||
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
|
||||
"version": "1.10.3",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz",
|
||||
"integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
@@ -5403,9 +5403,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/cssnano/node_modules/yaml": {
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
|
||||
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
|
||||
"version": "1.10.3",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz",
|
||||
"integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
@@ -7143,9 +7143,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/i18next": {
|
||||
"version": "25.8.20",
|
||||
"resolved": "https://registry.npmjs.org/i18next/-/i18next-25.8.20.tgz",
|
||||
"integrity": "sha512-xjo9+lbX/P1tQt3xpO2rfJiBppNfUnNIPKgCvNsTKsvTOCro1Qr/geXVg1N47j5ScOSaXAPq8ET93raK3Rr06A==",
|
||||
"version": "25.9.0",
|
||||
"resolved": "https://registry.npmjs.org/i18next/-/i18next-25.9.0.tgz",
|
||||
"integrity": "sha512-mJ4rVRNWOTkqh5xnaGR6iMFT5vEw3Y2MTJhcjinR/7u8cRv6dAfC0ofuePh5fVPxoh395p6JdrJTStCcNW66gg==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -9156,9 +9156,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-load-config/node_modules/yaml": {
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
|
||||
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
|
||||
"version": "1.10.3",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz",
|
||||
"integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
@@ -10128,9 +10128,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz",
|
||||
"integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==",
|
||||
"version": "4.59.1",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.1.tgz",
|
||||
"integrity": "sha512-iZKH8BeoCwTCBTZBZWQQMreekd4mdomwdjIQ40GC1oZm6o+8PnNMIxFOiCsGMWeS8iDJ7KZcl7KwmKk/0HOQpA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -10144,31 +10144,31 @@
|
||||
"npm": ">=8.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rollup/rollup-android-arm-eabi": "4.59.0",
|
||||
"@rollup/rollup-android-arm64": "4.59.0",
|
||||
"@rollup/rollup-darwin-arm64": "4.59.0",
|
||||
"@rollup/rollup-darwin-x64": "4.59.0",
|
||||
"@rollup/rollup-freebsd-arm64": "4.59.0",
|
||||
"@rollup/rollup-freebsd-x64": "4.59.0",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.59.0",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.59.0",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.59.0",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.59.0",
|
||||
"@rollup/rollup-linux-loong64-gnu": "4.59.0",
|
||||
"@rollup/rollup-linux-loong64-musl": "4.59.0",
|
||||
"@rollup/rollup-linux-ppc64-gnu": "4.59.0",
|
||||
"@rollup/rollup-linux-ppc64-musl": "4.59.0",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.59.0",
|
||||
"@rollup/rollup-linux-riscv64-musl": "4.59.0",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.59.0",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.59.0",
|
||||
"@rollup/rollup-linux-x64-musl": "4.59.0",
|
||||
"@rollup/rollup-openbsd-x64": "4.59.0",
|
||||
"@rollup/rollup-openharmony-arm64": "4.59.0",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.59.0",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.59.0",
|
||||
"@rollup/rollup-win32-x64-gnu": "4.59.0",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.59.0",
|
||||
"@rollup/rollup-android-arm-eabi": "4.59.1",
|
||||
"@rollup/rollup-android-arm64": "4.59.1",
|
||||
"@rollup/rollup-darwin-arm64": "4.59.1",
|
||||
"@rollup/rollup-darwin-x64": "4.59.1",
|
||||
"@rollup/rollup-freebsd-arm64": "4.59.1",
|
||||
"@rollup/rollup-freebsd-x64": "4.59.1",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.59.1",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.59.1",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.59.1",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.59.1",
|
||||
"@rollup/rollup-linux-loong64-gnu": "4.59.1",
|
||||
"@rollup/rollup-linux-loong64-musl": "4.59.1",
|
||||
"@rollup/rollup-linux-ppc64-gnu": "4.59.1",
|
||||
"@rollup/rollup-linux-ppc64-musl": "4.59.1",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.59.1",
|
||||
"@rollup/rollup-linux-riscv64-musl": "4.59.1",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.59.1",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.59.1",
|
||||
"@rollup/rollup-linux-x64-musl": "4.59.1",
|
||||
"@rollup/rollup-openbsd-x64": "4.59.1",
|
||||
"@rollup/rollup-openharmony-arm64": "4.59.1",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.59.1",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.59.1",
|
||||
"@rollup/rollup-win32-x64-gnu": "4.59.1",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.59.1",
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
@@ -12422,9 +12422,9 @@
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/yaml": {
|
||||
"version": "2.8.2",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz",
|
||||
"integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==",
|
||||
"version": "2.8.3",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz",
|
||||
"integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==",
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"yaml": "bin.mjs"
|
||||
|
||||
@@ -20,6 +20,14 @@
|
||||
|
||||
export default class GenericObjectRenderer {
|
||||
renderUrl(url, title, text) {
|
||||
return `<a href="${url}" title="${title}">${text}</a>`;
|
||||
return `<a href="${url}" title="${this.escapeHtml(title)}">${this.escapeHtml(text)}</a>`;
|
||||
}
|
||||
escapeHtml(unsafe) {
|
||||
return unsafe
|
||||
.replaceAll("&", "&")
|
||||
.replaceAll("<", "<")
|
||||
.replaceAll(">", ">")
|
||||
.replaceAll('"', """)
|
||||
.replaceAll("'", "'");
|
||||
};
|
||||
}
|
||||
|
||||
@@ -636,12 +636,9 @@ Route::group(
|
||||
],
|
||||
static function (): void {
|
||||
Route::get('', ['uses' => 'ShowController@index', 'as' => 'index']);
|
||||
Route::post('', ['uses' => 'StoreController@store', 'as' => 'store']);
|
||||
Route::get('primary', ['uses' => 'ShowController@showPrimary', 'as' => 'show.primary']);
|
||||
Route::get('default', ['uses' => 'ShowController@showPrimary', 'as' => 'show.default']);
|
||||
Route::get('{currency_code}', ['uses' => 'ShowController@show', 'as' => 'show']);
|
||||
Route::put('{currency_code?}', ['uses' => 'UpdateController@update', 'as' => 'update']);
|
||||
Route::delete('{currency_code}', ['uses' => 'DestroyController@destroy', 'as' => 'delete']);
|
||||
|
||||
Route::post('{currency_code}/enable', ['uses' => 'UpdateController@enable', 'as' => 'enable']);
|
||||
Route::post('{currency_code}/disable', ['uses' => 'UpdateController@disable', 'as' => 'disable']);
|
||||
@@ -658,6 +655,22 @@ Route::group(
|
||||
}
|
||||
);
|
||||
|
||||
// Transaction currency API routes that require admin rights:
|
||||
Route::group(
|
||||
[
|
||||
'namespace' => 'FireflyIII\Api\V1\Controllers\Models\TransactionCurrency',
|
||||
'prefix' => 'v1/currencies',
|
||||
'as' => 'api.v1.currencies.',
|
||||
'middleware' => ['api-admin'],
|
||||
],
|
||||
static function (): void {
|
||||
Route::delete('{currency_code}', ['uses' => 'DestroyController@destroy', 'as' => 'delete']);
|
||||
Route::post('', ['uses' => 'StoreController@store', 'as' => 'store']);
|
||||
Route::put('{currency_code?}', ['uses' => 'UpdateController@update', 'as' => 'update']);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
// Transaction Links API routes:
|
||||
Route::group(
|
||||
[
|
||||
@@ -683,11 +696,23 @@ Route::group(
|
||||
],
|
||||
static function (): void {
|
||||
Route::get('', ['uses' => 'ShowController@index', 'as' => 'index']);
|
||||
Route::post('', ['uses' => 'StoreController@store', 'as' => 'store']);
|
||||
Route::get('{linkType}', ['uses' => 'ShowController@show', 'as' => 'show']);
|
||||
Route::get('{linkType}/transactions', ['uses' => 'ListController@transactions', 'as' => 'transactions']);
|
||||
}
|
||||
);
|
||||
|
||||
// Transaction Link Type API routes that need admin rights.
|
||||
Route::group(
|
||||
[
|
||||
'namespace' => 'FireflyIII\Api\V1\Controllers\Models\TransactionLinkType',
|
||||
'prefix' => 'v1/link-types',
|
||||
'as' => 'api.v1.link-types.',
|
||||
'middleware' => ['api-admin'],
|
||||
],
|
||||
static function (): void {
|
||||
Route::post('', ['uses' => 'StoreController@store', 'as' => 'store']);
|
||||
Route::put('{linkType}', ['uses' => 'UpdateController@update', 'as' => 'update']);
|
||||
Route::delete('{linkType}', ['uses' => 'DestroyController@destroy', 'as' => 'delete']);
|
||||
Route::get('{linkType}/transactions', ['uses' => 'ListController@transactions', 'as' => 'transactions']);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -727,10 +752,23 @@ Route::group(
|
||||
],
|
||||
static function (): void {
|
||||
Route::get('', ['uses' => 'ConfigurationController@index', 'as' => 'index']);
|
||||
Route::put('{dynamicConfigKey}', ['uses' => 'ConfigurationController@update', 'as' => 'update']);
|
||||
Route::get('{eitherConfigKey}', ['uses' => 'ConfigurationController@show', 'as' => 'show']);
|
||||
}
|
||||
);
|
||||
|
||||
// Configuration API routes that need admin rights
|
||||
Route::group(
|
||||
[
|
||||
'namespace' => 'FireflyIII\Api\V1\Controllers\System',
|
||||
'prefix' => 'v1/configuration',
|
||||
'as' => 'api.v1.configuration.',
|
||||
'middleware' => ['api-admin'],
|
||||
],
|
||||
static function (): void {
|
||||
Route::put('{dynamicConfigKey}', ['uses' => 'ConfigurationController@update', 'as' => 'update']);
|
||||
}
|
||||
);
|
||||
|
||||
// Users API routes:
|
||||
Route::group(
|
||||
[
|
||||
|
||||
Reference in New Issue
Block a user