Skip to content

Commit

Permalink
Merge pull request #1711 from MTG/amount_max
Browse files Browse the repository at this point in the history
let Django cleaning handle amount validation; show errors close to input
  • Loading branch information
ffont authored Nov 17, 2023
2 parents ef04757 + ae3138a commit c349895
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 44 deletions.
48 changes: 23 additions & 25 deletions donations/forms.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,33 @@
import json
import base64
import json

from django import forms
from django.utils.safestring import mark_safe

from .models import DonationCampaign


class DonateForm(forms.Form):
RADIO_CHOICES = []

donation_type = forms.ChoiceField(
widget=forms.RadioSelect(), choices=RADIO_CHOICES,
label=mark_safe('Please choose the <b>name</b> that will appear with the donation:'))
name_option = forms.CharField(
required=False, max_length=255, label=False)
widget=forms.RadioSelect(),
choices=RADIO_CHOICES,
label=mark_safe('Please choose the <b>name</b> that will appear with the donation:')
)
name_option = forms.CharField(required=False, max_length=255, label=False)
amount = forms.FloatField(
initial=10.0, min_value=0., label=mark_safe('Donation amount (&euro;):'))
recurring = forms.BooleanField(required=False, initial=False,
label='I want this to be a recurring monthly donation',)
show_amount = forms.BooleanField(
label='Make donated amount public',
required=False,
initial=True)
initial=10.0,
min_value=1,
max_value=999999.99, # https://stripe.com/docs/currencies#minimum-and-maximum-charge-amounts
label=mark_safe('Donation amount (&euro;):')
)
recurring = forms.BooleanField(
required=False,
initial=False,
label='I want this to be a recurring monthly donation',
)
show_amount = forms.BooleanField(label='Make donated amount public', required=False, initial=True)

def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None)
Expand Down Expand Up @@ -56,23 +63,14 @@ def __init__(self, *args, **kwargs):

def clean(self):
cleaned_data = super().clean()
amount = cleaned_data.get('amount')
try:
if not amount or float(amount) < 1:
raise forms.ValidationError('The amount must be more than 1')
except ValueError:
raise forms.ValidationError('The amount must be a valid number, use \'.\' for decimals')

campaign = DonationCampaign.objects.order_by('date_start').last()
returned_data = {
"campaign_id": campaign.id,
"display_amount": cleaned_data.get('show_amount')
}
returned_data = {"campaign_id": campaign.id, "display_amount": cleaned_data.get('show_amount')}

annon = cleaned_data.get('donation_type')

# We store the user even if the donation is annonymous (but don't display the name)
if self.user_id :
# We store the user even if the donation is anonymous (but don't display the name)
if self.user_id:
returned_data['user_id'] = self.user_id

if annon == '1':
Expand All @@ -82,6 +80,6 @@ def clean(self):
if returned_data['name'] == '':
raise forms.ValidationError('You have to enter a name to display')

# Paypal gives only one field to add extra data so we send it as b64
# Paypal gives only one field to add extra data, so we send it as b64
self.encoded_data = base64.b64encode(json.dumps(returned_data).encode()).decode()
return cleaned_data
47 changes: 28 additions & 19 deletions freesound/static/bw-frontend/src/pages/donate.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,34 @@ nameOptionRadioButtons.forEach(element => {

// Disable credit card button if recurring option is checked
recurringCheckboxElement.addEventListener('change', () => {
if (recurringCheckboxElement.checked) {
donationButtonCreditCardElement.disabled = true;
} else {
donationButtonCreditCardElement.disabled = false;
}
donationButtonCreditCardElement.disabled = !!recurringCheckboxElement.checked;

});

function handleErrors(errors) {
Object.entries(errors).forEach(([key, values]) => {
const liElement = document.createElement("li");
liElement.innerText = key;
const newList = document.createElement("ul");
newList.classList.add("errorlist", "v-spacing-3");
values.forEach(error => {
const newLi = document.createElement("li");
newLi.innerText = error;
newList.appendChild(newLi);
});
// if we can find the element with the key as id, we add the error message to it
const elemError = document.getElementById(`id_${key}`);
if (elemError) {
// add an error message below the input field
elemError.insertAdjacentElement('afterend', newList);
} else {
// otherwise, we add it to the general error list (e.g., when key is '__all__')
formErrorlistElement.appendChild(liElement);
formErrorlistElement.appendChild(newList);
}
});
}

// Add actions for donate credit card/paypal buttons
donationButtonPaypalElement.addEventListener('click', (event) => {
event.preventDefault(); // Stop propagation of submit event
Expand All @@ -43,12 +63,7 @@ donationButtonPaypalElement.addEventListener('click', (event) => {
if (req.status >= 200 && req.status < 300) {
const data = JSON.parse(req.responseText);
if (data.errors != null) {
formErrorlistElement.innerHTML = '';
data.errors['__all__'].forEach(error => {
const liElement = document.createElement("li");
liElement.innerText = error;
formErrorlistElement.appendChild(liElement);
});
handleErrors(data.errors);
} else {
const hiddenFormElement = document.createElement("form");
hiddenFormElement.setAttribute("action", data.url);
Expand All @@ -68,7 +83,7 @@ donationButtonPaypalElement.addEventListener('click', (event) => {
}
}
req.onerror = () => {
// Unexpected errors happened while processing request: how error in toast
// Unexpected errors happened while processing request: show error in toast
showToast('Some errors occurred while processing the form. Please try again later.')
};
req.send(params); // Send request
Expand All @@ -87,12 +102,7 @@ donationButtonCreditCardElement.addEventListener('click', (event) => {
if (req.status >= 200 && req.status < 300) {
const data = JSON.parse(req.responseText);
if (data.errors != null) {
formErrorlistElement.innerHTML = '';
data.errors['__all__'].forEach(error => {
const liElement = document.createElement("li");
liElement.innerText = error;
formErrorlistElement.appendChild(liElement);
});
handleErrors(data.errors)
} else {
const session = data.session_id;
stripe.redirectToCheckout({
Expand All @@ -112,4 +122,3 @@ donationButtonCreditCardElement.addEventListener('click', (event) => {
};
req.send(params); // Send request
});

0 comments on commit c349895

Please sign in to comment.