Code Monkey home page Code Monkey logo

filament-api-service's Introduction

Hi šŸ‘‹, I'm Rupadana

I'm a Developer since 2019 joining my company as a R&D Team, Work with Programming language PHP, Javascript and Dart. Develop many things with Laravel. Currently active on Filament Community

rupadana

rupadana

Blogs posts

Connect with me:

rupadana rupadana _rupadana

Languages and Tools:

bash docker express figma flutter git grafana javascript mysql nginx nodejs php vuejs

rupadana

Ā rupadana

rupadana

filament-api-service's People

Contributors

atmonshi avatar dependabot[bot] avatar github-actions[bot] avatar jonerickson avatar luttje avatar paulovnas avatar rupadana avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

filament-api-service's Issues

[Bug]: Laravel 11 Support?

What happened?

āžœ  my-project git:(main) āœ— composer require rupadana/filament-api-service
./composer.json has been updated
Running composer update rupadana/filament-api-service
Loading composer repositories with package information
Updating dependencies
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - rupadana/filament-api-service[v1.0.0, ..., v1.0.3] require illuminate/contracts ^10.0 -> found illuminate/contracts[v10.0.0, ..., v10.48.3] but these were not loaded, likely because it conflicts with another require.
    - rupadana/filament-api-service[3.0.0, ..., 3.1.4] require laravel/framework ^10.10 -> found laravel/framework[v10.10.0, ..., v10.48.3] but it conflicts with your root composer.json require (^11.0).
    - Root composer.json requires rupadana/filament-api-service * -> satisfiable by rupadana/filament-api-service[v1.0.0, v1.0.1, v1.0.2, v1.0.3, 3.0.0, ..., 3.1.4].

Use the option --with-all-dependencies (-W) to allow upgrades, downgrades and removals for packages currently locked to specific versions.
You can also try re-running composer require with an explicit version constraint, e.g. "composer require rupadana/filament-api-service:*" to figure out if any version is installable, or "composer require rupadana/filament-api-service:^2.1" if you know which you need.

Installation failed, reverting ./composer.json and ./composer.lock to their original content.

Laravel 11 is not supported

How to reproduce the bug

Install the package on Laravel 11 app

Package Version

3.1.4

PHP Version

8.3.1

Laravel Version

11.x

Which operating systems does with happen with?

No response

Notes

No response

[Bug]: in some cases groupStack for api routes are not correct (fix available)

What happened?

in ApiService.php in function registerRoutes(Panel $panel) there is a static function call to static::handlers(). But this makes the group() of routes in some specific cases incorrect

the array length of the groupStack should be 3 like so:

#groupStack: array:3 [ā–¼
    0 => array:2 [ā–¼
      "prefix" => "api"
      "as" => "api."
    ]
    1 => array:5 [ā–¼
      "as" => "api.admin."
      "middleware" => array:3 [ ā€¦3]
      "prefix" => "api/admin/{tenant}"
      "namespace" => null
      "where" => []
    ]
    2 => array:5 [ā–¼
      "middleware" => array:3 [ ā€¦3]
      "as" => "api.admin.users."
      "prefix" => "api/admin/{tenant}/users"
      "namespace" => null
      "where" => []
    ]
  ]

but in somecases a 4th item will get appended with the next resource
like so:

#groupStack: array:3 [ā–¼
    0 => array:2 [ā–¼
      "prefix" => "api"
      "as" => "api."
    ]
    1 => array:5 [ā–¼
      "as" => "api.admin."
      "middleware" => array:3 [ ā€¦3]
      "prefix" => "api/admin/{tenant}"
      "namespace" => null
      "where" => []
    ]
    2 => array:5 [ā–¼
      "middleware" => array:3 [ ā€¦3]
      "as" => "api.admin.users."
      "prefix" => "api/admin/{tenant}/users"
      "namespace" => null
      "where" => []
    ]
    3 => array:5 [ā–¼
      "middleware" => array:3 [ ā€¦3]
      "as" => "api.admin.users."
      "prefix" => "api/admin/{tenant}/users/companies"
      "namespace" => null
      "where" => []
    ]
  ]

