How to correctly implement ExpressCheckout in cakePHP 3.x? - cakephp

I've implemented ExpressCheckoutDG in cakePHP3.x website, based on the ExpressCheckout Wizard. (https://devtools-paypal.com/integrationwizard/)
So the payment procedure is realized in a dedicated opened frame.
Everything goes well until payment is achived and Paypal call the return URL.
At the end of the called method named confirm, I don't know what to do to close the Paypal frame and go back to a specified url.
My confirm method is:
public function confirm() {
$this->log($this->request->url . ' confirm', 'debug' );
$this->loadModel('Orders');
$PaymentOption = "PayPal";
if ( $PaymentOption == "PayPal" )
{
$res = $this->GetExpressCheckoutDetails( $_REQUEST['token'] );
/**
* I removed this part of code as it doesn't concern the problem
*/
$resArray = $this->ConfirmPayment ( $token, $paymentType, $currencyCodeType, $payerID, $finalPaymentAmount, $items );
$ack = strtoupper($resArray["ACK"]);
$this->log($this->request->url . ' confirm :' . $ack, 'debug' );
if( $ack == "SUCCESS" || $ack == "SUCCESSWITHWARNING" )
{
/**
* I removed this part of code as it doesn't concern the problem
*/
/*
* Here I save the transaction
*/
// Add javascript to close Digital Goods frame. You may want to add more javascript code to
// display some info message indicating status of purchase in the parent window
$this->Flash->success(__("transaction successfully completed"));
$this->log($this->request->url . ' confirm : display confirm.ctp', 'debug' );
/*
* So the problem is here: What to do to close the Paypal frame, AND return to a given page of my website??
*/
//$this->redirect(['controller' => 'Sites', 'action' => 'view']);
$this->set(compact('ack'));
}
else
{
//Display a user friendly Error on the page using any of the following error information returned by PayPal
$ErrorCode = urldecode($resArray["L_ERRORCODE0"]);
$ErrorShortMsg = urldecode($resArray["L_SHORTMESSAGE0"]);
$ErrorLongMsg = urldecode($resArray["L_LONGMESSAGE0"]);
$ErrorSeverityCode = urldecode($resArray["L_SEVERITYCODE0"]);
echo "DoExpressCheckoutDetails API call failed. ";
echo "Detailed Error Message: " . $ErrorLongMsg;
echo "Short Error Message: " . $ErrorShortMsg;
echo "Error Code: " . $ErrorCode;
echo "Error Severity Code: " . $ErrorSeverityCode;
$this->Flash->error(__("votre achat n'a pas été accepté"));
$this->set(compact('ack'));
}
}
$this->set(compact('ack'));
}
As you can see, the payment process goes well until trying to finish:
2015-02-20 11:00:38 Debug: pros/Sitemessages/checkout checkout
2015-02-20 11:00:38 Debug: pros/Sitemessages/checkout SetExpressCheckoutDG
2015-02-20 11:00:38 Debug: pros/Sitemessages/checkout hash_call
2015-02-20 11:00:41 Debug: pros/Sitemessages/checkout deformatNVP
2015-02-20 11:00:41 Debug: pros/Sitemessages/checkout deformatNVP
2015-02-20 11:00:41 Debug: pros/Sitemessages/checkout hash_call: closing
2015-02-20 11:00:41 Debug: pros/Sitemessages/checkout RedirectToPayPalDG
2015-02-20 11:01:15 Debug: pros/Sitemessages/confirm confirm
2015-02-20 11:01:15 Debug: pros/Sitemessages/confirm GetExpressCheckoutDetails
2015-02-20 11:01:15 Debug: pros/Sitemessages/confirm hash_call
2015-02-20 11:01:18 Debug: pros/Sitemessages/confirm deformatNVP
2015-02-20 11:01:18 Debug: pros/Sitemessages/confirm deformatNVP
2015-02-20 11:01:18 Debug: pros/Sitemessages/confirm hash_call: closing
2015-02-20 11:01:18 Debug: pros/Sitemessages/confirm ConfirmPayment
2015-02-20 11:01:18 Debug: pros/Sitemessages/confirm hash_call
2015-02-20 11:01:23 Debug: pros/Sitemessages/confirm deformatNVP
2015-02-20 11:01:23 Debug: pros/Sitemessages/confirm deformatNVP
2015-02-20 11:01:23 Debug: pros/Sitemessages/confirm hash_call: closing
2015-02-20 11:01:23 Debug: pros/Sitemessages/confirm confirm :SUCCESS
2015-02-20 11:01:23 Notice: pros/Sitemessages/confirm transaction successfully saved
2015-02-20 11:01:23 Debug: pros/Sitemessages/confirm confirm : display confirm.ctp
here is my confirm.ctp file:
<?php if ( $ack == "SUCCESS" || $ack == "SUCCESSWITHWARNING" ):?>
<script>
alert("Payment Successful");
// add relevant message above or remove the line if not required
window.onload = function(){
if(window.opener){
window.close();
}
else{
if(top.dg.isOpen() == true){
top.dg.closeFlow();
return true;
}
}
};
</script>
<?php else:?>
<script>
alert("Payment failed");
// add relevant message above or remove the line if not required
window.onload = function(){
if(window.opener){
window.close();
}
else{
if(top.dg.isOpen() == true){
top.dg.closeFlow();
return true;
}
}
};
</script>
<?php endif;?>
Any idea on the solution to close the Paypal Frame and go back to a given url?

