Request GetHumanStatus{model: ArrayObject} is not supported: ZF2 - zend-framework2

Creating a model for Sofort integration and extend the payments object from the payum module to use it in the capture.
<?php
namespace Reisesparer\Model;
use Payum\Core\Model\Payment;
class SofortueberWeisung extends Payment
{
protected $id;
}
Controller method for the sofort is like follows: I have created a seperate Model where extend to the payments object
public function sofortAction()
{
$storage = $this->getServiceLocator()->get('payum')->getStorage('Reisesparer\Model\SofortueberWeisung');
$payment = $storage->create();
$payment->setNumber(uniqid());
$payment->setCurrencyCode('EUR');
$payment->setTotalAmount(123); // 1.23 EUR
$payment->setDescription('A description');
$payment->setClientId('anId');
$payment->setClientEmail('foo#example.com');
$storage->update($payment);
$captureToken = $this->getServiceLocator()->get('payum.security.token_factory')->createCaptureToken(
'sofort', $payment, 'payment_done'
);
// print_r($captureToken);
// exit();
$this->redirect()->toUrl($captureToken->getTargetUrl());
}
And My config file has follows code to configure the payum/sofort mehthod in my project.
'sofort' => $sofortFactory->create(array(
'factory' => 'sofort',
'config_key' => '12345:123456:edc788a4316ce7e2ac0ede037aa623d7',
)),
And at the last my done action to capture the useful information after the successful payment is like follows:
public function doneAction()
{
$token = $this->getServiceLocator()->get('payum.security.http_request_verifier')->verify($this);
$gateway = $this->getServiceLocator()->get('payum')->getgateway($token->getgatewayName());
$gateway->execute($status = new GetHumanStatus($token));
$payment = $status->getFirstModel();
$viewModel = new ViewModel(array('status' => $status->getValue(),'details'=>$payment));
$viewModel->setTemplate('layout/pay_done');
return $viewModel;
}
Storage Config:
'storages' => array(
$detailsClass => new FilesystemStorage(__DIR__.'/../../data', $detailsClass, 'id'),
$paymentClass => new FilesystemStorage(__DIR__.'/../../data', $paymentClass, 'id'),
)
Now when ever i proceed with the sofort payment method to capture the payment it gaves me the error and not proceed further. but the other method like paypal, stripe and authorized.net are working fine in the same project how to resolve this issues
Error:
Request GetHumanStatus{model: ArrayObject} is not supported.

Related

Trying to read "bounce list" from AWS SNS in PHP

I'm programming an application to send emails through Amazon SES.
I would like to read the bounces (hard/soft bounces) from Amazon SNS (SES and SNS are already linked).
I tried the code shared on StackOverflow, but i constantly get an error message
//Create a SESClient
$SnsClient = new Aws\Sns\SnsClient([
//'profile' => 'default',
'version' => '2010-03-31',
'region' => 'eu-west-1',
'credentials' => [
'key' => $DatabaseLink->aws_access_key_id,
'secret' => $DatabaseLink->aws_secret_access_key],
]);
try {
$_SERVER['HTTP_X_AMZ_SNS_MESSAGE_TYPE'] = 'Notification';
// Retrieve the message
$message = Message::fromRawPostData();
// make validator instance
$validator = new MessageValidator();
// Validate the message
if ($validator->isValid($message)) {
if ($message['Type'] == 'SubscriptionConfirmation') {
// if it's subscription or unsubscribe event then call SubscribeURL
file_get_contents($message['SubscribeURL']);
} elseif ($message['Type'] === 'Notification') {
$subject = $message['Subject'];
$messageData = json_decode($message['Message']);
// use $subject and $messageData and take relevant action
}
}
} catch (Exception $e) {
// Handle exception
echo $e;
}
"Invalid POST data". I don't want to send a message for validation, i would like to get the list of email adresses that bounced. So, my backend can process them and remove them from my database.
Could you please help me to figure it out?
I'm going in circles with the aws documentation.

twilio/voice-sdk does not listen incoming call listener when I call on my twilio number

