I'm using Laravel with a personal integration of the Stripe API (using Stripe API from github).
Everything was working fine until i switched to manual confirmation mode, and now i'm receiving the following error:
This PaymentIntent pi_**************uVme cannot be confirmed using your publishable key because its `confirmation_method` is set to `manual`. Please use your secret key instead, or create a PaymentIntent with `confirmation_method` set to `automatic`.
Any idea?
This is my current code (which is not working):
Stripe::setApiKey(config('services.stripe.secret')); // config('services.stripe.secret') returns "sk_test_gFi********************nMepv"
$paymentIntent = PaymentIntent::create([
'amount' => $orderSession->order_total * 100,
'currency' => 'eur',
'description' => "Pagamento di ".(price($orderSession->order_total))."€ a ".$orderSession->user->user_name." in data ".(now()->format("d-m-Y H:m:s")),
'metadata' => [
'subtotal' => $orderSession->order_subtotal,
'user'=> "{$orderSession->user_id} : {$orderSession->user->user_email}",
'wines'=> substr(
$orderSession->wines()->select('wine_id', 'quantity')->get()->each(
function($el){
$el->q= $el->quantity;
$el->id = $el->wine_id;
unset($el->wine_id, $el->pivot, $el->quantity);
}
)->toJson(),
0,
500
),
],
'confirmation_method' => 'manual',
]);
JS frontend:
<button class="myButtonPayment" id="card-button" type="button" data-secret="{!!$stripePaymentIntent->client_secret!!}" ><span>Pay</span></button>
...
<script>
cardButton.addEventListener('click', function() {
if(!document.getElementById('order_telephone_number').value || /^\+?[0-9 ]{6,20}$/.test(document.getElementById('order_telephone_number').value)){
stripe.handleCardPayment(
clientSecret, cardElement, {
payment_method_data: {
billing_details: {name: cardholderName.value}
}
}
).then(function (result) {
if (result.error) {
console.log(result.error);
} else {
document.getElementById('myForm').submit();
}
});
}
});
</script>
The error is occuring when I click on the button (so is not related to the part of the code where I confirm the payment)
The error serialization is the following:
{
"type":"invalid_request_error",
"code":"payment_intent_invalid_parameter",
"doc_url":"https://stripe.com/docs/error-codes/payment-intent-invalid-parameter",
"message":"This PaymentIntent pi_1H3TQ*********T00uVme cannot be confirmed using your publishable key because its `confirmation_method` is set to `manual`. Please use your secret key instead, or create a PaymentIntent with `confirmation_method` set to `automatic`.",
"payment_intent":{
"id":"pi_1H3***********uVme",
"object":"payment_intent",
"amount":2060,
"canceled_at":null,
"cancellation_reason":null,
"capture_method":"automatic",
"client_secret":"pi_1H3TQ********T00uVme_secret_2T7Di*********nkoaceKx",
"confirmation_method":"manual",
"created":1594415166,
"currency":"eur",
"description":"....",
"last_payment_error":null,
"livemode":false,
"next_action":null,
"payment_method":null,
"payment_method_types":[
"card"
],
"receipt_email":null,
"setup_future_usage":null,
"shipping":null,
"source":null,
"status":"requires_payment_method"
}
}
Manual confirmation for Payment Intents is for server-side confirmation only (i.e. with your secret API key, not your publishable key). Setting confirmation_method to manual on a Payment Intent is the same as saying, "this Payment Intent can only be confirmed server-side".
You can read more about this in in the finalize payments on the server guide in Stripe's documentation.
Related
Inspired by the Supabase docs, I have this code in a React Native app:
useEffect(() => {
if (session?.user?.id === null) return
const channel = supabase
.channel('value-db-changes', { selfBroadcast: true })
.on(
'postgres_changes',
{
event: 'UPDATE',
schema: 'public',
table: 'messages',
filter: `user_id=${session?.user?.id}`
},
(payload) => console.log('Supabase change', payload)
)
?.subscribe()
}, [session?.user?.id])
VSCode warns me that Property 'subscribe' does not exist on type 'never' and the console.log never shows as I edit rows in my database.
You might be using the old version of Supabase but trying v2 syntax.
Supabase v1 documentation for realtime:
https://supabase.com/docs/reference/javascript/subscribe
As per the latest update for v2 - https://supabase.com/blog/supabase-js-v2,
// v2
supabaseClient
.channel('any_string_you_want')
.on(
'postgres_changes',
{
event: 'INSERT',
schema: 'public',
table: 'movies',
},
(payload) => {
console.log(payload)
}
)
.subscribe()
// v1
supabase
.from('movies')
.on('INSERT', (payload) => {
console.log(payload)
})
.subscribe()
I had similar issues with this code, but installing the right version with v1 syntax worked,
npm uninstall #supabase/supabase-js#rc
npm uninstall #supabase/supabase-js
npm install #supabase/supabase-js
Hi 👋🏼 from comparing your code snippet with the supabase docs, it should generally work.
I'm assuming your listener isn't triggered because one of those:
filter is too specific and your changes don't trigger it: e.g. are you editing the messages table with the same user.id that you're listening to?
the selfBroadcast option isn't in the Supabase docs and quick internet search didn't bring it up as well
As a first step I would set up the broadest subscription and test if this one is triggered and what's in the payload. Then step by step create the filter to only listen to the events that are of interest.
const mySubscription = supabase
.from('*')
.on('*', payload => {
console.log('Change received!', payload)
})
.subscribe()
I'm having problems with validator on Route.resource(). The validator is not been applied and when I run the command "adonis route:list" the av:TrainingPlan and Workout validators are not being listed. You can see that my other validators are working on single endpoint verb like "Route.post" on /users, /sessions/ and /passwords. On app.js under start folder I checked that the register was made too and all validator was generated by adonis cli.
My routes file was made based on documentation:
Route.group(() => {
Route.post('files', 'FileController.store')
Route
.resource('/training-plans', 'TrainingPlanController')
.apiOnly()
.validator(new Map([
[['training-plans.store'], ['TrainingPlan']]
]))
Route
.resource('/workouts', 'WorkoutController')
.apiOnly()
.validator(new Map([
[['workouts.store'], ['Workout']]
]))
}).middleware(['auth'])
TrainingPlan Validator:
'use strict'
class TrainingPlan {
get validateAll () {
return true
}
get rules () {
return {
title: 'required',
description: 'required',
start_date: `date|before:${new Date()}`,
end_date: `date|before:${new Date()}`
}
}
}
module.exports = TrainingPlan
What I'm missing out?
adonis route:list command result
The problem was resolved removing / before /workouts and /training-plans route.
I did not tested putting / before workouts.store and training-plans.store inside Map validator.
I need to test send SMS to mobile I get Credentials are required to create a Client error for My Code Here
.env
TWILIO_ACCOUNT_SID=AC15...................
TWILIO_AUTH_TOKEN=c3...................
TWILIO_NUMBER=+1111...
Config\App
'twilio' => [
'TWILIO_AUTH_TOKEN' => env('TWILIO_AUTH_TOKEN'),
'TWILIO_ACCOUNT_SID' => env('TWILIO_ACCOUNT_SID'),
'TWILIO_NUMBER' => env('TWILIO_NUMBER')
],
Controller
$accountSid = env('TWILIO_ACCOUNT_SID');
$authToken = env('TWILIO_AUTH_TOKEN');
$twilioNumber = env('TWILIO_NUMBER');
$client = new Client($accountSid, $authToken);
try {
$client->messages->create(
'0020109.....',
[
"body" => 'test',
"from" => $twilioNumber
// On US phone numbers, you could send an image as well!
// 'mediaUrl' => $imageUrl
]
);
Log::info('Message sent to ' . $twilioNumber);
} catch (TwilioException $e) {
Log::error(
'Could not send SMS notification.' .
' Twilio replied with: ' . $e
);
}
Twilio developer evangelist here.
A quick read over the environment config for Laravel suggests to me that you can use the env method within your config files, as you are doing, but it's not necessarily available in application code. Since you are committing your environment variables to the config object, I think you need to use the config method instead.
$accountSid = config('TWILIO_ACCOUNT_SID');
$authToken = config('TWILIO_AUTH_TOKEN');
$twilioNumber = config('TWILIO_NUMBER');
Let me know if that helps at all.
I'm trying to send an email with symfony 3, swiftmailer and twig.
I'm doing a form with formbuilder and when someone click on the submit button, it send the mail. I don't have an error, only a "1 spooled message".
What I've tried : I did : php bin/console swiftmailer:email:send
It returns : [OK] 1 emails were successfully sent. (also here i've no mail).
In my two boxes I have allowed less restrictions for connexions.
My code looks like :
For the controller :
/**
* #Route("testmail", name="testmail")
*/
public function testmail(Request $request)
{
$societe = null;
$form = $this->createFormBuilder()
->add('Societe', TextType::class, array('label' => 'Société'), array('constraints' => array(new NotBlank(array()),
new Length(array('min' => 2,
'max' => 25)))))
-> add('send',SubmitType::class, array('label' => 'Cotation'))
->getForm();
$form->handleRequest($request);
if ($form->isValid()) {
if ($request->isMethod('POST')) {
$societe = $form["Societe"]->getData();
$message = \Swift_Message::newInstance()
->setSubject('Etude Financiere')
->setFrom('wolffvianney#gmail.com')
->setTo('vianney.wolff#yahoo.fr')
->setCharset('utf-8')
->setContentType('text/html')
->setBody($this->render('#gkeep/Finance/email.html.twig', array('Societe' => $societe)));
$this->get('mailer')->send($message);
}
}
return $this->render('#gkeep/Finance/finance.html.twig', array('form' =>$form->createView(),
'Societe'=>$societe));
}
the config.yml :
swiftmailer:
transport: '%mailer_transport%'
host: '%mailer_host%'
username: '%mailer_user%'
password: '%mailer_password%'
spool: { type: memory }
the parameters.yml :
mailer_transport: mail
mailer_host: smtp.gmail.com
mailer_user: wolffvianney#gmail.com
mailer_password: *mypasswordforwolffvianney#gmail.com*
secret: thesecret
the Finance/email.html.twig
<html>
hi
société : {{ Societe }}
</html>
if anyone has any advices or help, I can send other files if needed. I don't understand what is wrong, thanks for advance. (I also tried to delete the line spool{type:memory
it says then that 1 email has been sent but here also, I don't receive any mails.
Vianney
Try
php bin/console swiftmailer:spool:send --env={your_env}
I've been reading the docs for the Google Calendar API and the google-api-ruby-client library, but I'm having a lot of trouble understanding them.
I have a Rails application that has a front end that lets users create objects called Events, and it saves them in a database on my server. What I would like is, after these Events are saved in the database, I want to call the Google Calendar API to create an event on a Google Calendar (that the server created, and only the server has access to modify that calendar).
I'm having lots of issues figuring out how to authenticate with the API using the ruby library. It doesn't make sense for me to use OAuth2 because I don't need to authorize anything with the user because I'm not interested in their data. I looked into Service Accounts (http://code.google.com/p/google-api-ruby-client/wiki/ServiceAccounts), but it looks like Google Calendars is not supported by Service Accounts.
Anyone have any ideas? This is the code I was experimenting with (using Service Accounts):
#client = Google::APIClient.new(:key => 'my_api_key')
path_to_key_file = '/somepath/aaaaaa-privatekey.p12'
passphrase = 'my_pass_phrase'
key = Google::APIClient::PKCS12.load_key(path_to_key_file, passphrase)
asserter = Google::APIClient::JWTAsserter.new(
'blah_blah#developer.gserviceaccount.com',
'https://www.googleapis.com/auth/calendar',
key)
# To request an access token, call authorize:
#client.authorization = asserter.authorize()
calendar = #client.discovered_api('calendar', 'v3')
event = {
'summary' => 'Appointment',
'location' => 'Somewhere',
'start' => {
'dateTime' => '2012-06-03T10:00:00.000-07:00'
},
'end' => {
'dateTime' => '2012-06-03T10:25:00.000-07:00'
},
'attendees' => [
{
'email' => 'attendeeEmail'
},
#...
]
}
result = #client.execute!(:api_method => calendar.events.insert,
:parameters => {'calendarId' => 'primary'},
:body => JSON.dump(event),
:headers => {'Content-Type' => 'application/json'})
Then of course I get this error message: Google::APIClient::ClientError (The user must be signed up for Google Calendar.) because the Service Account does not support Google Calendars.
I think you'll still need a real google user to host the calendar instance. But once you've got the calendar created under your identity, you can share it with the service account. In the sharing settings for the calendar, just use the email address of the service account (my service account ends with #developer.gserviceaccount.com). With the right sharing permissions, your service account can create/alter the event info, and not mess with your specific identity. From there, you can share the calendar with more people (or public) for their consumption of the mirrored events.
The other hitch I've run into is that it seems you can only authorize() the service account once per expiration period. You'll have to save the token you get and reuse it for the next hour, and then fetch a new one.
I don't know anything about Ruby. But it seems like understanding the underlying REST queries would help debug your problem. I've documented them here: http://www.tqis.com/eloquency/googlecalendar.htm
I was having trouble with this too and finally got a handle on it. The bottom line is that Google Calendar API v3 requires OAuth and you need to setup an App/Project through the Google Developer Console and then request OAuth permission on the target Google account. Once authorization is granted, you'll want to save the refresh token and use it on subsequent calls to get new access tokens (which expire!). I wrote a detailed blog post about this here: http://www.geekytidbits.com/google-calendar-api-from-ruby/ and this is my example script that should hopefully help you understand the flow:
#gem install 'google-api-client'
require 'google/api_client'
#Setup auth client
client_secrets = Google::APIClient::ClientSecrets.load #client_secrets.json must be present in current directory!
auth_client = client_secrets.to_authorization
auth_client.update!(
:scope => 'https://www.googleapis.com/auth/calendar',
:access_type => "offline", #will make refresh_token available
:approval_prompt =>'force',
:redirect_uri => 'http://www.myauthorizedredirecturl.com'
)
refresh_token_available = File.exist?('refresh_token.txt')
if !refresh_token_available
#OAuth URL - this is the url that will prompt a Google Account owner to give access to this app.
puts "Navigate browser to: '#{auth_client.authorization_uri.to_s}' and copy/paste auth code after redirect."
#Once the authorization_uri (above) is followed and authorization is given, a redirect will be made
#to http://www.myauthorizedredirecturl.com (defined above) and include the auth code in the request url.
print "Auth code: "
auth_client.code = gets
else
#If authorization has already been given and refresh token saved previously, simply set the refresh code here.
auth_client.refresh_token = File.read('refresh_token.txt')
end
#Now, get our access token which is what we will need to work with the API.
auth_client.fetch_access_token!
if !refresh_token_available
#Save refresh_token for next time
#Note: auth_client.refresh_token is only available the first time after OAuth permission is granted.
#If you need it again, the Google Account owner would have deauthorize your app and you would have to request access again.
#Therefore, it is important that the refresh token is saved after authenticating the first time!
File.open('refresh_token.txt', 'w') { |file| file.write(auth_client.refresh_token) }
refresh_token_available = true
end
api_client = Google::APIClient.new
cal = api_client.discovered_api('calendar', 'v3')
#Get Event List
puts "Getting list of events..."
list = api_client.execute(:api_method => cal.events.list,
:authorization => auth_client,
:parameters => {
'maxResults' => 20,
'timeMin' => '2014-06-18T03:12:24-00:00',
'q' => 'Meeting',
'calendarId' => 'primary'})
puts "Fetched #{list.data.items.count} events..."
#Update Event
puts "Updating first event from list..."
update_event = list.data.items[0]
update_event.description = "Updated Description here"
result = api_client.execute(:api_method => cal.events.update,
:authorization => auth_client,
:parameters => { 'calendarId' => 'primary', 'eventId' => update_event.id},
:headers => {'Content-Type' => 'application/json'},
:body_object => update_event)
puts "Done with update."
#Add New Event
puts "Inserting new event..."
new_event = cal.events.insert.request_schema.new
new_event.start = { 'date' => '2015-01-01' } #All day event
new_event.end = { 'date' => '2015-01-01' }
new_event.description = "Description here"
new_event.summary = "Summary here"
result = api_client.execute(:api_method => cal.events.insert,
:authorization => auth_client,
:parameters => { 'calendarId' => 'primary'},
:headers => {'Content-Type' => 'application/json'},
:body_object => new_event)
puts "Done with insert."