You need to have a page with nothing on it except for the javascript to close the window. That's what you would set as your return URL and your cancel URL, so that the window simply closes.
Here's a demo I put together using my PHP class library for PayPal that will show you how to make it work.

Sorry, I found my mistake.
I had to add the following line at the begining of the ctp file.
<?php $this->layout=false?>

Related

Ansible nested_loops and product filter

I want to improve my ansible role because i have a lot of users to roll out.
For each user that is created there will be also multiple folders
created and this is very time consuming.
This is my users.yml file where i put every single user in (>1000)
ftp_users:
testuser1:
public_key: "public key"
password: "sha string"
home: /home/testuser1
customer_type: linux
testuser2:
public_key: "public key"
password: "sha string"
home: /home/testuser2
customer_type: windows
For this 2 users i want to create two folders "in" and "out".
Therefore i've created two tasks where i iterating over the dictionary:
- name: Create required out-folder for jailed users.
become: true
ansible.builtin.file:
owner: "{{ item.key }}"
group: ftpusers
mode: 0770
path: "/home/{{ item.value.customer_type }}/{{ item.key }}/out"
state: directory
loop: "{{ ftp_users | dict2items }}"
when: "'state' not in item.value or item.value.state == 'present'"
- name: Create required in-folder for jailed users.
become: true
ansible.builtin.file:
owner: "{{ item.key }}"
group: ftpusers
mode: 0770
path: "/home/{{ item.value.customer_type }}/{{ item.key }}/in"
state: directory
loop: "{{ ftp_users | dict2items }}"
when: "'state' not in item.value or item.value.state == 'present'"
This is very stupid because it takes a lot of time when 1000 users are rolled out.
I want to make one tasks to simultaniously create the "in" and "out" folder for every user, that i dont have to iterate two times over the whole dictionary.
What would be better nested_loops or the product filter?
Can someone show me an example?
Unfortunately block doesnt accept loop, so you could use include_tasks:
- name: "tips4"
hosts: localhost
gather_facts: false
vars:
ftp_users:
testuser1:
public_key: "public key"
password: "sha string"
home: /home/testuser1
customer_type: linux
testuser2:
public_key: "public key"
password: "sha string"
home: /home/testuser2
customer_type: windows
tasks:
- name: Create required out-folder for jailed users
include_tasks: create_folders.yml
loop: "{{ ftp_users | dict2items }}"
when: "'state' not in item.value or item.value.state == 'present'"
Create another file create_folders.yml in same folder than your playbook
# create_folders.yml
---
- name: Create required out-folder for jailed users
debug:
msg: "owner: {{ item.key }}, path: /home/{{ item.value.customer_type }}/{{ item.key }}/out"
- name: Create required in-folder for jailed users
debug:
msg: "owner: {{ item.key }}, path: /home/{{ item.value.customer_type }}/{{ item.key }}/in"
result:
TASK [Create required out-folder for jailed users]
ok: [localhost] => {
"msg": "owner: testuser1, path: /home/linux/testuser1/out"
}
TASK [Create required in-folder for jailed users]
ok: [localhost] => {
"msg": "owner: testuser1, path: /home/linux/testuser1/in"
}
TASK [Create required out-folder for jailed users]
ok: [localhost] => {
"msg": "owner: testuser2, path: /home/windows/testuser2/out"
}
TASK [Create required in-folder for jailed users]
ok: [localhost] => {
"msg": "owner: testuser2, path: /home/windows/testuser2/in"
}
with this playbook, in and out folder are created in same loop, so you just iterate one time...

Ansible cannot invoke variable for hostname in playbook