I am using the following stack with versions
Laravel (9.11) vue.js (2.x) php (8.1.0) twilio/voice-sdk
(2.1.1) twilio/sdk (6.37)
Workflow of my application:
I am making an inbound contact center for voice calls by using a task router, where a customer initiates the call from his/her phone to our contact center base number(+1 873 --- 0331)
Step #1
when the user call on this number(+1 873 --- 0331) voice webhook is called with the following code for IVR
public function webhookForContactCenterBaseNumber(Request $request)
{
$response = new VoiceResponse();
$params = array();
$params['action'] = secure_url('/api/webhook-for-contact-center-ivr');
$params['numDigits'] = 1;
$params['timeout'] = 10;
$params['method'] = "POST";
$gather = $response->gather($params);
$gather->say('For Spanish, please press one.', ['language' => 'es']);
$gather->say('For Enghlish,please press two.', ['language' => 'en']);
return $response;
}
Step #2
When the user presses A digit(1/2) I create a task with workflow via the task router
public function webhookForContactCenterIvr(Request $request)
{
$response = new VoiceResponse();
$digits = $request['Digits'];
$language = $digits == 1 ? 'es' : 'en';
switch ($digits) {
case 1 || 2:
$response->enqueue(null, [
'waitUrl' => 'http://twimlets.com/holdmusic?Bucket=com.twilio.music.classical',
'workflowSid' => 'WW456fb07f4fdc4f55779dcb6bd90f9273'
])
->task(json_encode([
'selected_language' => $language,
]));
break;
default:
$response->say("Sorry, Caller. You can only press 1 for spanish, or 2 for english.");
break;
}
return $response;
}
step #3
After task creation, I make the targeted agent available manually from the console with the label ‘idle’, then following webhook called.
According to documentation bridge call was created between caller and agent Twilio phone number via Twilio caller id
public function assigment(Request $request)
{
$assignment_instruction = [
'instruction' => 'dequeue',
'post_work_activity_sid' => 'WA92871fe67075e6556c02e92de6---924',
'from' => '+1647---4676' // a verified phone number from your twilio account
];
return $this->respond($assignment_instruction, ['Content-Type', 'application/json']);
}
Call logs:
step #4
namespace App\Http\Controllers\Api;
use Twilio\Jwt\AccessToken;
use Twilio\Jwt\Grants\VoiceGrant;
use Illuminate\Http\Request;
use Twilio\Rest\Client;
class TwilioController extends ApiController
{
// Required for all Twilio access tokens
private $twilioAccountSid;
private $twilioAccountAuthToken;
private $twilioApiKey;
private $twilioApiSecret;
private $identity;
public function __construct()
{
$this->twilioAccountSid = config('general.twilio_account_sid');
$this->twilioAccountAuthToken = config('general.twilio_auth_token');
$this->twilioApiKey = 'SK45e57c57f923e5c3c0903f48b70ba9de';
$this->twilioApiSecret = 'uqDNnlnDZbWZCKBwlmMdlMIIonhh3X3K';
// choose a random username for the connecting user
$this->identity = 'daffdfwerweds';
}
public function getCallAccessToken()
{
$token = new AccessToken(
$this->twilioAccountSid,
$this->twilioApiKey,
$this->twilioApiSecret,
3600,
$this->identity
);
// Create Voice grant
$voiceGrant = new VoiceGrant();
// Optional: add to allow incoming calls
$voiceGrant->setIncomingAllow(true);
// Add grant to token
$token->addGrant($voiceGrant);
return $this->respond([
'status' => true,
'message' => '',
'data' => [
'accessToken' => $token->toJWT()
]
]);
}
public function getTwilioKey($frindlyName)
{
$twilio = new Client($this->twilioAccountSid, $this->twilioAccountAuthToken);
return $twilio->newKeys->create(["friendlyName" => $frindlyName]);
}
public function getKeys()
{
$twilio = new Client($this->twilioAccountSid, $this->twilioAccountAuthToken);
$keys = $twilio->keys
->read(20);
foreach ($keys as $record) {
$twilio->keys($record->sid)
->delete();
}
}
public function getAllCalls(Request $request)
{
$twilio = new Client($this->twilioAccountSid, $this->twilioAccountAuthToken);
$calls = $twilio->calls
->read([], 20);
foreach ($calls as $record) {
// print($record->sid);
$twilio->calls($record->sid)
->delete();
}
}
}
Step #5
I have installed twilio/voice-sdk in vue and register my device with following code
const accessToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImN0eSI6InR3aWxpby1mcGE7dj0xIn0.eyJqdGkiOiJTSzQ1ZTU3YzU3ZjkyM2U1YzNjMDkwM2Y0OGI3MGJhOWRlLTE2NTU3MzgxNjMiLCJpc3MiOiJTSzQ1ZTU3YzU3ZjkyM2U1YzNjMDkwM2Y0OGI3MGJhOWRlIiwic3ViIjoiQUMwMWExYTRmMDdjMGMwMDlhMmIyZTEyYmJkZWVhYjQ2NSIsImV4cCI6MTY1NTc0MTc2MywiZ3JhbnRzIjp7ImlkZW50aXR5IjoiZGFmZmRmd2Vyd2VkcyIsInZvaWNlIjp7ImluY29taW5nIjp7ImFsbG93Ijp0cnVlfX19fQ.4COIn-EQMQnD6alKUSOZPGIWG3jB5k17K418xCsSiZs"
const device = new Device(accessToken, {
logLevel: 1,
// Set Opus as our preferred codec. Opus generally performs better, requiring less bandwidth and
// providing better audio quality in restrained network conditions.
codecPreferences: ["opus", "pcmu"]
});
const handleSuccessfulRegistration = () => {
console.log('The device is ready to receive incoming calls.')
}
device.register();
device.on('registered', handleSuccessfulRegistration);
device.on('error', (twilioError, call) => {
console.log('An error has occurred: ', twilioError);
});
device.on('incoming', call => {
console.log('call received-----------------')
});
Verify token on jwt.io
Test Device Registration in console:
I was facing the same issue, thanks for detailed information, I go through the whole detail, and here is the answer after that issue will be fixed,
in step #4 you are creating call access token, and you are adding worker/agent identity you need to add some identity against the worker inside the Twilio console, in your case, it should be like that,
in code
$this->identity = 'daffdfwerweds';
in Twilio console under task router/workspace/workers/open target work
most important part
{contact_uri":"client:daffdfwerweds"}
Your browser will listen the incoming call via SDK if call router toward you this worker.
that's all.

Enable Oauth2 client credentials flow in Swashbuckle

Im using IdentityServer3 to secure a Web API with the client credentials grant. For documentation Im using Swashbuckle but can't figure out how to enable Oauth2 in the SwaggerConfig for the client credentials (application) flow. Any help would be appreciated!
I was able to get this working. Most of the answer can be found here.
There were a few parts I had to change to get the client_credential grant to work.
The first part is in the EnableSwagger and EnableSwaggerUi calls:
config.EnableSwagger(c =>
{
c.SingleApiVersion("v1", "sample api");
c.OAuth2("oauth2")
.Description("client credentials grant flow")
.Flow("application")
.Scopes(scopes => scopes.Add("sampleapi", "try out the sample api"))
.TokenUrl("http://authuri/token");
c.OperationFilter<AssignOAuth2SecurityRequirements>();
}).EnableSwaggerUi(c =>
{
c.EnableOAuth2Support("sampleapi", "samplerealm", "Swagger UI");
});
The important change here is .Flow("application") I also used the .TokenUrl call instead of .AuthorizationUrl This is just dependent on your particular authorization scheme is set up.
I also used a slightly different AssignOAuth2SecurityRequirements class
public class AssignOAuth2SecurityRequirements : IOperationFilter
{
public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
{
var authorized = apiDescription.ActionDescriptor.GetCustomAttributes<AuthorizeAttribute>();
if (!authorized.Any()) return;
if (operation.security == null)
operation.security = new List<IDictionary<string, IEnumerable<string>>>();
var oAuthRequirements = new Dictionary<string, IEnumerable<string>>
{
{"oauth2", Enumerable.Empty<string>()}
};
operation.security.Add(oAuthRequirements);
}
}
This should be sufficient to get the authentication switch to show. The other problem for me was that the default authentication dialog is set up so a user just has to select a scope and then click authorize. In my case this didn't work due to the way I have authentication set up. I had to re-write the dialog in the swagger-oauth.js script and inject it into the SwaggerUI.
I had a bit more trouble getting this all working, but after a lot of perseverance I found a solution that works without having to inject any JavaScript into the SwaggerUI. NOTE: Part of my difficulties might have been due to using IdentityServer3, which is a great product, just didn't know about a configuration issue.
Most of my changes are similar to bills answer above, but my Operation Filter is different. In my controller all the methods have an Authorize tag with no Roles like so:
[Authorize]
// Not this
[Authorize(Roles = "Read")] // This doesn't work for me.
With no Roles defined on the Authorize tag the OperationFilter looks like this:
public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
{
// Correspond each "Authorize" role to an oauth2 scope, since I don't have any "Roles" defined, this didn't work
// and is in most of the Apply methods I found online. If you are like me and your [Authorize] tag doesn't contain
// any roles this will not work.
//var scopes = apiDescription.ActionDescriptor.GetFilterPipeline()
// .Select(filterInfo => filterInfo.Instance)
// .OfType<AuthorizeAttribute>()
// .SelectMany(attr => attr.Roles.Split(','))
// .Distinct();
var scopes = new List<string>() { "Read" }; // For me I just had one scope that is added to all all my methods, you might have to be more selective on how scopes are added.
if (scopes.Any())
{
if (operation.security == null)
operation.security = new List<IDictionary<string, IEnumerable<string>>>();
var oAuthRequirements = new Dictionary<string, IEnumerable<string>>
{
{ "oauth2", scopes }
};
operation.security.Add(oAuthRequirements);
}
}
The SwaggerConfig looks like this:
public static void Register()
{
var thisAssembly = typeof(SwaggerConfig).Assembly;
GlobalConfiguration.Configuration
.EnableSwagger(c =>
{
c.SingleApiVersion("v1", "waPortal");
c.OAuth2("oauth2")
.Description("OAuth2 Client Credentials Grant Flow")
.Flow("application")
.TokenUrl("http://security.RogueOne.com/core/connect/token")
.Scopes(scopes =>
{
scopes.Add("Read", "Read access to protected resources");
});
c.IncludeXmlComments(GetXmlCommentsPath());
c.UseFullTypeNameInSchemaIds();
c.DescribeAllEnumsAsStrings();
c.OperationFilter<AssignOAuth2SecurityRequirements>();
})
.EnableSwaggerUi(c =>
{
c.EnableOAuth2Support(
clientId: "swaggerUI",
clientSecret: "BigSecretWooH00",
realm: "swagger-realm",
appName: "Swagger UI"
);
});
}
The last part was the hardest to figure out, which I finally did with the help of the Chrome Developer tools that showed a little red X on the network tag showing the following error message:
XMLHttpRequest cannot load http://security.RogueOne.com/core/connect/token. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:62561' is therefore not allowed access.
I described this error here Swagger UI not parsing reponse which was due to IdentityServer3 correctly not adding a response header of "Access-Control-Allow-Origin:http://localhost:62561" You can force IdentityServer3 to send that header by updating you client creation to be the following:
new Client
{
ClientName = "SwaggerUI",
Enabled = true,
ClientId = "swaggerUI",
ClientSecrets = new List<Secret>
{
new Secret("PasswordGoesHere".Sha256())
},
Flow = Flows.ClientCredentials,
AllowClientCredentialsOnly = true,
AllowedScopes = new List<string>
{
"Read"
},
Claims = new List<Claim>
{
new Claim("client_type", "headless"),
new Claim("client_owner", "Portal"),
new Claim("app_detail", "allow")
},
PrefixClientClaims = false
// Add the AllowedCorOrigins to get the Access-Control-Allow-Origin header to be inserted for the following domains
,AllowedCorsOrigins = new List<string>
{
"http://localhost:62561/"
,"http://portaldev.RogueOne.com"
,"https://portaldev.RogueOne.com"
}
}
The AllowedCorsOrigins was the last piece of my puzzle. Hopefully this helps someone else who is facing the same issue

cakephp2 i want to only tweet

I use cakephp2.x and use this Consuming OAuth-enabled APIs with CakePHP http://code.42dh.com/oauth/
I only want to be able to tweet. But I can't now.
Download consuming package and put app/vender/OAuth
Write this code in PostsController
App::import('Vendor', 'OAuth/OAuthClient');
public function add() {
$client = $this->createClient();
$requestToken = $client->getRequestToken('https://api.twitter.com/oauth/request_token',
'http://' . $_SERVER['HTTP_HOST'] . '/lolch/posts');
if ($requestToken) {
$this->Session->write('twitter_request_token', $requestToken);
$this->redirect('https://api.twitter.com/oauth/authorize?oauth_token='
. $requestToken->key);
}
}
public function callback() {
$requestToken = $this->Session->read('twitter_request_token');
$client = $this->createClient();
$accessToken = $client->getAccessToken('https://api.twitter.com/oauth/access_token',
$requestToken);
$client->post($accessToken->key, $accessToken->secret, 'https://api.twitter.com/1.1/statuses/update.json', array('status' =>
'hello world!'));
private function createClient() {
return new OAuthClient('my key', 'my secret');
}
Where should I change the code??
You can use https://github.com/LubosRemplik/CakePHP-Twitter-API-Plugin‎ plugin or other twitter plugin for cakephp and read the documentation there to apply what you want. It is easy to use ready made plugin than reinventing the wheel.

image resize zf2

I need to implement image resize functionality (preferably with gd2 library extension) in zend framework 2.
I could not find any component/helper for the same. Any references?
If i want to create one, where should I add it. In older Zend framework, there was a concept of Action Helper, what about Zend framework 2 ?
Please suggest the best solution here.
I currently use Imagine together with Zend Framework 2 to handle this.
Install Imagine: php composer.phar require imagine/Imagine:0.3.*
Create a service factory for the Imagine service (in YourModule::getServiceConfig):
return array(
'invokables' => array(
// defining it as invokable here, any factory will do too
'my_image_service' => 'Imagine\Gd\Imagine',
),
);
Use it in your logic (hereby a small example with a controller):
public function imageAction()
{
$file = $this->params('file'); // #todo: apply STRICT validation!
$width = $this->params('width', 30); // #todo: apply validation!
$height = $this->params('height', 30); // #todo: apply validation!
$imagine = $this->getServiceLocator()->get('my_image_service');
$image = $imagine->open($file);
$transformation = new \Imagine\Filter\Transformation();
$transformation->thumbnail(new \Imagine\Image\Box($width, $height));
$transformation->apply($image);
$response = $this->getResponse();
$response->setContent($image->get('png'));
$response
->getHeaders()
->addHeaderLine('Content-Transfer-Encoding', 'binary')
->addHeaderLine('Content-Type', 'image/png')
->addHeaderLine('Content-Length', mb_strlen($imageContent));
return $response;
}
This is obviously the "quick and dirty" way, since you should do following (optional but good practice for re-usability):
probably handle image transformations in a service
retrieve images from a service
use an input filter to validate files and parameters
cache output (see http://zend-framework-community.634137.n4.nabble.com/How-to-handle-404-with-action-controller-td4659101.html eventually)
Related: Zend Framework - Returning Image/File using Controller
Use a service for this and inject it to controllers needing the functionality.
Here is a module called WebinoImageThumb in Zend Framework 2. Checkout this. It has some great feature such as -
Image Resize
Image crop, pad, rotate, show and save images
Create image reflection
For those who are unable to integrate Imagine properly like me..
I found another solution WebinoImageThumb here which worked perfectly fine with me. Here is little explanation if you don't want to read full documentation :
Run: php composer.phar require webino/webino-image-thumb:dev-develop
and add WebinoImageThumb as active module in config/application.config.php which further looks like :
<?php
return array(
// This should be an array of module namespaces used in the application.
'modules' => array(
'Application',
'WebinoImageThumb'
),
.. below remains the same
Now in your controller action use this through service locator like below :
// at top on your controller
use Zend\Validator\File\Size;
use Zend\Validator\File\ImageSize;
use Zend\Validator\File\IsImage;
use Zend\Http\Request
// in action
$file = $request->getFiles();
$fileAdapter = new \Zend\File\Transfer\Adapter\Http();
$imageValidator = new IsImage();
if ($imageValidator->isValid($file['file_url']['tmp_name'])) {
$fileParts = explode('.', $file['file_url']['name']);
$filter = new \Zend\Filter\File\Rename(array(
"target" => "file/path/to/image." . $fileParts[1],
"randomize" => true,
));
try {
$filePath = $filter->filter($file['file_url'])['tmp_name'];
$thumbnailer = $this->getServiceLocator()
->get('WebinoImageThumb');
$thumb = $thumbnailer->create($filePath, $options = [], $plugins = []);
$thumb->adaptiveResize(540, 340)->save($filePath);
} catch (\Exception $e) {
return new ViewModel(array('form' => $form,
'file_errors' => array($e->getMessage())));
}
} else {
return new ViewModel(array('form' => $form,
'file_errors' => $imageValidator->getMessages()));
}
Good luck..!!
In order to resize uploaded image on the fly you should do this:
public function imageAction()
{
// ...
$imagine = $this->getImagineService();
$size = new \Imagine\Image\Box(150, 150);
$mode = \Imagine\Image\ImageInterface::THUMBNAIL_INSET;
$image = $imagine->open($destinationPath);
$image->thumbnail($size, $mode)->save($destinationPath);
// ...
}
public function getImagineService()
{
if ($this->imagineService === null)
{
$this->imagineService = $this->getServiceLocator()->get('my_image_service');
}
return $this->imagineService;
}

Resources