mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2026-01-26 07:25:14 +00:00
Compare commits
15 Commits
develop-20
...
develop-20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ccb44d6fbd | ||
|
|
b9fe074080 | ||
|
|
033281ff51 | ||
|
|
5e8d23ba91 | ||
|
|
35509f19ad | ||
|
|
5e56eeb22e | ||
|
|
e921bb3ebe | ||
|
|
353cd0f4f1 | ||
|
|
1376ed16cf | ||
|
|
36646b9c05 | ||
|
|
0b20c9d53b | ||
|
|
b91d8661bc | ||
|
|
b684f3fc70 | ||
|
|
c8a235b0b0 | ||
|
|
229db34d13 |
@@ -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
|
||||
- mateuszkulapl
|
||||
- Gianluca Martino
|
||||
- embedded
|
||||
|
||||
|
||||
71
app/Api/V1/Controllers/System/BatchController.php
Normal file
71
app/Api/V1/Controllers/System/BatchController.php
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* BatchController.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\Api\V1\Controllers\System;
|
||||
|
||||
use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Events\Model\TransactionGroup\CreatedSingleTransactionGroup;
|
||||
use FireflyIII\Events\Model\TransactionGroup\TransactionGroupEventFlags;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class BatchController extends Controller
|
||||
{
|
||||
private JournalRepositoryInterface $repository;
|
||||
|
||||
/**
|
||||
* UserController constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->middleware(function ($request, $next) {
|
||||
$this->repository = app(JournalRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
});
|
||||
}
|
||||
|
||||
public function finishBatch(Request $request): JsonResponse
|
||||
{
|
||||
$journals = $this->repository->getUncompletedJournals();
|
||||
if (0 === count($journals)) {
|
||||
return response()->json([], 204);
|
||||
}
|
||||
|
||||
/** @var TransactionJournal $first */
|
||||
$first = $journals->first();
|
||||
$group = $first?->transactionGroup;
|
||||
if (null === $group) {
|
||||
return response()->json([], 204);
|
||||
}
|
||||
$flags = new TransactionGroupEventFlags();
|
||||
$flags->applyRules = 'true' === $request->get('apply_rules');
|
||||
event(new CreatedSingleTransactionGroup($group, $flags));
|
||||
|
||||
return response()->json([], 204);
|
||||
}
|
||||
}
|
||||
@@ -58,6 +58,8 @@ class UserController extends Controller
|
||||
});
|
||||
}
|
||||
|
||||
public function finishBatch(): JsonResponse {}
|
||||
|
||||
/**
|
||||
* This endpoint is documented at:
|
||||
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/users/deleteUser
|
||||
|
||||
@@ -45,6 +45,6 @@ class TrustProxies extends Middleware
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->proxies = (string) config('firefly.trusted_proxies');
|
||||
$this->proxies = (string) config('trustedproxy.proxies');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ use Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance;
|
||||
use Illuminate\Foundation\Http\Middleware\TrimStrings;
|
||||
use Illuminate\Http\Middleware\HandleCors;
|
||||
use Illuminate\Http\Middleware\ValidatePostSize;
|
||||
use Illuminate\Routing\Middleware\SubstituteBindings;
|
||||
use Illuminate\View\Middleware\ShareErrorsFromSession;
|
||||
use Laravel\Passport\Http\Middleware\CreateFreshApiToken;
|
||||
use Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful;
|
||||
@@ -88,11 +89,6 @@ if (!function_exists('stringIsEqual')) {
|
||||
}
|
||||
}
|
||||
|
||||
//$app = new Application(
|
||||
// realpath(__DIR__ . '/../')
|
||||
//);
|
||||
|
||||
|
||||
$app = Application::configure(basePath: dirname(__DIR__))
|
||||
->withRouting(
|
||||
web : __DIR__ . '/../routes/web.php',
|
||||
@@ -101,30 +97,39 @@ $app = Application::configure(basePath: dirname(__DIR__))
|
||||
)
|
||||
->withMiddleware(function (Middleware $middleware): void {
|
||||
// overrule the standard middleware
|
||||
$middleware->use([
|
||||
InvokeDeferredCallbacks::class,
|
||||
// \Illuminate\Http\Middleware\TrustHosts::class,
|
||||
TrustProxies::class,
|
||||
HandleCors::class,
|
||||
PreventRequestsDuringMaintenance::class,
|
||||
ValidatePostSize::class,
|
||||
TrimStrings::class,
|
||||
ConvertEmptyStringsToNull::class,
|
||||
SecureHeaders::class,
|
||||
]);
|
||||
$middleware->use(
|
||||
[
|
||||
InvokeDeferredCallbacks::class,
|
||||
HandleCors::class,
|
||||
PreventRequestsDuringMaintenance::class,
|
||||
ValidatePostSize::class,
|
||||
TrimStrings::class,
|
||||
ConvertEmptyStringsToNull::class,
|
||||
SecureHeaders::class,
|
||||
TrustProxies::class,
|
||||
]
|
||||
);
|
||||
|
||||
// overrule the web group
|
||||
$middleware->group('web', [
|
||||
Illuminate\Cookie\Middleware\EncryptCookies::class,
|
||||
Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
|
||||
StartFireflySession::class,
|
||||
Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
||||
VerifyCsrfToken::class,
|
||||
Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
CreateFreshApiToken::class,
|
||||
]);
|
||||
$middleware->group('web',
|
||||
[
|
||||
EncryptCookies::class,
|
||||
AddQueuedCookiesToResponse::class,
|
||||
StartFireflySession::class,
|
||||
ShareErrorsFromSession::class,
|
||||
VerifyCsrfToken::class,
|
||||
SubstituteBindings::class,
|
||||
CreateFreshApiToken::class,
|
||||
]
|
||||
);
|
||||
// new group?
|
||||
$middleware->appendToGroup('binders-only', [Installer::class, EncryptCookies::class, AddQueuedCookiesToResponse::class, Binder::class]);
|
||||
$middleware->appendToGroup('binders-only',
|
||||
[
|
||||
Installer::class,
|
||||
EncryptCookies::class,
|
||||
AddQueuedCookiesToResponse::class,
|
||||
Binder::class,
|
||||
]);
|
||||
|
||||
//
|
||||
$middleware->appendToGroup('user-not-logged-in', [
|
||||
|
||||
@@ -64,6 +64,7 @@ return [
|
||||
'web' => [
|
||||
'driver' => 'session',
|
||||
'provider' => 'users',
|
||||
'remember' => true,
|
||||
],
|
||||
'remote_user_guard' => [
|
||||
'driver' => 'remote_user_guard',
|
||||
|
||||
@@ -67,61 +67,62 @@ use FireflyIII\User;
|
||||
return [
|
||||
'bindables' => [
|
||||
// models
|
||||
'account' => Account::class,
|
||||
'attachment' => Attachment::class,
|
||||
'availableBudget' => AvailableBudget::class,
|
||||
'bill' => Bill::class,
|
||||
'budget' => Budget::class,
|
||||
'budgetLimit' => BudgetLimit::class,
|
||||
'category' => Category::class,
|
||||
'linkType' => LinkType::class,
|
||||
'transactionType' => TransactionType::class,
|
||||
'journalLink' => TransactionJournalLink::class,
|
||||
'currency' => TransactionCurrency::class,
|
||||
'objectGroup' => ObjectGroup::class,
|
||||
'piggyBank' => PiggyBank::class,
|
||||
'preference' => Preference::class,
|
||||
'tj' => TransactionJournal::class,
|
||||
'tag' => Tag::class,
|
||||
'recurrence' => Recurrence::class,
|
||||
'rule' => Rule::class,
|
||||
'ruleGroup' => RuleGroup::class,
|
||||
'transactionGroup' => TransactionGroup::class,
|
||||
'user' => User::class,
|
||||
'webhook' => Webhook::class,
|
||||
'webhookMessage' => WebhookMessage::class,
|
||||
'webhookAttempt' => WebhookAttempt::class,
|
||||
'invitedUser' => InvitedUser::class,
|
||||
'account' => Account::class,
|
||||
'attachment' => Attachment::class,
|
||||
'availableBudget' => AvailableBudget::class,
|
||||
'bill' => Bill::class,
|
||||
'budget' => Budget::class,
|
||||
'budgetLimit' => BudgetLimit::class,
|
||||
'category' => Category::class,
|
||||
'linkType' => LinkType::class,
|
||||
'transactionType' => TransactionType::class,
|
||||
'journalLink' => TransactionJournalLink::class,
|
||||
'currency' => TransactionCurrency::class,
|
||||
'objectGroup' => ObjectGroup::class,
|
||||
'piggyBank' => PiggyBank::class,
|
||||
'preference' => Preference::class,
|
||||
'preferenceName' => Preference::class,
|
||||
'tj' => TransactionJournal::class,
|
||||
'tag' => Tag::class,
|
||||
'recurrence' => Recurrence::class,
|
||||
'rule' => Rule::class,
|
||||
'ruleGroup' => RuleGroup::class,
|
||||
'transactionGroup' => TransactionGroup::class,
|
||||
'user' => User::class,
|
||||
'webhook' => Webhook::class,
|
||||
'webhookMessage' => WebhookMessage::class,
|
||||
'webhookAttempt' => WebhookAttempt::class,
|
||||
'invitedUser' => InvitedUser::class,
|
||||
|
||||
// strings
|
||||
'currency_code' => CurrencyCode::class,
|
||||
'currency_code' => CurrencyCode::class,
|
||||
|
||||
// dates
|
||||
'start_date' => Date::class,
|
||||
'end_date' => Date::class,
|
||||
'date' => Date::class,
|
||||
'start_date' => Date::class,
|
||||
'end_date' => Date::class,
|
||||
'date' => Date::class,
|
||||
|
||||
// lists
|
||||
'accountList' => AccountList::class,
|
||||
'doubleList' => AccountList::class,
|
||||
'budgetList' => BudgetList::class,
|
||||
'journalList' => JournalList::class,
|
||||
'categoryList' => CategoryList::class,
|
||||
'tagList' => TagList::class,
|
||||
'accountList' => AccountList::class,
|
||||
'doubleList' => AccountList::class,
|
||||
'budgetList' => BudgetList::class,
|
||||
'journalList' => JournalList::class,
|
||||
'categoryList' => CategoryList::class,
|
||||
'tagList' => TagList::class,
|
||||
|
||||
// others
|
||||
'fromCurrencyCode' => CurrencyCode::class,
|
||||
'toCurrencyCode' => CurrencyCode::class,
|
||||
'cliToken' => CLIToken::class,
|
||||
'tagOrId' => TagOrId::class,
|
||||
'dynamicConfigKey' => DynamicConfigKey::class,
|
||||
'eitherConfigKey' => EitherConfigKey::class,
|
||||
'fromCurrencyCode' => CurrencyCode::class,
|
||||
'toCurrencyCode' => CurrencyCode::class,
|
||||
'cliToken' => CLIToken::class,
|
||||
'tagOrId' => TagOrId::class,
|
||||
'dynamicConfigKey' => DynamicConfigKey::class,
|
||||
'eitherConfigKey' => EitherConfigKey::class,
|
||||
|
||||
// V2 API endpoints:
|
||||
'userGroupAccount' => UserGroupAccount::class,
|
||||
'userGroupTransaction' => UserGroupTransaction::class,
|
||||
'userGroupBill' => UserGroupBill::class,
|
||||
'userGroupExchangeRate' => UserGroupExchangeRate::class,
|
||||
'userGroup' => UserGroup::class,
|
||||
'userGroupAccount' => UserGroupAccount::class,
|
||||
'userGroupTransaction' => UserGroupTransaction::class,
|
||||
'userGroupBill' => UserGroupBill::class,
|
||||
'userGroupExchangeRate' => UserGroupExchangeRate::class,
|
||||
'userGroup' => UserGroup::class,
|
||||
],
|
||||
];
|
||||
|
||||
@@ -78,8 +78,8 @@ return [
|
||||
'running_balance_column' => (bool)envNonEmpty('USE_RUNNING_BALANCE', true), // this is only the default value, is not used.
|
||||
// see cer.php for exchange rates feature flag.
|
||||
],
|
||||
'version' => 'develop/2026-01-25',
|
||||
'build_time' => 1769359942,
|
||||
'version' => 'develop/2026-01-26',
|
||||
'build_time' => 1769407779,
|
||||
'api_version' => '2.1.0', // field is no longer used.
|
||||
'db_version' => 28, // field is no longer used.
|
||||
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
<meta name="robots" content="noindex, nofollow, noarchive, noodp, NoImageIndex, noydir">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="color-scheme" content="light dark">
|
||||
|
||||
<title>
|
||||
{% if pageTitle %}
|
||||
{{ pageTitle }} »
|
||||
@@ -39,6 +37,7 @@
|
||||
<link href="v1/lib/adminlte/css/AdminLTE.min.css?v={{ FF_BUILD_TIME }}" rel="stylesheet" type="text/css"
|
||||
nonce="{{ JS_NONCE }}">
|
||||
{% if 'browser' == darkMode %}
|
||||
<meta name="color-scheme" content="light dark">
|
||||
<script nonce="{{ JS_NONCE }}">
|
||||
// If `prefers-color-scheme` is not supported, fall back to light mode.
|
||||
// In this case, light.css will be downloaded with `highest` priority.
|
||||
@@ -58,12 +57,14 @@
|
||||
nonce="{{ JS_NONCE }}" media="(prefers-color-scheme: light)">
|
||||
{% endif %}
|
||||
{% if 'dark' == darkMode %}
|
||||
<meta name="color-scheme" content="dark">
|
||||
<link href="v1/css/daterangepicker-dark.css?v={{ FF_BUILD_TIME }}" rel="stylesheet" type="text/css"
|
||||
nonce="{{ JS_NONCE }}">
|
||||
<link href="v1/lib/adminlte/css/skins/skin-dark.min.css?v={{ FF_BUILD_TIME }}" rel="stylesheet" type="text/css"
|
||||
nonce="{{ JS_NONCE }}">
|
||||
{% endif %}
|
||||
{% if 'light' == darkMode %}
|
||||
<meta name="color-scheme" content="light">
|
||||
<link href="v1/css/daterangepicker-light.css?v={{ FF_BUILD_TIME }}" rel="stylesheet" type="text/css"
|
||||
nonce="{{ JS_NONCE }}">
|
||||
<link href="v1/lib/adminlte/css/skins/skin-light.min.css?v={{ FF_BUILD_TIME }}" rel="stylesheet" type="text/css"
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
<meta content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no' name='viewport'>
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="color-scheme" content="light dark">
|
||||
|
||||
{# CSS things #}
|
||||
|
||||
@@ -20,6 +19,7 @@
|
||||
{# the theme #}
|
||||
<link href="v1/lib/adminlte/css/AdminLTE.min.css?v={{ FF_BUILD_TIME }}" rel="stylesheet" type="text/css" nonce="{{ JS_NONCE }}">
|
||||
{% if 'browser' == darkMode %}
|
||||
<meta name="color-scheme" content="light dark">
|
||||
<script nonce="{{ JS_NONCE }}">
|
||||
// If `prefers-color-scheme` is not supported, fall back to light mode.
|
||||
// In this case, light.css will be downloaded with `highest` priority.
|
||||
@@ -35,9 +35,11 @@
|
||||
<link href="v1/lib/adminlte/css/skins/skin-light.min.css?v={{ FF_BUILD_TIME }}" rel="stylesheet" type="text/css" nonce="{{ JS_NONCE }}" media="(prefers-color-scheme: light)">
|
||||
{% endif %}
|
||||
{% if 'dark' == darkMode %}
|
||||
<meta name="color-scheme" content="dark">
|
||||
<link href="v1/lib/adminlte/css/skins/skin-dark.min.css?v={{ FF_BUILD_TIME }}" rel="stylesheet" type="text/css" nonce="{{ JS_NONCE }}">
|
||||
{% endif %}
|
||||
{% if 'light' == darkMode %}
|
||||
<meta name="color-scheme" content="light">
|
||||
<link href="v1/lib/adminlte/css/skins/skin-light.min.css?v={{ FF_BUILD_TIME }}" rel="stylesheet" type="text/css" nonce="{{ JS_NONCE }}">
|
||||
{% endif %}
|
||||
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="robots" content="noindex, nofollow, noarchive, noodp, NoImageIndex, noydir">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="color-scheme" content="light dark">
|
||||
|
||||
<title>Firefly III
|
||||
|
||||
{% if title != "Firefly" and title != "" %}
|
||||
@@ -30,6 +28,7 @@
|
||||
{# the theme #}
|
||||
<link href="v1/lib/adminlte/css/AdminLTE.min.css?v={{ FF_BUILD_TIME }}" rel="stylesheet" type="text/css" nonce="{{ JS_NONCE }}">
|
||||
{% if 'browser' == darkMode %}
|
||||
<meta name="color-scheme" content="light dark">
|
||||
<script nonce="{{ JS_NONCE }}">
|
||||
// If `prefers-color-scheme` is not supported, fall back to light mode.
|
||||
// In this case, light.css will be downloaded with `highest` priority.
|
||||
@@ -45,9 +44,11 @@
|
||||
<link href="v1/lib/adminlte/css/skins/skin-light.min.css?v={{ FF_BUILD_TIME }}" rel="stylesheet" type="text/css" nonce="{{ JS_NONCE }}" media="(prefers-color-scheme: light)">
|
||||
{% endif %}
|
||||
{% if 'dark' == darkMode %}
|
||||
<meta name="color-scheme" content="dark">
|
||||
<link href="v1/lib/adminlte/css/skins/skin-dark.min.css?v={{ FF_BUILD_TIME }}" rel="stylesheet" type="text/css" nonce="{{ JS_NONCE }}">
|
||||
{% endif %}
|
||||
{% if 'light' == darkMode %}
|
||||
<meta name="color-scheme" content="light">
|
||||
<link href="v1/lib/adminlte/css/skins/skin-light.min.css?v={{ FF_BUILD_TIME }}" rel="stylesheet" type="text/css" nonce="{{ JS_NONCE }}">
|
||||
{% endif %}
|
||||
|
||||
|
||||
@@ -730,6 +730,19 @@ Route::group(
|
||||
}
|
||||
);
|
||||
|
||||
// Batch API routes:
|
||||
Route::group(
|
||||
[
|
||||
'middleware' => ['auth:api,sanctum', 'bindings'],
|
||||
'namespace' => 'FireflyIII\Api\V1\Controllers\System',
|
||||
'prefix' => 'v1/batch',
|
||||
'as' => 'api.v1.batch.',
|
||||
],
|
||||
static function (): void {
|
||||
Route::post('finish', ['uses' => 'BatchController@finishBatch', 'as' => 'finish']);
|
||||
}
|
||||
);
|
||||
|
||||
// USER
|
||||
|
||||
// Preference API routes:
|
||||
@@ -743,8 +756,8 @@ Route::group(
|
||||
Route::get('', ['uses' => 'PreferencesController@index', 'as' => 'index']);
|
||||
Route::post('', ['uses' => 'PreferencesController@store', 'as' => 'store']);
|
||||
// Route::get('{preferenceList}', ['uses' => 'PreferencesController@showList', 'as' => 'show-list'])->where('preferenceList', ',+');
|
||||
Route::get('{preference}', ['uses' => 'PreferencesController@show', 'as' => 'show']);
|
||||
Route::put('{preference}', ['uses' => 'PreferencesController@update', 'as' => 'update']);
|
||||
Route::get('{preferenceName}', ['uses' => 'PreferencesController@show', 'as' => 'show']);
|
||||
Route::put('{preferenceName}', ['uses' => 'PreferencesController@update', 'as' => 'update']);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user