wip
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\ApiControllers;
|
||||
|
||||
abstract class Controller
|
||||
{
|
||||
//
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\ApiControllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Resources\UserResource;
|
||||
use App\Http\ApiControllers\Controller as ApiController;
|
||||
|
||||
class HoldingController extends ApiController
|
||||
{
|
||||
public function me(Request $request)
|
||||
{
|
||||
return UserResource::make($request->user());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\ApiControllers;
|
||||
|
||||
use App\Models\Portfolio;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Support\FilterRequest;
|
||||
use App\Http\Resources\PortfolioResource;
|
||||
use App\Http\ApiControllers\Controller as ApiController;
|
||||
|
||||
class PortfolioController extends ApiController
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$filterRequest = new FilterRequest(Portfolio::class);
|
||||
|
||||
$filterRequest->setScopes(['myPortfolios']);
|
||||
$filterRequest->setEagerRelations(['users', 'transactions', 'holdings']);
|
||||
$filterRequest->setFilterableRelations(['holdings' => 'symbol', 'transactions' => 'symbol']);
|
||||
$filterRequest->setSearchableColumns(['title', 'notes']);
|
||||
|
||||
return PortfolioResource::collection($filterRequest->get());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\ApiControllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Resources\UserResource;
|
||||
use App\Http\ApiControllers\Controller as ApiController;
|
||||
|
||||
class TransactionController extends ApiController
|
||||
{
|
||||
public function me(Request $request)
|
||||
{
|
||||
return UserResource::make($request->user());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\ApiControllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Resources\UserResource;
|
||||
use App\Http\ApiControllers\Controller as ApiController;
|
||||
|
||||
class UserController extends ApiController
|
||||
{
|
||||
public function me(Request $request)
|
||||
{
|
||||
return UserResource::make($request->user());
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@ use Exception;
|
||||
use App\Models\User;
|
||||
use App\Models\ConnectedAccount;
|
||||
use Illuminate\Support\MessageBag;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Blade;
|
||||
use Laravel\Socialite\Facades\Socialite;
|
||||
|
||||
@@ -5,7 +5,6 @@ namespace App\Http\Controllers;
|
||||
use App\Models\User;
|
||||
use App\Models\Portfolio;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class InvitedOnboardingController extends Controller
|
||||
{
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class HoldingResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return parent::toArray($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class PortfolioResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'title' => $this->title,
|
||||
'wishlist' => $this->wishlist,
|
||||
'owner' => UserResource::make($this->owner),
|
||||
'transactions' => TransactionResource::collection($this->whenLoaded('transactions')),
|
||||
'holdings' => HoldingResource::collection($this->whenLoaded('holdings')),
|
||||
'created_at' => $this->created_at,
|
||||
'updated_at' => $this->updated_at,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class TransactionResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return parent::toArray($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class UserResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'name' => $this->name,
|
||||
'email' => $this->email,
|
||||
'profile_photo_url' => $this->profile_photo_url,
|
||||
'created_at' => $this->created_at,
|
||||
'updated_at' => $this->updated_at,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
{
|
||||
@@ -22,6 +23,6 @@ class AppServiceProvider extends ServiceProvider
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
//
|
||||
JsonResource::withoutWrapping();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,13 +43,8 @@ class JetstreamServiceProvider extends ServiceProvider
|
||||
*/
|
||||
protected function configurePermissions(): void
|
||||
{
|
||||
Jetstream::defaultApiTokenPermissions(['read']);
|
||||
Jetstream::defaultApiTokenPermissions([]);
|
||||
|
||||
Jetstream::permissions([
|
||||
'create',
|
||||
'read',
|
||||
'update',
|
||||
'delete',
|
||||
]);
|
||||
Jetstream::permissions([]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Support;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
|
||||
class FilterRequest
|
||||
{
|
||||
public Builder $query;
|
||||
public array $searchableColumns;
|
||||
public array $filterableRelations = [];
|
||||
public array $scopes;
|
||||
public array $select = [];
|
||||
|
||||
public function __construct(
|
||||
public string $modelClass
|
||||
) {
|
||||
$this->query = (new $modelClass)->query();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets eager loads on the underlying query
|
||||
*
|
||||
* @param array $scopes
|
||||
* @return void
|
||||
*/
|
||||
public function setEagerRelations(string|array $relations)
|
||||
{
|
||||
$this->query = $this->query->with($relations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets scopes on the underlying query
|
||||
*
|
||||
* @param array $scopes
|
||||
* @return void
|
||||
*/
|
||||
public function setScopes(string|array $scopes): void
|
||||
{
|
||||
$this->query = $this->query->scopes($scopes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows nested json data to be aliased into a virtual column for the query
|
||||
*
|
||||
* @param array $columns can be an array of keys (e.g. `body.total_amount`)
|
||||
* @return void
|
||||
*/
|
||||
public function setVirtualColumns(array $columns)
|
||||
{
|
||||
foreach($columns as $column) {
|
||||
$column = Str::replace('.', '->', $column);
|
||||
$alias = Str::snake(Str::afterLast($column, '->'));
|
||||
|
||||
array_push($this->select, $column . ' as ' . $alias);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set columns that should be searched
|
||||
*
|
||||
* @param array $columns can be an array of keys (e.g. `user.name` or a nested array with
|
||||
* `relation`, `table`, and `column` attributes)
|
||||
* @return void
|
||||
*/
|
||||
public function setSearchableColumns(array $columns)
|
||||
{
|
||||
$this->searchableColumns = $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set relations that can be filtered
|
||||
*
|
||||
* @param array $relations is an array of keys (relations) and values (columns)
|
||||
* @return void
|
||||
*/
|
||||
public function setFilterableRelations(array $relations)
|
||||
{
|
||||
$this->filterableRelations = $relations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set related columns using aggregate function (e.g. `package.label` would become `package_label`)
|
||||
* which enables filtering, searching, and sorting on the front end
|
||||
*
|
||||
* @param array $columns can be an array of keys (e.g. `user.name` or a nested array with
|
||||
* `relation`, `table`, and `column` attributes)
|
||||
* @return void
|
||||
*/
|
||||
public function setRelationshipColumns(array $columns)
|
||||
{
|
||||
foreach($columns as $column) {
|
||||
|
||||
// advanced
|
||||
if (is_array($column)) {
|
||||
|
||||
$this->query->withAggregate($column['relation'], $column['table'].'.'.$column['column']);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// not a relationship
|
||||
if(!Str::contains($column, '.')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// normal rx
|
||||
$relationship = Str::before($column, '.');
|
||||
$key = Str::after($column, '.');
|
||||
|
||||
$this->query->withAggregate($relationship, $key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the resulting paginated collection
|
||||
*
|
||||
* @return LengthAwarePaginator
|
||||
*/
|
||||
public function get(): LengthAwarePaginator
|
||||
{
|
||||
// handle sort
|
||||
if (!empty(request()->query('sortBy'))) {
|
||||
if (Str::contains(request()->query('sortBy'), '.')) {
|
||||
$this->query->joinRelation(Str::before(request()->query('sortBy'), '.'));
|
||||
}
|
||||
$this->query->orderBy(
|
||||
request()->query('sortBy'),
|
||||
request()->query('sortDesc', false) == "true" ? 'DESC' : 'ASC'
|
||||
);
|
||||
}
|
||||
|
||||
// handle filter
|
||||
if (request()->has('filter')) {
|
||||
|
||||
foreach(request()->query('filter') as $filter => $params) {
|
||||
|
||||
if (array_key_exists($filter, $this->filterableRelations)) {
|
||||
|
||||
// filtered rx
|
||||
foreach(explode(',', $params) as $param) {
|
||||
$this->query->whereHas($filter, function ($query) use ($filter, $param) {
|
||||
$query->where($this->filterableRelations[$filter], $param);
|
||||
});
|
||||
}
|
||||
|
||||
} else {
|
||||
// traditional filter
|
||||
foreach(explode(',', $params) as $param) {
|
||||
$this->query->having($filter, $param);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// handle search
|
||||
if (request()->has('search') && !empty($this->searchableColumns)) {
|
||||
// make searchable relationships aggregate columns
|
||||
$this->setRelationshipColumns($this->searchableColumns);
|
||||
|
||||
$this->query->where(function($query) {
|
||||
|
||||
foreach($this->searchableColumns as $column) {
|
||||
|
||||
// advanced
|
||||
if (is_array($column)) {
|
||||
$query->orWhereHas($column['relation'], function($query) use ($column) {
|
||||
$query->where($column['table'].'.'.$column['column'], "like", '%' . request()->query('search') . '%');
|
||||
});
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// normal RX
|
||||
if(Str::contains($column, '.')) {
|
||||
|
||||
$query->orWhereHas(Str::before($column, '.'), function($query) use ($column) {
|
||||
$query->where(Str::after($column, '.'), "like", '%' . request()->query('search') . '%');
|
||||
});
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// not rx
|
||||
$query->orWhere($column, "like", '%' . request()->query('search') . '%');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// handle per page
|
||||
if (request()->query('itemsPerPage') == "-1") {
|
||||
$perPage = $this->query->count();
|
||||
} else {
|
||||
$perPage = request()->query('itemsPerPage', 15);
|
||||
}
|
||||
|
||||
// run
|
||||
return $this->query->addSelect($this->select)->paginate($perPage);
|
||||
}
|
||||
}
|
||||
@@ -60,7 +60,7 @@ return [
|
||||
'features' => [
|
||||
Features::termsAndPrivacyPolicy(),
|
||||
Features::profilePhotos(),
|
||||
// Features::api(),
|
||||
Features::api(),
|
||||
// Features::teams(['invitations' => true]),
|
||||
Features::accountDeletion(),
|
||||
],
|
||||
|
||||
+1
-1
@@ -70,7 +70,7 @@
|
||||
"API Token": "API Token",
|
||||
"Please copy your new API token. For your security, it won\\'t be shown again.": "Please copy your new API token. For your security, it won\\'t be shown again.",
|
||||
"API Token Permissions": "API Token Permissions",
|
||||
"API tokens allow third-party services to authenticate with our application on your behalf.": "API tokens allow third-party services to authenticate with our application on your behalf.",
|
||||
"API tokens allow third-party services to authenticate with Investbrain on your behalf.": "API tokens allow third-party services to authenticate with Investbrain on your behalf.",
|
||||
"Delete API Token": "Delete API Token",
|
||||
"Are you sure you would like to delete this API token?": "Are you sure you would like to delete this API token?",
|
||||
"This is a secure area of the application. Please confirm your password before continuing.": "This is a secure area of the application. Please confirm your password before continuing.",
|
||||
|
||||
+1
-1
@@ -70,7 +70,7 @@
|
||||
"API Token": "Token API",
|
||||
"Please copy your new API token. For your security, it won't be shown again.": "Por favor, copia tu nuevo token API. Por seguridad, no se mostrará nuevamente.",
|
||||
"API Token Permissions": "Permisos del Token API",
|
||||
"API tokens allow third-party services to authenticate with our application on your behalf.": "Los tokens API permiten que servicios de terceros se autentiquen con nuestra aplicación en tu nombre.",
|
||||
"API tokens allow third-party services to authenticate with Investbrain on your behalf.": "Los tokens API permiten que servicios de terceros se autentiquen con Investbrain en tu nombre.",
|
||||
"Delete API Token": "Eliminar Token API",
|
||||
"Are you sure you would like to delete this API token?": "¿Estás seguro de que deseas eliminar este token API?",
|
||||
"This is a secure area of the application. Please confirm your password before continuing.": "Esta es un área segura de la aplicación. Por favor, confirma tu contraseña antes de continuar.",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
</x-slot>
|
||||
|
||||
<x-slot name="description">
|
||||
{{ __('API tokens allow third-party services to authenticate with our application on your behalf.') }}
|
||||
{{ __('API tokens allow third-party services to authenticate with Investbrain on your behalf.') }}
|
||||
</x-slot>
|
||||
|
||||
<x-slot name="form">
|
||||
|
||||
+14
-4
@@ -1,8 +1,18 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\ApiControllers\PortfolioController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use App\Http\ApiControllers\UserController;
|
||||
|
||||
Route::get('/user', function (Request $request) {
|
||||
return $request->user();
|
||||
})->middleware('auth:sanctum');
|
||||
Route::middleware(['auth:sanctum'])->group(function () {
|
||||
|
||||
// user
|
||||
Route::get('/me', [UserController::class, 'me']);
|
||||
|
||||
// portfolio
|
||||
Route::get('/portfolio', [PortfolioController::class, 'index']);
|
||||
|
||||
// transaction
|
||||
|
||||
// holding
|
||||
});
|
||||
+1
-1
@@ -5,8 +5,8 @@ use Illuminate\Support\Facades\Route;
|
||||
use App\Http\Controllers\HoldingController;
|
||||
use App\Http\Controllers\DashboardController;
|
||||
use App\Http\Controllers\PortfolioController;
|
||||
use App\Http\Controllers\ConnectedAccountController;
|
||||
use App\Http\Controllers\TransactionController;
|
||||
use App\Http\Controllers\ConnectedAccountController;
|
||||
use App\Http\Controllers\InvitedOnboardingController;
|
||||
use Laravel\Jetstream\Http\Controllers\Livewire\PrivacyPolicyController;
|
||||
use Laravel\Jetstream\Http\Controllers\Livewire\TermsOfServiceController;
|
||||
|
||||
Reference in New Issue
Block a user