Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 33a48f47de | |||
| cf5ece0b5f | |||
| db8df612b4 | |||
| 75f4d0b10a | |||
| 7fed1c2a85 | |||
| 28a9e390cc | |||
| a565d2899b | |||
| 58b126ab83 | |||
| e9a6332ad0 | |||
| a79fd519ed | |||
| 04aa9fa019 |
49
.github/workflows/ci.yml
vendored
Normal file
49
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
name: CI
|
||||
run-name: ${{ github.actor}} runs CI
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
ci-tests:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: php-actions/composer@v6
|
||||
env:
|
||||
COMPOSER_ROOT_VERSION: dev-master
|
||||
- name: "Restore result cache"
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: ./tmp
|
||||
key: "result-cache-v1-${{ matrix.php-version }}-${{ github.run_id }}"
|
||||
restore-keys: |
|
||||
result-cache-v1-${{ matrix.php-version }}-
|
||||
- name: PHPStan Static Analysis
|
||||
uses: php-actions/phpstan@v3
|
||||
with:
|
||||
path: src/
|
||||
- name: "Save result cache"
|
||||
uses: actions/cache/save@v4
|
||||
if: always()
|
||||
with:
|
||||
path: ./tmp
|
||||
key: "result-cache-v1-${{ matrix.php-version }}-${{ github.run_id }}"
|
||||
# We need to use phpunit from the self install to get the class paths
|
||||
# Skip auto tests here, there are too many problems with flooding of the AWS API from github
|
||||
- name: PHPunit Tests Prepare
|
||||
env:
|
||||
AWS_GIFT_CARD_ENDPOINT: "${{ secrets.AWS_GIFT_CARD_ENDPOINT }}"
|
||||
AWS_GIFT_CARD_KEY: "${{ secrets.AWS_GIFT_CARD_KEY }}"
|
||||
AWS_GIFT_CARD_SECRET: "${{ secrets.AWS_GIFT_CARD_SECRET }}"
|
||||
AWS_GIFT_CARD_PARTNER_ID: "${{ secrets.AWS_GIFT_CARD_PARTNER_ID }}"
|
||||
AWS_GIFT_CARD_CURRENCY: "${{ secrets.AWS_GIFT_CARD_CURRENCY }}"
|
||||
run: |
|
||||
echo "AWS_GIFT_CARD_ENDPOINT=${AWS_GIFT_CARD_ENDPOINT}" > test/.env;
|
||||
echo "AWS_GIFT_CARD_KEY=${AWS_GIFT_CARD_KEY}" >> test/.env;
|
||||
echo "AWS_GIFT_CARD_SECRET=${AWS_GIFT_CARD_SECRET}" >> test/.env;
|
||||
echo "AWS_GIFT_CARD_PARTNER_ID=${AWS_GIFT_CARD_PARTNER_ID}" >> test/.env;
|
||||
echo "AWS_GIFT_CARD_CURRENCY=${AWS_GIFT_CARD_CURRENCY}" >> test/.env;
|
||||
echo "AWS_DEBUG=1" >> test/.env;
|
||||
- name: PHPunit Tests
|
||||
run: |
|
||||
vendor/bin/phpunit
|
||||
@@ -26,6 +26,7 @@
|
||||
// use Phan\Config;
|
||||
|
||||
return [
|
||||
"minimum_target_php_version" => "7.4",
|
||||
// If true, missing properties will be created when
|
||||
// they are first seen. If false, we'll report an
|
||||
// error message.
|
||||
@@ -65,7 +66,7 @@ return [
|
||||
'directory_list' => [
|
||||
// Change this to include the folders you wish to analyze
|
||||
// (and the folders of their dependencies)
|
||||
'.'
|
||||
'src/'
|
||||
// 'www',
|
||||
// To speed up analysis, we recommend going back later and
|
||||
// limiting this to only the vendor/ subdirectories your
|
||||
|
||||
@@ -127,6 +127,11 @@ fif code is C001 curl failed to init
|
||||
|
||||
if code is C002 a curl error has happened
|
||||
|
||||
### J-number
|
||||
|
||||
if a JSON error was encountered during some encoding this error will be found.
|
||||
The number is the json error code.
|
||||
|
||||
### empty error code
|
||||
|
||||
any other NON amazon error will have only 'message' set if run through decode
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9",
|
||||
"gullevek/dotenv": "dev-master",
|
||||
"dg/bypass-finals": "dev-master"
|
||||
"dg/bypass-finals": "dev-master",
|
||||
"phpstan/phpstan": "2.1.x-dev",
|
||||
"phpstan/phpstan-deprecation-rules": "2.0.x-dev"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# PHP Stan Config
|
||||
|
||||
parameters:
|
||||
tmpDir: /tmp/phpstan-codeblocks-amazon-incentives
|
||||
level: 8
|
||||
tmpDir: %currentWorkingDirectory%/tmp/phpstan-codeblocks-amazon-incentives
|
||||
level: 9
|
||||
paths:
|
||||
- %currentWorkingDirectory%
|
||||
- %currentWorkingDirectory%/src
|
||||
excludePaths:
|
||||
# ignore composer
|
||||
- vendor
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
<phpunit
|
||||
colors="true"
|
||||
verbose="true"
|
||||
verbose="false"
|
||||
>
|
||||
<!-- Below removes final from classes for mock tests -->
|
||||
<extensions>
|
||||
<extension class="test\phpUnit\Hook\BypassFinalHook" file="test/phpUnit/Hook/BypassFinalHook.php" />
|
||||
</extensions>
|
||||
<testsuites>
|
||||
<testsuite name="unit">
|
||||
<directory>test/phpUnit/</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
</phpunit>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace gullevek\AmazonIncentives\AWS;
|
||||
|
||||
use gullevek\AmazonIncentives\Client\Client;
|
||||
@@ -9,6 +11,7 @@ use gullevek\AmazonIncentives\Debug\AmazonDebug;
|
||||
use gullevek\AmazonIncentives\Response\CancelResponse;
|
||||
use gullevek\AmazonIncentives\Response\CreateBalanceResponse;
|
||||
use gullevek\AmazonIncentives\Response\CreateResponse;
|
||||
use gullevek\AmazonIncentives\Handle\Json;
|
||||
|
||||
class AWS
|
||||
{
|
||||
@@ -72,12 +75,12 @@ class AWS
|
||||
$canonical_request = $this->getCanonicalRequest($service_operation, $payload);
|
||||
$date_time_string = $this->getTimestamp();
|
||||
AmazonDebug::writeLog(['call' => __METHOD__]);
|
||||
$result = json_decode($this->makeRequest(
|
||||
$result = Json::jsonDecode($this->makeRequest(
|
||||
$payload,
|
||||
$canonical_request,
|
||||
$service_operation,
|
||||
$date_time_string
|
||||
), true);
|
||||
));
|
||||
return new CreateResponse($result);
|
||||
}
|
||||
|
||||
@@ -97,12 +100,12 @@ class AWS
|
||||
$canonical_request = $this->getCanonicalRequest($service_operation, $payload);
|
||||
$date_time_string = $this->getTimestamp();
|
||||
AmazonDebug::writeLog(['call' => __METHOD__]);
|
||||
$result = json_decode($this->makeRequest(
|
||||
$result = Json::jsonDecode($this->makeRequest(
|
||||
$payload,
|
||||
$canonical_request,
|
||||
$service_operation,
|
||||
$date_time_string
|
||||
), true);
|
||||
));
|
||||
return new CancelResponse($result);
|
||||
}
|
||||
|
||||
@@ -120,12 +123,12 @@ class AWS
|
||||
$canonical_request = $this->getCanonicalRequest($service_operation, $payload);
|
||||
$date_time_string = $this->getTimestamp();
|
||||
AmazonDebug::writeLog(['call' => __METHOD__]);
|
||||
$result = json_decode($this->makeRequest(
|
||||
$result = Json::jsonDecode($this->makeRequest(
|
||||
$payload,
|
||||
$canonical_request,
|
||||
$service_operation,
|
||||
$date_time_string
|
||||
), true);
|
||||
));
|
||||
return new CreateBalanceResponse($result);
|
||||
}
|
||||
|
||||
@@ -212,7 +215,7 @@ class AWS
|
||||
* @param string $date_time_string Ymd\THis\Z encoded timestamp, getTimestamp()
|
||||
* @param string $service_target Target service in the agcod string:
|
||||
* Value like com.amazonaws.agcod.<sn>.<so>
|
||||
* @return array<mixed> Header data as array for curl request
|
||||
* @return array<int,string> Header data as array for curl request
|
||||
*/
|
||||
public function buildHeaders(
|
||||
string $payload,
|
||||
|
||||
@@ -30,12 +30,12 @@ final class AmazonIncentives
|
||||
* @param bool|null $debug Debug flag
|
||||
*/
|
||||
public function __construct(
|
||||
string $key = null,
|
||||
string $secret = null,
|
||||
string $partner = null,
|
||||
string $endpoint = null,
|
||||
string $currency = null,
|
||||
bool $debug = null
|
||||
?string $key = null,
|
||||
?string $secret = null,
|
||||
?string $partner = null,
|
||||
?string $endpoint = null,
|
||||
?string $currency = null,
|
||||
?bool $debug = null
|
||||
) {
|
||||
// load AWS settings
|
||||
// fail here if settings missing
|
||||
@@ -65,7 +65,7 @@ final class AmazonIncentives
|
||||
*
|
||||
* @throws AmazonErrors
|
||||
*/
|
||||
public function buyGiftCard(float $value, string $creation_request_id = null): Response\CreateResponse
|
||||
public function buyGiftCard(float $value, ?string $creation_request_id = null): Response\CreateResponse
|
||||
{
|
||||
return ($this->newAWS())->getCode($value, $creation_request_id);
|
||||
}
|
||||
@@ -109,12 +109,12 @@ final class AmazonIncentives
|
||||
* @return AmazonIncentives self class
|
||||
*/
|
||||
public static function make(
|
||||
string $key = null,
|
||||
string $secret = null,
|
||||
string $partner = null,
|
||||
string $endpoint = null,
|
||||
string $currency = null,
|
||||
bool $debug = null
|
||||
?string $key = null,
|
||||
?string $secret = null,
|
||||
?string $partner = null,
|
||||
?string $endpoint = null,
|
||||
?string $currency = null,
|
||||
?bool $debug = null
|
||||
): AmazonIncentives {
|
||||
return new static($key, $secret, $partner, $endpoint, $currency, $debug);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace gullevek\AmazonIncentives\Client;
|
||||
|
||||
use gullevek\AmazonIncentives\Exceptions\AmazonErrors;
|
||||
use gullevek\AmazonIncentives\Debug\AmazonDebug;
|
||||
use gullevek\AmazonIncentives\Handle\Json;
|
||||
|
||||
class Client implements ClientInterface
|
||||
{
|
||||
@@ -16,7 +19,7 @@ class Client implements ClientInterface
|
||||
*
|
||||
* @param string $url The URL being requested,
|
||||
* including domain and protocol
|
||||
* @param array<mixed> $headers Headers to be used in the request
|
||||
* @param array<int,string> $headers Headers to be used in the request
|
||||
* @param array<mixed>|string $params Can be nested for arrays and hashes
|
||||
* @return string Result as json string
|
||||
*/
|
||||
@@ -50,7 +53,12 @@ class Client implements ClientInterface
|
||||
$err = curl_errno($handle);
|
||||
AmazonDebug::writeLog(['CURL_REQUEST_RESULT' => $result]);
|
||||
// extract all the error codes from Amazon
|
||||
$result_ar = json_decode((string)$result, true);
|
||||
// note we do not care about result errors here, if json decode fails, just set to empty
|
||||
try {
|
||||
$result_ar = Json::jsonDecode((string)$result);
|
||||
} catch (AmazonErrors $e) {
|
||||
$result_ar = [];
|
||||
}
|
||||
// if message is 'Rate exceeded', set different error
|
||||
if (($result_ar['message'] ?? '') == 'Rate exceeded') {
|
||||
$error_status = 'RESEND';
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace gullevek\AmazonIncentives\Client;
|
||||
|
||||
interface ClientInterface
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace gullevek\AmazonIncentives\Config;
|
||||
|
||||
class Config implements ConfigInterface
|
||||
@@ -85,7 +87,8 @@ class Config implements ConfigInterface
|
||||
case 'AWS_GIFT_CARD_PARTNER_ID':
|
||||
case 'AWS_GIFT_CARD_ENDPOINT':
|
||||
case 'AWS_GIFT_CARD_CURRENCY':
|
||||
$return = (string)($_ENV[$key] ?? '');
|
||||
$return = !empty($_ENV[$key]) && is_string($_ENV[$key]) ?
|
||||
$_ENV[$key] : '';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace gullevek\AmazonIncentives\Config;
|
||||
|
||||
interface ConfigInterface
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
// simple write all into an array that we can poll in the return group
|
||||
// to activate AmazonDebug::setDebug(true) must be called once
|
||||
|
||||
@@ -7,7 +9,7 @@ namespace gullevek\AmazonIncentives\Debug;
|
||||
|
||||
class AmazonDebug
|
||||
{
|
||||
/** @var array<mixed> Log data array log id -> array of log entries */
|
||||
/** @var array<string,array<array<mixed>>> Log data array log id -> array of log entries */
|
||||
private static $log = [];
|
||||
/** @var bool debug flag */
|
||||
private static $debug = false;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace gullevek\AmazonIncentives\Exceptions;
|
||||
|
||||
use RuntimeException;
|
||||
@@ -32,7 +34,7 @@ final class AmazonErrors extends RuntimeException
|
||||
'code' => $error_code,
|
||||
'type' => $error_type,
|
||||
'message' => $message,
|
||||
// atach log data if exists
|
||||
// attach log data if exists
|
||||
'log_id' => AmazonDebug::getId(),
|
||||
'log' => AmazonDebug::getLog(),
|
||||
])) ?: 'AmazonErrors: json encode problem: ' . $message,
|
||||
@@ -52,7 +54,7 @@ final class AmazonErrors extends RuntimeException
|
||||
{
|
||||
$message_ar = json_decode($message, true);
|
||||
// if we have an error, build empty block and only fill message
|
||||
if (json_last_error()) {
|
||||
if (json_last_error() || $message_ar === null || !is_array($message_ar)) {
|
||||
$message_ar = [
|
||||
'status' => '',
|
||||
'code' => '',
|
||||
|
||||
42
src/Handle/Json.php
Normal file
42
src/Handle/Json.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Handle json conversions
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace gullevek\AmazonIncentives\Handle;
|
||||
|
||||
use gullevek\AmazonIncentives\Exceptions\AmazonErrors;
|
||||
|
||||
class Json
|
||||
{
|
||||
/**
|
||||
* decode json string
|
||||
*
|
||||
* @param string $json
|
||||
* @return array<mixed>
|
||||
* @throws AmazonErrors
|
||||
*/
|
||||
public static function jsonDecode(string $json): array
|
||||
{
|
||||
$result = json_decode($json, true);
|
||||
if (
|
||||
($json_last_error = json_last_error()) ||
|
||||
$result === null ||
|
||||
!is_array($result)
|
||||
) {
|
||||
throw AmazonErrors::getError(
|
||||
'FAILURE',
|
||||
'J-' . $json_last_error,
|
||||
'jsonDecoreError',
|
||||
'Failed to decode json data',
|
||||
0
|
||||
);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
// __END__
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace gullevek\AmazonIncentives\Response;
|
||||
|
||||
use gullevek\AmazonIncentives\Debug\AmazonDebug;
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace gullevek\AmazonIncentives\Response;
|
||||
|
||||
use gullevek\AmazonIncentives\Debug\AmazonDebug;
|
||||
|
||||
class CreateBalanceResponse
|
||||
{
|
||||
/** @var string Amazon Gift Card Balance Amount */
|
||||
protected $amount = '';
|
||||
/** @var float Amazon Gift Card Balance Amount */
|
||||
protected $amount = 0;
|
||||
/** @var string Amazon Gift Card Balance Currency */
|
||||
protected $currency = '';
|
||||
/** @var string Amazon Gift Card Balance Status */
|
||||
@@ -41,9 +43,9 @@ class CreateBalanceResponse
|
||||
/**
|
||||
* Return the current available funds amount
|
||||
*
|
||||
* @return string Funds amount in set currency
|
||||
* @return float Funds amount in set currency
|
||||
*/
|
||||
public function getAmount(): string
|
||||
public function getAmount(): float
|
||||
{
|
||||
return $this->amount;
|
||||
}
|
||||
@@ -98,10 +100,18 @@ class CreateBalanceResponse
|
||||
*/
|
||||
public function parseJsonResponse(array $json_response): self
|
||||
{
|
||||
if (array_key_exists('amount', $json_response['availableFunds'])) {
|
||||
$this->amount = $json_response['availableFunds']['amount'];
|
||||
if (
|
||||
is_array($json_response['availableFunds']) &&
|
||||
array_key_exists('amount', $json_response['availableFunds']) &&
|
||||
is_numeric($json_response['availableFunds']['amount'])
|
||||
) {
|
||||
$this->amount = (float)$json_response['availableFunds']['amount'];
|
||||
}
|
||||
if (array_key_exists('currencyCode', $json_response['availableFunds'])) {
|
||||
if (
|
||||
is_array($json_response['availableFunds']) &&
|
||||
array_key_exists('currencyCode', $json_response['availableFunds']) &&
|
||||
is_string($json_response['availableFunds']['currencyCode'])
|
||||
) {
|
||||
$this->currency = $json_response['availableFunds']['currencyCode'];
|
||||
}
|
||||
// SUCCESS, FAILURE, RESEND
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace gullevek\AmazonIncentives\Response;
|
||||
|
||||
use gullevek\AmazonIncentives\Debug\AmazonDebug;
|
||||
|
||||
@@ -109,7 +109,7 @@ final class AmazonIncentivesTest extends TestCase
|
||||
try {
|
||||
// set expected throw error
|
||||
$result = $client->request($url, [], '');
|
||||
print "R: " . $result . "\n";
|
||||
$this->assertTrue(true, 'Successful client request');
|
||||
} catch (AmazonIncentives\Exceptions\AmazonErrors $e) {
|
||||
$curl_error = AmazonIncentives\Exceptions\AmazonErrors::decodeExceptionMessage($e->getMessage());
|
||||
// print "E-B: " . print_r($curl_error, true) . "\n";
|
||||
@@ -333,7 +333,13 @@ final class AmazonIncentivesTest extends TestCase
|
||||
// - getAmount
|
||||
// - getCurrency
|
||||
// - getTimestamp
|
||||
$funds = $agcod->getAvailableFunds();
|
||||
try {
|
||||
$funds = $agcod->getAvailableFunds();
|
||||
} catch (\Exception $e) {
|
||||
$this->markTestSkipped(
|
||||
$e->getMessage()
|
||||
);
|
||||
}
|
||||
// if not mock do type check
|
||||
// if mock do matching check from mcok
|
||||
if ($mock === false) {
|
||||
@@ -345,7 +351,7 @@ final class AmazonIncentivesTest extends TestCase
|
||||
// numeric number
|
||||
$this->assertIsNumeric(
|
||||
$funds->getAmount(),
|
||||
'Assert amoount is numerc'
|
||||
'Assert amoount is numeric'
|
||||
);
|
||||
// USD, JPY, etc
|
||||
$this->assertIsString(
|
||||
@@ -948,6 +954,11 @@ final class AmazonIncentivesTest extends TestCase
|
||||
);
|
||||
} catch (\Exception $e) {
|
||||
$error = AmazonIncentives\Exceptions\AmazonErrors::decodeExceptionMessage($e->getMessage());
|
||||
if ($error['code'] == "T001") {
|
||||
$this->markTestSkipped(
|
||||
"Skipped because of flooding"
|
||||
);
|
||||
}
|
||||
$this->assertEquals(
|
||||
[
|
||||
'code' => $expected_code,
|
||||
|
||||
2
tmp/.gitignore
vendored
Normal file
2
tmp/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
Reference in New Issue
Block a user