Accessing Jquery Key/Values in Python - javascript

I have a simple form and I need to access the key/value and properties of the jquery code for the form. Also when I try to create a customer in my view with request.form['stripeToken'] it gives error mentioned at end of question. I need to access following fields in Jquery script with key/value attributes:
$("#stripeToken").val(token.id);
$("#stripeEmail").val(token.email);
Following is the code:
Jquery Code:
<form id="myForm" action="/yearly" method="POST">
<input type="hidden" id="stripeToken" name="stripeToken" />
<input type="hidden" id="stripeEmail" name="stripeEmail" />
<button id="customButton">Purchase</button>
</form>
<script type="text/javascript">
var handler = StripeCheckout.configure({
key: 'pk_test_YgHVTCLIMQLW4NV6ntnJPAXs',
image: 'https://stripe.com/img/documentation/checkout/marketplace.png',
locale: 'auto',
token: function (token) {
$("#stripeToken").val(token.id);
$("#stripeEmail").val(token.email);
$("#myForm").submit();
}
});
$('#customButton12').on('click', function (e) {
handler.open({
name: 'Yearly',
description: 'Yearly Charge',
amount: 9500
});
e.preventDefault();
});
$(window).on('popstate', function () {
handler.close();
});
</script>
Following is the view:
#app.route('/yearly', methods=['GET', 'POST'])
def yearly_charge():
key = stripe_keys['publishable_key']
data = get_profile_data(session['auth_token'])
profile_data = data['Student']
student_id = profile_data.id
student = get_profile_data(session['auth_token'])['StudentProfile']
pkg = Package.query.filter_by(student_id=profile_data.id).first()
# customer
stripe_token = request.form['stripeToken']
email = request.form['stripeEmail']
if not pkg:
try:
customer = stripe.Customer.create(
email=email,
source=request.form['stripeToken']
)
print request.form
subscription = stripe.Subscription.create(
customer=customer.id,
plan="yearly",
)
student_id = profile_data.id
student.stripe_customer_id = customer.id
student.stripe_subscription_id = subscription.id
package = Package(
student_id=student_id,
stripe_id = customer.id,
student_email=request.form['stripeEmail'],
is_active=True,
package_type='yearly',
subscription_id=subscription.id
)
dbase.session.add(package)
dbase.session.commit()
except stripe.error.CardError as e:
# The card has been declined
body = e.json_body
err = body['error']
flash("You've successfylly subscribed for annual package.")
return redirect(url_for('new_template', key=key))
Error:
stripe.error.InvalidRequestError
InvalidRequestError: Request req_AMbjoYEtQR1d6Y: Invalid source object: must be a dictionary or a non-empty string. See API docs at https://stripe.com/docs'

It seems you are trying to implement custom button for stripe. There is an easy way instead of going to write all the code if you don't know how to communicate between python and js.
<form action='/yoururl' method='post'>
<script src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="{{ key }}"
data-description="Your Description"
data-amount="500"
data-locale="auto"></script>
<input type="submit" value='Subscribe' class='btn' style='height:33px;width:50%;color:white;'>
</form>
<script>
document.getElementsByClassName("stripe-button-el")[0].style.display = 'none';
</script>
What actually happened in the code is it hides the default stripe button. So then any input button will work for you inside tag. You can use multiple buttons such as if you have another button you can use different price or other variables and just change the script like below:
<script>
document.getElementsByClassName("stripe-button-el")[1].style.display = 'none';
</script>
If there is a third button you can do it like:
<script>
document.getElementsByClassName("stripe-button-el")[2].style.display = 'none';
</script>

Related

How can I add a JavaScript event to my Django HTML template?

