Add some experimental account endpoints using a package

This commit is contained in:
James Cole
2024-05-10 06:43:18 +02:00
parent 16bf186312
commit 794e31e487
18 changed files with 1098 additions and 0 deletions

View File

@@ -36,6 +36,7 @@ use Illuminate\Session\TokenMismatchException;
use Illuminate\Support\Arr; use Illuminate\Support\Arr;
use Illuminate\Validation\ValidationException as LaravelValidationException; use Illuminate\Validation\ValidationException as LaravelValidationException;
use Laravel\Passport\Exceptions\OAuthServerException as LaravelOAuthException; use Laravel\Passport\Exceptions\OAuthServerException as LaravelOAuthException;
use LaravelJsonApi\Core\Exceptions\JsonApiException;
use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Exception\OAuthServerException;
use Symfony\Component\HttpFoundation\Exception\SuspiciousOperationException; use Symfony\Component\HttpFoundation\Exception\SuspiciousOperationException;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
@@ -63,6 +64,7 @@ class Handler extends ExceptionHandler
HttpException::class, HttpException::class,
SuspiciousOperationException::class, SuspiciousOperationException::class,
BadHttpHeaderException::class, BadHttpHeaderException::class,
JsonApiException::class,
]; ];
/** /**

View File

@@ -0,0 +1,59 @@
<?php
/*
* AccountRepository.php
* Copyright (c) 2024 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\JsonApi\V3\Accounts;
use FireflyIII\Models\Account;
use FireflyIII\Support\JsonApi\Concerns\UsergroupAware;
use LaravelJsonApi\Contracts\Store\QueriesAll;
use LaravelJsonApi\NonEloquent\AbstractRepository;
class AccountRepository extends AbstractRepository implements QueriesAll
{
use UsergroupAware;
/**
* SiteRepository constructor.
*
*/
public function __construct() {}
/**
* @inheritDoc
*/
public function find(string $resourceId): ?object
{
return Account::find((int) $resourceId);
}
public function queryAll(): Capabilities\AccountQuery
{
return Capabilities\AccountQuery::make()
->withUserGroup($this->userGroup)
->withServer($this->server)
->withSchema($this->schema);
}
}

View File