I need to add new users to multiple Ubuntu servers. Unfortunately, the password and username are not consistent. Every machine has its own username and the password cannot be the same. For example, host-1 will have a user account host-1_username with password host-1_password and host-2 will have a user account host-2_username with password host-2_password, and so on.
I would like to do that by Ansible. I have a list.yaml file:
---
list:
- hostname: host-1
username: host-1_username
password: host-1_password
- hostname: host-2
username: host-2_username
password: host-2_password
- hostname: host-3
username: host-3_username
password: host-3_password
Here is my Ansible playbook:
- name: Crate new user
vars_files:
- list.yml
hosts: "{{ item.hostname }}"
remote_user: root
become: true
tasks:
- name: Create new user
ansible.builtin.user:
name: "{{ item.username }}"
groups: sudo
password: "{{ item.password | password_hash('sha512') }}"
shell: /bin/bash
- name: Modify sshd_config
ansible.builtin.lineinfile:
dest: /etc/ssh/sshd_config
line: 'AllowUsers {{ item.username }}'
loop: "{{ list }}"
But looks like Ansible cannot invoke the variable to add into hosts column:
ERROR! couldn't resolve module/action 'hosts'. This often indicates a misspelling, missing collection, or incorrect module path.
I am very new to Ansible, any help is appreciated!
Given the data
shell> cat list.yml
users_list:
- hostname: host-1
username: host-1_username
password: host-1_password
- hostname: host-2
username: host-2_username
password: host-2_password
- hostname: host-3
username: host-3_username
password: host-3_password
Create an inventory file, e.g.
shell> cat hosts
host-1
host-2
host-3
Convert the data to dictionaries, e.g.
- hosts: all
gather_facts: false
vars_files:
- list.yml
tasks:
- set_fact:
users_dict: "{{ users_list|items2dict(key_name='hostname', value_name='username') }}"
psswd_dict: "{{ users_list|items2dict(key_name='hostname', value_name='password') }}"
run_once: true
gives
users_dict:
host-1: host-1_username
host-2: host-2_username
host-3: host-3_username
and
psswd_dict:
host-1: host-1_password
host-2: host-2_password
host-3: host-3_password
Use the dictionaries to select the hosts' specific users and passwords, e.g.
- debug:
msg: "Create user: {{ users_dict[inventory_hostname] }}
password: {{ psswd_dict[inventory_hostname] }}"
gives
TASK [debug] ***************************************************************
ok: [host-1] =>
msg: 'Create user: host-1_username password: host-1_password'
ok: [host-2] =>
msg: 'Create user: host-2_username password: host-2_password'
ok: [host-3] =>
msg: 'Create user: host-3_username password: host-3_password'
You can omit the inventory file and create a playbook completely driven by the data. Create dynamic group my_group in the first play and use it in the second one. The playbook below gives the same results
- name: Create dynamic group of the hosts from users_list
hosts: localhost
gather_facts: false
vars_files:
- list.yml
tasks:
- add_host:
name: "{{ item.hostname }}"
groups: my_group
loop: "{{ users_list }}"
- name: Create users
hosts: my_group
gather_facts: false
vars_files:
- list.yml
tasks:
- set_fact:
users_dict: "{{ users_list|items2dict(key_name='hostname', value_name='username') }}"
psswd_dict: "{{ users_list|items2dict(key_name='hostname', value_name='password') }}"
run_once: true
- debug:
var: users_dict
run_once: true
- debug:
var: psswd_dict
run_once: true
- debug:
msg: "Create user: {{ users_dict[inventory_hostname] }}
password: {{ psswd_dict[inventory_hostname] }}"

In Ansible how to execute a role while looping over an array in the playbook

