Testing Laravel 5.3 protected API - php

I have just set up a small Laravel API that is protected via Passport that was introduced in 5.3. So far, everything is working well.
Since I will be the only one consuming the API, I simply added \Laravel\Passport\Http\Middleware\CreateFreshApiToken::class to my web middleware-group in order to generate and handle my API tokens.
To my question: How may I handle tokens in my application tests? actingAs($user) does not seem to magically add the user's token to the request. I can use $this->withoutMiddleware();, but then all middleware is disabled, and not only the one responsible for authentication.
Any ideas on how to solve this?
Thank you very much for you help!

A much easier solution is to add the api guard to the actingAs() method:
$this->actingAs($user, 'api');

I finally made it work by building upon on this answer:
https://laracasts.com/discuss/channels/testing/passport-personal-access-token-unit-test
Copy pasted from the author of above-mentioned post:
/**
*#test
*/
public function Create_an_access_token()
{
$clientRepository = new ClientRepository();
$client = $clientRepository->createPersonalAccessClient(
null, 'Test Personal Access Client', 'http://localhost'
);
DB::table('oauth_personal_access_clients')->insert([
'client_id' => $client->id,
'created_at' => new DateTime,
'updated_at' => new DateTime,
]);
$user = factory(User::class)->create();
$token = $user->createToken('TestToken')->accessToken;
$header = [];
$header['Accept'] = 'application/json';
$header['Authorization'] = 'Bearer '.$token;
$this->json('GET', '/api/user', [], $header)
->seeJson([
'id' => $user->id,
'email' => $user->email,
'name' => $user->name,
]);
}
I extracted the relevant and reusable parts into a small helper-class, and now the testing-code is rather short and readable.
Hope this helps someone in a similar situation.

If you take a look at the existing Laravel Passport tests, this should provide you sufficient information on how to clearly test this:
https://github.com/laravel/passport/tree/master/tests

Related

3rd party API Response - Laravel updateOrCreate, delete the rest that previously existed?

I'm getting data from an outside API. What's the cleanest way to delete existing records that no longer appear from the API after using updateOrCreate? Right now, I have a working method which gets the collection before and forgets the collection record on the API loop. Afterwards, it deletes anything that's left.
This feels hacky and I'm sure there's a better solution. Thanks in advance!
Using: Laravel 7.x
$apiPosts = api('....')->json(); // array
$existingPosts = Post::get();
foreach ($apiPosts as $post) {
Post::updateOrCreate(['id' => $post['id']], [
'title' => $post['title'],
'body' => $post['body'],
'is_active' => $post['post_visible'],
]);
// Works but ugly
if ($existingPosts->where('id', $post['id'])->first()) {
$existingPosts->where('id', $post['id'])->first()->forget();
}
}
// Works but ugly
foreach($existingPosts as $post) {
$post->delete();
}

Why WooCommerce REST API seems not working?

I'm currently working on my admin website using WooCommerce REST API, It works very well since last week but now it shows error like
Error: Sorry, you cannot list resources. [woocommerce_rest_cannot_view]
I don't change anything in my code, The authentication credentials are all fine. Thanks for any advice.
Edited:
protected $url = 'https://mywebsite.com';
protected const CONSUMER_KEY = 'ck_b7144d17091aa01a7a096154a445180c603d****';
protected const CONSUMER_SECRET = 'cs_cdb7705d4ad5bf29aa2b6366c55ac98397e4****';
function __construct(){
$this->woocommerce = new Woo(
$this->url,
self::CONSUMER_KEY,
self::CONSUMER_SECRET,
[
'wp_api' => true,
'version' => 'wc/v2',
]
);
}
This is often as a result of an setup issue, specifically with what values you've passed to verifySsl and queryStringAuth. You didn't post your code, so I can't tell you specifically, but these two resources might help:
https://github.com/woocommerce/wc-api-node/issues/43
https://robotninja.com/blog/fix-common-woocommerce-rest-api-issues/

Active Collab API: How to get projects