@@ -0,0 +1,160 @@
<?php
/*
* AccountResource.php
* Copyright (c) 2024 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\JsonApi\V3\Accounts;
use Illuminate\Http\Request;
use LaravelJsonApi\Core\Resources\JsonApiResource;
class AccountResource extends JsonApiResource
{
/**
* Get the resource id.
*
* @return string
*/
public function id(): string
{
return (string) $this->resource->id;
}
/**
* Get the resource's attributes.
*
* @param Request|null $request
*
* @return iterable
*/
public function attributes($request): iterable
{
return [
'created_at' => $this->resource->created_at,
'updated_at' => $this->resource->updated_at,
'name' => $this->resource->name,
'iban' => '' === $this->resource->iban ? null : $this->resource->iban,
'active' => $this->resource->active,
'virtual_balance' => $this->resource->virtual_balance,
'last_activity' => $this->resource->last_activity,
'balance' => $this->resource->balance,
'native_balance' => $this->resource->native_balance,
'type' => $this->resource->name,
// 'type' => strtolower($accountType),
// 'account_role' => $accountRole,
// 'currency_id' => $currencyId,
// 'currency_code' => $currencyCode,
// 'currency_symbol' => $currencySymbol,
// 'currency_decimal_places' => $decimalPlaces,
// 'current_balance' => app('steam')->bcround(app('steam')->balance($account, $date), $decimalPlaces),
// 'current_balance_date' => $date->toAtomString(),
// 'notes' => $this->repository->getNoteText($account),
// 'monthly_payment_date' => $monthlyPaymentDate,
// 'credit_card_type' => $creditCardType,
// 'account_number' => $this->repository->getMetaValue($account, 'account_number'),
// 'bic' => $this->repository->getMetaValue($account, 'BIC'),
// 'opening_balance' => $openingBalance,
// 'opening_balance_date' => $openingBalanceDate,
// 'liability_type' => $liabilityType,
// 'liability_direction' => $liabilityDirection,
// 'interest' => $interest,
// 'interest_period' => $interestPeriod,
// 'current_debt' => $this->repository->getMetaValue($account, 'current_debt'),
// 'include_net_worth' => $includeNetWorth,
// 'longitude' => $longitude,
// 'latitude' => $latitude,
// 'zoom_level' => $zoomLevel,
// 'id' => (string) $account->id,
// 'created_at' => $account->created_at->toAtomString(),
// 'updated_at' => $account->updated_at->toAtomString(),
// 'active' => $account->active,
// 'order' => $order,
// 'name' => $account->name,
// 'iban' => '' === (string) $account->iban ? null : $account->iban,
// 'account_number' => $this->accountMeta[$id]['account_number'] ?? null,
// 'type' => strtolower($accountType),
// 'account_role' => $accountRole,
// 'currency_id' => (string) $currency->id,
// 'currency_code' => $currency->code,
// 'currency_symbol' => $currency->symbol,
// 'currency_decimal_places' => $currency->decimal_places,
//
// 'native_currency_id' => (string) $this->default->id,
// 'native_currency_code' => $this->default->code,
// 'native_currency_symbol' => $this->default->symbol,
// 'native_currency_decimal_places' => $this->default->decimal_places,
//
// // balance:
// 'current_balance' => $balance,
// 'native_current_balance' => $nativeBalance,
// 'current_balance_date' => $this->getDate()->endOfDay()->toAtomString(),
//
// // balance difference
// 'balance_difference' => $balanceDiff,
// 'native_balance_difference' => $nativeBalanceDiff,
// 'balance_difference_start' => $diffStart,
// 'balance_difference_end' => $diffEnd,
//
// // more meta
// 'last_activity' => array_key_exists($id, $this->lastActivity) ? $this->lastActivity[$id]->toAtomString() : null,
//
// // liability stuff
// 'liability_type' => $liabilityType,
// 'liability_direction' => $liabilityDirection,
// 'interest' => $interest,
// 'interest_period' => $interestPeriod,
// 'current_debt' => $currentDebt,
//
// // object group
// 'object_group_id' => null !== $objectGroupId ? (string) $objectGroupId : null,
// 'object_group_order' => $objectGroupOrder,
// 'object_group_title' => $objectGroupTitle,
// 'notes' => $this->repository->getNoteText($account),
// 'monthly_payment_date' => $monthlyPaymentDate,
// 'credit_card_type' => $creditCardType,
// 'bic' => $this->repository->getMetaValue($account, 'BIC'),
// 'virtual_balance' => number_format((float) $account->virtual_balance, $decimalPlaces, '.', ''),
// 'opening_balance' => $openingBalance,
// 'opening_balance_date' => $openingBalanceDate,
// 'include_net_worth' => $includeNetWorth,
// 'longitude' => $longitude,
// 'latitude' => $latitude,
// 'zoom_level' => $zoomLevel,
];
}
/**
* Get the resource's relationships.
*
* @param Request|null $request
*
* @return iterable
*/
public function relationships($request): iterable
{
return [
$this->relation('user')->withData($this->resource->user),
//$this->relation('tags')->withData($this->resource->getTags()),
];
}
}

View File