which is incorrect. because in this example the prefix should be on index 2: api/admin/{tenant}/companies and not a third index added with: api/admin/{tenant}/users/companies.

The fix should be:

remove: static::handlers(); in the ->group() function:

$route = Route::name(
            $name
        )
            ->middleware($resourceRouteMiddlewares)
            ->prefix(static::$groupRouteName ?? $slug)
            ->group(function (Router $route) {
                foreach (static::handlers() as $key => $handler) {
                    app($handler)->route($route);
                }
            });

How to reproduce the bug

see above

Package Version

3.2

PHP Version

8.3

Laravel Version

10

Which operating systems does with happen with?

No response

Notes

No response

[Feature]: Swagger API docs

What happened?

Use PHP Swagger API docs generator with https://github.com/DarkaOnLine/L5-Swagger and https://github.com/zircote/swagger-php to add these codeblocks to the stubs.

use OpenApi\Attributes as OA;

#[OA\Info(
    title:"API Documentation",
    version: "0.1",
    contact: new OA\Contact(name: "", email: "")
)]
#[OA\Server(
    description: "API Server",
    url: "http://localhost:8000/api/"
)]

#[OA\SecurityScheme(
    name: "bearerAuth",
    securityScheme: "bearerAuth",
    type: "http",
    scheme: "bearer",
    description: "Enter JWT Token",
    in: "header"
)]

#[OA\PathParameter(
    name: 'tenant',
    parameter: 'tenant',
    description: 'ID of the tenant',
    schema: new OA\Schema(type: 'integer'),
    required: TENANT_AWARENESS,
    in: "path",
)]

Most of the parameters can be set as custom CONSTANTS when the plugin is configured via config variables in l5-swagger.php

define('TENANT_AWARENESS', config('api-service.tenancy.awareness');
or so...

check if tenancy for resource is enabled set constant per resource in for example the BrandApiService.php

#[OA\Tag(
    name: "Brands",
    description: "API Endpoints of Brands",
)]

class BrandApiService extends ApiService
{

public static function handlers(): array
    {
        if (
            ApiService::isTenancyEnabled() &&
            ApiService::tenancyAwareness() &&
            static::getResource()::isScopedToTenant()
        ) {
            define('TENANT_AWARENESS_BRANDS', true);
        } else {
            define('TENANT_AWARENESS_BRANDS', false);
        }

        $handlers =  [
            Handlers\CreateHandler::class,
            Handlers\UpdateHandler::class,
            Handlers\DeleteHandler::class,
            Handlers\PaginationHandler::class,
            Handlers\DetailHandler::class
        ];

        foreach($handlers as $handler) {
            if(app($handler)->isPublic()) {
                define('RESOURCE_PUBLIC_BRANDS_' . Str::upper(app($handler)->getKebabClassName()), true);
            } else {
                define('RESOURCE_PUBLIC_BRANDS_' . Str::upper(app($handler)->getKebabClassName()), false);
            }
        }

        return $handlers;
    }
}

as an example for the different resource API Handlers.php (CreateHandler.php, UpdateHandler.php etc...) :

use OpenApi\Attributes as OA;

#[OA\Post(
    path: "/admin/" . ((TENANT_AWARENESS_BRANDS) ? "{tenant}/" : "") . "brands",
    operationId: "storeBrand",
    tags: ["Brands"],
    summary: "Store new Brand",
    description: "Returns inserted brand data",
    security: (!RESOURCE_PUBLIC_BRANDS_CREATE) ?  [["bearerAuth" => []]]: null,
    parameters: [
        (TENANT_AWARENESS_BRANDS) ? new OA\Parameter(ref: "#/components/parameters/tenant") : null,
    ],
    requestBody: new OA\RequestBody(
        required: true,
        content: new OA\JsonContent(ref: "#/components/schemas/BrandTransformer/properties/data/items")
    ),
    responses: [
        new OA\Response(response: 200, description: 'Operation succesful', content: new OA\JsonContent(type: "object", properties: [
            new OA\Property(property: "message", type: "string", example: "Successfully Inserted Resource"),
            new OA\Property(property: "data", type: "object", ref: "#/components/schemas/BrandTransformer/properties/data/items")
        ])),
        new OA\Response(response: 400, description: 'Bad Request'),
        new OA\Response(response: 401, description: 'Unauthenticated'),
        new OA\Response(response: 403, description: 'Forbidden'),
        new OA\Response(response: 404, description: 'Resource not Found'),
    ]
)]

