diff --git a/.github/workflows/ec2-deploy.yaml b/.github/workflows/ec2-deploy.yaml new file mode 100644 index 000000000..0d52c46a2 --- /dev/null +++ b/.github/workflows/ec2-deploy.yaml @@ -0,0 +1,23 @@ +name: Deploy to EC2 + +on: + workflow_dispatch: + +jobs: + deploy-to-ec2: + runs-on: ubuntu-latest + environment: ${{ github.ref_name }} + permissions: + contents: read + packages: write + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Copy folder content recursively to remote VM + uses: appleboy/scp-action@v0.1.7 + with: + host: ${{ secrets.AWS_EC2_HOST }} + username: ${{ secrets.AWS_EC2_USERNAME }} + key: ${{ secrets.AWS_EC2_PRIVATE_SSH_KEY }} + source: . + target: ${{secrets.AWS_EC2_TARGET_DIR}} \ No newline at end of file diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 2753a245f..387506510 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -34,10 +34,10 @@ jobs: DB_COMMERCE_USERNAME: root DB_COMMERCE_PASSWORD: password KANVAS_APP_ID: 059ddaaf-89b5-4158-a85a-90cbd69aa34b - APP_KEY: base64:4QZVysw1MIFmwZi0KvEOaHs0leAix3U6zueUZJtQYjY= - APP_JWT_TOKEN: 4QZVysw1MIFmwZi0KvEOaHs0leAix3U6zueUZJtQYjY4QZVysw1MIFmwZi0KvEOaHs0leAix3U6zueUZJtQYjY + APP_KEY: base64:Wm5KmkE4aWFjdFUzU2o3SElYNGc0QlpLcXNWR0hMME0= + APP_JWT_TOKEN: Wm5KmkE4aWFjdFUzU2o3SElYNGc0QlpLcXNWR0hMME0=4QZVysw1MIFmwZi0KvEOaHs0leAix3U6zueUZJtQYjYj + TOKEN_PASSWORD: base64:Z1dVYk5TcEZWUVhMNHZCUllIc3JQTVg0ZEdWTTh5eDg= TOKEN_AUDIENCE: http://localhost - TOKEN_PASSWORD: base64:4QZVysw1MIFmwZi0KvEOaHs0leAix3U6zueUZJtQYjY= AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} @@ -56,6 +56,7 @@ jobs: TEST_SHOPIFY_API_KEY: ${{ secrets.TEST_SHOPIFY_API_KEY }} TEST_SHOPIFY_API_SECRET: ${{ secrets.TEST_SHOPIFY_API_SECRET }} TEST_SHOPIFY_SHOP_URL: ${{ secrets.TEST_SHOPIFY_SHOP_URL }} + TEST_APPLE_LOGIN_TOKEN: ${{ secrets.TEST_APPLE_LOGIN_TOKEN }} strategy: fail-fast: false matrix: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 3c69108e0..b6d30f3e7 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -35,10 +35,10 @@ jobs: DB_COMMERCE_USERNAME: root DB_COMMERCE_PASSWORD: password KANVAS_APP_ID: 059ddaaf-89b5-4158-a85a-90cbd69aa34b - APP_KEY: base64:4QZVysw1MIFmwZi0KvEOaHs0leAix3U6zueUZJtQYjY= - APP_JWT_TOKEN: 4QZVysw1MIFmwZi0KvEOaHs0leAix3U6zueUZJtQYjY4QZVysw1MIFmwZi0KvEOaHs0leAix3U6zueUZJtQYjY + APP_KEY: base64:Wm5KmkE4aWFjdFUzU2o3SElYNGc0QlpLcXNWR0hMME0= + APP_JWT_TOKEN: Wm5KmkE4aWFjdFUzU2o3SElYNGc0QlpLcXNWR0hMME0=4QZVysw1MIFmwZi0KvEOaHs0leAix3U6zueUZJtQYjYj + TOKEN_PASSWORD: base64:Z1dVYk5TcEZWUVhMNHZCUllIc3JQTVg0ZEdWTTh5eDg= TOKEN_AUDIENCE: http://localhost - TOKEN_PASSWORD: base64:4QZVysw1MIFmwZi0KvEOaHs0leAix3U6zueUZJtQYjY= AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} @@ -64,6 +64,7 @@ jobs: TEST_SHOPIFY_API_KEY: ${{ secrets.TEST_SHOPIFY_API_KEY }} TEST_SHOPIFY_API_SECRET: ${{ secrets.TEST_SHOPIFY_API_SECRET }} TEST_SHOPIFY_SHOP_URL: ${{ secrets.TEST_SHOPIFY_SHOP_URL }} + TEST_APPLE_LOGIN_TOKEN: ${{ secrets.TEST_APPLE_LOGIN_TOKEN }} strategy: fail-fast: false matrix: diff --git a/README.md b/README.md index ba6b22fb9..1ce402103 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Todo: - [x] CRM (in progress) - [x] Social (in progress) - [x] Workflow -- [ ] Action Engine +- [x] Action Engine - [x] GraphQL Documentation (in progress) ## Prerequisites diff --git a/app/Console/Commands/Connectors/Notifications/MailCaddieLabCommand.php b/app/Console/Commands/Connectors/Notifications/MailCaddieLabCommand.php index b5f34fe3c..d62874f53 100644 --- a/app/Console/Commands/Connectors/Notifications/MailCaddieLabCommand.php +++ b/app/Console/Commands/Connectors/Notifications/MailCaddieLabCommand.php @@ -13,7 +13,7 @@ class MailCaddieLabCommand extends Command public function handle() { $this->info('Sending internal mail to Caddie Lab'); - dump($this->argument('email')); + //dump($this->argument('email')); $app = AppsRepository::findFirstByKey($this->argument('apps_id')); $email = $this->argument('email'); MailCaddieLabJob::dispatch($app, $email); diff --git a/app/Console/Commands/Guild/AgentsImportCommand.php b/app/Console/Commands/Guild/AgentsImportCommand.php index b877546ee..e1526629d 100644 --- a/app/Console/Commands/Guild/AgentsImportCommand.php +++ b/app/Console/Commands/Guild/AgentsImportCommand.php @@ -118,6 +118,7 @@ public function handle(): void [ 'users_id' => $user->getId(), 'companies_id' => $company->getId(), + 'apps_id' => $app->getId(), ], [ 'name' => $record['Agent Name'], diff --git a/app/GraphQL/Ecosystem/Mutations/Auth/AuthManagementMutation.php b/app/GraphQL/Ecosystem/Mutations/Auth/AuthManagementMutation.php index ff6a949e3..0f3e355fa 100644 --- a/app/GraphQL/Ecosystem/Mutations/Auth/AuthManagementMutation.php +++ b/app/GraphQL/Ecosystem/Mutations/Auth/AuthManagementMutation.php @@ -19,6 +19,7 @@ use Kanvas\Auth\Traits\AuthTrait; use Kanvas\Auth\Traits\TokenTrait; use Kanvas\Companies\Models\CompaniesBranches; +use Kanvas\Enums\AppEnums; use Kanvas\Enums\AppSettingsEnums; use Kanvas\Sessions\Models\Sessions; use Kanvas\Users\Actions\SwitchCompanyBranchAction; @@ -57,7 +58,7 @@ public function loginMutation( ]) ); - return $user->createToken(name: 'kanvas-login', deviceId: $deviceId)->toArray(); + return $user->createToken(name: AppEnums::DEFAULT_APP_JWT_TOKEN_NAME->getValue(), deviceId: $deviceId)->toArray(); } /** @@ -132,7 +133,7 @@ public function register( $request = request(); $registeredUser = $user->execute(); - $tokenResponse = $registeredUser->createToken('kanvas-login')->toArray(); + $tokenResponse = $registeredUser->createToken(AppEnums::DEFAULT_APP_JWT_TOKEN_NAME->getValue())->toArray(); return [ 'user' => $registeredUser, @@ -151,7 +152,7 @@ public function refreshToken(mixed $rootValue, array $req): array } $user = UsersRepository::getByEmail($token->claims()->get('email')); - return $user->createToken('kanvas-login')->toArray(); + return $user->createToken(AppEnums::DEFAULT_APP_JWT_TOKEN_NAME->getValue())->toArray(); } /** @@ -172,11 +173,12 @@ public function socialLogin(mixed $root, array $req): array $data = $req['data']; $token = $data['token']; $provider = $data['provider']; - $user = SocialManager::getDriver($provider)->getUserFromToken($token); - $socialLogin = new SocialLoginAction($user, $provider); + $app = app(Apps::class); + $user = SocialManager::getDriver($provider, $app)->getUserFromToken($token); + $socialLogin = new SocialLoginAction($user, $provider, $app); $loggedUser = $socialLogin->execute(); - $tokenResponse = $loggedUser->createToken(name: 'kanvas-login')->toArray(); + $tokenResponse = $loggedUser->createToken(name: AppEnums::DEFAULT_APP_JWT_TOKEN_NAME->getValue())->toArray(); return $tokenResponse; } @@ -195,7 +197,7 @@ public function forgot( $user = new ForgotPasswordService(); $registeredUser = $user->forgot($request['data']['email']); - $tokenResponse = $registeredUser->createToken('kanvas-login')->toArray(); + $tokenResponse = $registeredUser->createToken(AppEnums::DEFAULT_APP_JWT_TOKEN_NAME->getValue())->toArray(); $request = request(); diff --git a/app/GraphQL/Guild/Mutations/Leads/LeadManagementMutation.php b/app/GraphQL/Guild/Mutations/Leads/LeadManagementMutation.php index 537958c42..ebe85a597 100644 --- a/app/GraphQL/Guild/Mutations/Leads/LeadManagementMutation.php +++ b/app/GraphQL/Guild/Mutations/Leads/LeadManagementMutation.php @@ -4,6 +4,7 @@ namespace App\GraphQL\Guild\Mutations\Leads; +use Kanvas\Apps\Models\Apps; use Kanvas\Guild\Leads\Actions\CreateLeadAction; use Kanvas\Guild\Leads\Actions\CreateLeadAttemptAction; use Kanvas\Guild\Leads\Actions\UpdateLeadAction; @@ -19,17 +20,19 @@ class LeadManagementMutation public function create(mixed $root, array $req): ModelsLead { $user = auth()->user(); + $app = app(Apps::class); $leadAttempt = new CreateLeadAttemptAction( $req, request()->headers->all(), $user->getCurrentCompany(), + $app, request()->ip(), - 'API' + 'API - Create' ); $attempt = $leadAttempt->execute(); $createLead = new CreateLeadAction( - Lead::viaRequest($user, $req['input']), + Lead::viaRequest($user, $app, $req['input']), $attempt ); $lead = $createLead->execute(); @@ -40,7 +43,9 @@ public function create(mixed $root, array $req): ModelsLead public function update(mixed $root, array $req): ModelsLead { $user = auth()->user(); + $app = app(Apps::class); + //@todo get from app $lead = ModelsLead::getByIdFromBranch( $req['id'], $user->getCurrentBranch() @@ -50,6 +55,7 @@ public function update(mixed $root, array $req): ModelsLead $req, request()->headers->all(), $user->getCurrentCompany(), + $app, request()->ip(), 'API - Update' ); diff --git a/app/GraphQL/Guild/Mutations/Leads/ParticipantMutation.php b/app/GraphQL/Guild/Mutations/Leads/ParticipantMutation.php index e627b744d..3eca3f471 100644 --- a/app/GraphQL/Guild/Mutations/Leads/ParticipantMutation.php +++ b/app/GraphQL/Guild/Mutations/Leads/ParticipantMutation.php @@ -7,6 +7,7 @@ use Kanvas\Guild\Leads\Actions\AddLeadParticipantAction; use Kanvas\Guild\Leads\Actions\RemoveLeadParticipantAction; use Kanvas\Guild\Leads\DataTransferObject\LeadsParticipant; +use Kanvas\Guild\Leads\Models\LeadParticipant; class ParticipantMutation { @@ -19,7 +20,7 @@ public function add(mixed $root, array $req): bool $action = new AddLeadParticipantAction($leadParticipant); - return $action->execute() instanceof LeadsParticipant; + return $action->execute() instanceof LeadParticipant; } /** diff --git a/app/GraphQL/Guild/Mutations/Organizations/OrganizationManagementMutation.php b/app/GraphQL/Guild/Mutations/Organizations/OrganizationManagementMutation.php index fe7a787bc..281eab60d 100644 --- a/app/GraphQL/Guild/Mutations/Organizations/OrganizationManagementMutation.php +++ b/app/GraphQL/Guild/Mutations/Organizations/OrganizationManagementMutation.php @@ -4,6 +4,7 @@ namespace App\GraphQL\Guild\Mutations\Organizations; +use Kanvas\Apps\Models\Apps; use Kanvas\Guild\Organizations\Actions\CreateOrganizationAction; use Kanvas\Guild\Organizations\Actions\UpdateOrganizationAction; use Kanvas\Guild\Organizations\DataTransferObject\Organization as DataTransferObjectOrganization; @@ -18,10 +19,12 @@ public function create(mixed $root, array $req): Organization { $user = auth()->user(); $data = $req['input']; + $app = app(Apps::class); $organizationData = new DataTransferObjectOrganization( $user->getCurrentCompany(), $user, + $app, $data['name'], $data['address'] ?? null ); @@ -35,12 +38,14 @@ public function update(mixed $root, array $req): Organization { $user = auth()->user(); $data = $req['input']; + $app = app(Apps::class); - $organization = Organization::getByIdFromCompany((int) $req['id'], $user->getCurrentCompany()); + $organization = Organization::getByIdFromCompanyApp((int) $req['id'], $user->getCurrentCompany(), $app); $organizationData = new DataTransferObjectOrganization( $user->getCurrentCompany(), $user, + $app, $data['name'], $data['address'] ?? null ); @@ -53,8 +58,9 @@ public function update(mixed $root, array $req): Organization public function delete(mixed $root, array $req): bool { $user = auth()->user(); + $app = app(Apps::class); - $organization = Organization::getByIdFromCompany((int) $req['id'], $user->getCurrentCompany()); + $organization = Organization::getByIdFromCompanyApp((int) $req['id'], $user->getCurrentCompany(), $app); return $organization->softDelete(); } @@ -62,9 +68,11 @@ public function delete(mixed $root, array $req): bool public function restore(mixed $root, array $req): bool { $user = auth()->user(); + $app = app(Apps::class); $organization = Organization::where('id', (int) $req['id']) - ->where('companies_id', $user->getCurrentCompany()->getId()) + ->fromCompany($user->getCurrentCompany()) + ->fromApp($app) ->firstOrFail(); return $organization->restoreRecord(); diff --git a/app/GraphQL/Guild/Mutations/Peoples/PeopleImportMutation.php b/app/GraphQL/Guild/Mutations/Peoples/PeopleImportMutation.php new file mode 100644 index 000000000..bd1c8d9d1 --- /dev/null +++ b/app/GraphQL/Guild/Mutations/Peoples/PeopleImportMutation.php @@ -0,0 +1,39 @@ +user(); + $company = isset($req['companyId']) ? Companies::getById($req['companyId']) : $user->getCurrentCompany(); + + CompaniesRepository::userAssociatedToCompany( + $company, + $user + ); + + $jobUuid = Str::uuid()->toString(); + + CustomerImporterJob::dispatch( + $jobUuid, + $req['input'], + $company->branch, + $user, + app(Apps::class) + ); + return $jobUuid; + } +} diff --git a/app/GraphQL/Guild/Mutations/Peoples/PeopleManagementMutation.php b/app/GraphQL/Guild/Mutations/Peoples/PeopleManagementMutation.php index 04d71af52..93c94ac54 100644 --- a/app/GraphQL/Guild/Mutations/Peoples/PeopleManagementMutation.php +++ b/app/GraphQL/Guild/Mutations/Peoples/PeopleManagementMutation.php @@ -30,7 +30,7 @@ public function create(mixed $root, array $req): ModelsPeople 'user' => $user, 'firstname' => $data['firstname'], 'middlename' => $data['middlename'] ?? null, - 'lastname' => $data['lastname'], + 'lastname' => $data['lastname'] ?? null, 'contacts' => Contact::collect($data['contacts'] ?? [], DataCollection::class), 'address' => Address::collect($data['address'] ?? [], DataCollection::class), 'id' => $data['id'] ?? 0, @@ -60,7 +60,7 @@ public function update(mixed $root, array $req): ModelsPeople 'user' => $user, 'firstname' => $data['firstname'], 'middlename' => $data['middlename'] ?? null, - 'lastname' => $data['lastname'], + 'lastname' => $data['lastname'] ?? null, 'contacts' => Contact::collect($data['contacts'] ?? [], DataCollection::class), 'address' => Address::collect($data['address'] ?? [], DataCollection::class), 'id' => $people->getId(), diff --git a/app/GraphQL/Guild/Mutations/Pipelines/PipelineManagementMutation.php b/app/GraphQL/Guild/Mutations/Pipelines/PipelineManagementMutation.php index 4db183cb6..58df48f08 100644 --- a/app/GraphQL/Guild/Mutations/Pipelines/PipelineManagementMutation.php +++ b/app/GraphQL/Guild/Mutations/Pipelines/PipelineManagementMutation.php @@ -4,6 +4,7 @@ namespace App\GraphQL\Guild\Mutations\Pipelines; +use Kanvas\Apps\Models\Apps; use Kanvas\Exceptions\ValidationException; use Kanvas\Guild\Pipelines\Actions\CreatePipelineAction; use Kanvas\Guild\Pipelines\Actions\UpdatePipelineAction; @@ -20,11 +21,13 @@ public function create(mixed $root, array $req): ModelsPipeline { $user = auth()->user(); $branch = $user->getCurrentBranch(); + $app = app(Apps::class); $pipeline = new CreatePipelineAction( Pipeline::viaRequest( $user, $branch, + $app, $req['input'] ) ); @@ -38,6 +41,7 @@ public function update(mixed $root, array $req): ModelsPipeline $company = $user->getCurrentCompany(); $branch = $user->getCurrentBranch(); $id = (int) $req['id']; + $app = app(Apps::class); $pipeline = ModelsPipeline::getByIdFromCompany($id, $company); @@ -46,6 +50,7 @@ public function update(mixed $root, array $req): ModelsPipeline Pipeline::viaRequest( $user, $branch, + $app, $req['input'] ) ); diff --git a/app/GraphQL/Inventory/Mutations/Variants/Variants.php b/app/GraphQL/Inventory/Mutations/Variants/Variants.php index 6f29fd3c6..27e3b5c19 100644 --- a/app/GraphQL/Inventory/Mutations/Variants/Variants.php +++ b/app/GraphQL/Inventory/Mutations/Variants/Variants.php @@ -134,7 +134,7 @@ public function addToWarehouse(mixed $root, array $req): VariantModel $company = auth()->user()->getCurrentCompany(); $variant = VariantsRepository::getById((int) $req['id'], $company); - $warehouse = WarehouseRepository::getById((int) $req['input']['warehouse_id']); + $warehouse = WarehouseRepository::getById((int) $req['input']['id']); if (isset($req['input']['status'])) { $req['input']['status_id'] = StatusRepository::getById((int) $req['input']['status']['id'], $company)->getId(); } @@ -153,7 +153,7 @@ public function updateVariantInWarehouse(mixed $root, array $req): VariantModel $company = auth()->user()->getCurrentCompany(); $variant = VariantsRepository::getById((int) $req['id'], $company); - $warehouse = WarehouseRepository::getById((int) $req['input']['warehouse_id'], $company); + $warehouse = WarehouseRepository::getById((int) $req['input']['id'], $company); return VariantService::updateWarehouseVariant($variant, $warehouse, $req['input']); } diff --git a/composer.lock b/composer.lock index 5eec2d4b5..2f3fde0b8 100644 --- a/composer.lock +++ b/composer.lock @@ -384,16 +384,16 @@ }, { "name": "amphp/dns", - "version": "v2.1.2", + "version": "v2.2.0", "source": { "type": "git", "url": "https://github.com/amphp/dns.git", - "reference": "04c88e67bef804203df934703bd422ea72f46b0e" + "reference": "758266b0ea7470e2e42cd098493bc6d6c7100cf7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/dns/zipball/04c88e67bef804203df934703bd422ea72f46b0e", - "reference": "04c88e67bef804203df934703bd422ea72f46b0e", + "url": "https://api.github.com/repos/amphp/dns/zipball/758266b0ea7470e2e42cd098493bc6d6c7100cf7", + "reference": "758266b0ea7470e2e42cd098493bc6d6c7100cf7", "shasum": "" }, "require": { @@ -460,7 +460,7 @@ ], "support": { "issues": "https://github.com/amphp/dns/issues", - "source": "https://github.com/amphp/dns/tree/v2.1.2" + "source": "https://github.com/amphp/dns/tree/v2.2.0" }, "funding": [ { @@ -468,7 +468,7 @@ "type": "github" } ], - "time": "2024-04-19T03:49:29+00:00" + "time": "2024-06-02T19:54:12+00:00" }, { "name": "amphp/parallel", @@ -1195,16 +1195,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.308.4", + "version": "3.310.0", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "c88e9df7e076b6e2c652a1c87d2c3af0a9ac30b6" + "reference": "8ac02d36c609c6507136e5996f60cfd5152b4fd7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/c88e9df7e076b6e2c652a1c87d2c3af0a9ac30b6", - "reference": "c88e9df7e076b6e2c652a1c87d2c3af0a9ac30b6", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/8ac02d36c609c6507136e5996f60cfd5152b4fd7", + "reference": "8ac02d36c609c6507136e5996f60cfd5152b4fd7", "shasum": "" }, "require": { @@ -1284,9 +1284,9 @@ "support": { "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.308.4" + "source": "https://github.com/aws/aws-sdk-php/tree/3.310.0" }, - "time": "2024-05-28T18:05:38+00:00" + "time": "2024-06-04T18:05:36+00:00" }, { "name": "berkayk/onesignal-laravel", @@ -2503,16 +2503,16 @@ }, { "name": "google/apiclient-services", - "version": "v0.356.0", + "version": "v0.358.0", "source": { "type": "git", "url": "https://github.com/googleapis/google-api-php-client-services.git", - "reference": "8e22b0a6f661f2db3f99abb6ee5a1dcf28d370e7" + "reference": "a6daf60ee25cb45b6e3dbd04b62d1df39a609fbd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/8e22b0a6f661f2db3f99abb6ee5a1dcf28d370e7", - "reference": "8e22b0a6f661f2db3f99abb6ee5a1dcf28d370e7", + "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/a6daf60ee25cb45b6e3dbd04b62d1df39a609fbd", + "reference": "a6daf60ee25cb45b6e3dbd04b62d1df39a609fbd", "shasum": "" }, "require": { @@ -2541,22 +2541,22 @@ ], "support": { "issues": "https://github.com/googleapis/google-api-php-client-services/issues", - "source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.356.0" + "source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.358.0" }, - "time": "2024-05-18T01:10:18+00:00" + "time": "2024-06-03T01:02:16+00:00" }, { "name": "google/auth", - "version": "v1.39.0", + "version": "v1.40.0", "source": { "type": "git", "url": "https://github.com/googleapis/google-auth-library-php.git", - "reference": "23e8e696d87f8d7dfefbd347ca1c99ce17ecb368" + "reference": "bff9f2d01677e71a98394b5ac981b99523df5178" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/googleapis/google-auth-library-php/zipball/23e8e696d87f8d7dfefbd347ca1c99ce17ecb368", - "reference": "23e8e696d87f8d7dfefbd347ca1c99ce17ecb368", + "url": "https://api.github.com/repos/googleapis/google-auth-library-php/zipball/bff9f2d01677e71a98394b5ac981b99523df5178", + "reference": "bff9f2d01677e71a98394b5ac981b99523df5178", "shasum": "" }, "require": { @@ -2601,27 +2601,27 @@ "support": { "docs": "https://googleapis.github.io/google-auth-library-php/main/", "issues": "https://github.com/googleapis/google-auth-library-php/issues", - "source": "https://github.com/googleapis/google-auth-library-php/tree/v1.39.0" + "source": "https://github.com/googleapis/google-auth-library-php/tree/v1.40.0" }, - "time": "2024-05-02T16:03:51+00:00" + "time": "2024-05-31T19:16:15+00:00" }, { "name": "google/cloud-core", - "version": "v1.58.1", + "version": "v1.58.2", "source": { "type": "git", "url": "https://github.com/googleapis/google-cloud-php-core.git", - "reference": "db3e0ab25103e0ca953f6e1e0ca5a39e363b8988" + "reference": "56df58d70cca3c429e2cfd32270e42596f6c002f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/googleapis/google-cloud-php-core/zipball/db3e0ab25103e0ca953f6e1e0ca5a39e363b8988", - "reference": "db3e0ab25103e0ca953f6e1e0ca5a39e363b8988", + "url": "https://api.github.com/repos/googleapis/google-cloud-php-core/zipball/56df58d70cca3c429e2cfd32270e42596f6c002f", + "reference": "56df58d70cca3c429e2cfd32270e42596f6c002f", "shasum": "" }, "require": { "google/auth": "^1.34", - "google/gax": "^1.30", + "google/gax": "^1.34.0", "guzzlehttp/guzzle": "^6.5.8|^7.4.4", "guzzlehttp/promises": "^1.4||^2.0", "guzzlehttp/psr7": "^2.6", @@ -2667,9 +2667,9 @@ ], "description": "Google Cloud PHP shared dependency, providing functionality useful to all components.", "support": { - "source": "https://github.com/googleapis/google-cloud-php-core/tree/v1.58.1" + "source": "https://github.com/googleapis/google-cloud-php-core/tree/v1.58.2" }, - "time": "2024-05-03T18:32:44+00:00" + "time": "2024-06-01T03:14:01+00:00" }, { "name": "google/cloud-storage", @@ -2782,16 +2782,16 @@ }, { "name": "google/gax", - "version": "v1.33.0", + "version": "v1.34.0", "source": { "type": "git", "url": "https://github.com/googleapis/gax-php.git", - "reference": "12a158e9b503df0087ebf9e218e8d75dc815a521" + "reference": "28aa3e95969a75b278606a88448992a6396a119e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/googleapis/gax-php/zipball/12a158e9b503df0087ebf9e218e8d75dc815a521", - "reference": "12a158e9b503df0087ebf9e218e8d75dc815a521", + "url": "https://api.github.com/repos/googleapis/gax-php/zipball/28aa3e95969a75b278606a88448992a6396a119e", + "reference": "28aa3e95969a75b278606a88448992a6396a119e", "shasum": "" }, "require": { @@ -2833,9 +2833,9 @@ ], "support": { "issues": "https://github.com/googleapis/gax-php/issues", - "source": "https://github.com/googleapis/gax-php/tree/v1.33.0" + "source": "https://github.com/googleapis/gax-php/tree/v1.34.0" }, - "time": "2024-05-14T14:55:14+00:00" + "time": "2024-05-30T00:35:13+00:00" }, { "name": "google/grpc-gcp", @@ -2884,20 +2884,20 @@ }, { "name": "google/longrunning", - "version": "0.4.2", + "version": "0.4.3", "source": { "type": "git", "url": "https://github.com/googleapis/php-longrunning.git", - "reference": "dd38c97ee348ad73bfb581aa276a536161f4b181" + "reference": "ed718a735e407826c3332b7197a44602eb03e608" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/googleapis/php-longrunning/zipball/dd38c97ee348ad73bfb581aa276a536161f4b181", - "reference": "dd38c97ee348ad73bfb581aa276a536161f4b181", + "url": "https://api.github.com/repos/googleapis/php-longrunning/zipball/ed718a735e407826c3332b7197a44602eb03e608", + "reference": "ed718a735e407826c3332b7197a44602eb03e608", "shasum": "" }, "require-dev": { - "google/gax": "^1.30", + "google/gax": "^1.34.0", "phpunit/phpunit": "^9.0" }, "type": "library", @@ -2922,9 +2922,9 @@ ], "description": "Google LongRunning Client for PHP", "support": { - "source": "https://github.com/googleapis/php-longrunning/tree/v0.4.2" + "source": "https://github.com/googleapis/php-longrunning/tree/v0.4.3" }, - "time": "2024-05-03T18:32:44+00:00" + "time": "2024-06-01T03:14:01+00:00" }, { "name": "google/protobuf", @@ -3906,16 +3906,16 @@ }, { "name": "laravel/framework", - "version": "v11.9.1", + "version": "v11.10.0", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "60167ce91c59ed5eea2ad4f2a7b6d686fb103ba7" + "reference": "99b4255194912044b75ab72329f8c19e6345720e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/60167ce91c59ed5eea2ad4f2a7b6d686fb103ba7", - "reference": "60167ce91c59ed5eea2ad4f2a7b6d686fb103ba7", + "url": "https://api.github.com/repos/laravel/framework/zipball/99b4255194912044b75ab72329f8c19e6345720e", + "reference": "99b4255194912044b75ab72329f8c19e6345720e", "shasum": "" }, "require": { @@ -4107,20 +4107,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2024-05-28T18:16:41+00:00" + "time": "2024-06-04T13:45:55+00:00" }, { "name": "laravel/octane", - "version": "v2.3.12", + "version": "v2.4.0", "source": { "type": "git", "url": "https://github.com/laravel/octane.git", - "reference": "e0ab5c8d151e49487a4d92599d7b83abd35490bc" + "reference": "2c818d7d213de793b180fc2a079f71c951d494c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/octane/zipball/e0ab5c8d151e49487a4d92599d7b83abd35490bc", - "reference": "e0ab5c8d151e49487a4d92599d7b83abd35490bc", + "url": "https://api.github.com/repos/laravel/octane/zipball/2c818d7d213de793b180fc2a079f71c951d494c7", + "reference": "2c818d7d213de793b180fc2a079f71c951d494c7", "shasum": "" }, "require": { @@ -4196,7 +4196,7 @@ "issues": "https://github.com/laravel/octane/issues", "source": "https://github.com/laravel/octane" }, - "time": "2024-05-24T14:26:00+00:00" + "time": "2024-05-31T19:17:54+00:00" }, { "name": "laravel/prompts", @@ -5919,16 +5919,16 @@ }, { "name": "nesbot/carbon", - "version": "3.4.0", + "version": "3.5.0", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "8eab8983c83c30e0bacbef8d311e3f3b8172727f" + "reference": "415782b7e48223342f1a616c16c45a95b15b2318" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/8eab8983c83c30e0bacbef8d311e3f3b8172727f", - "reference": "8eab8983c83c30e0bacbef8d311e3f3b8172727f", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/415782b7e48223342f1a616c16c45a95b15b2318", + "reference": "415782b7e48223342f1a616c16c45a95b15b2318", "shasum": "" }, "require": { @@ -5946,13 +5946,13 @@ "require-dev": { "doctrine/dbal": "^3.6.3 || ^4.0", "doctrine/orm": "^2.15.2 || ^3.0", - "friendsofphp/php-cs-fixer": "^3.52.1", + "friendsofphp/php-cs-fixer": "^3.57.2", "kylekatarnls/multi-tester": "^2.5.3", "ondrejmirtes/better-reflection": "^6.25.0.4", "phpmd/phpmd": "^2.15.0", "phpstan/extension-installer": "^1.3.1", - "phpstan/phpstan": "^1.10.65", - "phpunit/phpunit": "^10.5.15", + "phpstan/phpstan": "^1.11.2", + "phpunit/phpunit": "^10.5.20", "squizlabs/php_codesniffer": "^3.9.0" }, "bin": [ @@ -6021,7 +6021,7 @@ "type": "tidelift" } ], - "time": "2024-05-24T14:26:34+00:00" + "time": "2024-06-03T17:25:54+00:00" }, { "name": "nette/schema", @@ -7464,16 +7464,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "1.29.0", + "version": "1.29.1", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "536889f2b340489d328f5ffb7b02bb6b183ddedc" + "reference": "fcaefacf2d5c417e928405b71b400d4ce10daaf4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/536889f2b340489d328f5ffb7b02bb6b183ddedc", - "reference": "536889f2b340489d328f5ffb7b02bb6b183ddedc", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/fcaefacf2d5c417e928405b71b400d4ce10daaf4", + "reference": "fcaefacf2d5c417e928405b71b400d4ce10daaf4", "shasum": "" }, "require": { @@ -7505,9 +7505,9 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.29.0" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.29.1" }, - "time": "2024-05-06T12:04:23+00:00" + "time": "2024-05-31T08:52:43+00:00" }, { "name": "powersync/authorizenet-sdk-php", @@ -8578,16 +8578,16 @@ }, { "name": "sentry/sentry", - "version": "4.7.0", + "version": "4.8.0", "source": { "type": "git", "url": "https://github.com/getsentry/sentry-php.git", - "reference": "d6769b2a5e6bf19ed3bbfbf52328ceaf8e6fcb1f" + "reference": "3cf5778ff425a23f2d22ed41b423691d36f47163" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/getsentry/sentry-php/zipball/d6769b2a5e6bf19ed3bbfbf52328ceaf8e6fcb1f", - "reference": "d6769b2a5e6bf19ed3bbfbf52328ceaf8e6fcb1f", + "url": "https://api.github.com/repos/getsentry/sentry-php/zipball/3cf5778ff425a23f2d22ed41b423691d36f47163", + "reference": "3cf5778ff425a23f2d22ed41b423691d36f47163", "shasum": "" }, "require": { @@ -8651,7 +8651,7 @@ ], "support": { "issues": "https://github.com/getsentry/sentry-php/issues", - "source": "https://github.com/getsentry/sentry-php/tree/4.7.0" + "source": "https://github.com/getsentry/sentry-php/tree/4.8.0" }, "funding": [ { @@ -8663,7 +8663,7 @@ "type": "custom" } ], - "time": "2024-04-10T13:22:13+00:00" + "time": "2024-06-05T13:18:43+00:00" }, { "name": "sentry/sentry-laravel", @@ -9730,16 +9730,16 @@ }, { "name": "symfony/cache", - "version": "v7.0.7", + "version": "v7.1.1", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "48e3508338987d63b0114a00c208c4cbb76e5303" + "reference": "760294dc7158372699dccd077965c16c328f8719" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/48e3508338987d63b0114a00c208c4cbb76e5303", - "reference": "48e3508338987d63b0114a00c208c4cbb76e5303", + "url": "https://api.github.com/repos/symfony/cache/zipball/760294dc7158372699dccd077965c16c328f8719", + "reference": "760294dc7158372699dccd077965c16c328f8719", "shasum": "" }, "require": { @@ -9747,6 +9747,7 @@ "psr/cache": "^2.0|^3.0", "psr/log": "^1.1|^2|^3", "symfony/cache-contracts": "^2.5|^3", + "symfony/deprecation-contracts": "^2.5|^3.0", "symfony/service-contracts": "^2.5|^3", "symfony/var-exporter": "^6.4|^7.0" }, @@ -9806,7 +9807,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v7.0.7" + "source": "https://github.com/symfony/cache/tree/v7.1.1" }, "funding": [ { @@ -9822,7 +9823,7 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:29:19+00:00" + "time": "2024-05-31T14:57:53+00:00" }, { "name": "symfony/cache-contracts", @@ -9902,16 +9903,16 @@ }, { "name": "symfony/clock", - "version": "v7.0.7", + "version": "v7.1.1", "source": { "type": "git", "url": "https://github.com/symfony/clock.git", - "reference": "2008671acb4a30b01c453de193cf9c80549ebda6" + "reference": "3dfc8b084853586de51dd1441c6242c76a28cbe7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/clock/zipball/2008671acb4a30b01c453de193cf9c80549ebda6", - "reference": "2008671acb4a30b01c453de193cf9c80549ebda6", + "url": "https://api.github.com/repos/symfony/clock/zipball/3dfc8b084853586de51dd1441c6242c76a28cbe7", + "reference": "3dfc8b084853586de51dd1441c6242c76a28cbe7", "shasum": "" }, "require": { @@ -9956,7 +9957,7 @@ "time" ], "support": { - "source": "https://github.com/symfony/clock/tree/v7.0.7" + "source": "https://github.com/symfony/clock/tree/v7.1.1" }, "funding": [ { @@ -9972,20 +9973,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:29:19+00:00" + "time": "2024-05-31T14:57:53+00:00" }, { "name": "symfony/console", - "version": "v7.0.7", + "version": "v7.1.1", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "c981e0e9380ce9f146416bde3150c79197ce9986" + "reference": "9b008f2d7b21c74ef4d0c3de6077a642bc55ece3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/c981e0e9380ce9f146416bde3150c79197ce9986", - "reference": "c981e0e9380ce9f146416bde3150c79197ce9986", + "url": "https://api.github.com/repos/symfony/console/zipball/9b008f2d7b21c74ef4d0c3de6077a642bc55ece3", + "reference": "9b008f2d7b21c74ef4d0c3de6077a642bc55ece3", "shasum": "" }, "require": { @@ -10049,7 +10050,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.0.7" + "source": "https://github.com/symfony/console/tree/v7.1.1" }, "funding": [ { @@ -10065,20 +10066,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:29:19+00:00" + "time": "2024-05-31T14:57:53+00:00" }, { "name": "symfony/css-selector", - "version": "v7.0.7", + "version": "v7.1.1", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "b08a4ad89e84b29cec285b7b1f781a7ae51cf4bc" + "reference": "1c7cee86c6f812896af54434f8ce29c8d94f9ff4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/b08a4ad89e84b29cec285b7b1f781a7ae51cf4bc", - "reference": "b08a4ad89e84b29cec285b7b1f781a7ae51cf4bc", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/1c7cee86c6f812896af54434f8ce29c8d94f9ff4", + "reference": "1c7cee86c6f812896af54434f8ce29c8d94f9ff4", "shasum": "" }, "require": { @@ -10114,7 +10115,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v7.0.7" + "source": "https://github.com/symfony/css-selector/tree/v7.1.1" }, "funding": [ { @@ -10130,7 +10131,7 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:29:19+00:00" + "time": "2024-05-31T14:57:53+00:00" }, { "name": "symfony/deprecation-contracts", @@ -10201,16 +10202,16 @@ }, { "name": "symfony/error-handler", - "version": "v7.0.7", + "version": "v7.1.1", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "cf97429887e40480c847bfeb6c3991e1e2c086ab" + "reference": "e9b8bbce0b4f322939332ab7b6b81d8c11da27dd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/cf97429887e40480c847bfeb6c3991e1e2c086ab", - "reference": "cf97429887e40480c847bfeb6c3991e1e2c086ab", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/e9b8bbce0b4f322939332ab7b6b81d8c11da27dd", + "reference": "e9b8bbce0b4f322939332ab7b6b81d8c11da27dd", "shasum": "" }, "require": { @@ -10256,7 +10257,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v7.0.7" + "source": "https://github.com/symfony/error-handler/tree/v7.1.1" }, "funding": [ { @@ -10272,20 +10273,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:29:19+00:00" + "time": "2024-05-31T14:57:53+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v7.0.7", + "version": "v7.1.1", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "db2a7fab994d67d92356bb39c367db115d9d30f9" + "reference": "9fa7f7a21beb22a39a8f3f28618b29e50d7a55a7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/db2a7fab994d67d92356bb39c367db115d9d30f9", - "reference": "db2a7fab994d67d92356bb39c367db115d9d30f9", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/9fa7f7a21beb22a39a8f3f28618b29e50d7a55a7", + "reference": "9fa7f7a21beb22a39a8f3f28618b29e50d7a55a7", "shasum": "" }, "require": { @@ -10336,7 +10337,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v7.0.7" + "source": "https://github.com/symfony/event-dispatcher/tree/v7.1.1" }, "funding": [ { @@ -10352,7 +10353,7 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:29:19+00:00" + "time": "2024-05-31T14:57:53+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -10432,21 +10433,22 @@ }, { "name": "symfony/expression-language", - "version": "v7.0.7", + "version": "v7.1.1", "source": { "type": "git", "url": "https://github.com/symfony/expression-language.git", - "reference": "b8ec919a6d3d47fc4e7845c256d164413207bf73" + "reference": "463cb95f80c14136175f4e03f7f6199b01c6b8b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/expression-language/zipball/b8ec919a6d3d47fc4e7845c256d164413207bf73", - "reference": "b8ec919a6d3d47fc4e7845c256d164413207bf73", + "url": "https://api.github.com/repos/symfony/expression-language/zipball/463cb95f80c14136175f4e03f7f6199b01c6b8b4", + "reference": "463cb95f80c14136175f4e03f7f6199b01c6b8b4", "shasum": "" }, "require": { "php": ">=8.2", "symfony/cache": "^6.4|^7.0", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/service-contracts": "^2.5|^3" }, "type": "library", @@ -10475,7 +10477,7 @@ "description": "Provides an engine that can compile and evaluate expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/expression-language/tree/v7.0.7" + "source": "https://github.com/symfony/expression-language/tree/v7.1.1" }, "funding": [ { @@ -10491,20 +10493,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:29:19+00:00" + "time": "2024-05-31T14:57:53+00:00" }, { "name": "symfony/finder", - "version": "v7.0.7", + "version": "v7.1.1", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "4d58f0f4fe95a30d7b538d71197135483560b97c" + "reference": "fbb0ba67688b780efbc886c1a0a0948dcf7205d6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/4d58f0f4fe95a30d7b538d71197135483560b97c", - "reference": "4d58f0f4fe95a30d7b538d71197135483560b97c", + "url": "https://api.github.com/repos/symfony/finder/zipball/fbb0ba67688b780efbc886c1a0a0948dcf7205d6", + "reference": "fbb0ba67688b780efbc886c1a0a0948dcf7205d6", "shasum": "" }, "require": { @@ -10539,7 +10541,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.0.7" + "source": "https://github.com/symfony/finder/tree/v7.1.1" }, "funding": [ { @@ -10555,25 +10557,26 @@ "type": "tidelift" } ], - "time": "2024-04-28T11:44:19+00:00" + "time": "2024-05-31T14:57:53+00:00" }, { "name": "symfony/http-client", - "version": "v7.0.7", + "version": "v7.1.1", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "6ce3c4c899051b3d7326ea1a1dda3729e29ae6d7" + "reference": "1ec24a54d1885b11e862d6ddab31bd6749720d20" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/6ce3c4c899051b3d7326ea1a1dda3729e29ae6d7", - "reference": "6ce3c4c899051b3d7326ea1a1dda3729e29ae6d7", + "url": "https://api.github.com/repos/symfony/http-client/zipball/1ec24a54d1885b11e862d6ddab31bd6749720d20", + "reference": "1ec24a54d1885b11e862d6ddab31bd6749720d20", "shasum": "" }, "require": { "php": ">=8.2", "psr/log": "^1|^2|^3", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/http-client-contracts": "^3.4.1", "symfony/service-contracts": "^2.5|^3" }, @@ -10600,6 +10603,7 @@ "symfony/http-kernel": "^6.4|^7.0", "symfony/messenger": "^6.4|^7.0", "symfony/process": "^6.4|^7.0", + "symfony/rate-limiter": "^6.4|^7.0", "symfony/stopwatch": "^6.4|^7.0" }, "type": "library", @@ -10631,7 +10635,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v7.0.7" + "source": "https://github.com/symfony/http-client/tree/v7.1.1" }, "funding": [ { @@ -10647,7 +10651,7 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:29:19+00:00" + "time": "2024-05-31T14:57:53+00:00" }, { "name": "symfony/http-client-contracts", @@ -10729,16 +10733,16 @@ }, { "name": "symfony/http-foundation", - "version": "v7.0.7", + "version": "v7.1.1", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "0194e064b8bdc29381462f790bab04e1cac8fdc8" + "reference": "74d171d5b6a1d9e4bfee09a41937c17a7536acfa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/0194e064b8bdc29381462f790bab04e1cac8fdc8", - "reference": "0194e064b8bdc29381462f790bab04e1cac8fdc8", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/74d171d5b6a1d9e4bfee09a41937c17a7536acfa", + "reference": "74d171d5b6a1d9e4bfee09a41937c17a7536acfa", "shasum": "" }, "require": { @@ -10786,7 +10790,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v7.0.7" + "source": "https://github.com/symfony/http-foundation/tree/v7.1.1" }, "funding": [ { @@ -10802,25 +10806,26 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:29:19+00:00" + "time": "2024-05-31T14:57:53+00:00" }, { "name": "symfony/http-kernel", - "version": "v7.0.7", + "version": "v7.1.1", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "e07bb9bd86e7cd8ba2d3d9c618eec9d1bbe06d25" + "reference": "fa8d1c75b5f33b1302afccf81811f93976c6e26f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/e07bb9bd86e7cd8ba2d3d9c618eec9d1bbe06d25", - "reference": "e07bb9bd86e7cd8ba2d3d9c618eec9d1bbe06d25", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/fa8d1c75b5f33b1302afccf81811f93976c6e26f", + "reference": "fa8d1c75b5f33b1302afccf81811f93976c6e26f", "shasum": "" }, "require": { "php": ">=8.2", "psr/log": "^1|^2|^3", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/error-handler": "^6.4|^7.0", "symfony/event-dispatcher": "^6.4|^7.0", "symfony/http-foundation": "^6.4|^7.0", @@ -10861,9 +10866,9 @@ "symfony/finder": "^6.4|^7.0", "symfony/http-client-contracts": "^2.5|^3", "symfony/process": "^6.4|^7.0", - "symfony/property-access": "^6.4|^7.0", + "symfony/property-access": "^7.1", "symfony/routing": "^6.4|^7.0", - "symfony/serializer": "^6.4.4|^7.0.4", + "symfony/serializer": "^7.1", "symfony/stopwatch": "^6.4|^7.0", "symfony/translation": "^6.4|^7.0", "symfony/translation-contracts": "^2.5|^3", @@ -10899,7 +10904,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v7.0.7" + "source": "https://github.com/symfony/http-kernel/tree/v7.1.1" }, "funding": [ { @@ -10915,20 +10920,20 @@ "type": "tidelift" } ], - "time": "2024-04-29T12:20:25+00:00" + "time": "2024-06-04T06:52:15+00:00" }, { "name": "symfony/mailer", - "version": "v7.0.7", + "version": "v7.1.1", "source": { "type": "git", "url": "https://github.com/symfony/mailer.git", - "reference": "4ff41a7c7998a88cfdc31b5841ef64d9246fc56a" + "reference": "2eaad2e167cae930f25a3d731fec8b2ded5e751e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailer/zipball/4ff41a7c7998a88cfdc31b5841ef64d9246fc56a", - "reference": "4ff41a7c7998a88cfdc31b5841ef64d9246fc56a", + "url": "https://api.github.com/repos/symfony/mailer/zipball/2eaad2e167cae930f25a3d731fec8b2ded5e751e", + "reference": "2eaad2e167cae930f25a3d731fec8b2ded5e751e", "shasum": "" }, "require": { @@ -10979,7 +10984,7 @@ "description": "Helps sending emails", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailer/tree/v7.0.7" + "source": "https://github.com/symfony/mailer/tree/v7.1.1" }, "funding": [ { @@ -10995,20 +11000,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:29:19+00:00" + "time": "2024-05-31T14:57:53+00:00" }, { "name": "symfony/mailgun-mailer", - "version": "v7.0.7", + "version": "v7.1.1", "source": { "type": "git", "url": "https://github.com/symfony/mailgun-mailer.git", - "reference": "e9bb8fdbdd79334a8a88bdd233204315abd992c5" + "reference": "08d9b1fe18db2ea3b3a69c8c280b3f85479efdaa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailgun-mailer/zipball/e9bb8fdbdd79334a8a88bdd233204315abd992c5", - "reference": "e9bb8fdbdd79334a8a88bdd233204315abd992c5", + "url": "https://api.github.com/repos/symfony/mailgun-mailer/zipball/08d9b1fe18db2ea3b3a69c8c280b3f85479efdaa", + "reference": "08d9b1fe18db2ea3b3a69c8c280b3f85479efdaa", "shasum": "" }, "require": { @@ -11048,7 +11053,7 @@ "description": "Symfony Mailgun Mailer Bridge", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailgun-mailer/tree/v7.0.7" + "source": "https://github.com/symfony/mailgun-mailer/tree/v7.1.1" }, "funding": [ { @@ -11064,20 +11069,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:29:19+00:00" + "time": "2024-05-31T14:57:53+00:00" }, { "name": "symfony/mime", - "version": "v7.0.7", + "version": "v7.1.1", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "3adbf110c306546f6f00337f421d2edca0e8d3c0" + "reference": "21027eaacc1a8a20f5e616c25c3580f5dd3a15df" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/3adbf110c306546f6f00337f421d2edca0e8d3c0", - "reference": "3adbf110c306546f6f00337f421d2edca0e8d3c0", + "url": "https://api.github.com/repos/symfony/mime/zipball/21027eaacc1a8a20f5e616c25c3580f5dd3a15df", + "reference": "21027eaacc1a8a20f5e616c25c3580f5dd3a15df", "shasum": "" }, "require": { @@ -11090,7 +11095,7 @@ "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<1.4.0", "symfony/mailer": "<6.4", - "symfony/serializer": "<6.4" + "symfony/serializer": "<6.4.3|>7.0,<7.0.3" }, "require-dev": { "egulias/email-validator": "^2.1.10|^3.1|^4", @@ -11100,7 +11105,7 @@ "symfony/process": "^6.4|^7.0", "symfony/property-access": "^6.4|^7.0", "symfony/property-info": "^6.4|^7.0", - "symfony/serializer": "^6.4|^7.0" + "symfony/serializer": "^6.4.3|^7.0.3" }, "type": "library", "autoload": { @@ -11132,7 +11137,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v7.0.7" + "source": "https://github.com/symfony/mime/tree/v7.1.1" }, "funding": [ { @@ -11148,20 +11153,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:29:19+00:00" + "time": "2024-06-04T06:40:14+00:00" }, { "name": "symfony/options-resolver", - "version": "v7.0.7", + "version": "v7.1.1", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "23cc173858776ad451e31f053b1c9f47840b2cfa" + "reference": "47aa818121ed3950acd2b58d1d37d08a94f9bf55" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/23cc173858776ad451e31f053b1c9f47840b2cfa", - "reference": "23cc173858776ad451e31f053b1c9f47840b2cfa", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/47aa818121ed3950acd2b58d1d37d08a94f9bf55", + "reference": "47aa818121ed3950acd2b58d1d37d08a94f9bf55", "shasum": "" }, "require": { @@ -11199,7 +11204,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v7.0.7" + "source": "https://github.com/symfony/options-resolver/tree/v7.1.1" }, "funding": [ { @@ -11215,7 +11220,7 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:29:19+00:00" + "time": "2024-05-31T14:57:53+00:00" }, { "name": "symfony/polyfill-ctype", @@ -11930,16 +11935,16 @@ }, { "name": "symfony/process", - "version": "v7.0.7", + "version": "v7.1.1", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "3839e56b94dd1dbd13235d27504e66baf23faba0" + "reference": "febf90124323a093c7ee06fdb30e765ca3c20028" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/3839e56b94dd1dbd13235d27504e66baf23faba0", - "reference": "3839e56b94dd1dbd13235d27504e66baf23faba0", + "url": "https://api.github.com/repos/symfony/process/zipball/febf90124323a093c7ee06fdb30e765ca3c20028", + "reference": "febf90124323a093c7ee06fdb30e765ca3c20028", "shasum": "" }, "require": { @@ -11971,7 +11976,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.0.7" + "source": "https://github.com/symfony/process/tree/v7.1.1" }, "funding": [ { @@ -11987,20 +11992,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:29:19+00:00" + "time": "2024-05-31T14:57:53+00:00" }, { "name": "symfony/psr-http-message-bridge", - "version": "v7.0.7", + "version": "v7.1.1", "source": { "type": "git", "url": "https://github.com/symfony/psr-http-message-bridge.git", - "reference": "727befd41438a8feb64066871d3656d8cbdcdbe2" + "reference": "9a5dbb606da711f5d40a7596ad577856f9402140" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/727befd41438a8feb64066871d3656d8cbdcdbe2", - "reference": "727befd41438a8feb64066871d3656d8cbdcdbe2", + "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/9a5dbb606da711f5d40a7596ad577856f9402140", + "reference": "9a5dbb606da711f5d40a7596ad577856f9402140", "shasum": "" }, "require": { @@ -12054,7 +12059,7 @@ "psr-7" ], "support": { - "source": "https://github.com/symfony/psr-http-message-bridge/tree/v7.0.7" + "source": "https://github.com/symfony/psr-http-message-bridge/tree/v7.1.1" }, "funding": [ { @@ -12070,20 +12075,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:29:19+00:00" + "time": "2024-05-31T14:57:53+00:00" }, { "name": "symfony/routing", - "version": "v7.0.7", + "version": "v7.1.1", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "9f82bf7766ccc9c22ab7aeb9bebb98351483fa5b" + "reference": "60c31bab5c45af7f13091b87deb708830f3c96c0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/9f82bf7766ccc9c22ab7aeb9bebb98351483fa5b", - "reference": "9f82bf7766ccc9c22ab7aeb9bebb98351483fa5b", + "url": "https://api.github.com/repos/symfony/routing/zipball/60c31bab5c45af7f13091b87deb708830f3c96c0", + "reference": "60c31bab5c45af7f13091b87deb708830f3c96c0", "shasum": "" }, "require": { @@ -12135,7 +12140,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v7.0.7" + "source": "https://github.com/symfony/routing/tree/v7.1.1" }, "funding": [ { @@ -12151,7 +12156,7 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:29:19+00:00" + "time": "2024-05-31T14:57:53+00:00" }, { "name": "symfony/service-contracts", @@ -12238,16 +12243,16 @@ }, { "name": "symfony/string", - "version": "v7.0.7", + "version": "v7.1.1", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "e405b5424dc2528e02e31ba26b83a79fd4eb8f63" + "reference": "60bc311c74e0af215101235aa6f471bcbc032df2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/e405b5424dc2528e02e31ba26b83a79fd4eb8f63", - "reference": "e405b5424dc2528e02e31ba26b83a79fd4eb8f63", + "url": "https://api.github.com/repos/symfony/string/zipball/60bc311c74e0af215101235aa6f471bcbc032df2", + "reference": "60bc311c74e0af215101235aa6f471bcbc032df2", "shasum": "" }, "require": { @@ -12261,6 +12266,7 @@ "symfony/translation-contracts": "<2.5" }, "require-dev": { + "symfony/emoji": "^7.1", "symfony/error-handler": "^6.4|^7.0", "symfony/http-client": "^6.4|^7.0", "symfony/intl": "^6.4|^7.0", @@ -12304,7 +12310,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.0.7" + "source": "https://github.com/symfony/string/tree/v7.1.1" }, "funding": [ { @@ -12320,20 +12326,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:29:19+00:00" + "time": "2024-06-04T06:40:14+00:00" }, { "name": "symfony/translation", - "version": "v7.0.7", + "version": "v7.1.1", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "1515e03afaa93e6419aba5d5c9d209159317100b" + "reference": "cf5ae136e124fc7681b34ce9fac9d5b9ae8ceee3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/1515e03afaa93e6419aba5d5c9d209159317100b", - "reference": "1515e03afaa93e6419aba5d5c9d209159317100b", + "url": "https://api.github.com/repos/symfony/translation/zipball/cf5ae136e124fc7681b34ce9fac9d5b9ae8ceee3", + "reference": "cf5ae136e124fc7681b34ce9fac9d5b9ae8ceee3", "shasum": "" }, "require": { @@ -12398,7 +12404,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v7.0.7" + "source": "https://github.com/symfony/translation/tree/v7.1.1" }, "funding": [ { @@ -12414,7 +12420,7 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:29:19+00:00" + "time": "2024-05-31T14:57:53+00:00" }, { "name": "symfony/translation-contracts", @@ -12496,16 +12502,16 @@ }, { "name": "symfony/uid", - "version": "v7.0.7", + "version": "v7.1.1", "source": { "type": "git", "url": "https://github.com/symfony/uid.git", - "reference": "4f3a5d181999e25918586c8369de09e7814e7be2" + "reference": "bb59febeecc81528ff672fad5dab7f06db8c8277" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/uid/zipball/4f3a5d181999e25918586c8369de09e7814e7be2", - "reference": "4f3a5d181999e25918586c8369de09e7814e7be2", + "url": "https://api.github.com/repos/symfony/uid/zipball/bb59febeecc81528ff672fad5dab7f06db8c8277", + "reference": "bb59febeecc81528ff672fad5dab7f06db8c8277", "shasum": "" }, "require": { @@ -12550,7 +12556,7 @@ "uuid" ], "support": { - "source": "https://github.com/symfony/uid/tree/v7.0.7" + "source": "https://github.com/symfony/uid/tree/v7.1.1" }, "funding": [ { @@ -12566,20 +12572,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:29:19+00:00" + "time": "2024-05-31T14:57:53+00:00" }, { "name": "symfony/var-dumper", - "version": "v7.0.7", + "version": "v7.1.1", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "d1627b66fd87c8b4d90cabe5671c29d575690924" + "reference": "deb2c2b506ff6fdbb340e00b34e9901e1605f293" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/d1627b66fd87c8b4d90cabe5671c29d575690924", - "reference": "d1627b66fd87c8b4d90cabe5671c29d575690924", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/deb2c2b506ff6fdbb340e00b34e9901e1605f293", + "reference": "deb2c2b506ff6fdbb340e00b34e9901e1605f293", "shasum": "" }, "require": { @@ -12633,7 +12639,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.0.7" + "source": "https://github.com/symfony/var-dumper/tree/v7.1.1" }, "funding": [ { @@ -12649,20 +12655,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:29:19+00:00" + "time": "2024-05-31T14:57:53+00:00" }, { "name": "symfony/var-exporter", - "version": "v7.0.7", + "version": "v7.1.1", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "cdecc0022e40e90340ba1a59a3d5ccf069777078" + "reference": "db82c2b73b88734557cfc30e3270d83fa651b712" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/cdecc0022e40e90340ba1a59a3d5ccf069777078", - "reference": "cdecc0022e40e90340ba1a59a3d5ccf069777078", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/db82c2b73b88734557cfc30e3270d83fa651b712", + "reference": "db82c2b73b88734557cfc30e3270d83fa651b712", "shasum": "" }, "require": { @@ -12709,7 +12715,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v7.0.7" + "source": "https://github.com/symfony/var-exporter/tree/v7.1.1" }, "funding": [ { @@ -12725,7 +12731,7 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:29:19+00:00" + "time": "2024-05-31T14:57:53+00:00" }, { "name": "thecodingmachine/safe", @@ -13701,16 +13707,16 @@ }, { "name": "kitloong/laravel-migrations-generator", - "version": "v7.0.2", + "version": "v7.0.3", "source": { "type": "git", "url": "https://github.com/kitloong/laravel-migrations-generator.git", - "reference": "88532360173d33d0492e88feb5d4810e9db9c2ff" + "reference": "ca7d318e4922f276d2f862d22a2089bee8eb6921" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/kitloong/laravel-migrations-generator/zipball/88532360173d33d0492e88feb5d4810e9db9c2ff", - "reference": "88532360173d33d0492e88feb5d4810e9db9c2ff", + "url": "https://api.github.com/repos/kitloong/laravel-migrations-generator/zipball/ca7d318e4922f276d2f862d22a2089bee8eb6921", + "reference": "ca7d318e4922f276d2f862d22a2089bee8eb6921", "shasum": "" }, "require": { @@ -13762,15 +13768,19 @@ ], "support": { "issues": "https://github.com/kitloong/laravel-migrations-generator/issues", - "source": "https://github.com/kitloong/laravel-migrations-generator/tree/v7.0.2" + "source": "https://github.com/kitloong/laravel-migrations-generator/tree/v7.0.3" }, "funding": [ { "url": "https://www.buymeacoffee.com/kitloong", - "type": "custom" + "type": "buy_me_a_coffee" + }, + { + "url": "https://github.com/kitloong", + "type": "github" } ], - "time": "2024-04-23T14:01:01+00:00" + "time": "2024-06-01T17:17:59+00:00" }, { "name": "mockery/mockery", @@ -14131,16 +14141,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.11.2", + "version": "1.11.3", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "0d5d4294a70deb7547db655c47685d680e39cfec" + "reference": "e64220a05c1209fc856d58e789c3b7a32c0bb9a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/0d5d4294a70deb7547db655c47685d680e39cfec", - "reference": "0d5d4294a70deb7547db655c47685d680e39cfec", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e64220a05c1209fc856d58e789c3b7a32c0bb9a5", + "reference": "e64220a05c1209fc856d58e789c3b7a32c0bb9a5", "shasum": "" }, "require": { @@ -14185,7 +14195,7 @@ "type": "github" } ], - "time": "2024-05-24T13:23:04+00:00" + "time": "2024-05-31T13:53:37+00:00" }, { "name": "phpunit/php-code-coverage", diff --git a/database/migrations/Guild/2024_05_28_030618_apps_id_people.php b/database/migrations/Guild/2024_05_28_030618_apps_id_people.php index 3161b7e1c..09211760c 100644 --- a/database/migrations/Guild/2024_05_28_030618_apps_id_people.php +++ b/database/migrations/Guild/2024_05_28_030618_apps_id_people.php @@ -11,7 +11,6 @@ public function up(): void { Schema::table('peoples', function (Blueprint $table) { - // $table->bigInteger('apps_id')->unsigned()->nullable()->index()->after('companies_id'); }); } @@ -22,7 +21,6 @@ public function up(): void public function down(): void { Schema::table('peoples', function (Blueprint $table) { - // $table->dropColumn('apps_id'); }); } diff --git a/database/migrations/Guild/2024_06_02_105943_add_missing_apps_id.php b/database/migrations/Guild/2024_06_02_105943_add_missing_apps_id.php new file mode 100644 index 000000000..81950d4f5 --- /dev/null +++ b/database/migrations/Guild/2024_06_02_105943_add_missing_apps_id.php @@ -0,0 +1,67 @@ +bigInteger('apps_id')->unsigned()->nullable()->index()->after('companies_id'); + }); + + Schema::table('leads_attempt', function (Blueprint $table) { + $table->bigInteger('apps_id')->unsigned()->nullable()->index()->after('companies_id'); + }); + + Schema::table('leads_receivers', function (Blueprint $table) { + $table->bigInteger('apps_id')->unsigned()->nullable()->index()->after('companies_id'); + }); + + Schema::table('leads_rotations', function (Blueprint $table) { + $table->bigInteger('apps_id')->unsigned()->nullable()->index()->after('companies_id'); + }); + + Schema::table('organizations', function (Blueprint $table) { + $table->bigInteger('apps_id')->unsigned()->nullable()->index()->after('companies_id'); + }); + + Schema::table('pipelines', function (Blueprint $table) { + $table->bigInteger('apps_id')->unsigned()->nullable()->index()->after('companies_id'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('agents', function (Blueprint $table) { + $table->dropColumn('apps_id'); + }); + + Schema::table('leads_attempt', function (Blueprint $table) { + $table->dropColumn('apps_id'); + }); + + Schema::table('leads_receivers', function (Blueprint $table) { + $table->dropColumn('apps_id'); + }); + + Schema::table('leads_rotations', function (Blueprint $table) { + $table->dropColumn('apps_id'); + }); + + Schema::table('organizations', function (Blueprint $table) { + $table->dropColumn('apps_id'); + }); + + Schema::table('pipelines', function (Blueprint $table) { + $table->dropColumn('apps_id'); + }); + } +}; diff --git a/database/migrations/Inventory/2024_06_04_164025_create-attribute-slug.php b/database/migrations/Inventory/2024_06_04_164025_create-attribute-slug.php new file mode 100644 index 000000000..b87ce8582 --- /dev/null +++ b/database/migrations/Inventory/2024_06_04_164025_create-attribute-slug.php @@ -0,0 +1,25 @@ +string('slug')->after('name')->nullable(true); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + // + } +}; diff --git a/docker/nginx.conf b/docker/nginx.conf index b03928606..4b4948e35 100644 --- a/docker/nginx.conf +++ b/docker/nginx.conf @@ -1,32 +1,30 @@ server { listen 80; - server_name php.local + server_name php.local; client_max_body_size 100M; add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE'; location / { - if ($request_method = 'OPTIONS') { - add_header 'Access-Control-Allow-Origin' '*'; - add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE'; - # Custom headers and headers various browsers *should* be OK with but aren't - add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range,Public-Key,Authorization,X-Kanvas-App,X-Kanvas-Key,X-Kanvas-Location'; - - # Tell client that this pre-flight info is valid for 20 days - add_header 'Access-Control-Max-Age' 1728000; - add_header 'Content-Type' 'text/plain charset=UTF-8'; - add_header 'Content-Length' 0; - return 204; - } - - proxy_pass http://php:8080; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; + if ($request_method = 'OPTIONS') { + add_header 'Access-Control-Allow-Origin' '*'; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE'; + add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range,Public-Key,Authorization,X-Kanvas-App,X-Kanvas-Key,X-Kanvas-Location'; + add_header 'Access-Control-Max-Age' 1728000; + add_header 'Content-Type' 'text/plain charset=UTF-8'; + add_header 'Content-Length' 0; + return 204; + } + proxy_pass http://php:8080; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; } - location ~ /\.ht { - deny all; - } -} + location ~ /\.ht { + deny all; + } +} \ No newline at end of file diff --git a/docker/php.ini b/docker/php.ini index dd19720b2..1a4b6953c 100644 --- a/docker/php.ini +++ b/docker/php.ini @@ -1,7 +1,7 @@ log_errors=1 display_errors=1 -post_max_size=40M -upload_max_filesize=40M +upload_max_filesize = 100M +post_max_size = 100M display_startup_errors=1 error_log=/var/log/php/errors.log memory_limit=512M diff --git a/graphql/schemas/Guild/people.graphql b/graphql/schemas/Guild/people.graphql index 8599e3b1a..404c9d056 100644 --- a/graphql/schemas/Guild/people.graphql +++ b/graphql/schemas/Guild/people.graphql @@ -10,6 +10,11 @@ type People { dob: Date contacts: [Contact!]! @hasMany address: [Address!]! @hasMany + files: [Filesystem!]! + @paginate( + defaultCount: 25 + builder: "App\\GraphQL\\Ecosystem\\Queries\\Filesystem\\FilesystemQuery@getFileByGraphType" + ) custom_fields: [CustomField!]! @paginate( defaultCount: 25 @@ -28,7 +33,7 @@ input PeopleInput { id: ID firstname: String! middlename: String - lastname: String! + lastname: String facebook_contact_id: String twitter_contact_id: String linkedin_contact_id: String @@ -36,7 +41,9 @@ input PeopleInput { dob: String contacts: [ContactInput!] address: [AddressInput!] + files: [FilesystemInputUrl!] custom_fields: [CustomFieldEntityInput!] + created_at: DateTime } input PeopleParticipantInput { @@ -56,6 +63,7 @@ input PeopleParticipantInput { extend type Query @guard { peoples( + search: String @search where: _ @whereConditions(columns: ["id", "uuid", "companies_id", "dob"]) hasEmails: _ @@ -72,7 +80,7 @@ extend type Query @guard { ): [People!]! @paginate( model: "Kanvas\\Guild\\Customers\\Models\\People" - scopes: ["fromCompany"] + scopes: ["fromApp", "fromCompany", "notDeleted"] defaultCount: 25 ) peopleRelationships( @@ -102,4 +110,8 @@ extend type Mutation @guard { @field( resolver: "App\\GraphQL\\Guild\\Mutations\\Peoples\\PeopleManagementMutation@restore" ) + importPeoples(input: [PeopleInput!]!, companyId: Int): String! + @field( + resolver: "App\\GraphQL\\Guild\\Mutations\\Peoples\\PeopleImportMutation@import" + ) } diff --git a/graphql/schemas/Inventory/attributes.graphql b/graphql/schemas/Inventory/attributes.graphql index e9e645c20..8a2f62264 100644 --- a/graphql/schemas/Inventory/attributes.graphql +++ b/graphql/schemas/Inventory/attributes.graphql @@ -1,6 +1,7 @@ input AttributeInput { name: String! values: [AttributesValueInput!] + slug: String is_visible: Boolean is_searchable: Boolean is_filtrable: Boolean @@ -8,6 +9,7 @@ input AttributeInput { input AttributeUpdateInput { name: String + slug: String values: [AttributesValueInput!] is_visible: Boolean is_searchable: Boolean @@ -22,6 +24,7 @@ type Attributes { id: ID! uuid: String name: String + slug: String created_at: String updated_at: String companies: [Company] diff --git a/graphql/schemas/Inventory/variantWarehouse.graphql b/graphql/schemas/Inventory/variantWarehouse.graphql index 77b1d33c2..58eff32da 100644 --- a/graphql/schemas/Inventory/variantWarehouse.graphql +++ b/graphql/schemas/Inventory/variantWarehouse.graphql @@ -46,11 +46,11 @@ input VariantsWarehousesInput { } extend type Mutation @guard { - addVariantToWarehouse(id: ID!, input: VariantsWarehousesInput!): Variant + addVariantToWarehouse(id: ID!, input: WarehouseReferenceInput!): Variant @field( resolver: "App\\GraphQL\\Inventory\\Mutations\\Variants\\Variants@addToWarehouse" ) - updateVariantInWarehouse(id: ID!, input: VariantsWarehousesInput!): Variant + updateVariantInWarehouse(id: ID!, input: WarehouseReferenceInput!): Variant @field( resolver: "App\\GraphQL\\Inventory\\Mutations\\Variants\\Variants@updateVariantInWarehouse" ) diff --git a/operations/2024_06_04_184825_attribute-slug-update.php b/operations/2024_06_04_184825_attribute-slug-update.php new file mode 100644 index 000000000..7a2b8f4be --- /dev/null +++ b/operations/2024_06_04_184825_attribute-slug-update.php @@ -0,0 +1,35 @@ +slug = Str::slug($attribute->name); + $attribute->saveQuietly(); + } + } +}; diff --git a/src/Baka/Traits/KanvasModelTrait.php b/src/Baka/Traits/KanvasModelTrait.php index 461c5533b..2edbad36b 100644 --- a/src/Baka/Traits/KanvasModelTrait.php +++ b/src/Baka/Traits/KanvasModelTrait.php @@ -90,6 +90,20 @@ public static function getByIdFromCompany(mixed $id, CompanyInterface $company): } } + public static function getByIdFromCompanyApp(mixed $id, CompanyInterface $company, AppInterface $app): self + { + try { + return self::where('id', $id) + ->notDeleted() + ->fromCompany($company) + ->fromApp($app) + ->firstOrFail(); + } catch (ModelNotFoundException $e) { + //we want to expose the not found msg + throw new ExceptionsModelNotFoundException("No record found for $id from company {$company->getId()}"); + } + } + public static function getByUuidFromCompanyApp(string $uuid, ?CompanyInterface $company = null, ?AppInterface $app = null): self { return self::where('uuid', $uuid) diff --git a/src/Baka/Validations/Date.php b/src/Baka/Validations/Date.php index b8fe0e813..d12bd49f6 100644 --- a/src/Baka/Validations/Date.php +++ b/src/Baka/Validations/Date.php @@ -10,11 +10,6 @@ class Date { /** * Is validate date? - * - * @param string|null $date - * @param string $format - * - * @return bool */ public static function isValid(?string $date, string $format = 'Y-m-d'): bool { @@ -22,7 +17,10 @@ public static function isValid(?string $date, string $format = 'Y-m-d'): bool return false; } + $format = trim($format); + $d = DateTime::createFromFormat($format, $date); + return $d && $d->format($format) === $date; } } diff --git a/src/Domains/Connectors/Notifications/Jobs/MailCaddieLabJob.php b/src/Domains/Connectors/Notifications/Jobs/MailCaddieLabJob.php index fea45a9c3..88b31b8e1 100644 --- a/src/Domains/Connectors/Notifications/Jobs/MailCaddieLabJob.php +++ b/src/Domains/Connectors/Notifications/Jobs/MailCaddieLabJob.php @@ -33,10 +33,20 @@ public function __construct( public function handle() { $peoples = PeoplesRepository::getByDaysCreated(7, $this->app); - $this->sendMails($peoples, 'join-caddie', $this->app->get('billing_url'), $this->app->get('subject-join-caddie')); + $this->sendMails( + $peoples, + 'join-caddie', + $this->app->get('billing_url'), + $this->app->get('subject-join-caddie') + ); $peoples = PeoplesRepository::getByDaysCreated(28, $this->app); - $this->sendMails($peoples, 'deal-caddie', $this->app->get('billing_url_pro'), $this->app->get('subject-join-caddie-pro')); + $this->sendMails( + $peoples, + 'deal-caddie', + $this->app->get('billing_url_pro'), + $this->app->get('subject-join-caddie-pro') + ); } public function sendMails(Collection $peoples, string $template, string $baseUrl, string $subject) diff --git a/src/Domains/Connectors/Zoho/Actions/SyncZohoAgentAction.php b/src/Domains/Connectors/Zoho/Actions/SyncZohoAgentAction.php index d0ad5ddb5..9de26eced 100644 --- a/src/Domains/Connectors/Zoho/Actions/SyncZohoAgentAction.php +++ b/src/Domains/Connectors/Zoho/Actions/SyncZohoAgentAction.php @@ -32,7 +32,7 @@ public function execute(): Agent $name = explode(' ', $record->Name); $firstName = $name[0]; - $lastName = $name[1] ?? ''; + $lastName = implode(' ', array_slice($name, 1)); $memberNumber = $record->Member_Number; $zohoId = $record->id; $owner = $record->Owner; diff --git a/src/Domains/Connectors/Zoho/Workflows/ZohoAgentActivity.php b/src/Domains/Connectors/Zoho/Workflows/ZohoAgentActivity.php index f632a4b24..92661154d 100644 --- a/src/Domains/Connectors/Zoho/Workflows/ZohoAgentActivity.php +++ b/src/Domains/Connectors/Zoho/Workflows/ZohoAgentActivity.php @@ -175,6 +175,7 @@ protected function createAgent(AppInterface $app, ZohoService $zohoService, User $agent = new Agent(); $agent->users_id = $user->getId(); + $agent->apps_id = $app->getId(); $agent->companies_id = $company->getId(); $agent->name = $user->firstname . ' ' . $user->lastname; $agent->member_id = Agent::getNextAgentNumber($company); diff --git a/src/Domains/Guild/Agents/Models/Agent.php b/src/Domains/Guild/Agents/Models/Agent.php index 3e1e87b01..be03a6a11 100644 --- a/src/Domains/Guild/Agents/Models/Agent.php +++ b/src/Domains/Guild/Agents/Models/Agent.php @@ -20,6 +20,7 @@ * @property int $id * @property int $users_id * @property int $companies_id + * @property int|null $apps_id * @property string $name * @property string $users_linked_source_id * @property string $member_id @@ -30,8 +31,6 @@ */ class Agent extends BaseModel { - use NoAppRelationshipTrait; - protected $table = 'agents'; protected $guarded = []; diff --git a/src/Domains/Guild/Customers/Actions/CreatePeopleAction.php b/src/Domains/Guild/Customers/Actions/CreatePeopleAction.php index 4113c4f71..906f95e3f 100644 --- a/src/Domains/Guild/Customers/Actions/CreatePeopleAction.php +++ b/src/Domains/Guild/Customers/Actions/CreatePeopleAction.php @@ -4,6 +4,7 @@ namespace Kanvas\Guild\Customers\Actions; +use Baka\Validations\Date; use Kanvas\Guild\Customers\DataTransferObject\People as PeopleDataInput; use Kanvas\Guild\Customers\Models\Address; use Kanvas\Guild\Customers\Models\Contact; @@ -40,6 +41,10 @@ public function execute(): People 'apple_contact_id' => $this->peopleData->apple_contact_id, ]; + if (Date::isValid($this->peopleData->created_at, 'Y-m-d H:i:s')) { + $attributes['created_at'] = date('Y-m-d H:i:s', strtotime($this->peopleData->created_at)); + } + //@todo how to avoid duplicated? should it be use or frontend? if ($this->peopleData->id) { $people = PeoplesRepository::getById($this->peopleData->id, $company); diff --git a/src/Domains/Guild/Customers/DataTransferObject/People.php b/src/Domains/Guild/Customers/DataTransferObject/People.php index d148bb78a..4c0f4fcda 100644 --- a/src/Domains/Guild/Customers/DataTransferObject/People.php +++ b/src/Domains/Guild/Customers/DataTransferObject/People.php @@ -24,12 +24,12 @@ public function __construct( public readonly CompaniesBranches $branch, public readonly UserInterface $user, public readonly string $firstname, - public readonly string $lastname, #[DataCollectionOf(Contact::class)] public readonly DataCollection $contacts, #[DataCollectionOf(Address::class)] public readonly DataCollection $address, - public readonly int $id = 0, + public readonly ?string $lastname = null, + public int $id = 0, #[WithCast(DateTimeInterfaceCast::class, format: 'Y-m-d')] public readonly ?DateTime $dob = null, public readonly ?string $facebook_contact_id = null, @@ -37,7 +37,8 @@ public function __construct( public readonly ?string $apple_contact_id = null, public readonly ?string $linkedin_contact_id = null, public readonly ?string $middlename = null, - public readonly array $custom_fields = [] + public readonly array $custom_fields = [], + public readonly ?string $created_at = null ) { } } diff --git a/src/Domains/Guild/Customers/Jobs/CustomerImporterJob.php b/src/Domains/Guild/Customers/Jobs/CustomerImporterJob.php new file mode 100644 index 000000000..c59ad3871 --- /dev/null +++ b/src/Domains/Guild/Customers/Jobs/CustomerImporterJob.php @@ -0,0 +1,126 @@ + $importer + */ + public function __construct( + public string $jobUuid, + public array $importer, + public CompaniesBranches $branch, + public UserInterface $user, + public AppInterface $app + ) { + } + + /** + * Get the unique ID for the job. + */ + public function uniqueId(): string + { + return $this->jobUuid . $this->app->getId() . $this->branch->getId(); + } + + /** + * handle. + * + * @return void + */ + public function handle() + { + config(['laravel-model-caching.disabled' => true]); + Auth::loginUsingId($this->user->getId()); + $this->overwriteAppService($this->app); + $this->overwriteAppServiceLocation($this->branch); + + /** + * @var Companies + */ + $company = $this->branch->company()->firstOrFail(); + + foreach ($this->importer as $customerData) { + try { + $people = People::from([ + 'app' => $this->app, + 'branch' => $this->branch, + 'user' => $this->user, + 'firstname' => $customerData['firstname'], + 'middlename' => $customerData['middlename'] ?? null, + 'lastname' => $data['lastname'] ?? null, + 'contacts' => Contact::collect($customerData['contacts'] ?? [], DataCollection::class), + 'address' => Address::collect($customerData['address'] ?? [], DataCollection::class), + 'dob' => $customerData['dob'] ?? null, + 'facebook_contact_id' => $customerData['facebook_contact_id'] ?? null, + 'google_contact_id' => $customerData['google_contact_id'] ?? null, + 'apple_contact_id' => $customerData['apple_contact_id'] ?? null, + 'linkedin_contact_id' => $customerData['linkedin_contact_id'] ?? null, + 'custom_fields' => $customerData['custom_fields'] ?? [], + 'created_at' => $customerData['created_at'] ?? null, + ]); + + if ($people->contacts->count()) { + foreach ($people->contacts as $contact) { + $customer = PeoplesRepository::getByValue($contact->value, $company, $this->app); + if ($customer) { + $people->id = $customer->id; + + break; + } + } + } + + $peopleSync = new CreatePeopleAction($people); + $peopleSync->execute(); + } catch (Throwable $e) { + Log::error($e->getMessage()); + captureException($e); + } + } + } +} diff --git a/src/Domains/Guild/Customers/Models/People.php b/src/Domains/Guild/Customers/Models/People.php index 0f07b29ee..55af8b428 100644 --- a/src/Domains/Guild/Customers/Models/People.php +++ b/src/Domains/Guild/Customers/Models/People.php @@ -35,7 +35,6 @@ class People extends BaseModel { use UuidTrait; use Searchable; - use NoAppRelationshipTrait; protected $table = 'peoples'; protected $guarded = []; diff --git a/src/Domains/Guild/Customers/Repositories/PeoplesRepository.php b/src/Domains/Guild/Customers/Repositories/PeoplesRepository.php index 0ed4f3e61..1d977d764 100644 --- a/src/Domains/Guild/Customers/Repositories/PeoplesRepository.php +++ b/src/Domains/Guild/Customers/Repositories/PeoplesRepository.php @@ -4,6 +4,7 @@ namespace Kanvas\Guild\Customers\Repositories; +use Baka\Contracts\AppInterface; use Baka\Contracts\CompanyInterface; use Baka\Traits\SearchableTrait; use Baka\Users\Contracts\UserInterface; @@ -45,11 +46,24 @@ public static function getByEmail(string $email, CompanyInterface $company): ?Pe * @psalm-suppress MixedReturnStatement */ return People::from('peoples as p') - ->join('contacts as c', 'p.id', '=', 'c.peoples_id') + ->join('peoples_contacts as c', 'p.id', '=', 'c.peoples_id') ->where('c.value', $email) ->where('c.contacts_types_id', ContactTypeEnum::EMAIL->value) // Assuming EMAIL is a constant in ContactsTypes model ->where('p.companies_id', $company->getId()) ->where('p.is_deleted', 0) + ->select('p.*') + ->first(); + } + + public static function getByValue(string $value, CompanyInterface $company, AppInterface $app): ?People + { + return People::from('peoples as p') + ->join('peoples_contacts as c', 'p.id', '=', 'c.peoples_id') + ->where('c.value', $value) + ->where('p.companies_id', $company->getId()) + ->where('p.apps_id', $app->getId()) + ->where('p.is_deleted', 0) + ->select('p.*') ->first(); } diff --git a/src/Domains/Guild/Leads/Actions/CreateLeadAction.php b/src/Domains/Guild/Leads/Actions/CreateLeadAction.php index 91c6d7fe0..279611fcf 100644 --- a/src/Domains/Guild/Leads/Actions/CreateLeadAction.php +++ b/src/Domains/Guild/Leads/Actions/CreateLeadAction.php @@ -24,13 +24,8 @@ class CreateLeadAction */ public function __construct( protected readonly LeadDataInput $leadData, - protected ?LeadAttempt $leadAttempt = null, - protected ?Apps $app = null + protected ?LeadAttempt $leadAttempt = null ) { - /** - * @psalm-suppress MixedAssignment - */ - $this->app = $this->app ?? app(Apps::class); $this->company = $this->leadData->branch->company()->firstOrFail(); } @@ -48,7 +43,7 @@ public function execute(): Lead } catch (ModelNotFoundException $e) { } } - $newLead->apps_id = $this->app->getId(); + $newLead->apps_id = $this->leadData->app->getId(); $newLead->users_id = $this->leadData->user->getId(); $newLead->companies_id = $this->company->getId(); $newLead->companies_branches_id = $this->leadData->branch->getId(); @@ -89,8 +84,6 @@ public function execute(): Lead $this->leadAttempt->saveOrFail(); } - //@todo add workflow - return $newLead; } } diff --git a/src/Domains/Guild/Leads/Actions/CreateLeadAttemptAction.php b/src/Domains/Guild/Leads/Actions/CreateLeadAttemptAction.php index 53af9664c..d8a4774c5 100644 --- a/src/Domains/Guild/Leads/Actions/CreateLeadAttemptAction.php +++ b/src/Domains/Guild/Leads/Actions/CreateLeadAttemptAction.php @@ -4,20 +4,22 @@ namespace Kanvas\Guild\Leads\Actions; +use Baka\Contracts\AppInterface; use Baka\Contracts\CompanyInterface; use Kanvas\Guild\Leads\Models\LeadAttempt; -class CreateLeadAttemptAction +readonly class CreateLeadAttemptAction { /** * __construct. */ public function __construct( - protected readonly array $request, - protected readonly array $headers, - protected readonly CompanyInterface $company, - protected readonly string $ip, - protected readonly string $source + protected array $request, + protected array $headers, + protected CompanyInterface $company, + protected AppInterface $app, + protected string $ip, + protected string $source ) { } @@ -28,6 +30,7 @@ public function execute(): LeadAttempt { return LeadAttempt::create([ 'companies_id' => $this->company->getId(), + 'apps_id' => $this->app->getId(), 'header' => $this->headers, 'request' => $this->request, 'ip' => $this->ip, diff --git a/src/Domains/Guild/Leads/Actions/UpdateLeadAction.php b/src/Domains/Guild/Leads/Actions/UpdateLeadAction.php index 8dcaae22f..bb7170643 100644 --- a/src/Domains/Guild/Leads/Actions/UpdateLeadAction.php +++ b/src/Domains/Guild/Leads/Actions/UpdateLeadAction.php @@ -121,9 +121,6 @@ public function execute(): Lead $this->leadAttempt->saveOrFail(); } - /** - * @psalm-suppress LessSpecificReturnStatement - */ return $lead; } } diff --git a/src/Domains/Guild/Leads/DataTransferObject/Lead.php b/src/Domains/Guild/Leads/DataTransferObject/Lead.php index 0024bf590..5858a0769 100644 --- a/src/Domains/Guild/Leads/DataTransferObject/Lead.php +++ b/src/Domains/Guild/Leads/DataTransferObject/Lead.php @@ -46,7 +46,7 @@ public function __construct( /** * @psalm-suppress ArgumentTypeCoercion */ - public static function viaRequest(UserInterface $user, array $request): self + public static function viaRequest(UserInterface $user, AppInterface $app, array $request): self { $branch = CompaniesBranches::getById($request['branch_id']); CompaniesRepository::userAssociatedToCompanyAndBranch( @@ -56,13 +56,13 @@ public static function viaRequest(UserInterface $user, array $request): self ); return new self( - app(Apps::class), + $app, $branch, $user, (string) $request['title'], (int) $request['pipeline_stage_id'], People::from([ - 'app' => app(Apps::class), + 'app' => $app, 'branch' => $branch, 'user' => $user, 'firstname' => $request['people']['firstname'], @@ -86,6 +86,7 @@ public static function viaRequest(UserInterface $user, array $request): self isset($request['organization']) ? Organization::from([ 'company' => $branch->company, 'user' => $user, + 'app' => $app, ...$request['organization'], ]) : null, $request['custom_fields'] ?? [], diff --git a/src/Domains/Guild/Leads/Models/Lead.php b/src/Domains/Guild/Leads/Models/Lead.php index 0204d8264..130765dce 100644 --- a/src/Domains/Guild/Leads/Models/Lead.php +++ b/src/Domains/Guild/Leads/Models/Lead.php @@ -5,7 +5,6 @@ namespace Kanvas\Guild\Leads\Models; use Baka\Support\Str; -use Baka\Traits\NoAppRelationshipTrait; use Baka\Traits\UuidTrait; use Baka\Users\Contracts\UserInterface; use Illuminate\Database\Eloquent\Builder; @@ -36,6 +35,7 @@ * @property string $uuid * @property int $users_id * @property int $companies_id + * @property int|null $apps_id * @property int $companies_branches_id * @property int $leads_receivers_id * @property int $leads_owner_id @@ -61,7 +61,6 @@ class Lead extends BaseModel { use UuidTrait; use Searchable; - use NoAppRelationshipTrait; use FollowersTrait; use CanUseWorkflow; diff --git a/src/Domains/Guild/Leads/Models/LeadAttempt.php b/src/Domains/Guild/Leads/Models/LeadAttempt.php index b1be31c70..86dfae21a 100644 --- a/src/Domains/Guild/Leads/Models/LeadAttempt.php +++ b/src/Domains/Guild/Leads/Models/LeadAttempt.php @@ -14,6 +14,7 @@ * * @property int $id * @property int $companies_id + * @property int|null $apps_id * @property int|null $leads_id * @property string $header * @property string $request @@ -27,8 +28,6 @@ */ class LeadAttempt extends BaseModel { - use NoAppRelationshipTrait; - protected $table = 'leads_attempt'; protected $guarded = []; protected $casts = [ diff --git a/src/Domains/Guild/Leads/Models/LeadReceiver.php b/src/Domains/Guild/Leads/Models/LeadReceiver.php index 25890c766..d679e1cad 100644 --- a/src/Domains/Guild/Leads/Models/LeadReceiver.php +++ b/src/Domains/Guild/Leads/Models/LeadReceiver.php @@ -4,7 +4,6 @@ namespace Kanvas\Guild\Leads\Models; -use Baka\Traits\NoAppRelationshipTrait; use Baka\Traits\UuidTrait; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Kanvas\Companies\Models\CompaniesBranches; @@ -16,6 +15,7 @@ * * @property int $id * @property string $uuid + * @property int|null $apps_id * @property int $companies_id * @property int|null $companies_branches_id * @property string $name @@ -33,7 +33,6 @@ class LeadReceiver extends BaseModel { use UuidTrait; - use NoAppRelationshipTrait; protected $table = 'leads_receivers'; protected $guarded = []; diff --git a/src/Domains/Guild/Leads/Models/LeadRotation.php b/src/Domains/Guild/Leads/Models/LeadRotation.php index 1f7850d8d..508f26b13 100644 --- a/src/Domains/Guild/Leads/Models/LeadRotation.php +++ b/src/Domains/Guild/Leads/Models/LeadRotation.php @@ -4,7 +4,6 @@ namespace Kanvas\Guild\Leads\Models; -use Baka\Traits\NoAppRelationshipTrait; use Baka\Users\Contracts\UserInterface; use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Relations\HasMany; @@ -15,6 +14,7 @@ * Class LeadRotation. * * @property int $id + * @property int|null $apps_id * @property int $companies_id * @property string $name * @property string $leads_rotations_email @@ -25,8 +25,6 @@ */ class LeadRotation extends BaseModel { - use NoAppRelationshipTrait; - protected $table = 'leads_rotations'; protected $guarded = []; diff --git a/src/Domains/Guild/Organizations/Actions/CreateOrganizationAction.php b/src/Domains/Guild/Organizations/Actions/CreateOrganizationAction.php index fd6095ca4..078be3da0 100644 --- a/src/Domains/Guild/Organizations/Actions/CreateOrganizationAction.php +++ b/src/Domains/Guild/Organizations/Actions/CreateOrganizationAction.php @@ -25,6 +25,7 @@ public function execute(): Organization return Organization::firstOrCreate([ 'name' => $this->organizationData->name, 'companies_id' => $this->organizationData->company->getId(), + 'apps_id' => $this->organizationData->app->getId(), ], [ 'address' => $this->organizationData->address, 'users_id' => $this->organizationData->user->getId(), diff --git a/src/Domains/Guild/Organizations/DataTransferObject/Organization.php b/src/Domains/Guild/Organizations/DataTransferObject/Organization.php index a83467dd6..645e6fc4d 100644 --- a/src/Domains/Guild/Organizations/DataTransferObject/Organization.php +++ b/src/Domains/Guild/Organizations/DataTransferObject/Organization.php @@ -4,6 +4,7 @@ namespace Kanvas\Guild\Organizations\DataTransferObject; +use Baka\Contracts\AppInterface; use Baka\Contracts\CompanyInterface; use Baka\Users\Contracts\UserInterface; use Spatie\LaravelData\Data; @@ -16,6 +17,7 @@ class Organization extends Data public function __construct( public readonly CompanyInterface $company, public readonly UserInterface $user, + public readonly AppInterface $app, public readonly string $name, public readonly ?string $address = null ) { diff --git a/src/Domains/Guild/Organizations/Models/Organization.php b/src/Domains/Guild/Organizations/Models/Organization.php index c68dc0cd6..e8eec2f63 100644 --- a/src/Domains/Guild/Organizations/Models/Organization.php +++ b/src/Domains/Guild/Organizations/Models/Organization.php @@ -4,7 +4,6 @@ namespace Kanvas\Guild\Organizations\Models; -use Baka\Traits\NoAppRelationshipTrait; use Baka\Traits\UuidTrait; use Illuminate\Database\Eloquent\Relations\HasManyThrough; use Kanvas\Guild\Customers\Models\People; @@ -15,6 +14,7 @@ * * @property int $id * @property string $uuid + * @property int|null $apps_id * @property int $users_id * @property int $companies_id * @property string $name @@ -23,7 +23,6 @@ class Organization extends BaseModel { use UuidTrait; - use NoAppRelationshipTrait; protected $table = 'organizations'; protected $guarded = []; diff --git a/src/Domains/Guild/Pipelines/Actions/CreatePipelineAction.php b/src/Domains/Guild/Pipelines/Actions/CreatePipelineAction.php index 1ee23899d..542c88170 100644 --- a/src/Domains/Guild/Pipelines/Actions/CreatePipelineAction.php +++ b/src/Domains/Guild/Pipelines/Actions/CreatePipelineAction.php @@ -26,6 +26,7 @@ public function execute(): ModelsPipeline $pipeline = ModelsPipeline::firstOrCreate([ 'companies_id' => $this->pipelineData->branch->companies_id, 'system_modules_id' => $this->pipelineData->systemModule->getId(), + 'apps_id' => $this->pipelineData->systemModule->apps_id, 'name' => $this->pipelineData->name, 'is_deleted' => 0, ], [ diff --git a/src/Domains/Guild/Pipelines/DataTransferObject/Pipeline.php b/src/Domains/Guild/Pipelines/DataTransferObject/Pipeline.php index 241ce0285..c012c683e 100644 --- a/src/Domains/Guild/Pipelines/DataTransferObject/Pipeline.php +++ b/src/Domains/Guild/Pipelines/DataTransferObject/Pipeline.php @@ -4,6 +4,7 @@ namespace Kanvas\Guild\Pipelines\DataTransferObject; +use Baka\Contracts\AppInterface; use Baka\Users\Contracts\UserInterface; use Kanvas\Companies\Models\CompaniesBranches; use Kanvas\Companies\Repositories\CompaniesRepository; @@ -35,6 +36,7 @@ public function __construct( public static function viaRequest( UserInterface $user, CompaniesBranches $branch, + AppInterface $app, array $request ): self { CompaniesRepository::userAssociatedToCompanyAndBranch( @@ -44,7 +46,7 @@ public static function viaRequest( ); //for now all pipelines are for leads - $systemModule = SystemModulesRepository::getByModelName(Lead::class); + $systemModule = SystemModulesRepository::getByModelName(Lead::class, $app); return new self( $branch, diff --git a/src/Domains/Guild/Pipelines/Models/Pipeline.php b/src/Domains/Guild/Pipelines/Models/Pipeline.php index 3204f18bc..6b67d3236 100644 --- a/src/Domains/Guild/Pipelines/Models/Pipeline.php +++ b/src/Domains/Guild/Pipelines/Models/Pipeline.php @@ -4,7 +4,6 @@ namespace Kanvas\Guild\Pipelines\Models; -use Baka\Traits\NoAppRelationshipTrait; use Baka\Traits\SlugTrait; use Illuminate\Database\Eloquent\Relations\HasMany; use Kanvas\Guild\Leads\Models\Lead; @@ -14,6 +13,7 @@ * Class Pipeline. * * @property int $id + * @property int|null $apps_id * @property int $companies_id * @property int $users_id * @property int $system_modules_id @@ -24,7 +24,6 @@ */ class Pipeline extends BaseModel { - use NoAppRelationshipTrait; use SlugTrait; protected $table = 'pipelines'; diff --git a/src/Domains/Guild/Support/Setup.php b/src/Domains/Guild/Support/Setup.php index c1056d282..d26c9da01 100644 --- a/src/Domains/Guild/Support/Setup.php +++ b/src/Domains/Guild/Support/Setup.php @@ -121,6 +121,7 @@ public function run(): bool LeadReceiver::firstOrCreate([ 'companies_branches_id' => $this->company->defaultBranch()->firstOrFail()->getId(), 'companies_id' => $this->company->getId(), + 'apps_id' => $this->app->getId(), 'is_default' => StateEnums::YES->getValue(), ], [ 'users_id' => $this->user->getId(), diff --git a/src/Domains/Inventory/Attributes/Actions/CreateAttribute.php b/src/Domains/Inventory/Attributes/Actions/CreateAttribute.php index 0a4322bc1..04d17c651 100644 --- a/src/Domains/Inventory/Attributes/Actions/CreateAttribute.php +++ b/src/Domains/Inventory/Attributes/Actions/CreateAttribute.php @@ -35,6 +35,7 @@ public function execute(): Attributes 'apps_id' => $this->dto->app->getId(), ], [ 'users_id' => $this->user->getId(), + 'slug' => $this->dto->slug, 'is_visible' => $this->dto->isVisible, 'is_searchable' => $this->dto->isSearchable, 'is_filtrable' => $this->dto->isFiltrable, diff --git a/src/Domains/Inventory/Attributes/Actions/UpdateAttribute.php b/src/Domains/Inventory/Attributes/Actions/UpdateAttribute.php index 5514dd834..e1978b29d 100644 --- a/src/Domains/Inventory/Attributes/Actions/UpdateAttribute.php +++ b/src/Domains/Inventory/Attributes/Actions/UpdateAttribute.php @@ -35,6 +35,7 @@ public function execute(): Attributes 'is_visible' => $this->dto->isVisible, 'is_searchable' => $this->dto->isSearchable, 'is_filtrable' => $this->dto->isFiltrable, + 'slug' => $this->dto->slug, ]); return $this->attribute; diff --git a/src/Domains/Inventory/Attributes/DataTransferObject/Attributes.php b/src/Domains/Inventory/Attributes/DataTransferObject/Attributes.php index 3e101ca19..04f7bcd8d 100644 --- a/src/Domains/Inventory/Attributes/DataTransferObject/Attributes.php +++ b/src/Domains/Inventory/Attributes/DataTransferObject/Attributes.php @@ -6,6 +6,7 @@ use Baka\Contracts\AppInterface; use Baka\Contracts\CompanyInterface; +use Baka\Support\Str; use Baka\Users\Contracts\UserInterface; use Kanvas\Apps\Models\Apps; use Kanvas\Companies\Models\Companies; @@ -18,6 +19,7 @@ public function __construct( public AppInterface $app, public UserInterface $user, public string $name, + public string $slug, public bool $isVisible = false, public bool $isSearchable = false, public bool $isFiltrable = false, @@ -31,9 +33,10 @@ public static function viaRequest(array $request): self app(Apps::class), auth()->user(), $request['name'], + $request['slug'] ?? Str::slug($request['name']), $request['is_visible'] ?? false, $request['is_searchable'] ?? false, - $request['is_filtrable'] ?? false + $request['is_filtrable'] ?? false, ); } } diff --git a/src/Domains/Inventory/Products/Actions/CreateProductAction.php b/src/Domains/Inventory/Products/Actions/CreateProductAction.php index c0195b68b..71c22e99b 100644 --- a/src/Domains/Inventory/Products/Actions/CreateProductAction.php +++ b/src/Domains/Inventory/Products/Actions/CreateProductAction.php @@ -92,6 +92,10 @@ public function execute(): Products 'user' => $this->user, 'company' => $this->productDto->company, 'name' => $attribute['name'], + 'isVisible' => false, + 'isSearchable' => false, + 'isFiltrable' => false, + 'slug' => Str::slug($attribute['name']) ]); $attributeModel = (new CreateAttribute($attributesDto, $this->user))->execute(); diff --git a/src/Domains/Inventory/Variants/Models/Variants.php b/src/Domains/Inventory/Variants/Models/Variants.php index 190a7a95f..531060e7c 100644 --- a/src/Domains/Inventory/Variants/Models/Variants.php +++ b/src/Domains/Inventory/Variants/Models/Variants.php @@ -6,6 +6,7 @@ use Awobaz\Compoships\Compoships; use Baka\Enums\StateEnums; +use Baka\Support\Str; use Baka\Traits\SlugTrait; use Baka\Traits\UuidTrait; use Baka\Users\Contracts\UserInterface; @@ -220,6 +221,10 @@ public function addAttributes(UserInterface $user, array $attributes): void 'company' => $this->product->company, 'name' => $attribute['name'], 'value' => $attribute['value'], + 'isVisible' => false, + 'isSearchable' => false, + 'isFiltrable' => false, + 'slug' => Str::slug($attribute['name']) ]); $attributeModel = (new CreateAttribute($attributesDto, $user))->execute(); } diff --git a/src/Domains/Inventory/Warehouses/Services/WarehouseService.php b/src/Domains/Inventory/Warehouses/Services/WarehouseService.php index 593b741b1..b8e847aaf 100644 --- a/src/Domains/Inventory/Warehouses/Services/WarehouseService.php +++ b/src/Domains/Inventory/Warehouses/Services/WarehouseService.php @@ -24,14 +24,14 @@ class WarehouseService */ public static function updateWarehouseVariant(Variants $variant, UserInterface $user, array $warehouses): Variants { - $warehousesId = array_column($warehouses, 'warehouse_id'); + $warehousesId = array_column($warehouses, 'id'); $existedWarehouses = $variant->variantWarehouses->keyBy('warehouses_id'); $existedWarehouses = $existedWarehouses->keys()->all(); $toDelete = array_diff($existedWarehouses, $warehousesId); foreach ($warehouses as $warehouseData) { - $warehouseModel = WarehouseRepository::getById((int) $warehouseData['warehouse_id'], $variant->product->company); + $warehouseModel = WarehouseRepository::getById((int) $warehouseData['id'], $variant->product->company); if (isset($warehouseData['status'])) { $warehouseData['status_id'] = StatusRepository::getById( diff --git a/src/Kanvas/Auth/Actions/CreateUserAction.php b/src/Kanvas/Auth/Actions/CreateUserAction.php index dfed993e1..20f4b5a5b 100644 --- a/src/Kanvas/Auth/Actions/CreateUserAction.php +++ b/src/Kanvas/Auth/Actions/CreateUserAction.php @@ -37,9 +37,10 @@ class CreateUserAction * Construct function. */ public function __construct( - protected RegisterInput $data + protected RegisterInput $data, + ?Apps $app = null ) { - $this->app = app(Apps::class); + $this->app = $app ?? app(Apps::class); } /** diff --git a/src/Kanvas/Auth/Actions/SocialLoginAction.php b/src/Kanvas/Auth/Actions/SocialLoginAction.php index dddadf2ab..bf71e861a 100644 --- a/src/Kanvas/Auth/Actions/SocialLoginAction.php +++ b/src/Kanvas/Auth/Actions/SocialLoginAction.php @@ -4,6 +4,7 @@ namespace Kanvas\Auth\Actions; +use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Support\Str; use Kanvas\Apps\Models\Apps; use Kanvas\Auth\DataTransferObject\RegisterInput; @@ -11,17 +12,17 @@ use Kanvas\Users\Models\Sources; use Kanvas\Users\Models\UserLinkedSources; use Kanvas\Users\Models\Users; +use Kanvas\Users\Repositories\UsersRepository; class SocialLoginAction { - protected Apps $app; - /** * Construct function. */ public function __construct( protected SocialiteUser $socialUser, - protected string $provider + protected string $provider, + protected Apps $app ) { } @@ -37,9 +38,9 @@ public function execute(): Users $userLinkedSource = UserLinkedSources::where('source_users_id', $this->socialUser->id)->where('source_id', $source->id)->first(); if (! $userLinkedSource) { - $existedUser = Users::where('email', $this->socialUser->email)->first(); - - if (! $existedUser) { + try { + $existedUser = UsersRepository::getUserOfAppByEmail($this->socialUser->email, $this->app); + } catch (ModelNotFoundException $e) { $userData = [ 'firstname' => $this->socialUser->name, 'email' => $this->socialUser->email, @@ -48,10 +49,11 @@ public function execute(): Users ]; $userData = RegisterInput::fromArray($userData); - $registeredUser = new RegisterUsersAction($userData); + $registeredUser = new RegisterUsersAction($userData, $this->app); $existedUser = $registeredUser->execute(); } + //$userAppProfile = $existedUser->getAppProfile($this->app); //$userLinkedSource = UserLinkedSources::createSocial($this->socialUser, $existedUser, $source); UserLinkedSources::firstOrCreate([ 'users_id' => $existedUser->getId(), diff --git a/src/Kanvas/Auth/Socialite/Decoders/ASDecoder.php b/src/Kanvas/Auth/Socialite/Decoders/ASDecoder.php new file mode 100644 index 000000000..5829d5a77 --- /dev/null +++ b/src/Kanvas/Auth/Socialite/Decoders/ASDecoder.php @@ -0,0 +1,68 @@ +getKeyMaterial()); + + if (! isset($publicKeyDetails['key'])) { + throw new Exception('Invalid public key details.'); + } + + return [ + 'publicKey' => $publicKeyDetails['key'], + 'alg' => $parsedKeyData['alg'], + ]; + } +} diff --git a/src/Kanvas/Auth/Socialite/Decoders/JWT.php b/src/Kanvas/Auth/Socialite/Decoders/JWT.php new file mode 100644 index 000000000..da06cbbe4 --- /dev/null +++ b/src/Kanvas/Auth/Socialite/Decoders/JWT.php @@ -0,0 +1,366 @@ + + * @author Anant Narayanan + * @license http://opensource.org/licenses/BSD-3-Clause 3-clause BSD + * + * @link https://github.com/firebase/php-jwt + * + * @todo HATE THIS but using old version cause it works :( , need to move to the new version + */ +class JWT +{ + /** + * The server leeway time in seconds, to aware the acceptable different time between clocks + * of token issued server and relying parties. + * When checking nbf, iat or expiration times, we want to provide some extra leeway time to + * account for clock skew. + */ + public static $leeway = 0; + + /** + * Allow the current timestamp to be specified. + * Useful for fixing a value within unit testing. + * + * Will default to PHP time() value if null. + */ + public static $timestamp = null; + + public static $supported_algs = [ + 'HS256' => ['hash_hmac', 'SHA256'], + 'HS512' => ['hash_hmac', 'SHA512'], + 'HS384' => ['hash_hmac', 'SHA384'], + 'RS256' => ['openssl', 'SHA256'], + 'RS384' => ['openssl', 'SHA384'], + 'RS512' => ['openssl', 'SHA512'], + ]; + + /** + * Decodes a JWT string into a PHP object. + * + * @param string $jwt The JWT + * @param string|array $key The key, or map of keys. + * If the algorithm used is asymmetric, this is the public key + * @param array $allowed_algs List of supported verification algorithms + * Supported algorithms are 'HS256', 'HS384', 'HS512' and 'RS256' + * + * @return object The JWT's payload as a PHP object + * + * @throws UnexpectedValueException Provided JWT was invalid + * @throws SignatureInvalidException Provided JWT was invalid because the signature verification failed + * @throws BeforeValidException Provided JWT is trying to be used before it's eligible as defined by 'nbf' + * @throws BeforeValidException Provided JWT is trying to be used before it's been created as defined by 'iat' + * @throws ExpiredException Provided JWT has since expired, as defined by the 'exp' claim + * + * @uses jsonDecode + * @uses urlsafeB64Decode + */ + public static function decode($jwt, $key, array $allowed_algs = []) + { + $timestamp = is_null(static::$timestamp) ? time() : static::$timestamp; + + if (empty($key)) { + throw new InvalidArgumentException('Key may not be empty'); + } + $tks = explode('.', $jwt); + if (count($tks) != 3) { + throw new UnexpectedValueException('Wrong number of segments'); + } + list($headb64, $bodyb64, $cryptob64) = $tks; + if (null === ($header = static::jsonDecode(static::urlsafeB64Decode($headb64)))) { + throw new UnexpectedValueException('Invalid header encoding'); + } + if (null === $payload = static::jsonDecode(static::urlsafeB64Decode($bodyb64))) { + throw new UnexpectedValueException('Invalid claims encoding'); + } + if (false === ($sig = static::urlsafeB64Decode($cryptob64))) { + throw new UnexpectedValueException('Invalid signature encoding'); + } + if (empty($header->alg)) { + throw new UnexpectedValueException('Empty algorithm'); + } + if (empty(static::$supported_algs[$header->alg])) { + throw new UnexpectedValueException('Algorithm not supported'); + } + if (! in_array($header->alg, $allowed_algs)) { + throw new UnexpectedValueException('Algorithm not allowed'); + } + if (is_array($key) || $key instanceof \ArrayAccess) { + if (isset($header->kid)) { + if (! isset($key[$header->kid])) { + throw new UnexpectedValueException('"kid" invalid, unable to lookup correct key'); + } + $key = $key[$header->kid]; + } else { + throw new UnexpectedValueException('"kid" empty, unable to lookup correct key'); + } + } + + return $payload; + } + + /** + * Converts and signs a PHP object or array into a JWT string. + * + * @param object|array $payload PHP object or array + * @param string $key The secret key. + * If the algorithm used is asymmetric, this is the private key + * @param string $alg The signing algorithm. + * Supported algorithms are 'HS256', 'HS384', 'HS512' and 'RS256' + * @param mixed $keyId + * @param array $head An array with header elements to attach + * + * @return string A signed JWT + * + * @uses jsonEncode + * @uses urlsafeB64Encode + */ + public static function encode($payload, $key, $alg = 'HS256', $keyId = null, $head = null) + { + $header = ['typ' => 'JWT', 'alg' => $alg]; + if ($keyId !== null) { + $header['kid'] = $keyId; + } + if (isset($head) && is_array($head)) { + $header = array_merge($head, $header); + } + $segments = []; + $segments[] = static::urlsafeB64Encode(static::jsonEncode($header)); + $segments[] = static::urlsafeB64Encode(static::jsonEncode($payload)); + $signing_input = implode('.', $segments); + + $signature = static::sign($signing_input, $key, $alg); + $segments[] = static::urlsafeB64Encode($signature); + + return implode('.', $segments); + } + + /** + * Sign a string with a given key and algorithm. + * + * @param string $msg The message to sign + * @param string|resource $key The secret key + * @param string $alg The signing algorithm. + * Supported algorithms are 'HS256', 'HS384', 'HS512' and 'RS256' + * + * @return string An encrypted message + * + * @throws DomainException Unsupported algorithm was specified + */ + public static function sign($msg, $key, $alg = 'HS256') + { + if (empty(static::$supported_algs[$alg])) { + throw new DomainException('Algorithm not supported'); + } + list($function, $algorithm) = static::$supported_algs[$alg]; + switch ($function) { + case 'hash_hmac': + return hash_hmac($algorithm, $msg, $key, true); + case 'openssl': + $signature = ''; + $success = openssl_sign($msg, $signature, $key, $algorithm); + if (! $success) { + throw new DomainException('OpenSSL unable to sign data'); + } else { + return $signature; + } + } + + throw new DomainException('Algorithm not supported'); + } + + /** + * Verify a signature with the message, key and method. Not all methods + * are symmetric, so we must have a separate verify and sign method. + * + * @param string $msg The original message (header and body) + * @param string $signature The original signature + * @param string|resource $key For HS*, a string key works. for RS*, must be a resource of an openssl public key + * @param string $alg The algorithm + * + * @return bool + * + * @throws DomainException Invalid Algorithm or OpenSSL failure + */ + private static function verify($msg, $signature, $key, $alg) + { + if (empty(static::$supported_algs[$alg])) { + throw new DomainException('Algorithm not supported'); + } + + list($function, $algorithm) = static::$supported_algs[$alg]; + switch ($function) { + case 'openssl': + $success = openssl_verify($msg, $signature, $key, $algorithm); + if ($success === 1) { + return true; + } elseif ($success === 0) { + return false; + } + + // returns 1 on success, 0 on failure, -1 on error. + throw new DomainException( + 'OpenSSL error: ' . openssl_error_string() + ); + case 'hash_hmac': + default: + $hash = hash_hmac($algorithm, $msg, $key, true); + if (function_exists('hash_equals')) { + return hash_equals($signature, $hash); + } + $len = min(static::safeStrlen($signature), static::safeStrlen($hash)); + + $status = 0; + for ($i = 0; $i < $len; $i++) { + $status |= (ord($signature[$i]) ^ ord($hash[$i])); + } + $status |= (static::safeStrlen($signature) ^ static::safeStrlen($hash)); + + return ($status === 0); + } + } + + /** + * Decode a JSON string into a PHP object. + * + * @param string $input JSON string + * + * @return object Object representation of JSON string + * + * @throws DomainException Provided string was invalid JSON + */ + public static function jsonDecode($input) + { + if (version_compare(PHP_VERSION, '5.4.0', '>=') && ! (defined('JSON_C_VERSION') && PHP_INT_SIZE > 4)) { + /** In PHP >=5.4.0, json_decode() accepts an options parameter, that allows you + * to specify that large ints (like Steam Transaction IDs) should be treated as + * strings, rather than the PHP default behaviour of converting them to floats. + */ + $obj = json_decode($input, false, 512, JSON_BIGINT_AS_STRING); + } else { + /** Not all servers will support that, however, so for older versions we must + * manually detect large ints in the JSON string and quote them (thus converting + *them to strings) before decoding, hence the preg_replace() call. + */ + $max_int_length = strlen((string) PHP_INT_MAX) - 1; + $json_without_bigints = preg_replace('/:\s*(-?\d{' . $max_int_length . ',})/', ': "$1"', $input); + $obj = json_decode($json_without_bigints); + } + + if (function_exists('json_last_error') && $errno = json_last_error()) { + static::handleJsonError($errno); + } elseif ($obj === null && $input !== 'null') { + throw new DomainException('Null result with non-null input'); + } + + return $obj; + } + + /** + * Encode a PHP object into a JSON string. + * + * @param object|array $input A PHP object or array + * + * @return string JSON representation of the PHP object or array + * + * @throws DomainException Provided object could not be encoded to valid JSON + */ + public static function jsonEncode($input) + { + $json = json_encode($input); + if (function_exists('json_last_error') && $errno = json_last_error()) { + static::handleJsonError($errno); + } elseif ($json === 'null' && $input !== null) { + throw new DomainException('Null result with non-null input'); + } + + return $json; + } + + /** + * Decode a string with URL-safe Base64. + * + * @param string $input A Base64 encoded string + * + * @return string A decoded string + */ + public static function urlsafeB64Decode($input) + { + $remainder = strlen($input) % 4; + if ($remainder) { + $padlen = 4 - $remainder; + $input .= str_repeat('=', $padlen); + } + + return base64_decode(strtr($input, '-_', '+/')); + } + + /** + * Encode a string with URL-safe Base64. + * + * @param string $input The string you want encoded + * + * @return string The base64 encode of what you passed in + */ + public static function urlsafeB64Encode($input) + { + return str_replace('=', '', strtr(base64_encode($input), '+/', '-_')); + } + + /** + * Helper method to create a JSON error. + * + * @param int $errno An error number from json_last_error() + * + * @return void + */ + private static function handleJsonError($errno) + { + $messages = [ + JSON_ERROR_DEPTH => 'Maximum stack depth exceeded', + JSON_ERROR_STATE_MISMATCH => 'Invalid or malformed JSON', + JSON_ERROR_CTRL_CHAR => 'Unexpected control character found', + JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON', + JSON_ERROR_UTF8 => 'Malformed UTF-8 characters', //PHP >= 5.3.3 + ]; + + throw new DomainException( + isset($messages[$errno]) + ? $messages[$errno] + : 'Unknown JSON error: ' . $errno + ); + } + + /** + * Get the number of bytes in cryptographic strings. + * + * @param string + * + * @return int + */ + private static function safeStrlen($str) + { + if (function_exists('mb_strlen')) { + return mb_strlen($str, '8bit'); + } + + return strlen($str); + } +} diff --git a/src/Kanvas/Auth/Socialite/Drivers/AppleDriver.php b/src/Kanvas/Auth/Socialite/Drivers/AppleDriver.php new file mode 100644 index 000000000..6f9815e1f --- /dev/null +++ b/src/Kanvas/Auth/Socialite/Drivers/AppleDriver.php @@ -0,0 +1,39 @@ + $data['sub'], + 'email' => $data['email'], + 'nickname' => $displayname, + 'name' => $displayname, + 'token' => $token, + ]); + } +} diff --git a/src/Kanvas/Auth/Socialite/Drivers/FacebookDriver.php b/src/Kanvas/Auth/Socialite/Drivers/FacebookDriver.php new file mode 100644 index 000000000..6cb0b5c82 --- /dev/null +++ b/src/Kanvas/Auth/Socialite/Drivers/FacebookDriver.php @@ -0,0 +1,72 @@ +client = new Client(); + $this->clientId = $config['client_id'] ?? throw new AuthenticationException('Facebook Client Id configuration is required'); + } + + public function getUserFromToken(string $token): User + { + $kid = json_decode(base64_decode(explode('.', $token)[0]), true)['kid'] ?? null; + + if ($kid === null) { + return null; + } + + $data = (array) JWT::decode($token, $this->getPublicKeyOfOIDCToken($kid)); + + throw_if($data['aud'] !== $this->clientId, new Exception('Token has incorrect audience.')); + throw_if($data['iss'] !== 'https://www.facebook.com', new Exception('Token has incorrect issuer.')); + + return User::from([ + 'id' => $data['sub'], + 'email' => $data['email'], + 'nickname' => Random::generateDisplayName($data['given_name']), + 'name' => $data['name'], + 'token' => $token, + ]); + } + + /** + * from socialite, https://github.com/laravel/socialite/blob/beb3adcff1a6e400955c459d5ad329c0576da3ed/src/Two/FacebookProvider.php#L158 + * cant extend the class because of our current implementation + */ + protected function getPublicKeyOfOIDCToken(string $kid) + { + $response = $this->client->get('https://limited.facebook.com/.well-known/oauth/openid/jwks/'); + + $key = Arr::first(json_decode($response->getBody()->getContents(), true)['keys'], function ($key) use ($kid) { + return $key['kid'] === $kid; + }); + + $key['n'] = new BigInteger(JWT::urlsafeB64Decode($key['n']), 256); + $key['e'] = new BigInteger(JWT::urlsafeB64Decode($key['e']), 256); + + return new Key((string) RSA::load($key), 'RS256'); + } +} diff --git a/src/Kanvas/Auth/Socialite/Drivers/GoogleDriver.php b/src/Kanvas/Auth/Socialite/Drivers/GoogleDriver.php index 6fd148d4e..fd531ec3d 100644 --- a/src/Kanvas/Auth/Socialite/Drivers/GoogleDriver.php +++ b/src/Kanvas/Auth/Socialite/Drivers/GoogleDriver.php @@ -4,6 +4,7 @@ namespace Kanvas\Auth\Socialite\Drivers; +use Baka\Support\Random; use Google_Client; use Kanvas\Auth\Exceptions\AuthenticationException; use Kanvas\Auth\Socialite\Contracts\DriverInterface; @@ -25,7 +26,7 @@ public function getUserFromToken(string $token): User { $payload = $this->client->verifyIdToken($token); if (! $payload) { - throw new AuthenticationException('Invalid token'); + throw new AuthenticationException('Invalid token for google login user'); } $this->client->setAccessToken( $token @@ -34,7 +35,7 @@ public function getUserFromToken(string $token): User return User::from([ 'id' => $payload['sub'], 'email' => $payload['email'], - 'nickname' => $payload['name'], + 'nickname' => Random::generateDisplayName($payload['name']), 'name' => $payload['name'], 'token' => $token, ]); diff --git a/src/Kanvas/Auth/Socialite/SocialManager.php b/src/Kanvas/Auth/Socialite/SocialManager.php index 4e32d3a8f..1d18e3215 100644 --- a/src/Kanvas/Auth/Socialite/SocialManager.php +++ b/src/Kanvas/Auth/Socialite/SocialManager.php @@ -7,20 +7,23 @@ use Exception; use Kanvas\Apps\Models\Apps; use Kanvas\Auth\Socialite\Contracts\DriverInterface; +use Kanvas\Auth\Socialite\Drivers\AppleDriver; +use Kanvas\Auth\Socialite\Drivers\FacebookDriver; use Kanvas\Auth\Socialite\Drivers\GoogleDriver; +use Kanvas\Enums\AppSettingsEnums; +use Kanvas\Enums\SourceEnum; class SocialManager { public static function getDriver(string $driver, ?Apps $app = null): DriverInterface { $app = $app ?? app(Apps::class); - switch ($driver) { - case 'google': - $config = $app->get('google_social_config'); - return new GoogleDriver($config); - default: - throw new Exception('Driver not found'); - } + return match ($driver) { + SourceEnum::GOOGLE->value => new GoogleDriver((array) $app->get(AppSettingsEnums::SOCIALITE_PROVIDER_GOOGLE->getValue())), + SourceEnum::FACEBOOK->value => new FacebookDriver((array) $app->get(AppSettingsEnums::SOCIALITE_PROVIDER_FACEBOOK->getValue())), + SourceEnum::APPLE->value => new AppleDriver((array) $app->get(AppSettingsEnums::SOCIALITE_PROVIDER_APPLE->getValue())), + default => throw new Exception('Driver not found'), + }; } } diff --git a/src/Kanvas/Enums/AppEnums.php b/src/Kanvas/Enums/AppEnums.php index a2ade3150..9d9bae31a 100644 --- a/src/Kanvas/Enums/AppEnums.php +++ b/src/Kanvas/Enums/AppEnums.php @@ -49,6 +49,7 @@ enum AppEnums implements EnumsInterface case KANVAS_APP_REGION_HEADER; case DISPLAYNAME_LOGIN; case ANONYMOUS_USER_ID; + case DEFAULT_APP_JWT_TOKEN_NAME; /** * Get value. @@ -95,8 +96,9 @@ public function getValue(): mixed self::KANVAS_APP_REGION_HEADER => 'X-Kanvas-Region', self::KANVAS_APP_COMPANY_AUTH_HEADER => 'Company-Authorization', //@deprecated self::DISPLAYNAME_LOGIN => 'displayname_login', - self::VERSION => '1.0-BETA-34', - self::ANONYMOUS_USER_ID => -1 + self::VERSION => '1.0-BETA-35', + self::ANONYMOUS_USER_ID => -1, + self::DEFAULT_APP_JWT_TOKEN_NAME => 'kanvas-login', }; } diff --git a/src/Kanvas/Enums/AppSettingsEnums.php b/src/Kanvas/Enums/AppSettingsEnums.php index ca7d02deb..800c30e09 100644 --- a/src/Kanvas/Enums/AppSettingsEnums.php +++ b/src/Kanvas/Enums/AppSettingsEnums.php @@ -22,6 +22,10 @@ enum AppSettingsEnums implements EnumsInterface case PASSWORD_STRENGTH; case DEFAULT_SIGNUP_ROLE; case INVITE_EMAIL_SUBJECT; + case RESET_LINK_URL; + case SOCIALITE_PROVIDER_FACEBOOK; + case SOCIALITE_PROVIDER_GOOGLE; + case SOCIALITE_PROVIDER_APPLE; /** * Get value. @@ -43,6 +47,10 @@ public function getValue(): mixed self::PASSWORD_STRENGTH => 'flag_password_strength', self::DEFAULT_SIGNUP_ROLE => 'default_signup_role', self::INVITE_EMAIL_SUBJECT => 'invite_email_subject', + self::RESET_LINK_URL => 'app_reset_link_url', + self::SOCIALITE_PROVIDER_FACEBOOK => 'facebook_social_config', + self::SOCIALITE_PROVIDER_GOOGLE => 'google_social_config', + self::SOCIALITE_PROVIDER_APPLE => 'apple_social_config', }; } } diff --git a/src/Kanvas/Enums/SourceEnum.php b/src/Kanvas/Enums/SourceEnum.php index 14944360f..75b9e8b22 100644 --- a/src/Kanvas/Enums/SourceEnum.php +++ b/src/Kanvas/Enums/SourceEnum.php @@ -10,4 +10,8 @@ enum SourceEnum: string case ANDROID = 'androidapp'; case WEBAPP = 'webapp'; case BAKA = 'baka'; + case FACEBOOK = 'facebook'; + case GOOGLE = 'google'; + case APPLE = 'apple'; + case TWITTER = 'twitter'; } diff --git a/src/Kanvas/Notifications/Templates/ResetPassword.php b/src/Kanvas/Notifications/Templates/ResetPassword.php index e2e356540..7a97f7309 100644 --- a/src/Kanvas/Notifications/Templates/ResetPassword.php +++ b/src/Kanvas/Notifications/Templates/ResetPassword.php @@ -2,6 +2,7 @@ namespace Kanvas\Notifications\Templates; +use Kanvas\Enums\AppSettingsEnums; use Kanvas\Notifications\Notification; /** @@ -14,7 +15,7 @@ class ResetPassword extends Notification public function getData(): array { //replace url for app link - $resetUrl = $this->app->url . '/reset-password'; + $resetUrl = $this->app->get(AppSettingsEnums::RESET_LINK_URL->getValue()) ?? $this->app->url . '/reset-password'; return [ ...parent::getData(), diff --git a/src/Kanvas/Users/Repositories/UsersRepository.php b/src/Kanvas/Users/Repositories/UsersRepository.php index 6ab7bc237..d446cb586 100644 --- a/src/Kanvas/Users/Repositories/UsersRepository.php +++ b/src/Kanvas/Users/Repositories/UsersRepository.php @@ -9,7 +9,6 @@ use Baka\Users\Contracts\UserInterface; use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\ModelNotFoundException; -use Illuminate\Support\Facades\DB; use Kanvas\Apps\Models\Apps; use Kanvas\Companies\Models\Companies; use Kanvas\Companies\Models\CompaniesBranches; @@ -61,6 +60,16 @@ public static function getByEmail(string $email): Users ->firstOrFail(); } + public static function getUserOfAppByEmail(string $email, AppInterface $app = null): Users + { + return Users::select('users.*') + ->join('users_associated_apps', 'users_associated_apps.users_id', 'users.id') + ->where('users_associated_apps.apps_id', $app->getId()) + ->where('users.email', $email) + ->where('users_associated_apps.is_deleted', StateEnums::NO->getValue()) + ->firstOrFail(); + } + /** * Get the user if he exist in the current company. * @psalm-suppress MixedReturnStatement diff --git a/tests/Ecosystem/Integration/Auth/AppleLoginTest.php b/tests/Ecosystem/Integration/Auth/AppleLoginTest.php new file mode 100644 index 000000000..a7a570b8d --- /dev/null +++ b/tests/Ecosystem/Integration/Auth/AppleLoginTest.php @@ -0,0 +1,42 @@ +set(AppSettingsEnums::SOCIALITE_PROVIDER_APPLE->getValue(), []); + + $socialManager = SocialManager::getDriver(SourceEnum::APPLE->value, $app); + + $user = $socialManager->getUserFromToken($token); + + $socialLogin = new SocialLoginAction($user, SourceEnum::APPLE->value, $app); + $loggedUser = $socialLogin->execute(); + $tokenResponse = $loggedUser->createToken(name: 'test-loging-apple')->toArray(); + + $this->assertIsObject($user); + $this->assertInstanceOf(User::class, $user); + $this->assertNotEmpty($user->id); + $this->assertNotEmpty($user->name); + $this->assertNotEmpty($user->email); + $this->assertIsArray($tokenResponse); + $this->assertArrayHasKey('token', $tokenResponse); + $this->assertArrayHasKey('refresh_token', $tokenResponse); + $this->assertArrayHasKey('id', $tokenResponse); + } +} diff --git a/tests/Ecosystem/Integration/Auth/FacebookLoginTest.php b/tests/Ecosystem/Integration/Auth/FacebookLoginTest.php new file mode 100644 index 000000000..c41c0fe65 --- /dev/null +++ b/tests/Ecosystem/Integration/Auth/FacebookLoginTest.php @@ -0,0 +1,29 @@ +set(AppSettingsEnums::SOCIALITE_PROVIDER_FACEBOOK->getValue(), ['client_id' => '1234567890']); + + $socialManager = SocialManager::getDriver(SourceEnum::FACEBOOK->value, $app); + + //$socialManager->getUserFromToken($token); + } +} diff --git a/tests/GraphQL/Guild/PeopleTest.php b/tests/GraphQL/Guild/PeopleTest.php index 5ad4d7f18..25dfc6c11 100644 --- a/tests/GraphQL/Guild/PeopleTest.php +++ b/tests/GraphQL/Guild/PeopleTest.php @@ -314,4 +314,98 @@ public function testRestoreLead() ], ]); } + + public function testImportUsers() + { + $user = auth()->user(); + $branch = $user->getCurrentBranch(); + $firstname = fake()->firstName(); + $middlename = fake()->firstName(); + $lastname = fake()->lastName(); + $name = $firstname . ' ' . $middlename . ' ' . $lastname; + + $peoplesToImport = [ + [ + 'firstname' => $firstname, + 'middlename' => $middlename, // @todo remove this + 'lastname' => $lastname, + 'contacts' => [ + [ + 'value' => fake()->email(), + 'contacts_types_id' => 1, + 'weight' => 0, + ], + [ + 'value' => fake()->phoneNumber(), + 'contacts_types_id' => 2, + 'weight' => 0, + ], + ], + 'address' => [ + [ + 'address' => fake()->address(), + 'city' => fake()->city(), + 'county' => fake()->city(), + 'state' => fake()->state(), + 'country' => fake()->country(), + 'zip' => fake()->postcode(), + ], + ], + 'custom_fields' => [ + [ + 'name' => 'paid_subscription', + 'data' => 1, + ], + [ + 'name' => 'position', + 'data' => 'developer', + ], + ], + ],[ + 'firstname' => fake()->firstName(), + 'middlename' => fake()->firstName(), // @todo remove this + 'lastname' => fake()->lastName(), + 'contacts' => [ + [ + 'value' => fake()->email(), + 'contacts_types_id' => 1, + 'weight' => 0, + ], + [ + 'value' => fake()->phoneNumber(), + 'contacts_types_id' => 2, + 'weight' => 0, + ], + ], + 'address' => [ + [ + 'address' => fake()->address(), + 'city' => fake()->city(), + 'county' => fake()->city(), + 'state' => fake()->state(), + 'country' => fake()->country(), + 'zip' => fake()->postcode(), + ], + ], + 'custom_fields' => [ + [ + 'name' => 'paid_subscription', + 'data' => 0, + ], + [ + 'name' => 'position', + 'data' => 'accountant', + ], + ], + ] + ]; + + $this->graphQL(' + mutation($input: [PeopleInput!]!) { + importPeoples(input: $input) + } + ', [ + 'input' => $peoplesToImport, + ])->assertSee('importPeoples'); + } } diff --git a/tests/GraphQL/Inventory/RemoveVariantsToWarehouseTest.php b/tests/GraphQL/Inventory/RemoveVariantsToWarehouseTest.php index 041e7fa94..28152d3d4 100644 --- a/tests/GraphQL/Inventory/RemoveVariantsToWarehouseTest.php +++ b/tests/GraphQL/Inventory/RemoveVariantsToWarehouseTest.php @@ -103,15 +103,40 @@ public function testRemoveVariantToWarehouse(): void }', ['data' => $data]); $variantId = $response->json()['data']['createVariant']['id']; + $warehouseDataUpdate = [ + 'regions_id' => $idRegion, + 'name' => fake()->name, + 'location' => 'Test Location', + 'is_default' => true, + 'is_published' => true, + ]; + $response = $this->graphQL(' + mutation($data: WarehouseInput!) { + createWarehouse(input: $data) + { + id + regions_id + name + location + is_default + is_published + } + }', ['data' => $warehouseDataUpdate])->assertJson([ + 'data' => ['createWarehouse' => $warehouseDataUpdate] + ]); + $warehouseData = [ + 'id' => $response->json()['data']['createWarehouse']['id'], + ]; $data = [ + 'id' => $warehouseData['id'], 'price' => rand(1, 1000), 'quantity' => rand(1, 5), 'position' => rand(1, 4), ]; $warehouseResponse = $this->graphQL(' - mutation($data: VariantsWarehousesInput! $id: ID! $warehouse_id: ID!) { - addVariantToWarehouse(input: $data id: $id warehouse_id: $warehouse_id) + mutation($data: WarehouseReferenceInput! $id: ID! $warehouse_id: ID!) { + addVariantToWarehouse(input: $data id: $id) { id name @@ -126,7 +151,6 @@ public function testRemoveVariantToWarehouse(): void }', [ 'data' => $data, 'id' => $variantId, - 'warehouse_id' => $warehouseData['id'] ]); $this->graphQL(' mutation($id: ID! $warehouse_id: ID!) { diff --git a/tests/GraphQL/Inventory/VariantTest.php b/tests/GraphQL/Inventory/VariantTest.php index 0aaca6ce5..c774978e3 100644 --- a/tests/GraphQL/Inventory/VariantTest.php +++ b/tests/GraphQL/Inventory/VariantTest.php @@ -266,13 +266,13 @@ public function testAddVariantToWarehouse(): void 'id' => $response->json()['data']['createWarehouse']['id'], ]; $data = [ - 'warehouse_id' => $warehouseData['id'], + 'id' => $warehouseData['id'], 'price' => rand(1, 1000), 'quantity' => rand(1, 5), 'position' => rand(1, 4), ]; $warehouseResponse = $this->graphQL(' - mutation($data: VariantsWarehousesInput! $id: ID!) { + mutation($data: WarehouseReferenceInput! $id: ID!) { addVariantToWarehouse(input: $data id: $id) { id @@ -395,13 +395,13 @@ public function testUpdateVariantToWarehouse(): void $variantId = $response->json()['data']['createVariant']['id']; $data = [ - 'warehouse_id' => $warehouseData['id'], + 'id' => $warehouseData['id'], 'price' => rand(1, 1000), 'quantity' => rand(1, 5), 'position' => rand(1, 4), ]; $warehouseResponse = $this->graphQL(' - mutation($data: VariantsWarehousesInput! $id: ID!) { + mutation($data: WarehouseReferenceInput! $id: ID!) { updateVariantInWarehouse(input: $data id: $id) { id