Update vaulted shopper on bluesnap - field

I tried to update a vaulted shopper "sandbox" but it return this error:
array(1) { ["message"]=> array(2) { [0]=> array(2) { ["errorName"]=> string(26) "VALIDATION_GENERAL_FAILURE" ["description"]=> string(76) "Seller 636*** encountered a problem updating shopper due to incorrect input." } [1]=> array(4) { ["errorName"]=> string(26) "VALIDATION_GENERAL_FAILURE" ["code"]=> string(5) "10001" ["description"]=> string(43) "'Card Number' should be a valid Credit Card" ["invalidProperty"]=> array(1) { ["name"]=> string(10) "cardNumber" } } } }} }
This is data I am sending
$data=array(
"paymentSources"=> array(
"creditCardInfo" => [array(
"pfToken"=> $Token
)]),
"firstName"=>"name of shopper",
"lastName"=> "last name of shopper",
"vaultedShopperId"=> 23074901
);

This might mean that your Hosted Payment Fields token (pfToken) has not been associated with a credit card.
I encountered this same error while trying to write an integration test. See this question.

Related

Slack bolt ack() with errors

I am trying to implement email validation in Slack modal.
documentation is here.
https://slack.dev/bolt-js/concepts#acknowledge
If I enter valid email, it works well.
And If I enter invalid email, it occurs error.
I believe that it occurs because of ack() with errors.
So, I want to ask. What is the meaning of "name": "email_address", in below code?
// Regex to determine if this is a valid email
let isEmail = /^[\w-\.]+#([\w-]+\.)+[\w-]{2,4}$/
// This uses a constraint object to listen for dialog submissions with a callback_id of ticket_submit
app.action({ callback_id: 'ticket_submit' }, async ({ action, ack }) => {
// it’s a valid email, accept the submission
if (isEmail.test(action.submission.email)) {
await ack();
} else {
// if it isn’t a valid email, acknowledge with an error
await ack({
errors: [{
"name": "email_address",
"error": "Sorry, this isn’t a valid email"
}]
});
}
});
I found the solution.
block_1 is block_id.
await ack({
response_action: 'errors',
errors: {
block_1: 'Sorry, this isn’t a valid email',
},
});

Twilio Autopilot Custom and Dynamic on_failure message on validation failure

In Twilio Autopilot, I want to validate user input. In this case order_number.
Assume order_number can be anything between 8-12 characters. I have a webhook for validation.
I want to let the user know why the validation failed if they entered an order number that was lt 8 or gt 12 characters, or if the order_number doesn't exists in our db.
My webhook returns { valid: true } or { valid: false } based on success or failure of validation.
My goal is to customize my failure message based on what validation failed. Is there a seamless way to achieve that ?
{
collect: {
name: 'collect_order_number',
questions: [
{
question: 'Can I have your order number ?',
name: 'order_number',
type: 'Twilio.ALPHANUMERIC',
validate: {
on_failure: {
messages: [ # How to customize this based on webhook validation ?
{ say: 'Order number too short' },
{ say: 'Order number too long' },
{ say: 'Could not find order number' },
],
repeat_question: true,
},
webhook: {
url: `https://<www.domain.com>/autopilot/validate_field`,
method: 'POST',
},
on_success: {
say: 'Great! got your order number',
}
}
},
{ ... more questions }
]
}
}

JIRA API after POST returns { errorMessages: [ 'Internal server error' ], errors: {} }