and

#[OA\Get(
    path: "/admin/" . ((TENANT_AWARENESS_BRANDS) ? "{tenant}/" : "") . "brands/{id}",
    operationId: "getBrandDetail",
    tags: ["Brands"],
    summary: "Get detail of Brand",
    description: "Returns detail of Brand",
    security: (!RESOURCE_PUBLIC_BRANDS_DETAIL) ?  [["bearerAuth" => []]]: null,
    parameters: [
        (TENANT_AWARENESS_BRANDS) ? new OA\Parameter(ref: "#/components/parameters/tenant") : null,
        new OA\Parameter(
            name: "id",
            description: "Brand ID",
            required: true,
            in: "path",
            schema: new OA\Schema(type: "integer"),
            example: "", // OA\Examples(example="int", value="0", summary="An int value."),
        ),
        new OA\Parameter(
            name: "page[offset]",
            description: "Pagination offset option",
            required: false,
            in: "query",
            schema: new OA\Schema(type: "integer"),
            example: "", // OA\Examples(example="int", value="0", summary="An int value."),
        ),
        new OA\Parameter(
            name: "page[limit]",
            description: "Pagination limit option",
            required: false,
            in: "query",
            schema: new OA\Schema(type: "integer"),
            example: "", // OA\Examples(example="int", value="0", summary="An int value."),
        ),
        new OA\Parameter(
            name: "sort",
            description: "Sorting",
            required: false,
            in: "query",
            schema: new OA\Schema(type: "string"),
            example: "", // @OA\Examples(example="string", value="-created,name", summary="A comma separated value"),
        ),
        new OA\Parameter(
            name: "include",
            description: "Include Relationships",
            required: false,
            in: "query",
            schema: new OA\Schema(type: "string"),
            example: "", // @OA\Examples(example="string", value="order,user", summary="A comma separated value of relationships"),
        ),
    ],
    responses: [
        new OA\Response(response: 200, description: 'Operation succesful', content:  new OA\JsonContent( type: "object", ref: "#/components/schemas/BrandTransformer/properties/data/items")),
        new OA\Response(response: 400, description: 'Bad Request'),
        new OA\Response(response: 401, description: 'Unauthenticated'),
        new OA\Response(response: 403, description: 'Forbidden'),
        new OA\Response(response: 404, description: 'Resource not Found'),
    ]
)]

and BrandTransformer.php

#[OA\Schema(
    title: "BrandTransformer",
    description: "Brands API Transformer",
    xml: new OA\XML(name: "BrandTransformer"),
)]