@@ -0,0 +1,190 @@
<?php
/*
* AccountSchema.php
* Copyright (c) 2024 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\JsonApi\V3\Accounts;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\Account;
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
use LaravelJsonApi\Core\Schema\Schema;
use LaravelJsonApi\Eloquent\Fields\DateTime;
use LaravelJsonApi\NonEloquent\Fields\Attribute;
use LaravelJsonApi\NonEloquent\Fields\ID;
use LaravelJsonApi\NonEloquent\Fields\ToMany;
use LaravelJsonApi\NonEloquent\Fields\ToOne;
use LaravelJsonApi\NonEloquent\Filters\Filter;
use LaravelJsonApi\NonEloquent\Pagination\EnumerablePagination;
class AccountSchema extends Schema
{
use ValidatesUserGroupTrait;
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY, UserRoleEnum::MANAGE_TRANSACTIONS];
/**
* The model the schema corresponds to.
*
* @var string
*/
public static string $model = Account::class;
/**
* @inheritDoc
*/
public function fields(): iterable
{
return [
ID::make(),
DateTime::make('created_at')->sortable()->readOnly(),
DateTime::make('updated_at')->sortable()->readOnly(),
Attribute::make('name')->sortable(),
Attribute::make('iban'),
Attribute::make('active'),
Attribute::make('virtual_balance'),
Attribute::make('last_activity')->sortable(),
Attribute::make('balance')->sortable(),
Attribute::make('native_balance')->sortable(),
Attribute::make('type'),
// fancy fields:
//Attribute::make('current_balance')->sortable(),
// 'type' => strtolower($accountType),
// 'account_role' => $accountRole,
// 'currency_id' => $currencyId,
// 'currency_code' => $currencyCode,
// 'currency_symbol' => $currencySymbol,
// 'currency_decimal_places' => $decimalPlaces,
// 'current_balance' => app('steam')->bcround(app('steam')->balance($account, $date), $decimalPlaces),
// 'current_balance_date' => $date->toAtomString(),
// 'notes' => $this->repository->getNoteText($account),
// 'monthly_payment_date' => $monthlyPaymentDate,
// 'credit_card_type' => $creditCardType,
// 'account_number' => $this->repository->getMetaValue($account, 'account_number'),
// 'bic' => $this->repository->getMetaValue($account, 'BIC'),
// 'opening_balance' => $openingBalance,
// 'opening_balance_date' => $openingBalanceDate,
// 'liability_type' => $liabilityType,
// 'liability_direction' => $liabilityDirection,
// 'interest' => $interest,
// 'interest_period' => $interestPeriod,
// 'current_debt' => $this->repository->getMetaValue($account, 'current_debt'),
// 'include_net_worth' => $includeNetWorth,
// 'longitude' => $longitude,
// 'latitude' => $latitude,
// 'zoom_level' => $zoomLevel,
// 'id' => (string) $account->id,
// 'created_at' => $account->created_at->toAtomString(),
// 'updated_at' => $account->updated_at->toAtomString(),
// 'active' => $account->active,
// 'order' => $order,
// 'name' => $account->name,
// 'iban' => '' === (string) $account->iban ? null : $account->iban,
// 'account_number' => $this->accountMeta[$id]['account_number'] ?? null,
// 'type' => strtolower($accountType),
// 'account_role' => $accountRole,
// 'currency_id' => (string) $currency->id,
// 'currency_code' => $currency->code,
// 'currency_symbol' => $currency->symbol,
// 'currency_decimal_places' => $currency->decimal_places,
//
// 'native_currency_id' => (string) $this->default->id,
// 'native_currency_code' => $this->default->code,
// 'native_currency_symbol' => $this->default->symbol,
// 'native_currency_decimal_places' => $this->default->decimal_places,
//
// // balance:
// 'current_balance' => $balance,
// 'native_current_balance' => $nativeBalance,
// 'current_balance_date' => $this->getDate()->endOfDay()->toAtomString(),
//
// // balance difference
// 'balance_difference' => $balanceDiff,
// 'native_balance_difference' => $nativeBalanceDiff,
// 'balance_difference_start' => $diffStart,
// 'balance_difference_end' => $diffEnd,
//
// // more meta
// 'last_activity' => array_key_exists($id, $this->lastActivity) ? $this->lastActivity[$id]->toAtomString() : null,
//
// // liability stuff
// 'liability_type' => $liabilityType,
// 'liability_direction' => $liabilityDirection,
// 'interest' => $interest,
// 'interest_period' => $interestPeriod,
// 'current_debt' => $currentDebt,
//
// // object group
// 'object_group_id' => null !== $objectGroupId ? (string) $objectGroupId : null,
// 'object_group_order' => $objectGroupOrder,
// 'object_group_title' => $objectGroupTitle,
// 'notes' => $this->repository->getNoteText($account),
// 'monthly_payment_date' => $monthlyPaymentDate,
// 'credit_card_type' => $creditCardType,
// 'bic' => $this->repository->getMetaValue($account, 'BIC'),
// 'virtual_balance' => number_format((float) $account->virtual_balance, $decimalPlaces, '.', ''),
// 'opening_balance' => $openingBalance,
// 'opening_balance_date' => $openingBalanceDate,
// 'include_net_worth' => $includeNetWorth,
// 'longitude' => $longitude,
// 'latitude' => $latitude,
// 'zoom_level' => $zoomLevel,
ToOne::make('user'),
// ToMany::make('tags'),
];
}
/**
* @inheritDoc
*/
public function pagination(): EnumerablePagination
{
return EnumerablePagination::make();
}
/**
* @inheritDoc
*/
public function filters(): iterable
{
return [
Filter::make('name'),
];
}
public function repository(): AccountRepository
{
$userGroup = $this->validateUserGroup(request());
return AccountRepository::make()
->withUserGroup($userGroup)
->withServer($this->server)
->withSchema($this);
}
}