I am trying to create a new issue utilizing the JIRA REST API and whenever I try, I get back the following generic error:
{ errorMessages: [ 'Internal server error' ], errors: {} }
I can successfully GET from the API, and the credentials I'm connecting with have full Admin access to JIRA (so it's not an Auth issue), but I get this error every time with POST. Below is a snippet of the JSON data I'm sending. Am I missing anything obvious?
Below is my JavaScript code. Note I'm using jira-connector from npm. (Real domain replaced with mydomain for this sample code)
const JiraClient = require('jira-connector');
const dotenv = require('dotenv').config();
function createNewIssue(fields) {
const encoded = process.env.JIRA_ENCODED_PW;
const jira = new JiraClient({
host: 'mydomain.atlassian.net',
basic_auth: {
base64: encoded
}
});
return new Promise((resolve, reject) => {
jira.issue.createIssue(fields, (error, issue) => {
if (error) {
console.log(error);
reject(error);
} else {
console.log(issue);
resolve(encoded);
}
});
})
}
Below is the JSON that's being passed into fields in the JS above. Note customfield_17300 is a radio button, and customfield_17300 is a multi-select box. For both cases, I've tried using the "id" and also the actual string "name" value. All IDs below were taken straight from a API GET of the same issue in question:
{
"fields": {
"project": {
"id": "13400"
},
"summary": "TEST API TICKET - 01",
"issuetype": {
"id": "11701"
},
"customfield_14804": { "id": "13716" },
"customfield_14607": "Hardware",
"customfield_17300": [
{
"id": "18322"
}
] ,
"customfield_16301": "Customer PO",
"customfield_14800": "LA, California",
"customfield_16302": "FEDEX 234982347g"
}
}
sigh I figured it out... other posts that said this cryptic error was due to a malformed JSON were correct.
In my route, I passed fields as coming from req.body.fields which actually dove into the fields values instead of passing it straight through. This made it so that when the JSON was sent to JIRA the fields outer wrapper was missing. I changed my route to pass along req.body instead of req.body.fields and all was well.
...that was a fun 4 hours...

How do I filter videos from YouTube Data API v3 that are blocked on copyright grounds

Here is my code.
$videosResponse = $youtube->videos->listVideos('status, fileDetails, snippet, recordingDetails, topicDetails', array(
'id' => $id,
'maxResults' => 1,
'part' => 'status,snippet',
));
Here is Response
object(Google_Service_YouTube_VideoListResponse)#73 (16) {
["collection_key":protected]=>
string(5) "items"
["internal_gapi_mappings":protected]=>
array(0) {
}
["etag"]=>
string(57) ""fpJ9onbY0Rl_LqYLG6rOCJ9h9N8/lnLk97dQDMUpWh4EJfvVHiKXvG8""
["eventId"]=>
NULL
["itemsType":protected]=>
string(28) "Google_Service_YouTube_Video"
["itemsDataType":protected]=>
string(5) "array"
["kind"]=>
string(25) "youtube#videoListResponse"
["nextPageToken"]=>
NULL
["pageInfoType":protected]=>
string(31) "Google_Service_YouTube_PageInfo"
["pageInfoDataType":protected]=>
string(0) ""
["prevPageToken"]=>
NULL
["tokenPaginationType":protected]=>
string(38) "Google_Service_YouTube_TokenPagination"
["tokenPaginationDataType":protected]=>
string(0) ""
["visitorId"]=>
NULL
["modelData":protected]=>
array(2) {
["pageInfo"]=>
array(2) {
["totalResults"]=>
int(1)
["resultsPerPage"]=>
int(1)
}
["items"]=>
array(1) {
[0]=>
array(5) {
["kind"]=>
string(13) "youtube#video"
["etag"]=>
string(57) ""fpJ9onbY0Rl_LqYLG6rOCJ9h9N8/NCacXkm79gLd-LDp1PS5m7Z_FFc""
["id"]=>
string(11) "bdzxVW3zlZ0"
["snippet"]=>
array(10) {
["publishedAt"]=>
string(24) "2011-11-10T07:13:44.000Z"
["channelId"]=>
string(24) "UColEueTkpUJjnDlaO-P14DQ"
["title"]=>
string(32) "Leap of Faith Movie_Steve Martin"
["description"]=>
string(82) "I created this video with the YouTube Video Editor (http://www.youtube.com/editor)"
["thumbnails"]=>
array(4) {
["default"]=>
array(3) {
["url"]=>
string(46) "https://i.ytimg.com/vi/bdzxVW3zlZ0/default.jpg"
["width"]=>
int(120)
["height"]=>
int(90)
}
["medium"]=>
array(3) {
["url"]=>
string(48) "https://i.ytimg.com/vi/bdzxVW3zlZ0/mqdefault.jpg"
["width"]=>
int(320)
["height"]=>
int(180)
}
["high"]=>
array(3) {
["url"]=>
string(48) "https://i.ytimg.com/vi/bdzxVW3zlZ0/hqdefault.jpg"
["width"]=>
int(480)
["height"]=>
int(360)
}
["standard"]=>
array(3) {
["url"]=>
string(48) "https://i.ytimg.com/vi/bdzxVW3zlZ0/sddefault.jpg"
["width"]=>
int(640)
["height"]=>
int(480)
}
}
["channelTitle"]=>
string(10) "nenbanogon"
["tags"]=>
array(1) {
[0]=>
string(14) "YouTube editor"
}
["categoryId"]=>
string(2) "24"
["liveBroadcastContent"]=>
string(4) "none"
["localized"]=>
array(2) {
["title"]=>
string(32) "Leap of Faith Movie_Steve Martin"
["description"]=>
string(82) "I created this video with the YouTube Video Editor (http://www.youtube.com/editor)"
}
}
["status"]=>
array(5) {
["uploadStatus"]=>
string(9) "processed"
["privacyStatus"]=>
string(6) "public"
["license"]=>
string(7) "youtube"
["embeddable"]=>
bool(true)
["publicStatsViewable"]=>
bool(true)
}
}
}
}
["processed":protected]=>
array(0) {
}
}
In response object there is a 'status' array where I can filter private and not embeddable videos
["status"]=>
array(5) {
["uploadStatus"]=>
string(9) "processed"
["privacyStatus"]=>
string(6) "public"
["license"]=>
string(7) "youtube"
["embeddable"]=>
bool(true)
["publicStatsViewable"]=>
bool(true)
}
But I can't filter videos which are blocked on copyright grounds.
Here is similar question How do I filter videos from YouTube Data API v3
You can filter on regionRestriction property.
Please try to use safeSearch.
$videosResponse = $youtube->videos->listVideos('status, fileDetails, snippet, recordingDetails, topicDetails', array(
'id' => $id,
'maxResults' => 1,
'part' => 'status,snippet',
'safeSearch' => 'strict',
));

