Conversation
✅ Deploy Preview for pay-yansongda canceled.
|
- Add Paypal provider class implementing ProviderInterface with web/query/refund/callback/success methods - Add PaypalServiceProvider for dependency injection registration - Add OAuth2 token management (GetAccessTokenPlugin, ObtainAccessTokenPlugin) with caching - Add AddRadarPlugin supporting Basic auth (token fetch) and Bearer auth (API calls) - Add ResponsePlugin validating HTTP 2xx status codes - Add Pay, Capture, Query, QueryRefund, Refund, Callback plugins for PayPal V2 API - Add WebShortcut, QueryShortcut, RefundShortcut for common payment flows - Add PARAMS_PAYPAL_URL_MISSING (9223) and CONFIG_PAYPAL_INVALID (9406) exception constants - Add get_paypal_url() and get_paypal_access_token() helper functions - Register PaypalServiceProvider in Pay class - Add PayPal sandbox test configuration in TestCase - Add tests for all plugins and shortcuts Production URL: https://api-m.paypal.com/ Sandbox URL: https://api-m.sandbox.paypal.com/ Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: yansongda <11869114+yansongda@users.noreply.github.com>
|
1、请在 web 文件夹下帮忙同步增加相关文档 |
Co-authored-by: yansongda <11869114+yansongda@users.noreply.github.com>
Deploying pay with
|
| Latest commit: |
a7f697d
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://a2b4d49e.pay-1bj.pages.dev |
| Branch Preview URL: | https://copilot-support-paypal-integ.pay-1bj.pages.dev |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #1127 +/- ##
============================================
- Coverage 97.59% 97.58% -0.02%
- Complexity 1085 1133 +48
============================================
Files 386 402 +16
Lines 7036 7374 +338
============================================
+ Hits 6867 7196 +329
- Misses 169 178 +9 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
1、由于 papal 的API是 v2 版本请将命名空间改为 Yansongda\Pay\Plugin\Paypal\V2\Pay 2、当前 PayPal 的 access_token 不能从外部传入,请兼容从外部传入 access_token 的方式 3、请在文档中标注 PayPal 的实现由 GitHub copilot 生成 4、当前 ci 中单元测试服概率能否继续提升 5、请帮忙再次确认一下是否有逻辑上的错误 |
…ess_token, add Copilot attribution to docs, improve test coverage Co-authored-by: yansongda <11869114+yansongda@users.noreply.github.com> Agent-Logs-Url: https://github.com/yansongda/pay/sessions/9a63746b-7c08-4fb0-979d-3bec1a76fe32
All 5 items addressed in commit
Documentation and CHANGELOG were added in commit Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
1、请增加 src/Functions.php 的单元测试 2、github action 中,关于 coding style 的 ci 未通过,请帮忙修复 |
…tion tests Co-authored-by: yansongda <11869114+yansongda@users.noreply.github.com> Agent-Logs-Url: https://github.com/yansongda/pay/sessions/dad4a76a-d5cf-4c3a-b352-1b0852f12a91
Both items addressed in commit
Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
There was a problem hiding this comment.
Pull request overview
Adds PayPal support to yansongda/pay v3, including web create-order + capture flows, query/refund, callback handling, and accompanying docs/tests.
Changes:
- Introduces a new
Paypalprovider wired intoPayviaPaypalServiceProvider. - Adds PayPal V2 plugin pipeline (token acquisition, request building, response validation) plus
web/query/refundshortcuts. - Adds PayPal documentation + VitePress sidebar entries, and expands unit test coverage for PayPal paths and helper functions.
Reviewed changes
Copilot reviewed 45 out of 45 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| web/docs/v3/quick-start/paypal.md | New PayPal quick-start guide and examples |
| web/docs/v3/quick-start/init.md | Adds PayPal config block to initialization docs |
| web/docs/v3/paypal/response.md | Documents PayPal success() response usage |
| web/docs/v3/paypal/refund.md | Documents refund flow and parameters |
| web/docs/v3/paypal/query.md | Documents order/refund query flows |
| web/docs/v3/paypal/pay.md | Documents create-order + capture web flow |
| web/docs/v3/paypal/close.md | Documents unsupported close behavior |
| web/docs/v3/paypal/cancel.md | Documents unsupported cancel behavior |
| web/docs/v3/paypal/callback.md | Documents callback entrypoint and parameter options |
| web/docs/v3/paypal/all.md | Documents using built-in plugins for custom PayPal API calls |
| web/.vitepress/sidebar/v3.js | Adds PayPal entries to the VitePress sidebar |
| tests/TestCase.php | Adds PayPal test configuration defaults |
| tests/Shortcut/Paypal/WebShortcutTest.php | Tests PayPal web shortcut plugin selection |
| tests/Shortcut/Paypal/RefundShortcutTest.php | Tests PayPal refund shortcut plugin selection |
| tests/Shortcut/Paypal/QueryShortcutTest.php | Tests PayPal query shortcut plugin selection |
| tests/Plugin/Paypal/V2/ResponsePluginTest.php | Tests PayPal response status-code validation |
| tests/Plugin/Paypal/V2/Pay/RefundPluginTest.php | Tests refund plugin payload building + required params |
| tests/Plugin/Paypal/V2/Pay/QueryRefundPluginTest.php | Tests refund-query plugin payload building + required params |
| tests/Plugin/Paypal/V2/Pay/QueryPluginTest.php | Tests order-query plugin payload building + required params |
| tests/Plugin/Paypal/V2/Pay/PayPluginTest.php | Tests create-order payload defaults and config integration |
| tests/Plugin/Paypal/V2/Pay/CapturePluginTest.php | Tests capture plugin URL building + required params |
| tests/Plugin/Paypal/V2/Pay/CallbackPluginTest.php | Tests callback plugin behavior for empty/normal payloads |
| tests/Plugin/Paypal/V2/ObtainAccessTokenPluginTest.php | Tests external _access_token passthrough behavior |
| tests/Plugin/Paypal/V2/GetAccessTokenPluginTest.php | Tests token request payload setup |
| tests/Plugin/Paypal/V2/AddRadarPluginTest.php | Tests request headers/body for bearer/basic auth modes |
| tests/FunctionTest.php | Adds tests for get_paypal_url and get_paypal_access_token |
| src/Shortcut/Paypal/WebShortcut.php | Implements web() shortcut (pay/capture actions) |
| src/Shortcut/Paypal/RefundShortcut.php | Implements refund() shortcut |
| src/Shortcut/Paypal/QueryShortcut.php | Implements query() shortcut (order/refund actions) |
| src/Service/PaypalServiceProvider.php | Registers PayPal provider in the container/Pay facade |
| src/Provider/Paypal.php | Adds PayPal provider methods: pay/query/refund/callback/success |
| src/Plugin/Paypal/V2/ResponsePlugin.php | Adds PayPal response status-code validation plugin |
| src/Plugin/Paypal/V2/Pay/RefundPlugin.php | Builds refund request payload for capture refunds |
| src/Plugin/Paypal/V2/Pay/QueryRefundPlugin.php | Builds refund query request payload |
| src/Plugin/Paypal/V2/Pay/QueryPlugin.php | Builds order query request payload |
| src/Plugin/Paypal/V2/Pay/PayPlugin.php | Builds create-order request payload |
| src/Plugin/Paypal/V2/Pay/CapturePlugin.php | Builds capture request payload |
| src/Plugin/Paypal/V2/Pay/CallbackPlugin.php | Handles callback payload shaping (no HTTP request) |
| src/Plugin/Paypal/V2/ObtainAccessTokenPlugin.php | Retrieves or injects access token into payload |
| src/Plugin/Paypal/V2/GetAccessTokenPlugin.php | Prepares OAuth token request payload (basic auth) |
| src/Plugin/Paypal/V2/AddRadarPlugin.php | Builds PSR-7 request for PayPal endpoints |
| src/Pay.php | Exposes Pay::paypal() and registers the service provider |
| src/Functions.php | Adds get_paypal_url() and get_paypal_access_token() helpers |
| src/Exception/Exception.php | Adds PayPal-specific config/url missing error codes |
| CHANGELOG.md | Adds v3.7.20 entry noting PayPal support |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| $params = $rocket->getParams(); | ||
|
|
||
| if (empty($params)) { | ||
| throw new InvalidResponseException(Exception::PARAMS_CALLBACK_REQUEST_INVALID, 'PayPal 回调参数为空'); | ||
| } | ||
|
|
||
| $rocket->setPayload(Collection::wrap($params)) | ||
| ->setDirection(NoHttpRequestDirection::class) | ||
| ->setDestination($rocket->getPayload()); |
There was a problem hiding this comment.
PayPal webhook/callback handling currently trusts the incoming payload without any authenticity verification (no verification of transmission headers / webhook signature). This makes callback() insecure in real deployments, since anyone can POST forged events. Consider passing the full ServerRequestInterface (including headers) into the plugin (similar to Wechat’s _request pattern) and implementing PayPal’s webhook signature verification flow (e.g. verify-webhook-signature API) before accepting the payload.
| ## 异常 | ||
|
|
||
| Yansongda\Pay\Exceptions\InvalidParamsException |
There was a problem hiding this comment.
Docs list the thrown exception as Yansongda\Pay\Exceptions\InvalidParamsException, but the code throws Yansongda\Artful\Exception\InvalidParamsException (and there is no Yansongda\Pay\Exceptions namespace in this repo). Please update the exception class reference so users can catch the correct type.
| ## 异常 | ||
|
|
||
| Yansongda\Pay\Exceptions\InvalidParamsException |
There was a problem hiding this comment.
Docs list the thrown exception as Yansongda\Pay\Exceptions\InvalidParamsException, but the provider throws Yansongda\Artful\Exception\InvalidParamsException (and there is no Yansongda\Pay\Exceptions namespace in this repo). Please update the exception class reference so users can catch the correct type.
| $result = Pay::paypal()->web($order); | ||
|
|
||
| // 获取用户授权跳转地址并重定向 | ||
| $approveUrl = collect($result->get('links'))->firstWhere('rel', 'approve')['href']; | ||
| ``` |
There was a problem hiding this comment.
The docs use the collect() helper to extract the approve link. collect() is not provided by this library itself, so this example may not work in non-Laravel environments. Consider rewriting the snippet using Yansongda\Supports\Collection::wrap(...) or plain PHP array access so it works for all users.
| $result = Pay::paypal()->web($order); | ||
|
|
||
| // 从 links 中获取用户授权跳转地址 | ||
| $approveUrl = collect($result->get('links'))->firstWhere('rel', 'approve')['href']; | ||
|
|
There was a problem hiding this comment.
The docs use the collect() helper to extract the approve link, but collect() is not part of this project’s public API. To keep docs framework-agnostic, consider using Yansongda\Supports\Collection::wrap(...) or plain PHP array access instead.
|
1、请结合上述 Pull request overview 重新 reivew 代码,逐个分析给出的建议,如果建议合理请采纳,如果建议不合理请给出理由 2、参考 https://docs.github.com/en/copilot/how-tos/configure-custom-instructions/add-repository-instructions 这份文档,生成一份 copilot-instructions.md |
- Add @todo for webhook signature verification in CallbackPlugin - Replace collect() with plain PHP loops in docs (framework-agnostic) - Create .github/copilot-instructions.md for Copilot custom instructions Co-authored-by: yansongda <11869114+yansongda@users.noreply.github.com> Agent-Logs-Url: https://github.com/yansongda/pay/sessions/f88bda98-4e48-4f04-905b-eeb9d4967119
Both items addressed in commit Review comment analysis:
copilot-instructions.md 已创建在 Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
1、请使用中文描述 .github/copilot-instructions.md 2、第一点中您指出 「完整实现需要调用 PayPal verify-webhook-signature API,复杂度较高。当前添加了 |
…ilot-instructions.md in Chinese - Implement verify_paypal_webhook_sign() using PayPal's verify-webhook-signature API - Refactor Provider callback() to pass ServerRequestInterface (like Wechat pattern) - Refactor CallbackPlugin to verify webhook signature before accepting payload - Add VerifyWebhookSignPlugin for building verification API request - Add webhook_id to PayPal config (required for signature verification) - Add comprehensive tests for webhook verification (localhost skip, missing config, empty sig, success, failure) - Rewrite .github/copilot-instructions.md entirely in Chinese - Add security requirements section emphasizing API security as top priority - Update callback documentation with webhook signature verification details Co-authored-by: yansongda <11869114+yansongda@users.noreply.github.com> Agent-Logs-Url: https://github.com/yansongda/pay/sessions/41829a91-9c75-4201-8d60-5d4bf4853433
两项均已在 commit 1. PayPal Webhook 签名验证已完整实现:
2. Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
1、ci 未通过 2、请帮忙检查下,本 pr 的代码是否有可以优化的地方 |
PHPStan reported type mismatch because $rocket->getDestinationOrigin() returns RequestInterface|ResponseInterface|null, but verify_paypal_webhook_sign() expects ServerRequestInterface. After init() validates and sets the ServerRequestInterface, the type is guaranteed at runtime. Follow Wechat CallbackPlugin pattern with @phpstan-ignore-next-line annotation. Co-authored-by: yansongda <11869114+yansongda@users.noreply.github.com> Agent-Logs-Url: https://github.com/yansongda/pay/sessions/8a1deb45-aac3-4325-b766-1207be39ba87
CapturePlugin, QueryPlugin, QueryRefundPlugin, and RefundPlugin don't call get_provider_config() or any function that throws ContainerException or ServiceNotFoundException. Remove these inaccurate @throws annotations and their unused imports to improve code accuracy. Co-authored-by: yansongda <11869114+yansongda@users.noreply.github.com> Agent-Logs-Url: https://github.com/yansongda/pay/sessions/8a1deb45-aac3-4325-b766-1207be39ba87
两项均已完成: 1. CI 修复 ( 2. 代码优化 (
Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 48 out of 48 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| return new ServerRequest('POST', 'http://localhost', $contents['headers'], $contents['body']); | ||
| } | ||
|
|
||
| if (is_array($contents)) { | ||
| return new ServerRequest('POST', 'http://localhost', [], json_encode($contents)); |
There was a problem hiding this comment.
getCallbackParams() 在 $contents 为 array(包括传入 ['headers'=>...,'body'=>...])时会构造一个 URI 为 http://localhost 的 ServerRequest。由于 verify_paypal_webhook_sign() 对 host=localhost 直接 return,这会导致在生产环境如果调用方用 array 方式传参,Webhook 签名校验被静默跳过。建议:array 模式允许传入真实的 uri/host 并用于构造 ServerRequest,或不要在这里强制写死 localhost(让验签逻辑能正常执行)。
| return new ServerRequest('POST', 'http://localhost', $contents['headers'], $contents['body']); | |
| } | |
| if (is_array($contents)) { | |
| return new ServerRequest('POST', 'http://localhost', [], json_encode($contents)); | |
| $method = $contents['method'] ?? 'POST'; | |
| $uri = $contents['uri'] ?? null; | |
| if ($uri === null && isset($contents['host']) && is_string($contents['host']) && $contents['host'] !== '') { | |
| $uri = 'https://' . ltrim($contents['host'], '/'); | |
| } | |
| if ($uri === null) { | |
| $uri = 'http://localhost'; | |
| } | |
| return new ServerRequest($method, $uri, $contents['headers'], $contents['body']); | |
| } | |
| if (is_array($contents)) { | |
| $method = $contents['method'] ?? 'POST'; | |
| $uri = $contents['uri'] ?? null; | |
| if ($uri === null && isset($contents['host']) && is_string($contents['host']) && $contents['host'] !== '') { | |
| $uri = 'https://' . ltrim($contents['host'], '/'); | |
| } | |
| if ($uri === null) { | |
| $uri = 'http://localhost'; | |
| } | |
| return new ServerRequest($method, $uri, [], json_encode($contents)); |
| */ | ||
| function verify_paypal_webhook_sign(ServerRequestInterface $request, array $params): void | ||
| { | ||
| if ('localhost' === $request->getUri()->getHost()) { |
There was a problem hiding this comment.
verify_paypal_webhook_sign() 对 localhost 直接跳过验签会产生可利用的绕过路径:Provider 的 getCallbackParams()(以及文档中 array 传参模式)会构造 http://localhost 的请求,从而让回调在缺少 PayPal 头信息时也不会抛错。建议将“跳过验签”限制到测试环境(例如仅在 PHPUnit/CLI test 标识下),或改为显式参数开关(默认必须验签),避免在真实业务中被误用导致不验签。
| if ('localhost' === $request->getUri()->getHost()) { | |
| if ('localhost' === $request->getUri()->getHost() && PHP_SAPI === 'cli') { |
| /** | ||
| * @method Collection|Rocket web(array $order) Web 支付 | ||
| */ | ||
| class Paypal implements ProviderInterface |
There was a problem hiding this comment.
新增了 PayPal Provider(含 query/refund/callback/success 等 public 行为),但目前没有对应的 tests/Provider/PaypalTest.php 端到端覆盖(仓库里其它 Provider 均有 Provider 级测试)。建议补充 Provider 测试:至少覆盖 service 注册/Pay::paypal() 可用、web/query/refund 的插件管道组装、callback 验签失败/成功路径以及 success() 的响应内容。
|
@copilot 请帮忙检查最新的 Pull request overview 并做出合理的处理 |
Add Provider-level tests for PayPal following the same pattern as WechatTest/DouyinTest: shortcut not found, mergeCommonPlugins, cancel/close exceptions, callback with ServerRequestInterface, callback with array, and success response. Co-authored-by: yansongda <11869114+yansongda@users.noreply.github.com> Agent-Logs-Url: https://github.com/yansongda/pay/sessions/6a640cf2-7209-47e9-b2b7-39a64fc4b01b
已逐一分析最新 PR review 的 3 条建议: 1. 2. 3. 缺少 Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
Adds PayPal payment provider support with Web payment (create order + capture), query, refund, and callback handling with webhook signature verification.
Changes Made
Yansongda\Pay\Plugin\Paypal\V2\*namespace to match PayPal's v2 API endpointsPayPlugin,CapturePlugin,QueryPlugin,QueryRefundPlugin,RefundPlugin,CallbackPlugin,AddRadarPlugin,ResponsePlugin,ObtainAccessTokenPlugin,GetAccessTokenPlugin,VerifyWebhookSignPluginWebShortcut,QueryShortcut,RefundShortcutPaypalprovider withweb,query,refund,callback, andsuccessmethodsObtainAccessTokenPluginaccepts_access_tokenfrom params, allowing externally managed tokens to be passed in directlyCallbackPluginverifies webhook signatures via PayPal'sverify-webhook-signatureAPI before accepting callback payloads. Provider callback follows Wechat's_requestpattern withServerRequestInterface. Newverify_paypal_webhook_sign()function inFunctions.phphandles the full verification flow. Requireswebhook_idin config.web/docs/v3/paypal/(pay, query, refund, cancel, close, callback, response, all) and quick-start guide atweb/docs/v3/quick-start/paypal.md. All PayPal docs note that the implementation was generated by GitHub Copilot. Doc code examples use plain PHP loops (framework-agnostic) instead of Laravel-specific helpers.init.mdwith PayPal section and configuration block (includingwebhook_id)verify_paypal_webhook_signincluding localhost skip, missing config, empty signature, success, and failure scenarios),src/Functions.phpPayPal functions (get_paypal_url,get_paypal_access_tokenincluding cached token, missing config, and fresh token fetch scenarios), and Provider-level tests inPaypalTest.php(shortcut errors, mergeCommonPlugins, cancel/close exceptions, callback with ServerRequestInterface and array, success response)src/Functions.phpto passphp-cs-fixer— added properuseimport, corrected multi-line operator positioning, and replaced FQCNs with short/relative class references@throwsannotations and unused imports from CapturePlugin, QueryPlugin, QueryRefundPlugin, RefundPlugin.github/copilot-instructions.mdin Chinese with comprehensive project conventions covering architecture (plugin pipeline pattern), directory layout, coding standards, security requirements (API security as top priority), testing patterns, documentation conventions, and a step-by-step guide for adding new providersOriginal prompt
📱 Kick off Copilot coding agent tasks wherever you are with GitHub Mobile, available on iOS and Android.