My current logout is GET, I just redirect the user to /auth/logout
However, I’ve discovered that this is unsafe and I trying to add a post to this redirection. By the way, my login is using django-allauth, so I am looking to use this concept here too. But, I need to do it with JavaScript because my front end is written in Vue.js.
https://django-allauth.readthedocs.io/en/latest/views.html#logout-account-logout
This is my javascript file where I use too much vue:
let userNavigation = [
{ name: 'Account', href: '/account/'},
{ name: 'Logout', href: '/auth/logout'}
]
This is my HTML using vue
const menu =
`
<MenuItems>
<MenuItem v-for="item in userNavigation" :key="item.name">
<a :href="item.href">
[[ item.name ]]
</a>
</MenuItem>
</MenuItems>
`
This is what I am trying to do to:
<script type="text/javascript">
function logoutPost() {
let form = document.createElement('form');
form.setAttribute('method', 'post');
form.setAttribute('action', '/auth/logout/');
let csrf = document.createElement('input');
csrf.setAttribute('type', 'hidden');
csrf.setAttribute('name', 'csrfmiddlewaretoken');
csrf.setAttribute('value', '{{ csrf_token }}');
form.appendChild(csrf);
document.body.appendChild(form);
let logoutAnchor = document.getElementsByName('Logout')[0].value;
form.appendChild(logoutAnchor);
logoutAnchor.addEventListener('click', function (e) {
e.preventDefault();
form.submit();
console.log("logout clicked");
});
}
</script>
But, even if I try to add JavaScript DOM, nothing changes, I do not see anything in my console log and it just redirects. Where I am making a mistake?

Get user input and output Flask and HTML

I'm trying to develop a web-app with Flask and HTML and right now I need to get the user input, pass it to the Python back-end, execute a function and return its output, placing it inside an HTML element. I also want this to happen without refreshing the HTML page.
How can I do this?
Bellow I have the code that I've developed so far but it's not working correctly:
My HTML:
<div id="ThroughputRate" class="data_entry">
<form action="{{ url_for('background_check_throughputrate') }}" method="post">
<input name="throughput_rate_text" class="input_box">
<input id="checkThroughputRate" type="submit" class='new-button-data' value="Check Throughput Rate">
<output name="throughputRateResult" class="result_box" ></output>
</form>
</div>
My Flask backend:
#app.route('/background_check_throughputrate', methods=['GET', 'POST'])
def background_check_throughputrate():
if request.method == 'POST':
text = request.form['throughput_rate_text']
processed_text = str(text)
throughput = transition_throughput_rate(processed_text)
return jsonify(throughput)
My HTML (continuation to get the output of the function executed on Flask):
<script type=text/javascript>
$(function() {
$('a#checkThroughputRate').bind('click', function() {
$.getJSON('/background_check_throughputrate', function(data) {
console.log(data);
document.getElementById('throughputRateResult').innerHTML = data;
});
return false;
});
});
</script>
The idea behind my execution is that the user uses the first snippet of code (in HTML) to insert the input, this input is passed onto the second snippet of code (in flask) and finally, the output of the function is passed onto the last snippet of code (in JS inside HTML) so that it can be displayed on the corresponding HTML element.
So far, the input is being correctly processed inside flask but the issue is that when the function returns the jsonify, it appears on the screen, instead of sending it into the frontend. What am I doing wrong?
Thank you all
$.getJSON is designed to load the JSON data from endpoint using GET request, however, your Python code example responds to only POST requests.
Here is the working code:
HTML
<div id="ThroughputRate" class="data_entry">
<form action="{{ url_for('background_check_throughputrate') }}" method="post" id="throughputRateForm" enctype="multipart/form-data">
<input name="throughput_rate_text" class="input_box">
<input id="checkThroughputRate" type="submit" class='new-button-data' value="Check Throughput Rate">
<output id="throughputRateResult" class="result_box" ></output>
</form>
</div>
Python
#app.route('/background_check_throughputrate', methods=['GET', 'POST'])
def background_check_throughputrate():
if request.method == 'POST':
text = request.form['throughput_rate_text']
processed_text = str(text)
throughput = transition_throughput_rate(processed_text)
return jsonify(throughput)
JavaScript
<script type="text/javascript">
$(function () {
$('#throughputRateForm').on('submit', function (e) {
e.preventDefault();
var form = $(this)[0];
var formData = new FormData(form);
$.ajax({
url: '/background_check_throughputrate',
method: 'POST',
data: formData,
processData: false,
contentType: false,
success: function (data) {
console.log(data);
document.getElementById('throughputRateResult').innerHTML = data;
}
});
});
});
</script>
Also, this code blindly trusts the user input and displays it on the webpage which can result to Cross-Site Scripting (XSS) and that is not good!
Avoid using innerHTML property when displaying user input, because it can be used to inject malicious HTML tags (e.g. <script>), i would highly recommend using innerText property instead.

