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:
Pcoder 2017-10-01 23:24:06 +02:00 committed by GitHub
commit 350a52c657
19 changed files with 227 additions and 168 deletions

View file

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \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" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -423,30 +423,15 @@ msgstr "Abarbeitung..."
msgid "Hold tight, we are processing your request" msgid "Hold tight, we are processing your request"
msgstr "Bitte warten - wir verbeiten Deine Anfrage gerade" msgstr "Bitte warten - wir verbeiten Deine Anfrage gerade"
msgid "OK"
msgstr ""
msgid "Close"
msgstr ""
msgid "Some problem encountered. Please try again later." msgid "Some problem encountered. Please try again later."
msgstr "Ein Problem ist aufgetreten. Bitte versuche es später noch einmal." 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" msgid "Thank you for order! Our team will contact you via email"
msgstr "" msgstr ""
"Vielen Dank für die Bestellung. Unser Team setzt sich sobald wie möglich mit " "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 " "There was a payment related error. On close of this popup, you will be "
"redirected back to the payment page." "redirected back to the payment page."
msgstr "" 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." msgid "Thank you for the order."
msgstr "Danke für Deine Bestellung." msgstr "Danke für Deine Bestellung."
@ -558,6 +545,27 @@ msgstr ""
"Deine VM ist gleich bereit. Wir senden Dir eine Bestätigungsemail, sobald Du " "Deine VM ist gleich bereit. Wir senden Dir eine Bestätigungsemail, sobald Du "
"auf sie zugreifen kannst." "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" #~ msgid "Email Address"
#~ msgstr "E-Mail-Adresse" #~ msgstr "E-Mail-Adresse"

View file

@ -50,15 +50,20 @@ def retry_task(task, exception=None):
@app.task(bind=True, max_retries=settings.CELERY_MAX_RETRIES) @app.task(bind=True, max_retries=settings.CELERY_MAX_RETRIES)
def create_vm_task(self, vm_template_id, user, specs, template, def create_vm_task(self, vm_template_id, user, specs, template,
stripe_customer_id, billing_address_data, stripe_customer_id, billing_address_data,
billing_address_id, stripe_subscription_id, cc_details):
charge, cc_details):
logger.debug( logger.debug(
"Running create_vm_task on {}".format(current_task.request.hostname)) "Running create_vm_task on {}".format(current_task.request.hostname))
vm_id = None vm_id = None
try: try:
final_price = specs.get('price') final_price = specs.get('price')
billing_address = BillingAddress.objects.filter( billing_address = BillingAddress(
id=billing_address_id).first() 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() customer = StripeCustomer.objects.filter(id=stripe_customer_id).first()
if 'pass' in user: if 'pass' in user:
@ -111,8 +116,7 @@ def create_vm_task(self, vm_template_id, user, specs, template,
billing_address_user_form.save() billing_address_user_form.save()
# Associate an order with a stripe subscription # Associate an order with a stripe subscription
charge_object = DictDotLookup(charge) order.set_subscription_id(stripe_subscription_id, cc_details)
order.set_subscription_id(charge_object, cc_details)
# If the Stripe payment succeeds, set order status approved # If the Stripe payment succeeds, set order status approved
order.set_approved() order.set_approved()
@ -183,7 +187,8 @@ def create_vm_task(self, vm_template_id, user, specs, template,
public_keys] public_keys]
if len(keys) > 0: if len(keys) > 0:
logger.debug( 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))) host=new_host, num_keys=len(keys)))
# Let's delay the task by 75 seconds to be sure # Let's delay the task by 75 seconds to be sure
# that we run the cdist configure after the host # 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
return vm_id 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())

View file