I'm trying out the ActiveCollab API for my first time. I had to use StackOveflow to figure out how to get the API token since the docs don't tell me this.
Below is my code:
/* GET INTENT */
$url = 'https://my.activecollab.com/api/v1/external/login';
$fields = array(
'email' => "email#email.com",
'password' => "****"
);
$intent = curl_post_connector($url, $fields);
$intent = $intent->user->intent;
/* GET TOKEN */
$url = 'https://app.activecollab.com/my_app_id/api/v1/issue-token-intent';
$fields = array(
'intent' => $intent,
'client_name' => 'My App Name',
'client_vendor' => 'My Company Name'
);
$token = curl_post_connector($url, $fields);
$token = $token->token;
Everything above works and get's the token properly. What I find really weird is that I have to use API v1 to get this, and the docs on ActiveCollab's site don't mention any URL for API v5. It seems like this is the approach everything is taking here on StackOverflow.
Now with the token, I try to get my list of projects:
/* GET PROJECT */
$url = 'https://app.activecollab.com/my_app_id/api/v1/users';
$headers = array (
"X-Angie-AuthApiToken" => $token
);
$projects = curl_get_connector($url, $headers);
var_dump($projects);
But this does not work. There is no error returned - it instead returns an array of languages for some reason! I don't want to paste the massive json object here, so instead I'll link you to a photo of it: https://www.screencast.com/t/7p5JuFB4Gu
UPDATE:
When attempting to use the SDK, it works up until I try getting the token (which is just as far as I got without the SDK). I'm getting Server Error 500, and when looking at the logs, it says:
/home/working/public_html/ac/index.php(21): ActiveCollab\SDK\Authenticator\Cloud->issueToken(123456789)
#1 {main}
thrown in /home/working/public_html/ac/SDK/Authenticator/Cloud.php on line 115
This is line 115 of Cloud.php:
throw new InvalidArgumentException("Account #{$account_id} not loaded");
I honestly don't think I did anything wrong... there must be something wrong with my account ID.
Just for kicks, I commented out that line, and the error disappears and the page loads fine - except now I have no token...

Can I add middleware to the default Guzzle 6 HandlerStack, rather than creating a new stack?

I am using the Spatie\Crawler crawler software in a fairly standard way, like so:
$client = new Client([
RequestOptions::COOKIES => true,
RequestOptions::CONNECT_TIMEOUT => 10,
RequestOptions::TIMEOUT => 10,
RequestOptions::ALLOW_REDIRECTS => true,
]);
$crawler = new Crawler($client, 1);
$crawler->
setCrawlProfile(new MyCrawlProfile($startUrl, $pathRegex))->
setCrawlObserver(new MyCrawlObserver())->
startCrawling($url);
I've omitted the definition of the classes MyCrawlProfile of MyCrawlObserver for brevity, but anyway, this works as it stands.
I want to add some middleware in order to change some requests before they are made, so I added this demo code:
$stack = new HandlerStack();
$stack->setHandler(new CurlHandler());
$stack->push(
Middleware::mapRequest(function (RequestInterface $request) {
echo "Middleware running\n";
return $request;
})
);
$client = new Client([
RequestOptions::COOKIES => true,
RequestOptions::CONNECT_TIMEOUT => 10,
RequestOptions::TIMEOUT => 10,
RequestOptions::ALLOW_REDIRECTS => true,
'handler' => $stack,
]);
// ... rest of crawler code here ...
However, it falls on the first hurdle - it scrapes the root of the site (/) which is actually a Location redirect, and then stops. It turns out that I am now missing the RedirectMiddleware despite not having removed it deliberately.
So, my problem is fixed by also adding this:
$stack->push(Middleware::redirect());
I wonder now what other things are set up by default in Guzzle that I have accidentally removed by creating a fresh HandlerStack. Cookies? Retry mechanisms? Other stuff? I don't need those things right now, but I'd be a bit more confident about my system's long-term reliability if my code merely modified the existing stack.
Is there a way to do that? As far as I can tell, I'm doing things as per the manual.
$stack = HandlerStack::create();
instead of
$stack = new HandlerStack();
$stack->setHandler(new CurlHandler());
It's important, because create() adds additional middlewares, especially for redirects.

How do call a method inside a component in OctoberCMS?

I don't know if this is possible or if it's a complete madness but I'm trying to execute a PHP method from AJAX call using OctoberCMS Ajax Framework(I assume that this uses jQuery behind it) and is not working because I never get redirect to PayPal site. The PHP code I'm trying to get working is this one:
protected function onExecutePurchaseMethod()
{
Omnipay::gateway('PayPal_Express');
$params = [
'username' => $this->username,
'password' => $this->password,
'signature' => $this->signature,
'testMode' => $this->sandboxMode,
'amount' => Session::get('amountToReload'),
'cancelUrl' => url( 'payment/step4', "", $secure = null ),
'returnUrl' => url( 'payment/step2', "", $secure = null ),
'currency' => 'USD'
];
$response = Omnipay::purchase($params)->send();
if ($response->isSuccessful()) {
var_dump($response);
} else {
var_dump($response->getMessage());
}
}
What is happening since none redirect to PayPal is executed and page is getting stuck many times forcing me to close the browser and reopen again, no method is executed and no visible errors. It's possible to do what I'm trying to do? Is not a madness? If it's possible where is my error?
As extra info I'm using Barryvdh Laravel-omnipay package for handle Omnipay from within Laravel.
After looking briefly through the documentation, my best guess is that you're missing a required field for the purchase() method. I believe you need a card parameter (even if it's an invalid one) to get it to process.

Categories