and the transformer schema

 #[OA\Property(
        property: "data",
        type: "array",
        items: new OA\Items(
            properties: [
                new OA\Property(property: "id", type: "integer", title: "ID", description: "id of the brand", example: ""),
               // add your own...
                new OA\Property(property: "created_at", type: "string", title: "Created at", description: "Created at Datetime of Product", example: ""),
                new OA\Property(property: "updated_at", type: "string", title: "Updated at", description: "Updated at Datetime of Product", example: ""),
            ]
        ),
    )]
    #[OA\Property(
        property: "meta",
        type: "object",
        properties: [
            new OA\Property(property: "current_page", type: "integer", title: "Current Page", description: "current page of brand", example: ""),
            new OA\Property(property: "from", type: "integer", title: "", description: "", example: ""),
            new OA\Property(property: "last_page", type: "integer", title: "", description: "", example: ""),
            new OA\Property(property: "path", type: "string", title: "", description: "", example: ""),
            new OA\Property(property: "per_page", type: "integer", title: "", description: "", example: ""),
            new OA\Property(property: "to", type: "integer", title: "", description: "", example: ""),
            new OA\Property(property: "total", type: "integer", title: "", description: "", example: ""),
            new OA\Property(property: "", type: "integer", title: "", description: "", example: ""),
            new OA\Property(
                property: "links",
                type: "array",
                items: new OA\Items(properties: [
                    new OA\Property(property: "url", type: "string", description: "URL of Pagination"),
                    new OA\Property(property: "label", type: "string", description: "Label of Pagination"),
                    new OA\Property(property: "active", type: "bool", description: "Pagination is Active"),
                ])
            )
        ]
    )]
    #[OA\Property(
        property: "links",
        type: "object",
        properties: [
            new OA\Property(property: "first", type: "string", description: "first page link URL of brand", example: ""),
            new OA\Property(property: "last", type: "string", description: "last page link URL of brand", example: ""),
            new OA\Property(property: "prev", type: "string", description: "prev page link URL of brand", example: ""),
            new OA\Property(property: "next", type: "string", description: "next page link URL of brand", example: ""),
        ])
    ]

How to reproduce the bug

Implement OpenApi\Attributes;

Package Version

3.2

PHP Version

8.3

Laravel Version

10.0

Which operating systems does with happen with?

No response

Notes

This is just a start and code is not always cleaned up and i'm not quite sure everything is covered like response codes, panel prefix as CONST so it can be added in path: etc.... I could make time to add these features and do a PR if you prefer.

[Bug]: How publish config pckg?

What happened?

How can I publish the config file api-service.php?

How to reproduce the bug

when you try to publish with php artisan vendor:publish --provider="Rupadna\ApiService\ApiServiceServi
ceProvider" --tag=config
it returns No publishable resources for tag [config].

Package Version

2.0.0

PHP Version

8.1.0

Laravel Version

10.10

Which operating systems does with happen with?

No response

Notes

No response

[Enhancement]: Allow * in ability selection / scope

What happened?

Allow for an easy "allow all" Ability via ["*"] on the Token Resource page.

How to reproduce the bug

none

Package Version

3

PHP Version

8.3

Laravel Version

10

Which operating systems does with happen with?

No response

Notes

No response

[Feature]: add allowedIncludes() in PaginationHandler stub

What happened?

missing allowedIncludes

could you add allowedIncludes to the PaginationHandler.stub like so:

$query = QueryBuilder::for($model)
        ->allowedFields($model::$allowedFields ?? [])
        ->allowedSorts($model::$allowedSorts ?? [])
        ->allowedFilters($model::$allowedFilters ?? [])
        ->allowedIncludes($model::$allowedIncludes ?? null)
        ->paginate(request()->query('per_page'))
        ->appends(request()->query());

then it's at least added to the stub as reference..

How to reproduce the bug

.

Package Version

latest

PHP Version

8.3

Laravel Version

10

Which operating systems does with happen with?

No response

Notes

No response

[Question]: Hide token resource

What happened?

Hi, appreaciate your plugins, its helping me in a lot of ways, but I have a question.
Currently from the web perspective, I need to restrict some user from accessing the token page resources, how do I hide the token navigation?

How to reproduce the bug

Login using any user

Package Version

3.0

PHP Version

8.1

Laravel Version

10.10

Which operating systems does with happen with?

Windows

Notes

No response

[Bug]: Incorrect api operation when working with multi-tenant

What happened?

Errors regarding token creation in multi-tenancy mode

How to reproduce the bug

Hello! I have been unable to cope with numerous errors related to the creation of the token for several days now. Namely, if I try to go to the page with the creation of tokens, I get an error :
The model [Rupadana\ApiService\Models\Token] does not have a relationship named [company]. You can change the relationship being used by passing it to the [ownershipRelationship] argument of the [tenant()] method in configuration. You can change the relationship being used per-resource by setting it as the [$tenantOwnershipRelationshipName] static property on the [Rupadana\ApiService\Resources\TokenResource] resource class.