View File

@@ -0,0 +1,84 @@
<?php
/*
* AccountQuery.php
* Copyright (c) 2024 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\JsonApi\V3\Accounts\Capabilities;
use FireflyIII\Models\Account;
use FireflyIII\Support\JsonApi\Concerns\UsergroupAware;
use FireflyIII\Support\JsonApi\Enrichments\AccountEnrichment;
use FireflyIII\Support\JsonApi\ExpandsQuery;
use FireflyIII\Support\JsonApi\FiltersPagination;
use FireflyIII\Support\JsonApi\SortsCollection;
use FireflyIII\Support\JsonApi\ValidateSortParameters;
use LaravelJsonApi\Contracts\Store\HasPagination;
use LaravelJsonApi\NonEloquent\Capabilities\QueryAll;
use LaravelJsonApi\NonEloquent\Concerns\PaginatesEnumerables;
class AccountQuery extends QueryAll implements HasPagination
{
use PaginatesEnumerables;
use FiltersPagination;
use ValidateSortParameters;
use UsergroupAware;
use ExpandsQuery;
use SortsCollection;
/**
* @inheritDoc
*/
#[\Override] public function get(): iterable
{
$filters = $this->queryParameters->filter();
$sort = $this->queryParameters->sortFields();
$pagination = $this->filtersPagination($this->queryParameters->page());
$needsAll = $this->validateParams('account', $sort);
$query = $this->userGroup->accounts();
if (!$needsAll) {
$query = $this->addPagination($query, $pagination);
}
$query = $this->addSortParams($query, $sort);
$query = $this->addFilterParams('account', $query, $filters);
$collection = $query->get(['accounts.*']);
// enrich data
$enrichment = new AccountEnrichment();
$collection = $enrichment->enrich($collection);
// add filters after the query
// add sort after the query
$collection = $this->sortCollection($collection, $sort);
return $collection;
// var_dump($filters->value('name'));
// exit;
return Account::get();
}
}

42
app/JsonApi/V3/Server.php Normal file
View File

@@ -0,0 +1,42 @@
<?php
namespace FireflyIII\JsonApi\V3;
use FireflyIII\JsonApi\V3\Accounts\AccountSchema;
use FireflyIII\JsonApi\V3\Users\UserSchema;
use LaravelJsonApi\Core\Server\Server as BaseServer;
class Server extends BaseServer
{
/**
* The base URI namespace for this server.
*
* @var string
*/
protected string $baseUri = '/api/v3';
/**
* Bootstrap the server when it is handling an HTTP request.
*
* @return void
*/
public function serving(): void
{
// no-op
}
/**
* Get the server's list of schemas.
*
* @return array
*/
protected function allSchemas(): array
{
return [
AccountSchema::class,
UserSchema::class,
];
}
}

View File

@@ -0,0 +1,65 @@
<?php
namespace FireflyIII\JsonApi\V3\Users;
use FireflyIII\User;
use LaravelJsonApi\Eloquent\Contracts\Paginator;
use LaravelJsonApi\Eloquent\Fields\DateTime;
use LaravelJsonApi\Eloquent\Fields\ID;
use LaravelJsonApi\Eloquent\Fields\Relations\HasMany;
use LaravelJsonApi\Eloquent\Filters\WhereIdIn;
use LaravelJsonApi\Eloquent\Pagination\PagePagination;
use LaravelJsonApi\Eloquent\Schema;
class UserSchema extends Schema
{
/**
* The model the schema corresponds to.
*
* @var string
*/
public static string $model = User::class;
/**
* Get the resource fields.
*
* @return array
*/
public function fields(): array
{
return [
ID::make(),
DateTime::make('createdAt')->sortable()->readOnly(),
DateTime::make('updatedAt')->sortable()->readOnly(),
HasMany::make('accounts'),
];
}
/**
* Get the resource filters.
*
* @return array
*/
public function filters(): array
{
return [
WhereIdIn::make($this),
];
}
/**
* Get the resource paginator.
*
* @return Paginator|null
*/
public function pagination(): ?Paginator
{
return PagePagination::make();
}
public function authorizable(): bool
{
return false;
}
}

