Merge pull request #506 from ungleich/bugfix/stripe_error
- Bugfix/stripe error - #3835 [dcl] Forbidden (403) CSRF verification failed. Request aborted. - hosting/dashboard only available after login
This commit is contained in:
commit
350a52c657
19 changed files with 227 additions and 168 deletions
|
@ -8,7 +8,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-09-23 21:22+0000\n"
|
||||
"POT-Creation-Date: 2017-09-29 19:59+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
@ -423,30 +423,15 @@ msgstr "Abarbeitung..."
|
|||
msgid "Hold tight, we are processing your request"
|
||||
msgstr "Bitte warten - wir verbeiten Deine Anfrage gerade"
|
||||
|
||||
msgid "OK"
|
||||
msgstr ""
|
||||
|
||||
msgid "Close"
|
||||
msgstr ""
|
||||
|
||||
msgid "Some problem encountered. Please try again later."
|
||||
msgstr "Ein Problem ist aufgetreten. Bitte versuche es später noch einmal."
|
||||
|
||||
msgid "We are cutting down the costs significantly!"
|
||||
msgstr "Wir sorgen dafür, dass die Kosten für Dich signifikant abnehmen"
|
||||
|
||||
msgid "Order Now!"
|
||||
msgstr "Bestelle jetzt!"
|
||||
|
||||
msgid ""
|
||||
"Our VMs are hosted in Glarus, Switzerland, and our website is currently "
|
||||
"running in BETA mode. If you want more information that you did not find on "
|
||||
"our website, or if your order is more detailed, or if you encounter any "
|
||||
"technical hiccups, please contact us at support@datacenterlight.ch, our team "
|
||||
"will get in touch with you asap."
|
||||
msgstr ""
|
||||
"Unsere VMs werden in der Schweiz im Kanton Glarus gehostet und befinden sich "
|
||||
"zur Zeit noch in der BETA-Phase. Möchtest du mehr über uns erfahren und hast "
|
||||
"auf unserer Website nicht genügend Informationen gefunden? Möchtest eine "
|
||||
"detailliertere Bestellung aufgeben? Bist du auf technische Probleme "
|
||||
"gestossen, die du uns mitteilen möchtest? Dann zögere nicht und kontaktiere "
|
||||
"uns unter support@datacenterlight.ch. Unser Team wird sich umgehend um dein "
|
||||
"Anliegen kümmern!"
|
||||
|
||||
msgid "Thank you for order! Our team will contact you via email"
|
||||
msgstr ""
|
||||
"Vielen Dank für die Bestellung. Unser Team setzt sich sobald wie möglich mit "
|
||||
|
@ -547,6 +532,8 @@ msgid ""
|
|||
"There was a payment related error. On close of this popup, you will be "
|
||||
"redirected back to the payment page."
|
||||
msgstr ""
|
||||
"Es ist ein Fehler bei der Zahlung betreten. Du wirst nach dem "
|
||||
"Schliessen vom Popup zur Bezahlseite weitergeleitet."
|
||||
|
||||
msgid "Thank you for the order."
|
||||
msgstr "Danke für Deine Bestellung."
|
||||
|
@ -558,6 +545,27 @@ msgstr ""
|
|||
"Deine VM ist gleich bereit. Wir senden Dir eine Bestätigungsemail, sobald Du "
|
||||
"auf sie zugreifen kannst."
|
||||
|
||||
#~ msgid "We are cutting down the costs significantly!"
|
||||
#~ msgstr "Wir sorgen dafür, dass die Kosten für Dich signifikant abnehmen"
|
||||
|
||||
#~ msgid "Order Now!"
|
||||
#~ msgstr "Bestelle jetzt!"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Our VMs are hosted in Glarus, Switzerland, and our website is currently "
|
||||
#~ "running in BETA mode. If you want more information that you did not find "
|
||||
#~ "on our website, or if your order is more detailed, or if you encounter "
|
||||
#~ "any technical hiccups, please contact us at support@datacenterlight.ch, "
|
||||
#~ "our team will get in touch with you asap."
|
||||
#~ msgstr ""
|
||||
#~ "Unsere VMs werden in der Schweiz im Kanton Glarus gehostet und befinden "
|
||||
#~ "sich zur Zeit noch in der BETA-Phase. Möchtest du mehr über uns erfahren "
|
||||
#~ "und hast auf unserer Website nicht genügend Informationen gefunden? "
|
||||
#~ "Möchtest eine detailliertere Bestellung aufgeben? Bist du auf technische "
|
||||
#~ "Probleme gestossen, die du uns mitteilen möchtest? Dann zögere nicht und "
|
||||
#~ "kontaktiere uns unter support@datacenterlight.ch. Unser Team wird sich "
|
||||
#~ "umgehend um dein Anliegen kümmern!"
|
||||
|
||||
#~ msgid "Email Address"
|
||||
#~ msgstr "E-Mail-Adresse"
|
||||
|
||||
|
|
|
@ -50,15 +50,20 @@ def retry_task(task, exception=None):
|
|||
@app.task(bind=True, max_retries=settings.CELERY_MAX_RETRIES)
|
||||
def create_vm_task(self, vm_template_id, user, specs, template,
|
||||
stripe_customer_id, billing_address_data,
|
||||
billing_address_id,
|
||||
charge, cc_details):
|
||||
stripe_subscription_id, cc_details):
|
||||
logger.debug(
|
||||
"Running create_vm_task on {}".format(current_task.request.hostname))
|
||||
vm_id = None
|
||||
try:
|
||||
final_price = specs.get('price')
|
||||
billing_address = BillingAddress.objects.filter(
|
||||
id=billing_address_id).first()
|
||||
billing_address = BillingAddress(
|
||||
cardholder_name=billing_address_data['cardholder_name'],
|
||||
street_address=billing_address_data['street_address'],
|
||||
city=billing_address_data['city'],
|
||||
postal_code=billing_address_data['postal_code'],
|
||||
country=billing_address_data['country']
|
||||
)
|
||||
billing_address.save()
|
||||
customer = StripeCustomer.objects.filter(id=stripe_customer_id).first()
|
||||
|
||||
if 'pass' in user:
|
||||
|
@ -111,8 +116,7 @@ def create_vm_task(self, vm_template_id, user, specs, template,
|
|||
billing_address_user_form.save()
|
||||
|
||||
# Associate an order with a stripe subscription
|
||||
charge_object = DictDotLookup(charge)
|
||||
order.set_subscription_id(charge_object, cc_details)
|
||||
order.set_subscription_id(stripe_subscription_id, cc_details)
|
||||
|
||||
# If the Stripe payment succeeds, set order status approved
|
||||
order.set_approved()
|
||||
|
@ -183,7 +187,8 @@ def create_vm_task(self, vm_template_id, user, specs, template,
|
|||
public_keys]
|
||||
if len(keys) > 0:
|
||||
logger.debug(
|
||||
"Calling configure on {host} for {num_keys} keys".format(
|
||||
"Calling configure on {host} for "
|
||||
"{num_keys} keys".format(
|
||||
host=new_host, num_keys=len(keys)))
|
||||
# Let's delay the task by 75 seconds to be sure
|
||||
# that we run the cdist configure after the host
|
||||
|
@ -212,32 +217,3 @@ def create_vm_task(self, vm_template_id, user, specs, template,
|
|||
return
|
||||
|
||||
return vm_id
|
||||
|
||||
|
||||
class DictDotLookup(object):
|
||||
"""
|
||||
Creates objects that behave much like a dictionaries, but allow nested
|
||||
key access using object '.' (dot) lookups.
|
||||
"""
|
||||
|
||||
def __init__(self, d):
|
||||
for k in d:
|
||||
if isinstance(d[k], dict):
|
||||
self.__dict__[k] = DictDotLookup(d[k])
|
||||
elif isinstance(d[k], (list, tuple)):
|
||||
l = []
|
||||
for v in d[k]:
|
||||
if isinstance(v, dict):
|
||||
l.append(DictDotLookup(v))
|
||||
else:
|
||||
l.append(v)
|
||||
self.__dict__[k] = l
|
||||
else:
|
||||
self.__dict__[k] = d[k]
|
||||
|
||||
def __getitem__(self, name):
|
||||
if name in self.__dict__:
|
||||
return self.__dict__[name]
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self.__dict__.keys())
|
||||
|
|
|
@ -75,21 +75,12 @@ class CeleryTaskTestCase(TestCase):
|
|||
stripe_customer.stripe_id,
|
||||
self.token)
|
||||
card_details_dict = card_details.get('response_object')
|
||||
billing_address = BillingAddress(
|
||||
cardholder_name=self.customer_name,
|
||||
postal_code='1232',
|
||||
country='CH',
|
||||
street_address='Monty\'s Street',
|
||||
city='Hollywood')
|
||||
billing_address.save()
|
||||
billing_address_data = {'cardholder_name': self.customer_name,
|
||||
'postal_code': '1231',
|
||||
'country': 'CH',
|
||||
'token': self.token,
|
||||
'street_address': 'Monty\'s Street',
|
||||
'city': 'Hollywood'}
|
||||
|
||||
billing_address_id = billing_address.id
|
||||
vm_template_id = template_data.get('id', 1)
|
||||
|
||||
cpu = specs.get('cpu')
|
||||
|
@ -125,8 +116,7 @@ class CeleryTaskTestCase(TestCase):
|
|||
template_data,
|
||||
stripe_customer.id,
|
||||
billing_address_data,
|
||||
billing_address_id,
|
||||
stripe_subscription_obj,
|
||||
stripe_subscription_obj.id,
|
||||
card_details_dict)
|
||||
new_vm_id = 0
|
||||
res = None
|
||||
|
|
|
@ -348,6 +348,11 @@ class PaymentOrderView(FormView):
|
|||
form_kwargs.update({
|
||||
'instance': self.request.user.billing_addresses.first()
|
||||
})
|
||||
if 'billing_address_data' in self.request.session:
|
||||
billing_address_data = self.request.session['billing_address_data']
|
||||
form_kwargs.update({
|
||||
'initial': billing_address_data
|
||||
})
|
||||
return form_kwargs
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
|
@ -379,14 +384,40 @@ class PaymentOrderView(FormView):
|
|||
email=this_user.get('email'),
|
||||
token=token)
|
||||
else:
|
||||
user_email = form.cleaned_data.get('email')
|
||||
user_name = form.cleaned_data.get('name')
|
||||
this_user = {
|
||||
'email': form.cleaned_data.get('email'),
|
||||
'name': form.cleaned_data.get('name')
|
||||
'email': user_email,
|
||||
'name': user_name
|
||||
}
|
||||
customer = StripeCustomer.create_stripe_api_customer(
|
||||
email=this_user.get('email'),
|
||||
token=token,
|
||||
customer_name=form.cleaned_data.get('name'))
|
||||
try:
|
||||
custom_user = CustomUser.objects.get(email=user_email)
|
||||
customer = StripeCustomer.objects.filter(
|
||||
user_id=custom_user.id).first()
|
||||
if customer is None:
|
||||
logger.debug(
|
||||
("User {email} is already registered with us."
|
||||
"But, StripeCustomer does not exist for {email}."
|
||||
"Hence, creating a new StripeCustomer.").format(
|
||||
email=user_email
|
||||
)
|
||||
)
|
||||
customer = StripeCustomer.create_stripe_api_customer(
|
||||
email=user_email,
|
||||
token=token,
|
||||
customer_name=user_name)
|
||||
except CustomUser.DoesNotExist:
|
||||
logger.debug(
|
||||
("StripeCustomer does not exist for {email}."
|
||||
"Hence, creating a new StripeCustomer.").format(
|
||||
email=user_email
|
||||
)
|
||||
)
|
||||
customer = StripeCustomer.create_stripe_api_customer(
|
||||
email=user_email,
|
||||
token=token,
|
||||
customer_name=user_name)
|
||||
|
||||
request.session['billing_address_data'] = form.cleaned_data
|
||||
request.session['user'] = this_user
|
||||
# Get or create stripe customer
|
||||
|
@ -395,8 +426,10 @@ class PaymentOrderView(FormView):
|
|||
return self.render_to_response(
|
||||
self.get_context_data(form=form))
|
||||
request.session['token'] = token
|
||||
request.session[
|
||||
'customer'] = customer.id if request.user.is_authenticated() else customer
|
||||
if type(customer) is StripeCustomer:
|
||||
request.session['customer'] = customer.stripe_id
|
||||
else:
|
||||
request.session['customer'] = customer
|
||||
return HttpResponseRedirect(
|
||||
reverse('datacenterlight:order_confirmation'))
|
||||
else:
|
||||
|
@ -415,14 +448,7 @@ class OrderConfirmationView(DetailView):
|
|||
return HttpResponseRedirect(reverse('datacenterlight:index'))
|
||||
if 'token' not in request.session:
|
||||
return HttpResponseRedirect(reverse('datacenterlight:payment'))
|
||||
stripe_customer_id = request.session.get('customer')
|
||||
if request.user.is_authenticated():
|
||||
customer = StripeCustomer.objects.filter(
|
||||
id=stripe_customer_id).first()
|
||||
stripe_api_cus_id = customer.stripe_id
|
||||
else:
|
||||
stripe_api_cus_id = stripe_customer_id
|
||||
|
||||
stripe_api_cus_id = request.session.get('customer')
|
||||
stripe_utils = StripeUtils()
|
||||
card_details = stripe_utils.get_card_details(stripe_api_cus_id,
|
||||
request.session.get(
|
||||
|
@ -445,15 +471,8 @@ class OrderConfirmationView(DetailView):
|
|||
template = request.session.get('template')
|
||||
specs = request.session.get('specs')
|
||||
user = request.session.get('user')
|
||||
stripe_customer_id = request.session.get('customer')
|
||||
if request.user.is_authenticated():
|
||||
customer = StripeCustomer.objects.filter(
|
||||
id=stripe_customer_id).first()
|
||||
stripe_api_cus_id = customer.stripe_id
|
||||
else:
|
||||
stripe_api_cus_id = stripe_customer_id
|
||||
stripe_api_cus_id = request.session.get('customer')
|
||||
vm_template_id = template.get('id', 1)
|
||||
|
||||
stripe_utils = StripeUtils()
|
||||
card_details = stripe_utils.get_card_details(stripe_api_cus_id,
|
||||
request.session.get(
|
||||
|
@ -498,8 +517,8 @@ class OrderConfirmationView(DetailView):
|
|||
'response_object').stripe_plan_id}])
|
||||
stripe_subscription_obj = subscription_result.get('response_object')
|
||||
# Check if the subscription was approved and is active
|
||||
if stripe_subscription_obj is None or \
|
||||
stripe_subscription_obj.status != 'active':
|
||||
if (stripe_subscription_obj is None
|
||||
or stripe_subscription_obj.status != 'active'):
|
||||
msg = subscription_result.get('error')
|
||||
messages.add_message(self.request, messages.ERROR, msg,
|
||||
extra_tags='failed_payment')
|
||||
|
@ -546,10 +565,10 @@ class OrderConfirmationView(DetailView):
|
|||
password=password)
|
||||
login(request, new_user)
|
||||
else:
|
||||
customer = StripeCustomer.objects.filter(
|
||||
id=stripe_customer_id).first()
|
||||
custom_user = customer.user
|
||||
stripe_customer_id = customer.id
|
||||
# We assume that if the user is here, his/her StripeCustomer
|
||||
# object already exists
|
||||
stripe_customer_id = request.user.stripecustomer.id
|
||||
custom_user = request.user
|
||||
|
||||
# Save billing address
|
||||
billing_address_data = request.session.get('billing_address_data')
|
||||
|
@ -557,12 +576,6 @@ class OrderConfirmationView(DetailView):
|
|||
billing_address_data.update({
|
||||
'user': custom_user.id
|
||||
})
|
||||
billing_address_user_form = UserBillingAddressForm(
|
||||
instance=custom_user.billing_addresses.first(),
|
||||
data=billing_address_data)
|
||||
billing_address = billing_address_user_form.save()
|
||||
billing_address_id = billing_address.id
|
||||
logger.debug("billing address id = {}".format(billing_address_id))
|
||||
user = {
|
||||
'name': custom_user.name,
|
||||
'email': custom_user.email,
|
||||
|
@ -574,8 +587,7 @@ class OrderConfirmationView(DetailView):
|
|||
|
||||
create_vm_task.delay(vm_template_id, user, specs, template,
|
||||
stripe_customer_id, billing_address_data,
|
||||
billing_address_id,
|
||||
stripe_subscription_obj, card_details_dict)
|
||||
stripe_subscription_obj.id, card_details_dict)
|
||||
for session_var in ['specs', 'template', 'billing_address',
|
||||
'billing_address_data',
|
||||
'token', 'customer']:
|
||||
|
|
|
@ -161,6 +161,8 @@ MIDDLEWARE_CLASSES = (
|
|||
'cms.middleware.language.LanguageCookieMiddleware',
|
||||
)
|
||||
|
||||
CSRF_FAILURE_VIEW = 'hosting.views.forbidden_view'
|
||||
|
||||
ROOT_URLCONF = 'dynamicweb.urls'
|
||||
|
||||
TEMPLATES = [
|
||||
|
|
|
@ -8,7 +8,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-09-24 12:34+0000\n"
|
||||
"POT-Creation-Date: 2017-10-01 20:57+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
@ -337,6 +337,9 @@ msgstr "Rechnung Datum"
|
|||
msgid "Status"
|
||||
msgstr ""
|
||||
|
||||
msgid "Terminated"
|
||||
msgstr "Beendet"
|
||||
|
||||
msgid "Approved"
|
||||
msgstr "Akzeptiert"
|
||||
|
||||
|
@ -358,6 +361,9 @@ msgstr "Bestellungsübersicht"
|
|||
msgid "Product"
|
||||
msgstr "Produkt"
|
||||
|
||||
msgid "Period"
|
||||
msgstr ""
|
||||
|
||||
msgid "Cores"
|
||||
msgstr "Prozessorkerne"
|
||||
|
||||
|
@ -390,6 +396,12 @@ msgstr "Abarbeitung..."
|
|||
msgid "Hold tight, we are processing your request"
|
||||
msgstr "Bitte warten - wir bearbeiten Deine Anfrage gerade"
|
||||
|
||||
msgid "OK"
|
||||
msgstr ""
|
||||
|
||||
msgid "Close"
|
||||
msgstr "Schliessen"
|
||||
|
||||
msgid "Some problem encountered. Please try again later."
|
||||
msgstr "Ein Problem ist aufgetreten. Bitte versuche es später noch einmal."
|
||||
|
||||
|
@ -599,16 +611,13 @@ msgstr "Deine Virtuelle Maschine beenden"
|
|||
msgid "Do you want to cancel your Virtual Machine"
|
||||
msgstr "Bist Du sicher, dass Du Deine virtuelle Maschine beenden willst"
|
||||
|
||||
msgid "OK"
|
||||
msgstr ""
|
||||
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Your Virtual Machine <strong>%(machine_name)s</strong> is successfully "
|
||||
"terminated!"
|
||||
msgstr ""
|
||||
"Deine Virtuelle Machine (VM) <strong>%(machine_name)s</strong> wurde erfolgreich "
|
||||
"beendet!"
|
||||
"Deine Virtuelle Machine (VM) <strong>%(machine_name)s</strong> wurde "
|
||||
"erfolgreich beendet!"
|
||||
|
||||
msgid "Virtual Machines"
|
||||
msgstr "Virtuelle Maschinen"
|
||||
|
@ -616,6 +625,13 @@ msgstr "Virtuelle Maschinen"
|
|||
msgid "To create a new virtual machine, click \"Create VM\""
|
||||
msgstr "Um eine neue VM zu erzeugen, klicke \"Neue VM erzeugen\""
|
||||
|
||||
#, python-format
|
||||
msgid ""
|
||||
"To access your VM, <a href=\"%(create_ssh_url)s\">add your SSH key here</a>"
|
||||
msgstr ""
|
||||
"Um auf Deine VM zuzugreifen, <a href=\"%(create_ssh_url)s\">füge Deinen SSH-"
|
||||
"Key hinzu</a>"
|
||||
|
||||
msgid "CREATE VM"
|
||||
msgstr "NEUE VM"
|
||||
|
||||
|
@ -673,6 +689,16 @@ msgid "In order to create a VM, you need to create/upload your SSH KEY first."
|
|||
msgstr ""
|
||||
"Um eine VM zu erstellen musst du zuerst einen SSH-Key erstellen / hochladen."
|
||||
|
||||
msgid "Error."
|
||||
msgstr "Fehler"
|
||||
|
||||
msgid ""
|
||||
"There was a payment related error. On close of this popup, you will be "
|
||||
"redirected back to the payment page."
|
||||
msgstr ""
|
||||
"Es ist ein Fehler bei der Zahlung betreten. Du wirst nach dem "
|
||||
"Schliessen vom Popup zur Bezahlseite weitergeleitet"
|
||||
|
||||
msgid "Thank you for the order."
|
||||
msgstr "Danke für Deine Bestellung."
|
||||
|
||||
|
@ -697,8 +723,11 @@ msgid ""
|
|||
"contact Data Center Light Support."
|
||||
msgstr "Kontaktiere den Data Center Light Support."
|
||||
|
||||
msgid "Terminated"
|
||||
msgstr "Beendet"
|
||||
msgid ""
|
||||
"We could not find the requested VM. Please contact Data Center Light Support."
|
||||
msgstr ""
|
||||
"Wir konnten die gesucht VM nicht finden. Kontaktiere den Data Center Light "
|
||||
"Support."
|
||||
|
||||
msgid "Error terminating VM"
|
||||
msgstr "Fehler beenden VM"
|
||||
|
@ -706,8 +735,9 @@ msgstr "Fehler beenden VM"
|
|||
msgid "Virtual Machine Cancellation"
|
||||
msgstr "VM Kündigung"
|
||||
|
||||
#~ msgid "Close"
|
||||
#~ msgstr "Schliessen"
|
||||
msgid "There was an error processing your request. Please try again."
|
||||
msgstr "Es gab einen Fehler bei der Bearbeitung Deine Anfrage. Bitte"
|
||||
" versuche es noch einmal."
|
||||
|
||||
#~ msgid "VM %(VM_ID)s terminated successfully"
|
||||
#~ msgstr "VM %(VM_ID)s erfolgreich beendet"
|
||||
|
@ -842,5 +872,5 @@ msgstr "VM Kündigung"
|
|||
#~ "Your SSH private key was already generated and downloaded, if you lost "
|
||||
#~ "it, contact us. "
|
||||
#~ msgstr ""
|
||||
#~ "Dein privater SSH Key wurde bereits generiert und heruntergeladen. "
|
||||
#~ "Falls Du ihn verloren hast, kontaktiere uns."
|
||||
#~ "Dein privater SSH Key wurde bereits generiert und heruntergeladen. Falls "
|
||||
#~ "Du ihn verloren hast, kontaktiere uns."
|
||||
|
|
|
@ -88,19 +88,19 @@ class HostingOrder(AssignPermissionsMixin, models.Model):
|
|||
self.cc_brand = stripe_charge.source.brand
|
||||
self.save()
|
||||
|
||||
def set_subscription_id(self, subscription_object, cc_details):
|
||||
def set_subscription_id(self, subscription_id, cc_details):
|
||||
"""
|
||||
When creating a Stripe subscription, we have subscription id.
|
||||
We store this in the subscription_id field.
|
||||
This method sets the subscription id from subscription_object
|
||||
and also the last4 and credit card brands used for this order.
|
||||
This method sets the subscription id
|
||||
and the last4 and credit card brands used for this order.
|
||||
|
||||
:param subscription_object: Stripe's subscription object
|
||||
:param subscription_id: Stripe's subscription id
|
||||
:param cc_details: A dict containing card details
|
||||
{last4, brand}
|
||||
:return:
|
||||
"""
|
||||
self.subscription_id = subscription_object.id
|
||||
self.subscription_id = subscription_id
|
||||
self.last4 = cc_details.get('last4')
|
||||
self.cc_brand = cc_details.get('brand')
|
||||
self.save()
|
||||
|
|
|
@ -86,23 +86,31 @@ $(document).ready(function() {
|
|||
url: create_vm_form.attr('action'),
|
||||
type: 'POST',
|
||||
data: create_vm_form.serialize(),
|
||||
init: function(){
|
||||
ok_btn = $('#createvm-modal-done-btn');
|
||||
close_btn = $('#createvm-modal-close-btn');
|
||||
ok_btn.addClass('btn btn-success btn-ok btn-wide hide');
|
||||
close_btn.addClass('btn btn-danger btn-ok btn-wide hide');
|
||||
},
|
||||
success: function (data) {
|
||||
fa_icon = $('.modal-icon > .fa');
|
||||
modal_btn = $('#createvm-modal-done-btn');
|
||||
$('#createvm-modal-title').text(data.msg_title);
|
||||
$('#createvm-modal-body').html(data.msg_body);
|
||||
modal_btn.attr('href', data.redirect)
|
||||
.removeClass('hide');
|
||||
if (data.status === true) {
|
||||
fa_icon = $('.modal-icon > .fa');
|
||||
fa_icon.attr('class', 'checkmark');
|
||||
// $('.modal-header > .close').removeClass('hidden');
|
||||
$('#createvm-modal-title').text(data.msg_title);
|
||||
$('#createvm-modal-body').text(data.msg_body);
|
||||
$('#createvm-modal-done-btn')
|
||||
.attr('href', data.redirect)
|
||||
.removeClass('hide');
|
||||
} else {
|
||||
fa_icon.attr('class', 'fa fa-close');
|
||||
modal_btn.attr('class', '').addClass('btn btn-danger btn-ok btn-wide');
|
||||
}
|
||||
},
|
||||
error: function (xmlhttprequest, textstatus, message) {
|
||||
fa_icon = $('.modal-icon > .fa');
|
||||
fa_icon.attr('class', 'fa fa-close');
|
||||
if (typeof(create_vm_error_message) !== 'undefined') {
|
||||
$('#createvm-modal-text').text(create_vm_error_message);
|
||||
$('#createvm-modal-body').text(create_vm_error_message);
|
||||
}
|
||||
$('#btn-create-vm').prop('disabled', false);
|
||||
$('#createvm-modal-close-btn').removeClass('hide');
|
||||
|
|
8
hosting/templates/hosting/includes/_messages.html
Normal file
8
hosting/templates/hosting/includes/_messages.html
Normal file
|
@ -0,0 +1,8 @@
|
|||
{% if messages %}
|
||||
<ul class="list-unstyled msg-list">
|
||||
{% for message in messages %}
|
||||
<div
|
||||
class="alert {% if message.tags and message.tags == 'error' %} alert-danger {% else %} alert-{{message.tags}} {% endif %}">{{ message|safe }}</div>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
|
@ -16,13 +16,7 @@
|
|||
<div class="auth-content">
|
||||
<div class="intro-message auth-box">
|
||||
<h2 class="section-heading">{% trans "Login"%}</h2>
|
||||
{% if messages %}
|
||||
<ul class="list-unstyled msg-list">
|
||||
{% for message in messages %}
|
||||
<li>{{ message }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% include 'hosting/includes/_messages.html' %}
|
||||
<form action="{% url 'hosting:login' %}" method="post" class="form" novalidated>
|
||||
{% csrf_token %}
|
||||
{% for field in form %}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
<div class="auth-content">
|
||||
<div class="intro-message auth-box sign-up">
|
||||
<h2 class="section-heading">{% trans "Resend activation link"%}</h2>
|
||||
{% include 'hosting/includes/_messages.html' %}
|
||||
<form action="{% url 'hosting:resend_activation_link' %}" method="post" class="form" novalidate>
|
||||
{% csrf_token %}
|
||||
{% for field in form %}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
<div class="auth-content">
|
||||
<div class="intro-message auth-box sign-up">
|
||||
<h2 class="section-heading">{% trans "Reset your password"%}</h2>
|
||||
{% include 'hosting/includes/_messages.html' %}
|
||||
<form action="{% url 'hosting:reset_password' %}" method="post" class="form" novalidate>
|
||||
{% csrf_token %}
|
||||
{% for field in form %}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
<div class="auth-content">
|
||||
<div class="intro-message auth-box sign-up">
|
||||
<h2 class="section-heading">{% trans "Sign up"%}</h2>
|
||||
{% include 'hosting/includes/_messages.html' %}
|
||||
<form action="{% url 'hosting:signup' %}" method="post" class="form" novalidate>
|
||||
{% csrf_token %}
|
||||
{% for field in form %}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
<div class="auth-center">
|
||||
<div class="auth-title">
|
||||
<h2>{% trans "Your VM hosted in Switzerland"%}</h2>
|
||||
{% include 'hosting/includes/_messages.html' %}
|
||||
</div>
|
||||
<div class="auth-content">
|
||||
<div class="intro-message auth-box sign-up">
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
<p>{% trans 'To create a new virtual machine, click "Create VM"' %}
|
||||
{% if show_create_ssh_key_msg %}
|
||||
{% url 'hosting:create_ssh_key' as create_ssh_url %}
|
||||
<br/>{% blocktrans %}To access your VM, add your SSH key <a href="{{create_ssh_url}}">here</a>{% endblocktrans %}
|
||||
<br/>{% blocktrans %}To access your VM, <a href="{{create_ssh_url}}">add your SSH key here</a>{% endblocktrans %}
|
||||
{% endif %}
|
||||
</p>
|
||||
<div class="text-right">
|
||||
|
|
|
@ -60,8 +60,9 @@ CONNECTION_ERROR = "Your VMs cannot be displayed at the moment due to a \
|
|||
minutes."
|
||||
|
||||
|
||||
class DashboardView(View):
|
||||
class DashboardView(LoginRequiredMixin, View):
|
||||
template_name = "hosting/dashboard.html"
|
||||
login_url = reverse_lazy('hosting:login')
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = {}
|
||||
|
@ -80,8 +81,6 @@ class DjangoHostingView(ProcessVMSelectionMixin, View):
|
|||
templates = OpenNebulaManager().get_templates()
|
||||
data = VirtualMachineTemplateSerializer(templates, many=True).data
|
||||
configuration_options = HostingPlan.get_serialized_configs()
|
||||
|
||||
# configuration_detail = dict(VirtualMachinePlan.VM_CONFIGURATION).get(HOSTING)
|
||||
context = {
|
||||
'hosting': HOSTING,
|
||||
'hosting_long': "Django",
|
||||
|
@ -134,7 +133,6 @@ class NodeJSHostingView(ProcessVMSelectionMixin, View):
|
|||
|
||||
def get_context_data(self, **kwargs):
|
||||
HOSTING = 'nodejs'
|
||||
# configuration_detail = dict(VirtualMachinePlan.VM_CONFIGURATION).get(HOSTING)
|
||||
templates = OpenNebulaManager().get_templates()
|
||||
configuration_options = HostingPlan.get_serialized_configs()
|
||||
|
||||
|
@ -249,7 +247,8 @@ class SignupValidateView(TemplateView):
|
|||
<br />{go_back} {hurl}.'.format(
|
||||
signup_success_message=_(
|
||||
'Thank you for signing up. We have sent an email to you. '
|
||||
'Please follow the instructions in it to activate your account. Once activated, you can login using'),
|
||||
'Please follow the instructions in it to activate your '
|
||||
'account. Once activated, you can login using'),
|
||||
go_back=_('Go back to'),
|
||||
lurl=login_url,
|
||||
hurl=home_url
|
||||
|
@ -269,7 +268,8 @@ class SignupValidatedView(SignupValidateView):
|
|||
reverse('hosting:login') + '">' + str(_('login')) + '</a>'
|
||||
section_title = _('Account activation')
|
||||
if validated:
|
||||
message = '{account_activation_string} <br /> {login_string} {lurl}.'.format(
|
||||
message = ('{account_activation_string} <br />'
|
||||
' {login_string} {lurl}.').format(
|
||||
account_activation_string=_(
|
||||
"Your account has been activated."),
|
||||
login_string=_("You can now"),
|
||||
|
@ -636,10 +636,7 @@ class PaymentVMView(LoginRequiredMixin, FormView):
|
|||
return HttpResponseRedirect(
|
||||
reverse('hosting:payment') + '#payment_error')
|
||||
|
||||
# Create Billing Address
|
||||
billing_address = form.save()
|
||||
request.session['billing_address_data'] = billing_address_data
|
||||
request.session['billing_address'] = billing_address.id
|
||||
request.session['token'] = token
|
||||
request.session['customer'] = customer.id
|
||||
return HttpResponseRedirect("{url}?{query_params}".format(
|
||||
|
@ -687,7 +684,8 @@ class OrdersHostingDetailView(LoginRequiredMixin,
|
|||
try:
|
||||
vm_detail = VMDetail.objects.get(vm_id=obj.vm_id)
|
||||
context['vm'] = vm_detail.__dict__
|
||||
context['vm']['name'] = '{}-{}'.format(context['vm']['configuration'], context['vm']['vm_id'])
|
||||
context['vm']['name'] = '{}-{}'.format(
|
||||
context['vm']['configuration'], context['vm']['vm_id'])
|
||||
except VMDetail.DoesNotExist:
|
||||
try:
|
||||
manager = OpenNebulaManager(
|
||||
|
@ -750,7 +748,6 @@ class OrdersHostingDetailView(LoginRequiredMixin,
|
|||
stripe_customer_id = request.session.get('customer')
|
||||
customer = StripeCustomer.objects.filter(id=stripe_customer_id).first()
|
||||
billing_address_data = request.session.get('billing_address_data')
|
||||
billing_address_id = request.session.get('billing_address')
|
||||
vm_template_id = template.get('id', 1)
|
||||
|
||||
# Make stripe charge to a customer
|
||||
|
@ -768,8 +765,7 @@ class OrdersHostingDetailView(LoginRequiredMixin,
|
|||
cpu = specs.get('cpu')
|
||||
memory = specs.get('memory')
|
||||
disk_size = specs.get('disk_size')
|
||||
amount_to_be_charged = get_vm_price(cpu=cpu, memory=memory,
|
||||
disk_size=disk_size)
|
||||
amount_to_be_charged = specs.get('price')
|
||||
plan_name = StripeUtils.get_stripe_plan_name(cpu=cpu,
|
||||
memory=memory,
|
||||
disk_size=disk_size)
|
||||
|
@ -788,12 +784,24 @@ class OrdersHostingDetailView(LoginRequiredMixin,
|
|||
'response_object').stripe_plan_id}])
|
||||
stripe_subscription_obj = subscription_result.get('response_object')
|
||||
# Check if the subscription was approved and is active
|
||||
if stripe_subscription_obj is None or stripe_subscription_obj.status != 'active':
|
||||
if (stripe_subscription_obj is None or
|
||||
stripe_subscription_obj.status != 'active'):
|
||||
msg = subscription_result.get('error')
|
||||
messages.add_message(self.request, messages.ERROR, msg,
|
||||
extra_tags='failed_payment')
|
||||
return HttpResponseRedirect(
|
||||
reverse('hosting:payment') + '#payment_error')
|
||||
response = {
|
||||
'status': False,
|
||||
'redirect': "{url}#{section}".format(
|
||||
url=reverse('hosting:payment'),
|
||||
section='payment_error'),
|
||||
'msg_title': str(_('Error.')),
|
||||
'msg_body': str(
|
||||
_('There was a payment related error.'
|
||||
' On close of this popup, you will be redirected back to'
|
||||
' the payment page.'))
|
||||
}
|
||||
return HttpResponse(json.dumps(response),
|
||||
content_type="application/json")
|
||||
user = {
|
||||
'name': self.request.user.name,
|
||||
'email': self.request.user.email,
|
||||
|
@ -804,8 +812,7 @@ class OrdersHostingDetailView(LoginRequiredMixin,
|
|||
}
|
||||
create_vm_task.delay(vm_template_id, user, specs, template,
|
||||
stripe_customer_id, billing_address_data,
|
||||
billing_address_id,
|
||||
stripe_subscription_obj, card_details_dict)
|
||||
stripe_subscription_obj.id, card_details_dict)
|
||||
|
||||
for session_var in ['specs', 'template', 'billing_address',
|
||||
'billing_address_data',
|
||||
|
@ -1008,6 +1015,7 @@ class VirtualMachineView(LoginRequiredMixin, View):
|
|||
return redirect(reverse('hosting:virtual_machines'))
|
||||
elif self.request.is_ajax():
|
||||
return HttpResponse()
|
||||
context = None
|
||||
try:
|
||||
serializer = VirtualMachineSerializer(vm)
|
||||
context = {
|
||||
|
@ -1017,7 +1025,11 @@ class VirtualMachineView(LoginRequiredMixin, View):
|
|||
}
|
||||
except Exception as ex:
|
||||
logger.debug("Exception generated {}".format(str(ex)))
|
||||
pass
|
||||
messages.error(self.request,
|
||||
_('We could not find the requested VM. Please '
|
||||
'contact Data Center Light Support.')
|
||||
)
|
||||
return redirect(reverse('hosting:virtual_machines'))
|
||||
|
||||
return render(request, self.template_name, context)
|
||||
|
||||
|
@ -1125,3 +1137,15 @@ class HostingBillDetailView(PermissionRequiredMixin, LoginRequiredMixin,
|
|||
bill.total_price += vm['price']
|
||||
context['vms'] = vms
|
||||
return context
|
||||
|
||||
|
||||
def forbidden_view(request, exception=None, reason=''):
|
||||
"""
|
||||
Handle 403 error
|
||||
"""
|
||||
logger.error(str(exception) if exception else None)
|
||||
logger.error('Reason = {reason}'.format(reason=reason))
|
||||
err_msg = _('There was an error processing your request. Please try '
|
||||
'again.')
|
||||
messages.add_message(request, messages.ERROR, err_msg)
|
||||
return HttpResponseRedirect(request.get_full_path())
|
||||
|
|
|
@ -184,9 +184,9 @@ class StripeCustomer(models.Model):
|
|||
customer_name=None):
|
||||
"""
|
||||
This method creates a Stripe API customer with the given
|
||||
email, token and customer_name. This is different from
|
||||
get_or_create method below in that it does not create a
|
||||
CustomUser and associate the customer created in stripe
|
||||
email, token and customer_name. This is different from
|
||||
get_or_create method below in that it does not create a
|
||||
CustomUser and associate the customer created in stripe
|
||||
with it, while get_or_create does that before creating the
|
||||
stripe user.
|
||||
"""
|
||||
|
|
|
@ -8,7 +8,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-09-25 20:11+0000\n"
|
||||
"POT-Creation-Date: 2017-09-29 20:33+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
@ -771,10 +771,13 @@ msgstr ""
|
|||
msgid "Country"
|
||||
msgstr ""
|
||||
|
||||
msgid "Street Building"
|
||||
msgid "Name"
|
||||
msgstr ""
|
||||
|
||||
msgid "Name"
|
||||
msgid "Email Address"
|
||||
msgstr ""
|
||||
|
||||
msgid "Street Building"
|
||||
msgstr ""
|
||||
|
||||
msgid "Email"
|
||||
|
@ -786,9 +789,9 @@ msgstr "Telefon"
|
|||
msgid "Message"
|
||||
msgstr "Nachricht"
|
||||
|
||||
msgid "An email with the activation link has been sent to your email"
|
||||
msgid "An email with the activation link has been sent to you"
|
||||
msgstr ""
|
||||
"Der Link zum Zurücksetzen deines Passwortes wurde an deine E-Mail gesendet"
|
||||
"Es wurde eine E-Mail mit dem Aktivierungslink an Dich gesendet."
|
||||
|
||||
msgid "Account Activation"
|
||||
msgstr "Accountaktivierung"
|
||||
|
|
|
@ -66,7 +66,7 @@ class LoginViewMixin(FormView):
|
|||
|
||||
class ResendActivationLinkViewMixin(FormView):
|
||||
success_message = _(
|
||||
"An email with the activation link has been sent to your email")
|
||||
"An email with the activation link has been sent to you")
|
||||
|
||||
def generate_email_context(self, user):
|
||||
context = {
|
||||
|
|
Loading…
Reference in a new issue