I want to iterate over array and pass each array element value to role from playbook but it is not working in ansible, Can some one help
---
#play book
- name: create config for instance
hosts: all
vars:
LIST: [Asia, Americas, Artic, Antartic ,Oceania,Europe,Africa]
connection: local
roles:
- role: create_config
debug:
msg : "{{ item }}"
vars:
VENUE: "{{ item }}"
with_items:
- "{{ LIST }}"
## Role
- name: create directory structure
file:
path: "{{item}}"
state: directory
mode: 0755
with_items:
- "{{dest_folder}}/{{instance_name}}/{{VENUE}}"
I am getting below error
ansible-playbook -i inventory/AlgoTest_SP create_pkg_1.yml
PLAY [create config for instance] **************************************************************************************************************************************
TASK [Gathering Facts] ****************************************************************************************************************************************************
ok: [localhost]
TASK [create_config : create directory structure] *******************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "{{ item }}: 'item' is undefined"}
PLAY RECAP ****************************************************************************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
To be able to loop over roles, you need the include_role task, as in:
- name: create config for instance
hosts: localhost
vars:
LIST: [Asia, Americas, Artic, Antartic ,Oceania,Europe,Africa]
tasks:
- include_role:
name: create_config
vars:
VENUE: "{{ item }}"
with_items:
- "{{LIST}}"
cat roles/create_config/tasks/main.yml
- debug:
msg: "{{VENUE}}"
- name: create directory structure
file:
path: "{{item}}"
state: directory
mode: 0755
with_items:
- "{{inventory_hostname}}/{{VENUE}}"
Resulting in:
$ ansible-playbook 69045121.yml
PLAY [create config for instance] ********************************************************************************************************************************************************************************************************************************************************************************************
TASK [Gathering Facts] *******************************************************************************************************************************************************************************************************************************************************************************************************
ok: [localhost]
TASK [include_role : create_config] ******************************************************************************************************************************************************************************************************************************************************************************************
TASK [create_config : debug] *************************************************************************************************************************************************************************************************************************************************************************************************
ok: [localhost] => {
"msg": "Asia"
}
TASK [create_config : create directory structure] ****************************************************************************************************************************************************************************************************************************************************************************
changed: [localhost] => (item=localhost/Asia)
TASK [create_config : debug] *************************************************************************************************************************************************************************************************************************************************************************************************
ok: [localhost] => {
"msg": "Americas"
}
[...] and so on
As a final note, you could, and should, likely handle this differently. Also, you have clash in the item variable name from the outer (playbook) and inner (role) with_items, you can use loop_var to set a different looping varname.

ansible loop with items

I can get information for Individual Package Version like this
- name: Print zsh Version
debug:
msg: "{{ ansible_facts.packages['zsh'][0].version }}"
when: " 'zsh' in ansible_facts.packages"
I am trying to use a loop for a list, but I am unable to quote the {{item}}.
software: ['ksh','zsh','bash']
- name: Print Softwre Versions
debug:
msg: "{{ ansible_facts.packages['{{item}}'][0].version }}"
with_items: "{{ software }}"
I get the following error message
"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute '{{item}}'
How do I make this work ?
You don't need to quote it or put it in curly bracers, you are already in curly bracers:
- name: Print software versions
debug:
msg: "{{ ansible_facts.packages[item][0].version }}"
vars:
software:
- 'ksh'
- 'zsh'
- 'bash'
loop: "{{ software }}"
Fully working playbook:
- hosts: localhost
gather_facts: no
tasks:
- name: Gather package facts
package_facts:
manager: auto
- name: Print software versions
debug:
msg: "{{ ansible_facts.packages[item][0].version }}"
vars:
software:
- 'ksh'
- 'zsh'
- 'bash'
loop: "{{ software }}"
Gives this recap:
PLAY [localhost] ***************************************************************
TASK [Gather package facts] ****************************************************
ok: [localhost]
TASK [Print software versions] *************************************************
ok: [localhost] => (item=ksh) => {
"msg": "2020.0.0-5"
}
ok: [localhost] => (item=zsh) => {
"msg": "5.8-3ubuntu1"
}
ok: [localhost] => (item=bash) => {
"msg": "5.0-6ubuntu1"
}
PLAY RECAP *********************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
PS: try not to mix YAML and JSON notation, your software array is in JSON, while the rest of your playbook is in YAML.

How to do concurrent jsonrpc using gevent and requests in volttron

