Yii2 Stripe Webhook testing: "[ERROR] Failed to Post" - yii2

I set up a basic Webhook endpoint in a Yii2 controller just to test the connection:
class CreditCardController extends Controller
{
public function behaviors()
{
return [
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'webhook' => ['post'],
],
],
];
}
public function beforeAction($action)
{
if ($action->id == 'webhook')
$this->enableCsrfValidation = false;
return parent::beforeAction($action);
}
... I just want to dump the payload and return HTTP 200 (roughly based on an example I followed here)
public function actionWebhook()
{
$payload = file_get_contents('php://input');
ob_start();
var_dump($payload);
error_log(ob_get_clean(), 4);
echo json_encode(['status' => 'success']);
}
I installed the Stripe CLI and forwarded the Webhook to my local test server:
stripe listen -f https://testsite.office/credit-card/webhook
When I trigger an event that includes something I am listening for:
stripe trigger invoice.payment_succeeded
I get this message:
[ERROR] Failed to POST: Post "https://testsite.office/credit-card/webhook": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
If I remove the POST rule for the action and code the URL in a browser, it works fine.
Any ideas?
Joe

For anyone slogging along with the same issue (I don't see a lot of Stripe/Yii2 webhook chatter online), here is what worked for me.
I noticed that Yii threw a HeadersAlreadySentException in the Apache error_log. So I had to had to specify the response format as JSON:
return new Response([
'format' => Response::FORMAT_JSON,
'statusCode' => 200,
'statusText' => 'Webhook Handled',
]);
Probably not consequential to this problem, but I also changed accessing the payload to the "Yii way":
$payload = json_decode(Yii::$app->request->getRawBody(), true);

Related

Using the same action controller to render and save in yii2

the controllers actions of my yii2 application render and validate/save http input data. The first time (when the route was requested) it renders the form but with errors as follows:
I need to render form in the first time without error label. Is there way to solve this using the same action to render and save ?
This is my code:
public function actionCreate()
{
$model = new CourseForm;
$model->attributes = Yii::$app->request->post('CourseForm');
if ($model->validate()) {
// save...
} else {
return $this->render( 'create', [ 'model' => $model, 'errors' => $model->errors ]);
}
}
Because you are loading the attribute and calling the validate() every time the action is called and when the validation fails the view loads with the errors highlighted. So that pretty much makes sense why is it doing like that.
Secondly you can just use $model->load() and supply the post() array to it it will load the attributes automatically.
Your code can be reduced to the following and it will not show the error labels when the page loads untill unless you submit the form
public function actionCreate()
{
$model = new CourseForm();
if($model->load(Yii::$app->request->post()) && $model->validate()){
// save...
}
return $this->render('create', ['model' => $model, 'errors' => $model->errors]);
}

Can't authenticate for REST testing

I have the following virtual host name setup on xampp: reporting.dev
public function userIsAuthenticated(\ApiTester $I)
{
$I->amGoingTo('Check Authentication works');
// i've tried both of these ways to authenticate
$I->amHttpAuthenticated('my_email', 'my_password');
$I->haveHttpHeader('Authorization', 'Basic super_long_token');
$I->sendGET(Url::toRoute('/api/reports', true));
$I->seeResponseCodeIs(\Codeception\Util\HttpCode::OK); // 200
$I->deleteHeader('Authorization');
}
The following request works in postman http://reporting.dev/api/reports using a Basic Auth header and the same token in the test above.
This is my api suite config:
class_name: ApiTester
modules:
enabled:
- REST:
depends: PhpBrowser
#url: /api/
part: Json
- Yii2:
part: [orm, fixtures]
configFile: 'config/web.php'
I'm using Yii2, if I remove the behaviors function from my api controller that determines the authentication as Basic Auth, I then do get a 200 response and the expected json.
public function behaviors()
{
$behaviors = parent::behaviors();
$behaviors['authenticator'] = [
'class' => HttpBasicAuth::className(),
'except' => [],
];
return $behaviors;
}
So I'm unsure what else I can do here or why I'm not authenticated
The problem I had here was the auth token I have in my DB was not base64 encoded.
public function userIsAuthenticated(\ApiTester $I)
{
$I->amGoingTo('Check Authentication works');
// fixed now
$I->haveHttpHeader('Authorization', 'Basic ' . base64_encode('Basic super_long_db_auth_token'));
$I->sendGET(Url::toRoute('/api/reports', true));
$I->seeResponseCodeIs(\Codeception\Util\HttpCode::OK); // 200
$I->deleteHeader('Authorization');
}

Angular http post not working 1st time, but works on 2nd time

Trying my first angular exercise. Receiving undefined value on 1st time from http post, but 2nd time getting proper response (Edge, Firefox). Thanks!
LoginService (Calls Http post method and returns observable)
login(loginRequest: LoginRequest){
console.log("LoginService.login - userName " + loginRequest.username);
let options = new RequestOptions({ headers: headers });
return this.http.post(this.http_url, loginRequest, options).map( res =>
res.json());
LoginFormComponent (calls service class and convert JSON to typescript object)
onSubmit() {
this.loginSvc.login(this.loginRequest).subscribe(
data => this.loginResponseStr = data,
error => alert(error),
() => console.log('Request completed')
);
var loginResponse = new LoginResponse();
loginResponse.fillFromJSON(JSON.stringify(this.loginResponseStr));
console.log(loginResponse.status);
console.log(loginResponse.statusDesc);
if(loginResponse.status == "SUCCESS"){
this.router.navigate(['/home-page']);
}
Console log
LoginService.login - userName admin main.bundle.js:370:9
undefined main.bundle.js:266:9
undefined main.bundle.js:267:9
Request completed main.bundle.js:263:181
LoginService.login - userName admin main.bundle.js:370:9
SUCCESS main.bundle.js:266:9
VALID USER main.bundle.js:267:9
Request completed main.bundle.js:263:181
Angular server calls are asynchronous, that mean the code wont wait for the server to respond before executing the rest of the code. Such as PHP. So you would not see a blank page waiting for the server to send data. When you want to deal with the respose come from a server call you have to add all the code within the subscribe; that means if this information needed to be passed to another service.
Your code should look like this.
onSubmit() {
this.loginSvc.login(this.loginRequest).subscribe(
data => {
this.loginResponseStr = data
var loginResponse = new LoginResponse();
loginResponse.fillFromJSON(JSON.stringify(data));
console.log(loginResponse.status);
console.log(loginResponse.statusDesc);
if (loginResponse.status == "SUCCESS") {
this.router.navigate(['/home-page']);
}
},
error => alert(error),
() => console.log('Request completed')
);
}

Laravel setup for basic API and AJAX-calls

Laravel POST return type?
I'm setting up an API alpha version using basic auth single sign on.
Cant debug with postman/js because its not returning JSON but redirecting me instead. From what Ive read AJAX calls shouldnt be redirected? Do I have errors in the configuration?
Routes:
Route::post('/test1', 'tradesCtrl#test1']);
//Route::post('/test1', ['middleware' => 'auth.basic.once', 'uses' => 'tradesCtrl#test1']);
AJAX call:
$.post(
"http://localhost:8000/test1",
{
p1:"100a",
p2:80
},
function(data, status,jqXHR){
console.log(data);
});
Controller (this will echo HTTP (!):
public function test1(Request $request)
{
if($request->ajax()) {
echo "AJAX!";
} else {
echo "HTTP!";
}
}
Allow cross domain for now in App.php
// allow origin
header('Access-Control-Allow-Origin: *');
Kernel.php disable csrf protection by commeting out
app\Http\Middleware\VerifyCsrfToken::class
If I try to insert validation for parameters
public function test1(Request $request)
{
$this->validate($request, [
'p1' => 'Integer',
'p2' => 'Integer'
]);
echo "Serving stuff";
}
This immediately return in a 404 page not found when failing validation, probably a redirect to something else that's not working??

Laravel 5.1 consuming soap wsdl service using controller and model

Currently I'm using php and nusoap and wanted to convert it to Laravel.
When creating the soap calls I use data out of a mysql database.
So I think I would need a model (to get my data) and a controller (to create request).
EDIT:
<?php
namespace App\Http\Controllers;
use Artisaninweb\SoapWrapper\Facades\SoapWrapper;
class SoapController extends Controller {
public function demo()
{
// Add a new service to the wrapper
SoapWrapper::add(function ($service) {
$service
->name('currency')
->wsdl('path/to/wsdl')
->trace(true);
->options(['user' => 'username', 'pass' => 'password']);
});
// Using the added service
SoapWrapper::service('currency', function ($service) {
var_dump($service->getFunctions());
var_dump($service->call('Otherfunction'));
});
}
}
from laravel-soap I couldn't find a tutorial on how to send login parameters prior to any other request. In the example 'using the added service' I see the login credentials but it doesn't work.
This is how I got soap to work in Laravel 5.1
clean install laravel 5.1
install artisaninweb/laravel-soap
create a controller SoapController.php
<?php
namespace App\Http\Controllers;
use Artisaninweb\SoapWrapper\Facades\SoapWrapper;
class SoapController extends Controller {
public function demo()
{
// Add a new service to the wrapper
SoapWrapper::add(function ($service) {
$service
->name('currency')
->wsdl('path/to/wsdl')
->trace(true);
});
$data = [
'user' => 'username',
'pass' => 'password',
];
// Using the added service
SoapWrapper::service('currency', function ($service) use ($data) {
var_dump($service->call('Login', [$data]));
var_dump($service->call('Otherfunction'));
});
}
}
Create a route in your routes.php
Route::get('/demo', ['as' => 'demo', 'uses' => 'SoapController#demo']);
If requered you can also use the model extension as described here