But I fixed this error by changing the model Token.php and by changing the migration of create_personal_access_tokens . But now I'm facing a mistake. :
SQLSTATE[HY000]: General error: 1364 Field 'tokenable_type' doesn't have a default value INSERT INTO personal_access_tokens(name, token, abilities, expires_at, user_id, updated_at, created_at ) VALUES ( ssaddsa, 9a9284467652ea6ea8e33584f75de3bbfe764c4582120f0dc7b57b9b346c6bde, [ "company-contact:create", "company-contact:update", "company-contact:delete", "company-contact:pagination", "company-contact:detail" ], ?, 1, 2024 -01 -21 21: 31: 00, 2024 -01 -21 21: 31: 00 )

The redesigned version Token.php:


namespace Rupadana\ApiService\Models;

use...

class Token extends PersonalAccessToken
{
    use HasFactory;

    public function company(): BelongsTo
    {
        return $this->belongsTo(Company::class);
    }
    protected $table = 'personal_access_tokens';
}

api-service.php:


// config for Rupadana/ApiService
return [
    'navigation' => [
        'group' => [
            'token' => 'User',
        ],
    ],
];

Company:php:


namespace App\Models;

use ...

class Company extends Model
{
    protected  $fillable = [
        'user_id',
        'name',
        'short_name',
        'type',
    ];
    public static array $allowedFields = [
        'name'
    ];

    // Which fields can be used to sort the results through the query string
    public static array $allowedSorts = [
        'name',
        'created_at'
    ];

    // Which fields can be used to filter the results through the query string
    public static array $allowedFilters = [
        'name'
    ];
    public function token(): HasMany
    {
        return $this->hasMany(Token::class);
    }
    public function users(): BelongsToMany
    {
        return $this->belongsToMany(User::class);
    }
    //other functions ...

User.php:

<?php

namespace App\Models;

use ...

class User extends Authenticatable implements HasTenants
{
    use HasApiTokens, HasFactory, Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'name',
        'email',
        'password',
    ];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array<int, string>
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
        'password' => 'hashed',
    ];
    public function getTenants(Panel $panel): Collection
    {
        return $this->companies;
    }

    public function companies(): BelongsToMany
    {
        return $this->belongsToMany(Company::class);
    }

    public function canAccessTenant(Model $tenant): bool
    {
        return $this->companies->contains($tenant);
    }

    public function tokens(): HasMany
    {
        return $this->hasMany(Token::class);
    }
}

Package Version

3.0.2

PHP Version

8.1

Laravel Version

10.40

Which operating systems does with happen with?

Windows

Notes

Friends, your help is very important. I tried to contact the official filament discord, but to no avail. I really hope for you.

[Bug]: Route [login] not defined when access to an entity route

What happened?

I get the following error message : Route [login] not defined.

How to reproduce the bug

When I access to a route: e.g: api/admin/customers/1 I get an error message which implies the route login not defined.

Package Version

3.0

PHP Version

8.2.12

Laravel Version

10.35.0

Which operating systems does with happen with?

Windows

Notes

No response

Question: Resources under a 'company' panel?

What happened?

Hi sorry to bother you. Most of my resources are under a 'Company' panel right now. After scanning the readme, I didn't see whether it would work for resources under a different panel, like 'company' or not. Are there setup required in this case? thanks.

How to reproduce the bug

just a question.

Package Version

1.0.0

PHP Version

8.1

Laravel Version

10

Which operating systems does with happen with?

No response

Notes

No response

Allow non-admin users to generate API key to access their records

What happened?

Hi,

Is it possible/planned to allow individual users to generate API keys which allows them to access their records/data?

Thanks.

How to reproduce the bug

N/A

Package Version

00

PHP Version

00

Laravel Version

00

Which operating systems does with happen with?

No response

Notes

No response

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    šŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. šŸ“ŠšŸ“ˆšŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ā¤ļø Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.