View File

@@ -0,0 +1,54 @@
<?php
/*
* AccountPolicy.php
* Copyright (c) 2024 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\Policies;
use FireflyIII\Models\Account;
use FireflyIII\User;
class AccountPolicy
{
/**
* TODO needs better authentication.
*
* @param User $user
* @param Account $account
*
* @return bool
*/
public function view(User $user, Account $account): bool
{
return auth()->check() && $user->id === $account->user_id;
}
/**
* Everybody can do this, but selection should limit to user.
*
* @return true
*/
public function viewAny(): bool
{
return auth()->check();
}
}

View File

@@ -0,0 +1,29 @@
<?php
/*
* UserPolicy.php
* Copyright (c) 2024 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\Policies;
class UserPolicy
{
}

View File

@@ -0,0 +1,48 @@
<?php
/*
* UsergroupAware.php
* Copyright (c) 2024 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\Support\JsonApi\Concerns;
use FireflyIII\Models\UserGroup;
trait UsergroupAware
{
protected UserGroup $userGroup;
public function getUserGroup(): UserGroup
{
return $this->userGroup;
}
public function setUserGroup(UserGroup $userGroup): void
{
$this->userGroup = $userGroup;
}
public function withUserGroup(UserGroup $userGroup): self {
$this->userGroup = $userGroup;
return $this;
}
}

View File

@@ -0,0 +1,79 @@
<?php
/*
* AccountEnricher.php
* Copyright (c) 2024 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\Support\JsonApi\Enrichments;
use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
class AccountEnrichment implements EnrichmentInterface
{
private Collection $collection;
#[\Override] public function enrich(Collection $collection): Collection
{
$this->collection = $collection;
// do everything here:
$this->getLastActivity();
$this->getMetaBalances();
return $this->collection;
}
/**
* TODO this method refers to a single-use method inside Steam that could be moved here.
* @return void
*/
private function getLastActivity(): void
{
/** @var AccountRepositoryInterface $accountRepository */
$accountRepository = app(AccountRepositoryInterface::class);
$lastActivity = $accountRepository->getLastActivity($this->collection);
foreach ($lastActivity as $row) {
$this->collection->where('id', $row['account_id'])->first()->last_activity = Carbon::parse($row['date_max'], config('app.timezone'));
}
}
/**
* TODO this method refers to a single-use method inside Steam that could be moved here.
* @return void
*/
private function getMetaBalances(): void
{
try {
$array = app('steam')->balancesByAccountsConverted($this->collection, today());
} catch (FireflyException $e) {
Log::error(sprintf('Could not load balances: %s', $e->getMessage()));
return;
}
foreach ($array as $accountId => $row) {
$this->collection->where('id', $accountId)->first()->balance = $row['balance'];
$this->collection->where('id', $accountId)->first()->native_balance = $row['native_balance'];
}
}
}

View File