Symfony 4 - Set up Braintree drop in form

Trying to set up Braintree drop in UI in my Symfony 4 app.
(https://developers.braintreepayments.com/start/hello-client/javascript/v3,
https://developers.braintreepayments.com/start/hello-server/php)
I have created a service:
namespace App\Services;
use Braintree\ClientToken;
use Braintree\Configuration;
class Braintree
{
// environment variables:
const ENVIRONMENT = 'BRAINTREE_ENVIRONMENT';
const MERCHANT_ID = 'BRAINTREE_MERCHANT_ID';
const PUBLIC_KEY = 'BRAINTREE_PUBLIC_KEY';
const PRIVATE_KEY = 'BRAINTREE_PRIVATE_KEY';
function __construct() {
Configuration::environment(getenv(self::ENVIRONMENT));
Configuration::merchantId(getenv(self::MERCHANT_ID));
Configuration::publicKey(getenv(self::PUBLIC_KEY));
Configuration::privateKey(getenv(self::PRIVATE_KEY));
}
//
public function generateNonce() {
return ClientToken::generate();
}
}
and I have added a form and some javascript to my twig template:
{% block body %}
{{ parent() }}
<div class="container">
<div class="card">
<div class="row">
<div class="col-12">
<h3>Booking New</h3>
<div id="datepicker"></div>
{{ form_start(bookingForm) }}
{{ form_widget(bookingForm) }}
<button type="submit" class="btn btn-primary">Create</button>
{{ form_end(bookingForm) }}
</div>
</div>
<div class="row">
<div class="col-12">
<form method="post" id="payment-form">
<section>
<label for="amount">
<span class="input-label">Amount</span>
<div class="input-wrapper amount-wrapper">
<input id="amount" name="amount" type="tel" min="1" placeholder="Amount" value="10">
</div>
</label>
<div class="bt-drop-in-wrapper">
<div id="bt-dropin"></div>
</div>
</section>
<input id="nonce" name="payment_method_nonce" type="hidden" />
<button class="button" type="submit"><span>Test Transaction</span></button>
</form>
<button id="submit-button">Request payment method</button>
</div>
</div>
</div>
</div>
{% endblock %}
{% block javascripts %}
{{ parent() }}
<script src="https://js.braintreegateway.com/web/dropin/1.14.1/js/dropin.min.js"></script>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script>
var form = document.querySelector('#payment-form');
var client_token = "<?php echo($gateway->ClientToken()->generate()); ?>";
braintree.dropin.create({
authorization: client_token,
selector: '#bt-dropin',
paypal: {
flow: 'vault'
}
}, function (createErr, instance) {
if (createErr) {
console.log('Create Error', createErr);
return;
}
form.addEventListener('submit', function (event) {
event.preventDefault();
instance.requestPaymentMethod(function (err, payload) {
if (err) {
console.log('Request Payment Method Error', err);
return;
}
// Add the nonce to the form and submit
document.querySelector('#nonce').value = payload.nonce;
form.submit();
});
});
});
</script>
<script>
$( function() {
$( "#datepicker" ).datepicker();
} );
</script>
{% endblock %}
When I load the page it does not render the Braintree form as I expect braintree.dropin.create to do. When I press submit nothing happens also.
How do I set up this code correctly?
Edit:
Checked console:
Create Error
r
message: "There was an error creating Drop-in."
name: "DropinError"
_braintreeWebError: n {name: "BraintreeError", code: "CLIENT_INVALID_AUTHORIZATION", message: "Authorization is invalid. Make sure your client token or tokenization key is valid.", type: "MERCHANT", details: undefined}
__proto__: Error
From your console error, I can infer that this line is wrong:
var client_token = "<?php echo($gateway->ClientToken()->generate()); ?>";
Instead of using php block inside your javascript, you should make an AJAX request to your backend which will return client token which you can then use in your form.
Consider this example:
// Set up our HTTP request
var xhr = new XMLHttpRequest();
// Setup our listener to process completed requests
xhr.onload = function () {
// Process our return data
if (xhr.status >= 200 && xhr.status < 300) {
var client_token = xhr.response.client_token; // Set your client token and use it later
} else {
// What do when the request fails
console.log('The request failed!');
}
// Code that should run regardless of the request status
console.log('This always runs...');
};
// Create and send a GET request
// The first argument is the post type (GET, POST, PUT, DELETE, etc.)
// The second argument is the endpoint URL
xhr.open('GET', '/route/to/braintree/controller'); // Create a Symfony route which will use `BraintreeService` and return generated client token.
xhr.send();
This is more of a pseudo code, but it should give you general idea of what you should do. From your code, it looks like you should first get that client_token, and then render the form.
In case this is not the issue, keep looking into that console error, it's definitely the reason you can't render the form. Maybe visit Braintree docs again, they have excellent framework and framework agnostic examples.

Select File. Submit. Cannot select file again

I have a form with different fields and with input type="file". I use fileupload jQuery library.
Select file
Call
$('#some_id').fileupload().fileupload(
'send',
{
files: file,
url: widget.options.saveVideoUrl,
}
).success(
//...
(first fileupload called for init)
Try again to select file. Got: No files selected, clear console, etc..
Upd.1
The problem appear in E-commerce framework Magento2 in admin area.
The described form appear in such entity like 'slide-out panel'. It means that there is div block and this block wrapped in aside block using javascript.
<button onclick="jQuery('#new').modal('openModal')" .... >
<span>New</span>
</button>
Here is demo example:
Admin URL: https://iwdagency.com/magento2/admin
Username: admin
Password: admin123
Open Products / Catalog / select any product / click on New category
You should see following panel:
On such panel I've added by php constructor fields:
<div class="admin__field field field-new_video_screenshot " data-ui-id="product-tabs-tab-google-experiment-fieldset-element-form-field-new-video-screenshot">
<label class="label admin__field-label" for="..." data-ui-id="product-tabs-tab-google-experiment-fieldset-element-file-image-label"><span>Preview Image</span></label>
<div class="admin__field-control control">
<input id="...." name="image" data-ui-id="product-tabs-tab-google-experiment-fieldset-element-file-image" value="" title="Preview Image" type="file">
</div>
</div>
Script:
define([
'jquery',
'jquery/ui',
'Magento_Ui/js/modal/modal',
'mage/translate',
'mage/backend/tree-suggest',
'mage/backend/validation'
], function ($) {
'use strict';
$.widget('mage.newDialog', {
_create: function () {
var widget = this;
var newVideoForm = $('#new');
this.element.modal({
type: 'slide',
modalClass: 'mage-new-dialog form-inline',
title: $.mage.__('Create'),
buttons: [{
text: $.mage.__('Create'),
class: 'action-primary',
click: function (e) {
var file = $('#new_screenshot').get(0).files[0];
var result = $('#new_screenshot').fileupload().fileupload(
'send',
{
files: file,
url: widget.options.saveUrl,
}
).success(
function(result, textStatus, jqXHR)
{
var data = JSON.parse(result);
data['url'] = $('#new_url').val();
data['name'] = $('#new_name').val();
data['description'] = $('#new_description').val();
$('#media_gallery_content').trigger('addItem', data);
$('#new').modal('closeModal')
}
);
}
}],
});
}
});
return $.mage.newDialog;
});
I found the problem.
In my case the problem appear after initialization fileUpload library.
When I selected input:file, the library wasn't initialized (read as infected). When I pressed the button, initialization ran and any operations with this input become unavailable.
Solution is following: clone our input before it become infected, than do our operations and at the end replace existing infected input with its healthy copy, created before.

Save django forms on button click

I am currently trying to learn django. I decided to create a small app. currently I am making a form to create VoteType and Voting candidates on one page. I created a page where u can add as many candidate fields as you want, but when I click the button nothing happenes and even if I don't click the button some data is saved. I was watching this django guide on youtube. This guy is making one simple form. He added method = POST and action = '' to ... and in views he used (request.POST or None). I tried to do the similar, but as my form is a bit more complicated I got really confused.
so this is my views.py code:
def create(request):
voteTypeForm = VoteTypeForm(request.POST or None)
voteForm = VoteForm(request.POST or None)
instance = voteTypeForm.save(commit=False)
instance.pub_date = timezone.now()
instance.save()
instance2 = voteForm.save(commit=False)
instance2.save()
#print instance.pub_date
context = RequestContext(request,{
'voteTypeForm': voteTypeForm,
'voteForm': voteForm,
})
return render(request, 'Vote/create.html', context)
and this is my create.html django template:
{% load staticfiles %}
<link rel="stylesheet" type="text/css" href="{% static 'Vote/style.css' %}" />
<fieldset id="fieldset">
<form method = 'POST' action = ''>{%csrf_token %}
<p>{{ voteTypeForm }}</p>
</form>
<div id="placeholder">
</div>
<p>
<button type="button" name="Submit" onclick="Add();">+</button>
</p>
<input type = 'submit' value="create"/>
</fieldset>
<script type='text/javascript'>
{# document.write(code);#}
var _counter = 0;
var template = document.createTextNode('')
function appendStringAsNodes(element, html) {
var frag = document.createDocumentFragment(),
tmp = document.createElement('body'), child;
tmp.innerHTML = html;
// Append elements in a loop to a DocumentFragment, so that the browser does
// not re-render the document for each node
while (child = tmp.firstChild) {
frag.appendChild(child);
}
element.appendChild(frag); // Now, append all elements at once
frag = tmp = null;
}
function Add() {
var code = '<div id="template">' +
'<p>' +
'<fieldset id="fieldsets">' +
'<legend id="legends">Candidate No ['+ String(_counter+1) +']</legend>' +
' <form method = "POST" action = "">'+
'<input type="hidden" name="csrfmiddlewaretoken" value="{{csrf_token }}" />' +
'<p><label for="id_name">Name:</label> <input id="id_name" maxlength="50" name="name" type="text" /></p>'+
'<p><label for="id_image">Image:</label> <input id="id_image" name="image" type="file" /></p>'+
'</form>' +
' </fieldset>' +
'</p>' +
'</div>';
_counter++;
appendStringAsNodes(document.getElementById("placeholder"),code);
document.getElementById("someInput").value = _counter;
}
</script>
how do I fix this code so that my program only saves instances when I push the create button?
You still need to check that the action is a POST, and that the forms are valid, and you must redirect after a successful submission.
def create(request):
voteTypeForm = VoteTypeForm(request.POST or None)
voteForm = VoteForm(request.POST or None)
if request.method == 'POST':
# check validity separately to avoid short-cutting
vote_type_valid = voteTypeForm.is_valid()
vote_form_valid = voteForm.is_valid()
if vote_type_valid and vote_form_valid:
instance = voteTypeForm.save(commit=False)
instance.pub_date = timezone.now()
instance.save()
instance2 = voteForm.save(commit=False)
instance2.save()
return redirect('<view-you-redirect-to-on-success'>
context = RequestContext(request,{
'voteTypeForm': voteTypeForm,
'voteForm': voteForm,
})
return render(request, 'Vote/create.html', context)
The easiest way to do it is by making ajax request when you push the submit button.
Considering you have a form 'voteForm', try loading this form using django's inbuilt template as: {{voteForm.as_p}}
This will create your form for, which you have already done.
Now when you press submit button, make an ajax request with your form data in it.
The ajax request will take your data to the form and reverts back with a response which you can use to further do the processing.
A quick example for ajax request would be:
function youfunctionname()
$.ajax({
type: "POST",
url: url,
data: $("#yourformname").serialize(), // serializes the form's elements.
success: function(data)
{
alert(data);
}
});
}

Categories