Static API docs with source2swagger

source2swagger generates a swagger spec with all apis in one json file. Can swagger-ui actually use that? When I explore the generated json file with swagger-ui, it tries to read the api descriptions from their paths in the spec, instead of using the descriptions/operations right there in the single json file.
Swagger-UI will handle putting all the json in one file. I'm not sure yet if there can be multiple top-level resource listings though.
Here's a working example:
{"basePath":"http://localhost:3001/", "resourcePath":"/", "swaggerVersion":"1.1", "apiVersion":"1.0", "apis":[
{
"path":"/pay",
"format":"json",
"description":"Create a transaction with the given amount and token.",
"operations":[
{
"httpMethod":"GET",
"tags":["production"],
"nickname":"pay",
"deprecated":false,
"summary":"Create a transaction with the given amount and token.",
"parameters":[
{
"name":"token",
"description":"The token representing the pay card",
"dataType":"string",
"allowMultiple":false,
"required":true,
"paramType":"query"
},
{
"name":"amount",
"description":"The amount to pay",
"dataType":"string",
"allowMultiple":false,
"required":true,
"paramType":"query"
}
]
}
]
},
{
"path":"/customer",
"format":"json",
"description":"Create an HTML form for adding a customer.",
"operations":[
{
"httpMethod":"GET",
"tags":["production"],
"nickname":"createCustomerForm",
"deprecated":false,
"summary":"Create an HTML form for adding a customer.",
"parameters":[
{
"name":"customerId",
"description":"Your customer id",
"dataType":"string",
"allowMultiple":false,
"required":true,
"paramType":"query"
}
]
}
]
},
{
"path":"/customer/{customerId}",
"format":"json",
"description":"Delete the customer info for given id.",
"operations":[
{
"httpMethod":"DELETE",
"tags":["production"],
"nickname":"deleteCustomer",
"deprecated":false,
"summary":"Delete the customer info for given id.",
"parameters":[
{
"name":"customerId",
"description":"the customer id to delete",
"dataType":"string",
"allowMultiple":false,
"required":true,
"paramType":"path"
}
]
}
]
},
{
"path":"/card",
"format":"json",
"description":"Create an HTML form for adding a credit card.",
"operations":[
{
"httpMethod":"GET",
"tags":["production"],
"nickname":"createCardForm",
"deprecated":false,
"summary":"Create an HTML form for the given customer to add a credit card.",
"parameters":[
{
"name":"customerId",
"description":"Your customer id",
"dataType":"string",
"allowMultiple":false,
"required":true,
"paramType":"query"
}
]
}
]
},
{
"path":"/card/{token}",
"format":"json",
"description":"Delete a card record by token.",
"operations":[
{
"httpMethod":"DELETE",
"tags":["production"],
"nickname":"deleteCard",
"deprecated":false,
"summary":"Delete the card info for given token.",
"parameters":[
{
"name":"token",
"description":"the token to delete",
"dataType":"string",
"allowMultiple":false,
"required":true,
"paramType":"path"
}
]
}
]
}
]}

Resources