@@ -0,0 +1,32 @@
<?php
/*
* EnricherInterface.php
* Copyright (c) 2024 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\Support\JsonApi\Enrichments;
use Illuminate\Support\Collection;
interface EnrichmentInterface
{
public function enrich(Collection $collection): Collection;
}

View File

@@ -0,0 +1,68 @@
<?php
/*
* ExpandsQuery.php
* Copyright (c) 2024 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\Support\JsonApi;
use Illuminate\Contracts\Database\Eloquent\Builder;
use LaravelJsonApi\Core\Query\FilterParameters;
use LaravelJsonApi\Core\Query\SortFields;
trait ExpandsQuery
{
final protected function addPagination(Builder $query, array $pagination): Builder
{
$skip = ($pagination['number'] - 1) * $pagination['size'];
return $query->skip($skip)->take($pagination['size']);
}
final protected function addSortParams(Builder $query, SortFields $sort): Builder
{
foreach ($sort->all() as $sortField) {
$query->orderBy($sortField->name(), $sortField->isAscending() ? 'ASC' : 'DESC');
}
return $query;
}
final protected function addFilterParams(string $class, Builder $query, ?FilterParameters $filters): Builder
{
if (null === $filters) {
return $query;
}
$config = config(sprintf('firefly.valid_query_filters.%s', $class)) ?? [];
if (count($filters->all()) === 0) {
return $query;
}
$query->where(function (Builder $q) use ($config, $filters) {
foreach ($filters->all() as $filter) {
if (in_array($filter->key(), $config, true)) {
foreach($filter->value() as $value) {
$q->where($filter->key(), 'LIKE', sprintf('%%%s%%', $value));
}
}
}
});
return $query;
}
}

View File

@@ -0,0 +1,55 @@
<?php
/*
* FiltersPagination.php
* Copyright (c) 2024 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\Support\JsonApi;
trait FiltersPagination
{
protected function filtersPagination(?array $pagination): array
{
if (null === $pagination) {
return [
'number' => 1,
'size' => $this->getPageSize(),
];
}
// cleanup page number
$pagination['number'] = (int) ($pagination['number'] ?? 1);
$pagination['number'] = min(65536, max($pagination['number'], 1));
// clean up page size
$pagination['size'] = (int) ($pagination['size'] ?? $this->getPageSize());
$pagination['size'] = min(1337, max($pagination['size'], 1));
return $pagination;
}
private function getPageSize(): int
{
if (auth()->check()) {
return (int) app('preferences')->get('listPageSize', 50)->data;
}
return 50;
}
}

View File

@@ -0,0 +1,40 @@
<?php
/*
* SortsCollection.php
* Copyright (c) 2024 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\Support\JsonApi;
use Illuminate\Support\Collection;
use LaravelJsonApi\Core\Query\SortFields;
trait SortsCollection
{
protected function sortCollection(Collection $collection, SortFields $sortFields): Collection {
foreach($sortFields->all() as $sortField) {
$collection = $sortField->isAscending() ? $collection->sortBy($sortField->name()) : $collection->sortByDesc($sortField->name());
}
return $collection;
}
}

View File

@@ -0,0 +1,43 @@
<?php
/*
* ValidateSortParameters.php
* Copyright (c) 2024 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\Support\JsonApi;
use LaravelJsonApi\Core\Query\SortFields;
trait ValidateSortParameters
{
function validateParams(string $class, SortFields $params): bool
{
$config = config(sprintf('firefly.full_data_set.%s', $class)) ?? [];
foreach ($params->all() as $field) {
if (in_array($field->name(), $config, true)) {
return true;
}
}
return false;
}
}

35
config/jsonapi.php Normal file
View File

@@ -0,0 +1,35 @@
<?php
use FireflyIII\JsonApi\V3\Server;
return [
/*
|--------------------------------------------------------------------------
| Root Namespace
|--------------------------------------------------------------------------
|
| The root JSON:API namespace, within your application's namespace.
| This is used when generating any class that does not sit *within*
| a server's namespace. For example, new servers and filters.
|
| By default this is set to `JsonApi` which means the root namespace
| will be `\App\JsonApi`, if your application's namespace is `App`.
*/
'namespace' => 'JsonApi',
/*
|--------------------------------------------------------------------------
| Servers
|--------------------------------------------------------------------------
|
| A list of the JSON:API compliant APIs in your application, referred to
| as "servers". They must be listed below, with the array key being the
| unique name for each server, and the value being the fully-qualified
| class name of the server class.
*/
'servers' => [
// 'v1' => \App\JsonApi\V1\Server::class,
'v3' => Server::class,
],
];

View File

@@ -22,6 +22,19 @@
declare(strict_types=1); declare(strict_types=1);
use LaravelJsonApi\Laravel\Facades\JsonApiRoute;
use LaravelJsonApi\Laravel\Routing\ResourceRegistrar;
use LaravelJsonApi\Laravel\Http\Controllers\JsonApiController;
JsonApiRoute::server('v3')
->prefix('v3')
->resources(function (ResourceRegistrar $server) {
$server->resource('accounts', JsonApiController::class);
$server->resource('users', JsonApiController::class);
});
// V2 API route for Summary boxes // V2 API route for Summary boxes
// BASIC // BASIC
Route::group( Route::group(