I am trying to do concurrent JSONRPC calls to remote agents in Volttron. And am using Volttron 5.1.0 (with gevent 1.1.2 & requests 2.11.1).
The code works as expected. However, from the log files, I notice that the requests are not run concurrently. I am not sure what I am missing.
I tried suggestions mentioned in how enable requests async mode? (i.e,, handling async part in the request, monkey patch, etc.,). But none work-out, either the solution is outdated or required modules not available in volttron env (I am a bit worried about version requirements).
Any suggestions or inputs would be of great help.
The relevant part of the agent code is as follows:
Agent Code
import gevent
import requests
url_roots = ['http://192.168.1.51:8080/', 'http://192.168.1.52:8080/']
jobs = [gevent.spawn(do_rpc, self._agent_id, url_root, 'pricepoint'
, get_json_params()
) for url_root in url_roots
]
gevent.joinall(jobs, timeout=11)
def do_rpc(id, url_root, method, params=None):
result = False
json_package = {
'jsonrpc': '2.0',
'id': id,
'method':method,
}
json_package['params'] = params
response = requests.post(url_root, data=json.dumps(json_package), timeout=10)
if response.ok:
if 'result' in response.json().keys():
success = response.json()['result']
if success:
result = True
return result
Log
2020-02-19 21:12:15,913 (xyzagent-0.4 28079) xyz.ispace_msg_utils DEBUG: validate_bustopic_msg()
2020-02-19 21:12:15,918 (xyzagent-0.4 28079) xyz.agent DEBUG: New price point (pp) msg on the local-bus, topic: building/pricepoint ...
2020-02-19 21:12:15,919 (xyzagent-0.4 28079) xyz.agent DEBUG: ***** New bid price point from local: 0.20 price_id: 2218566
2020-02-19 21:12:15,931 (xyzagent-0.4 28079) xyz.agent DEBUG: post_ds_new_pp()...
2020-02-19 21:12:15,932 (xyzagent-0.4 28079) xyz.agent DEBUG: us pp messages count: 1...
2020-02-19 21:12:15,933 (xyzagent-0.4 28079) xyz.agent DEBUG: processing pp msg 1/1, price id: 2218566
2020-02-19 21:12:15,938 (xyzagent-0.4 28079) xyz.agent DEBUG: new ttl: 28.
2020-02-19 21:12:15,942 (xyzagent-0.4 28079) xyz.agent DEBUG: _ds_rpc_1_to_m()...
2020-02-19 21:12:15,953 (xyzagent-0.4 28079) requests.packages.urllib3.connectionpool INFO: Starting new HTTP connection (1): 192.168.1.51
2020-02-19 21:12:16,079 () volttron.platform.web DEBUG: {'jsonrpc': '2.0', 'id': '2503402', 'result': True}
2020-02-19 21:12:16,080 () volttron.platform.web DEBUG: res is a dictionary.
2020-02-19 21:12:16,238 (xyzagent-0.4 28079) requests.packages.urllib3.connectionpool DEBUG: "POST /bridge HTTP/1.1" 200 53
2020-02-19 21:12:16,245 (xyzagent-0.4 28079) requests.packages.urllib3.connectionpool INFO: Starting new HTTP connection (1): 192.168.1.52
2020-02-19 21:12:16,526 (xyzagent-0.4 28079) requests.packages.urllib3.connectionpool DEBUG: "POST /bridge HTTP/1.1" 200 53
2020-02-19 21:12:16,529 (xyzagent-0.4 28079) xyz.agent DEBUG: post pp to ds (ZoneController-51), result: success!!!
2020-02-19 21:12:16,529 (xyzagent-0.4 28079) xyz.agent DEBUG: post pp to ds (ZoneController-52), result: success!!!
2020-02-19 21:12:16,530 (xyzagent-0.4 28079) xyz.agent DEBUG: _ds_rpc_1_to_m()...done
2020-02-19 21:12:16,530 (xyzagent-0.4 28079) xyz.agent DEBUG: msg successfully posted to all ds, removing it from the queue
2020-02-19 21:12:16,530 (xyzagent-0.4 28079) xyz.agent DEBUG: reset the retry counter for success ds msg
2020-02-19 21:12:16,530 (xyzagent-0.4 28079) xyz.agent DEBUG: post_ds_new_pp()...done
The below changes did the trick. Please note that just monkey.patch_all() breaks volttron. Need to set flag thread=False.
Agent Code
import gevent
from gevent import monkey
monkey.patch_all(thread=False, select=False)
import requests
Logs
2020-02-20 14:36:29,981 (xyzagent-0.4 8657) xyz.agent DEBUG: _ds_rpc_1_to_m()...
2020-02-20 14:36:29,987 (xyzagent-0.4 8657) requests.packages.urllib3.connectionpool INFO: Starting new HTTP connection (1): 192.168.1.51
2020-02-20 14:36:29,992 (xyzagent-0.4 8657) requests.packages.urllib3.connectionpool INFO: Starting new HTTP connection (1): 192.168.1.52
2020-02-20 14:36:30,260 (xyzagent-0.4 8657) requests.packages.urllib3.connectionpool DEBUG: "POST /bridge HTTP/1.1" 200 53
2020-02-20 14:36:30,333 (xyzagent-0.4 8657) requests.packages.urllib3.connectionpool DEBUG: "POST /bridge HTTP/1.1" 200 53
2020-02-20 14:36:30,341 (xyzagent-0.4 8657) xyz.agent DEBUG: post pp to ds (ZoneController-51), result: success!!!
2020-02-20 14:36:30,342 (xyzagent-0.4 8657) xyz.agent DEBUG: post pp to ds (ZoneController-52), result: success!!!
2020-02-20 14:36:30,344 (xyzagent-0.4 8657) xyz.agent DEBUG: _ds_rpc_1_to_m()...done

Resources