@ -75,21 +75,12 @@ class CeleryTaskTestCase(TestCase):
stripe_customer.stripe_id, stripe_customer.stripe_id,
self.token) self.token)
card_details_dict = card_details.get('response_object') 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, billing_address_data = {'cardholder_name': self.customer_name,
'postal_code': '1231', 'postal_code': '1231',
'country': 'CH', 'country': 'CH',
'token': self.token, 'token': self.token,
'street_address': 'Monty\'s Street', 'street_address': 'Monty\'s Street',
'city': 'Hollywood'} 'city': 'Hollywood'}
billing_address_id = billing_address.id
vm_template_id = template_data.get('id', 1) vm_template_id = template_data.get('id', 1)
cpu = specs.get('cpu') cpu = specs.get('cpu')
@ -125,8 +116,7 @@ class CeleryTaskTestCase(TestCase):
template_data, template_data,
stripe_customer.id, stripe_customer.id,
billing_address_data, billing_address_data,
billing_address_id, stripe_subscription_obj.id,
stripe_subscription_obj,
card_details_dict) card_details_dict)
new_vm_id = 0 new_vm_id = 0
res = None res = None

View file

@ -348,6 +348,11 @@ class PaymentOrderView(FormView):
form_kwargs.update({ form_kwargs.update({
'instance': self.request.user.billing_addresses.first() '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 return form_kwargs
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
@ -379,14 +384,40 @@ class PaymentOrderView(FormView):
email=this_user.get('email'), email=this_user.get('email'),
token=token) token=token)
else: else:
user_email = form.cleaned_data.get('email')
user_name = form.cleaned_data.get('name')
this_user = { this_user = {
'email': form.cleaned_data.get('email'), 'email': user_email,
'name': form.cleaned_data.get('name') 'name': user_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( customer = StripeCustomer.create_stripe_api_customer(
email=this_user.get('email'), email=user_email,
token=token, token=token,
customer_name=form.cleaned_data.get('name')) 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['billing_address_data'] = form.cleaned_data
request.session['user'] = this_user request.session['user'] = this_user
# Get or create stripe customer # Get or create stripe customer
@ -395,8 +426,10 @@ class PaymentOrderView(FormView):
return self.render_to_response( return self.render_to_response(
self.get_context_data(form=form)) self.get_context_data(form=form))
request.session['token'] = token request.session['token'] = token
request.session[ if type(customer) is StripeCustomer:
'customer'] = customer.id if request.user.is_authenticated() else customer request.session['customer'] = customer.stripe_id
else:
request.session['customer'] = customer
return HttpResponseRedirect( return HttpResponseRedirect(
reverse('datacenterlight:order_confirmation')) reverse('datacenterlight:order_confirmation'))
else: else:
@ -415,14 +448,7 @@ class OrderConfirmationView(DetailView):
return HttpResponseRedirect(reverse('datacenterlight:index')) return HttpResponseRedirect(reverse('datacenterlight:index'))
if 'token' not in request.session: if 'token' not in request.session:
return HttpResponseRedirect(reverse('datacenterlight:payment')) return HttpResponseRedirect(reverse('datacenterlight:payment'))
stripe_customer_id = request.session.get('customer') stripe_api_cus_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_utils = StripeUtils() stripe_utils = StripeUtils()
card_details = stripe_utils.get_card_details(stripe_api_cus_id, card_details = stripe_utils.get_card_details(stripe_api_cus_id,
request.session.get( request.session.get(
@ -445,15 +471,8 @@ class OrderConfirmationView(DetailView):
template = request.session.get('template') template = request.session.get('template')
specs = request.session.get('specs') specs = request.session.get('specs')
user = request.session.get('user') user = request.session.get('user')
stripe_customer_id = request.session.get('customer') stripe_api_cus_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
vm_template_id = template.get('id', 1) vm_template_id = template.get('id', 1)
stripe_utils = StripeUtils() stripe_utils = StripeUtils()
card_details = stripe_utils.get_card_details(stripe_api_cus_id, card_details = stripe_utils.get_card_details(stripe_api_cus_id,
request.session.get( request.session.get(
@ -498,8 +517,8 @@ class OrderConfirmationView(DetailView):
'response_object').stripe_plan_id}]) 'response_object').stripe_plan_id}])
stripe_subscription_obj = subscription_result.get('response_object') stripe_subscription_obj = subscription_result.get('response_object')
# Check if the subscription was approved and is active # Check if the subscription was approved and is active
if stripe_subscription_obj is None or \ if (stripe_subscription_obj is None
stripe_subscription_obj.status != 'active': or stripe_subscription_obj.status != 'active'):
msg = subscription_result.get('error') msg = subscription_result.get('error')
messages.add_message(self.request, messages.ERROR, msg, messages.add_message(self.request, messages.ERROR, msg,
extra_tags='failed_payment') extra_tags='failed_payment')
@ -546,10 +565,10 @@ class OrderConfirmationView(DetailView):
password=password) password=password)
login(request, new_user) login(request, new_user)
else: else:
customer = StripeCustomer.objects.filter( # We assume that if the user is here, his/her StripeCustomer
id=stripe_customer_id).first() # object already exists
custom_user = customer.user stripe_customer_id = request.user.stripecustomer.id
stripe_customer_id = customer.id custom_user = request.user
# Save billing address # Save billing address
billing_address_data = request.session.get('billing_address_data') billing_address_data = request.session.get('billing_address_data')
@ -557,12 +576,6 @@ class OrderConfirmationView(DetailView):
billing_address_data.update({ billing_address_data.update({
'user': custom_user.id '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 = { user = {
'name': custom_user.name, 'name': custom_user.name,
'email': custom_user.email, 'email': custom_user.email,
@ -574,8 +587,7 @@ class OrderConfirmationView(DetailView):
create_vm_task.delay(vm_template_id, user, specs, template, create_vm_task.delay(vm_template_id, user, specs, template,
stripe_customer_id, billing_address_data, stripe_customer_id, billing_address_data,
billing_address_id, stripe_subscription_obj.id, card_details_dict)
stripe_subscription_obj, card_details_dict)
for session_var in ['specs', 'template', 'billing_address', for session_var in ['specs', 'template', 'billing_address',
'billing_address_data', 'billing_address_data',
'token', 'customer']: 'token', 'customer']:

View file

@ -161,6 +161,8 @@ MIDDLEWARE_CLASSES = (
'cms.middleware.language.LanguageCookieMiddleware', 'cms.middleware.language.LanguageCookieMiddleware',
) )
CSRF_FAILURE_VIEW = 'hosting.views.forbidden_view'
ROOT_URLCONF = 'dynamicweb.urls' ROOT_URLCONF = 'dynamicweb.urls'
TEMPLATES = [ TEMPLATES = [

View file

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \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" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -337,6 +337,9 @@ msgstr "Rechnung Datum"
msgid "Status" msgid "Status"
msgstr "" msgstr ""
msgid "Terminated"
msgstr "Beendet"
msgid "Approved" msgid "Approved"
msgstr "Akzeptiert" msgstr "Akzeptiert"
@ -358,6 +361,9 @@ msgstr "Bestellungsübersicht"
msgid "Product" msgid "Product"
msgstr "Produkt" msgstr "Produkt"
msgid "Period"
msgstr ""
msgid "Cores" msgid "Cores"
msgstr "Prozessorkerne" msgstr "Prozessorkerne"
@ -390,6 +396,12 @@ msgstr "Abarbeitung..."
msgid "Hold tight, we are processing your request" msgid "Hold tight, we are processing your request"
msgstr "Bitte warten - wir bearbeiten Deine Anfrage gerade" msgstr "Bitte warten - wir bearbeiten Deine Anfrage gerade"
msgid "OK"
msgstr ""
msgid "Close"
msgstr "Schliessen"
msgid "Some problem encountered. Please try again later." msgid "Some problem encountered. Please try again later."
msgstr "Ein Problem ist aufgetreten. Bitte versuche es später noch einmal." 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" msgid "Do you want to cancel your Virtual Machine"
msgstr "Bist Du sicher, dass Du Deine virtuelle Maschine beenden willst" msgstr "Bist Du sicher, dass Du Deine virtuelle Maschine beenden willst"
msgid "OK"
msgstr ""
#, python-format #, python-format
msgid "" msgid ""
"Your Virtual Machine <strong>%(machine_name)s</strong> is successfully " "Your Virtual Machine <strong>%(machine_name)s</strong> is successfully "
"terminated!" "terminated!"
msgstr "" msgstr ""
"Deine Virtuelle Machine (VM) <strong>%(machine_name)s</strong> wurde erfolgreich " "Deine Virtuelle Machine (VM) <strong>%(machine_name)s</strong> wurde "
"beendet!" "erfolgreich beendet!"
msgid "Virtual Machines" msgid "Virtual Machines"
msgstr "Virtuelle Maschinen" msgstr "Virtuelle Maschinen"
@ -616,6 +625,13 @@ msgstr "Virtuelle Maschinen"
msgid "To create a new virtual machine, click \"Create VM\"" msgid "To create a new virtual machine, click \"Create VM\""
msgstr "Um eine neue VM zu erzeugen, klicke \"Neue VM erzeugen\"" 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" msgid "CREATE VM"
msgstr "NEUE 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 "" msgstr ""
"Um eine VM zu erstellen musst du zuerst einen SSH-Key erstellen / hochladen." "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." msgid "Thank you for the order."
msgstr "Danke für Deine Bestellung." msgstr "Danke für Deine Bestellung."
@ -697,8 +723,11 @@ msgid ""
"contact Data Center Light Support." "contact Data Center Light Support."
msgstr "Kontaktiere den Data Center Light Support." msgstr "Kontaktiere den Data Center Light Support."
msgid "Terminated" msgid ""
msgstr "Beendet" "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" msgid "Error terminating VM"
msgstr "Fehler beenden VM" msgstr "Fehler beenden VM"
@ -706,8 +735,9 @@ msgstr "Fehler beenden VM"
msgid "Virtual Machine Cancellation" msgid "Virtual Machine Cancellation"
msgstr "VM Kündigung" msgstr "VM Kündigung"
#~ msgid "Close" msgid "There was an error processing your request. Please try again."
#~ msgstr "Schliessen" msgstr "Es gab einen Fehler bei der Bearbeitung Deine Anfrage. Bitte"
" versuche es noch einmal."
#~ msgid "VM %(VM_ID)s terminated successfully" #~ msgid "VM %(VM_ID)s terminated successfully"
#~ msgstr "VM %(VM_ID)s erfolgreich beendet" #~ 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 " #~ "Your SSH private key was already generated and downloaded, if you lost "
#~ "it, contact us. " #~ "it, contact us. "
#~ msgstr "" #~ msgstr ""
#~ "Dein privater SSH Key wurde bereits generiert und heruntergeladen. " #~ "Dein privater SSH Key wurde bereits generiert und heruntergeladen. Falls "
#~ "Falls Du ihn verloren hast, kontaktiere uns." #~ "Du ihn verloren hast, kontaktiere uns."

View file

@ -88,19 +88,19 @@ class HostingOrder(AssignPermissionsMixin, models.Model):
self.cc_brand = stripe_charge.source.brand self.cc_brand = stripe_charge.source.brand
self.save() 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. When creating a Stripe subscription, we have subscription id.
We store this in the subscription_id field. We store this in the subscription_id field.
This method sets the subscription id from subscription_object This method sets the subscription id
and also the last4 and credit card brands used for this order. 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 :param cc_details: A dict containing card details
{last4, brand} {last4, brand}
:return: :return:
""" """
self.subscription_id = subscription_object.id self.subscription_id = subscription_id
self.last4 = cc_details.get('last4') self.last4 = cc_details.get('last4')
self.cc_brand = cc_details.get('brand') self.cc_brand = cc_details.get('brand')
self.save() self.save()

View file

@ -86,23 +86,31 @@ $(document).ready(function() {
url: create_vm_form.attr('action'), url: create_vm_form.attr('action'),
type: 'POST', type: 'POST',
data: create_vm_form.serialize(), 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) { success: function (data) {
if (data.status === true) {
fa_icon = $('.modal-icon > .fa'); fa_icon = $('.modal-icon > .fa');
fa_icon.attr('class', 'checkmark'); modal_btn = $('#createvm-modal-done-btn');
// $('.modal-header > .close').removeClass('hidden');
$('#createvm-modal-title').text(data.msg_title); $('#createvm-modal-title').text(data.msg_title);
$('#createvm-modal-body').text(data.msg_body); $('#createvm-modal-body').html(data.msg_body);
$('#createvm-modal-done-btn') modal_btn.attr('href', data.redirect)
.attr('href', data.redirect)
.removeClass('hide'); .removeClass('hide');
if (data.status === true) {
fa_icon.attr('class', 'checkmark');
} 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) { error: function (xmlhttprequest, textstatus, message) {
fa_icon = $('.modal-icon > .fa'); fa_icon = $('.modal-icon > .fa');
fa_icon.attr('class', 'fa fa-close'); fa_icon.attr('class', 'fa fa-close');
if (typeof(create_vm_error_message) !== 'undefined') { 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); $('#btn-create-vm').prop('disabled', false);
$('#createvm-modal-close-btn').removeClass('hide'); $('#createvm-modal-close-btn').removeClass('hide');

View 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 %}

View file

@ -16,13 +16,7 @@
<div class="auth-content"> <div class="auth-content">
<div class="intro-message auth-box"> <div class="intro-message auth-box">
<h2 class="section-heading">{% trans "Login"%}</h2> <h2 class="section-heading">{% trans "Login"%}</h2>
{% if messages %} {% include 'hosting/includes/_messages.html' %}
<ul class="list-unstyled msg-list">
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
<form action="{% url 'hosting:login' %}" method="post" class="form" novalidated> <form action="{% url 'hosting:login' %}" method="post" class="form" novalidated>
{% csrf_token %} {% csrf_token %}
{% for field in form %} {% for field in form %}

View file

@ -17,6 +17,7 @@
<div class="auth-content"> <div class="auth-content">
<div class="intro-message auth-box sign-up"> <div class="intro-message auth-box sign-up">
<h2 class="section-heading">{% trans "Resend activation link"%}</h2> <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> <form action="{% url 'hosting:resend_activation_link' %}" method="post" class="form" novalidate>
{% csrf_token %} {% csrf_token %}
{% for field in form %} {% for field in form %}

View file

@ -17,6 +17,7 @@
<div class="auth-content"> <div class="auth-content">
<div class="intro-message auth-box sign-up"> <div class="intro-message auth-box sign-up">
<h2 class="section-heading">{% trans "Reset your password"%}</h2> <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> <form action="{% url 'hosting:reset_password' %}" method="post" class="form" novalidate>
{% csrf_token %} {% csrf_token %}
{% for field in form %} {% for field in form %}

View file

@ -15,6 +15,7 @@
<div class="auth-content"> <div class="auth-content">
<div class="intro-message auth-box sign-up"> <div class="intro-message auth-box sign-up">
<h2 class="section-heading">{% trans "Sign up"%}</h2> <h2 class="section-heading">{% trans "Sign up"%}</h2>
{% include 'hosting/includes/_messages.html' %}
<form action="{% url 'hosting:signup' %}" method="post" class="form" novalidate> <form action="{% url 'hosting:signup' %}" method="post" class="form" novalidate>
{% csrf_token %} {% csrf_token %}
{% for field in form %} {% for field in form %}

View file

@ -11,6 +11,7 @@
<div class="auth-center"> <div class="auth-center">
<div class="auth-title"> <div class="auth-title">
<h2>{% trans "Your VM hosted in Switzerland"%}</h2> <h2>{% trans "Your VM hosted in Switzerland"%}</h2>
{% include 'hosting/includes/_messages.html' %}
</div> </div>
<div class="auth-content"> <div class="auth-content">
<div class="intro-message auth-box sign-up"> <div class="intro-message auth-box sign-up">

View file

@ -16,7 +16,7 @@
<p>{% trans 'To create a new virtual machine, click "Create VM"' %} <p>{% trans 'To create a new virtual machine, click "Create VM"' %}
{% if show_create_ssh_key_msg %} {% if show_create_ssh_key_msg %}
{% url 'hosting:create_ssh_key' as create_ssh_url %} {% 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 %} {% endif %}
</p> </p>
<div class="text-right"> <div class="text-right">

View file

@ -60,8 +60,9 @@ CONNECTION_ERROR = "Your VMs cannot be displayed at the moment due to a \
minutes." minutes."
class DashboardView(View): class DashboardView(LoginRequiredMixin, View):
template_name = "hosting/dashboard.html" template_name = "hosting/dashboard.html"
login_url = reverse_lazy('hosting:login')
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = {} context = {}
@ -80,8 +81,6 @@ class DjangoHostingView(ProcessVMSelectionMixin, View):
templates = OpenNebulaManager().get_templates() templates = OpenNebulaManager().get_templates()
data = VirtualMachineTemplateSerializer(templates, many=True).data data = VirtualMachineTemplateSerializer(templates, many=True).data
configuration_options = HostingPlan.get_serialized_configs() configuration_options = HostingPlan.get_serialized_configs()
# configuration_detail = dict(VirtualMachinePlan.VM_CONFIGURATION).get(HOSTING)
context = { context = {
'hosting': HOSTING, 'hosting': HOSTING,
'hosting_long': "Django", 'hosting_long': "Django",
@ -134,7 +133,6 @@ class NodeJSHostingView(ProcessVMSelectionMixin, View):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
HOSTING = 'nodejs' HOSTING = 'nodejs'
# configuration_detail = dict(VirtualMachinePlan.VM_CONFIGURATION).get(HOSTING)
templates = OpenNebulaManager().get_templates() templates = OpenNebulaManager().get_templates()
configuration_options = HostingPlan.get_serialized_configs() configuration_options = HostingPlan.get_serialized_configs()
@ -249,7 +247,8 @@ class SignupValidateView(TemplateView):
<br />{go_back} {hurl}.'.format( <br />{go_back} {hurl}.'.format(
signup_success_message=_( signup_success_message=_(
'Thank you for signing up. We have sent an email to you. ' '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'), go_back=_('Go back to'),
lurl=login_url, lurl=login_url,
hurl=home_url hurl=home_url
@ -269,7 +268,8 @@ class SignupValidatedView(SignupValidateView):
reverse('hosting:login') + '">' + str(_('login')) + '</a>' reverse('hosting:login') + '">' + str(_('login')) + '</a>'
section_title = _('Account activation') section_title = _('Account activation')
if validated: if validated:
message = '{account_activation_string} <br /> {login_string} {lurl}.'.format( message = ('{account_activation_string} <br />'
' {login_string} {lurl}.').format(
account_activation_string=_( account_activation_string=_(
"Your account has been activated."), "Your account has been activated."),
login_string=_("You can now"), login_string=_("You can now"),
@ -636,10 +636,7 @@ class PaymentVMView(LoginRequiredMixin, FormView):
return HttpResponseRedirect( return HttpResponseRedirect(
reverse('hosting:payment') + '#payment_error') reverse('hosting:payment') + '#payment_error')
# Create Billing Address
billing_address = form.save()
request.session['billing_address_data'] = billing_address_data request.session['billing_address_data'] = billing_address_data
request.session['billing_address'] = billing_address.id
request.session['token'] = token request.session['token'] = token
request.session['customer'] = customer.id request.session['customer'] = customer.id
return HttpResponseRedirect("{url}?{query_params}".format( return HttpResponseRedirect("{url}?{query_params}".format(
@ -687,7 +684,8 @@ class OrdersHostingDetailView(LoginRequiredMixin,
try: try:
vm_detail = VMDetail.objects.get(vm_id=obj.vm_id) vm_detail = VMDetail.objects.get(vm_id=obj.vm_id)
context['vm'] = vm_detail.__dict__ 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: except VMDetail.DoesNotExist:
try: try:
manager = OpenNebulaManager( manager = OpenNebulaManager(
@ -750,7 +748,6 @@ class OrdersHostingDetailView(LoginRequiredMixin,
stripe_customer_id = request.session.get('customer') stripe_customer_id = request.session.get('customer')
customer = StripeCustomer.objects.filter(id=stripe_customer_id).first() customer = StripeCustomer.objects.filter(id=stripe_customer_id).first()
billing_address_data = request.session.get('billing_address_data') billing_address_data = request.session.get('billing_address_data')
billing_address_id = request.session.get('billing_address')
vm_template_id = template.get('id', 1) vm_template_id = template.get('id', 1)
# Make stripe charge to a customer # Make stripe charge to a customer
@ -768,8 +765,7 @@ class OrdersHostingDetailView(LoginRequiredMixin,
cpu = specs.get('cpu') cpu = specs.get('cpu')
memory = specs.get('memory') memory = specs.get('memory')
disk_size = specs.get('disk_size') disk_size = specs.get('disk_size')
amount_to_be_charged = get_vm_price(cpu=cpu, memory=memory, amount_to_be_charged = specs.get('price')
disk_size=disk_size)
plan_name = StripeUtils.get_stripe_plan_name(cpu=cpu, plan_name = StripeUtils.get_stripe_plan_name(cpu=cpu,
memory=memory, memory=memory,
disk_size=disk_size) disk_size=disk_size)
@ -788,12 +784,24 @@ class OrdersHostingDetailView(LoginRequiredMixin,
'response_object').stripe_plan_id}]) 'response_object').stripe_plan_id}])
stripe_subscription_obj = subscription_result.get('response_object') stripe_subscription_obj = subscription_result.get('response_object')
# Check if the subscription was approved and is active # 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') msg = subscription_result.get('error')
messages.add_message(self.request, messages.ERROR, msg, messages.add_message(self.request, messages.ERROR, msg,
extra_tags='failed_payment') extra_tags='failed_payment')
return HttpResponseRedirect( response = {
reverse('hosting:payment') + '#payment_error') '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 = { user = {
'name': self.request.user.name, 'name': self.request.user.name,
'email': self.request.user.email, 'email': self.request.user.email,
@ -804,8 +812,7 @@ class OrdersHostingDetailView(LoginRequiredMixin,
} }
create_vm_task.delay(vm_template_id, user, specs, template, create_vm_task.delay(vm_template_id, user, specs, template,
stripe_customer_id, billing_address_data, stripe_customer_id, billing_address_data,
billing_address_id, stripe_subscription_obj.id, card_details_dict)
stripe_subscription_obj, card_details_dict)
for session_var in ['specs', 'template', 'billing_address', for session_var in ['specs', 'template', 'billing_address',
'billing_address_data', 'billing_address_data',
@ -1008,6 +1015,7 @@ class VirtualMachineView(LoginRequiredMixin, View):
return redirect(reverse('hosting:virtual_machines')) return redirect(reverse('hosting:virtual_machines'))
elif self.request.is_ajax(): elif self.request.is_ajax():
return HttpResponse() return HttpResponse()
context = None
try: try:
serializer = VirtualMachineSerializer(vm) serializer = VirtualMachineSerializer(vm)
context = { context = {
@ -1017,7 +1025,11 @@ class VirtualMachineView(LoginRequiredMixin, View):
} }
except Exception as ex: except Exception as ex:
logger.debug("Exception generated {}".format(str(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) return render(request, self.template_name, context)
@ -1125,3 +1137,15 @@ class HostingBillDetailView(PermissionRequiredMixin, LoginRequiredMixin,
bill.total_price += vm['price'] bill.total_price += vm['price']
context['vms'] = vms context['vms'] = vms
return context 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())

View file

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \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" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -771,10 +771,13 @@ msgstr ""
msgid "Country" msgid "Country"
msgstr "" msgstr ""
msgid "Street Building" msgid "Name"
msgstr "" msgstr ""
msgid "Name" msgid "Email Address"
msgstr ""
msgid "Street Building"
msgstr "" msgstr ""
msgid "Email" msgid "Email"
@ -786,9 +789,9 @@ msgstr "Telefon"
msgid "Message" msgid "Message"
msgstr "Nachricht" 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 "" 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" msgid "Account Activation"
msgstr "Accountaktivierung" msgstr "Accountaktivierung"

View file

@ -66,7 +66,7 @@ class LoginViewMixin(FormView):
class ResendActivationLinkViewMixin(FormView): class ResendActivationLinkViewMixin(FormView):
success_message = _( 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): def generate_email_context(self, user):
context = { context = {