merged master
This commit is contained in:
commit
6802e2fdbc
26 changed files with 294 additions and 395 deletions
|
@ -1,10 +1,15 @@
|
||||||
Next:
|
1.2.4: 2017-10-02
|
||||||
|
* #3780: [hosting] Store VM details locally
|
||||||
* #3764: [hosting] Show cancelled VMs' invoices
|
* #3764: [hosting] Show cancelled VMs' invoices
|
||||||
* #3736: [dcl] Refactor the place where we compute the VM price
|
* #3736: [dcl] Refactor the place where we compute the VM price
|
||||||
* #3730: [dcl] Refactor price parameter passed in the DCL flow
|
* #3730: [dcl] Refactor price parameter passed in the DCL flow
|
||||||
* #3807: [dcl] Remove PricingView as it is no more used
|
* #3807: [dcl] Remove PricingView as it is no more used
|
||||||
* #3813: [hosting] JS error in create ssh key page
|
* #3813: [hosting] JS error in create ssh key page
|
||||||
* #3756: [dcl] Update landing calculator and billing info page
|
* #3756: [dcl] Update landing calculator and billing info page
|
||||||
|
* Bugfix: Fix PR 493 bug that creates a new StripeCustomer for each buying of VM with the same email id
|
||||||
|
* #3835: [all] Forbidden (403) CSRF verification failed issue.
|
||||||
|
* Bugfix: [hosting] Dashboard strictly available after login
|
||||||
|
* #3808: [dcl] Order confirmation page redesign
|
||||||
1.2.3: 2017-09-25
|
1.2.3: 2017-09-25
|
||||||
* #3484: [dcl, hosting] Refactored account activation, password reset, VM order and cancellation email
|
* #3484: [dcl, hosting] Refactored account activation, password reset, VM order and cancellation email
|
||||||
* #3731: [dcl, hosting] Added cdist ssh key handler
|
* #3731: [dcl, hosting] Added cdist ssh key handler
|
||||||
|
|
|
@ -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-28 18:36+0530\n"
|
"POT-Creation-Date: 2017-10-03 18:54+0530\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"
|
||||||
|
@ -374,24 +374,6 @@ msgstr "Weiter"
|
||||||
msgid "Enter your credit card number"
|
msgid "Enter your credit card number"
|
||||||
msgstr "Deine Kreditkartennummer"
|
msgstr "Deine Kreditkartennummer"
|
||||||
|
|
||||||
msgid "Confirm Order"
|
|
||||||
msgstr "Bestellung Bestätigen"
|
|
||||||
|
|
||||||
msgid "Date"
|
|
||||||
msgstr "Datum"
|
|
||||||
|
|
||||||
msgid "Billed To:"
|
|
||||||
msgstr "Rechnungsadresse"
|
|
||||||
|
|
||||||
msgid "Payment Method:"
|
|
||||||
msgstr "Bezahlmethode"
|
|
||||||
|
|
||||||
msgid "ending in"
|
|
||||||
msgstr "endend in"
|
|
||||||
|
|
||||||
msgid "Order summary"
|
|
||||||
msgstr "Bestellungsübersicht"
|
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"By clicking \"Place order\" this plan will charge your credit card account "
|
"By clicking \"Place order\" this plan will charge your credit card account "
|
||||||
|
@ -403,21 +385,6 @@ msgstr ""
|
||||||
msgid "Place order"
|
msgid "Place order"
|
||||||
msgstr "Bestellen"
|
msgstr "Bestellen"
|
||||||
|
|
||||||
msgid "Processing..."
|
|
||||||
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 "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 "
|
||||||
|
@ -511,6 +478,9 @@ msgstr "Ungültige RAM-Grösse"
|
||||||
msgid "Invalid storage size"
|
msgid "Invalid storage size"
|
||||||
msgstr "Ungültige Speicher-Grösse"
|
msgstr "Ungültige Speicher-Grösse"
|
||||||
|
|
||||||
|
msgid "Confirm Order"
|
||||||
|
msgstr "Bestellung Bestätigen"
|
||||||
|
|
||||||
msgid "Error."
|
msgid "Error."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -518,6 +488,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."
|
||||||
|
@ -529,6 +501,30 @@ 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 "Processing..."
|
||||||
|
#~ msgstr "Abarbeitung..."
|
||||||
|
|
||||||
|
#~ msgid "Hold tight, we are processing your request"
|
||||||
|
#~ msgstr "Bitte warten - wir verbeiten Deine Anfrage gerade"
|
||||||
|
|
||||||
|
#~ msgid "Some problem encountered. Please try again later."
|
||||||
|
#~ msgstr "Ein Problem ist aufgetreten. Bitte versuche es später noch einmal."
|
||||||
|
|
||||||
|
#~ msgid "Date"
|
||||||
|
#~ msgstr "Datum"
|
||||||
|
|
||||||
|
#~ msgid "Billed To:"
|
||||||
|
#~ msgstr "Rechnungsadresse"
|
||||||
|
|
||||||
|
#~ msgid "Payment Method:"
|
||||||
|
#~ msgstr "Bezahlmethode"
|
||||||
|
|
||||||
|
#~ msgid "ending in"
|
||||||
|
#~ msgstr "endend in"
|
||||||
|
|
||||||
|
#~ msgid "Order summary"
|
||||||
|
#~ msgstr "Bestellungsübersicht"
|
||||||
|
|
||||||
#~ msgid "We are cutting down the costs significantly!"
|
#~ msgid "We are cutting down the costs significantly!"
|
||||||
#~ msgstr "Wir sorgen dafür, dass die Kosten für Dich signifikant abnehmen"
|
#~ msgstr "Wir sorgen dafür, dass die Kosten für Dich signifikant abnehmen"
|
||||||
|
|
||||||
|
|
|
@ -1501,6 +1501,8 @@ tech-sub-sec h2 {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
letter-spacing: 2px;
|
letter-spacing: 2px;
|
||||||
|
line-height: 24px;
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content-section-a {
|
.content-section-a {
|
||||||
|
|
|
@ -51,15 +51,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:
|
||||||
|
@ -112,8 +117,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()
|
||||||
|
@ -185,7 +189,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
|
||||||
|
@ -214,32 +219,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())
|
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
<hr class="intro-divider">
|
<hr class="intro-divider">
|
||||||
<ul class="list-inline intro-social-buttons">
|
<ul class="list-inline intro-social-buttons">
|
||||||
<li>
|
<li>
|
||||||
<a class="btn btn-default btn-lg btn-transparent url" href="#how"><i class="#Services"></i> <span class="network-name">{% trans "Highlights" %}</span></a>
|
<a class="btn btn-default btn-lg btn-transparent url" href="#how"><span class="network-name">{% trans "Highlights" %}</span></a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a class="btn btn-primary btn-lg page-scroll url" href="#price"><span class="network-name">{% trans "I want it!" %}</span></a>
|
<a class="btn btn-primary btn-lg page-scroll url" href="#price"><span class="network-name">{% trans "I want it!" %}</span></a>
|
||||||
|
|
|
@ -1,143 +1,24 @@
|
||||||
{% extends "hosting/base_short.html" %}
|
{% extends "hosting/order_detail.html" %}
|
||||||
{% load staticfiles bootstrap3 %}
|
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load custom_tags %}
|
|
||||||
|
|
||||||
{% block navbar %}
|
{% block navbar %}
|
||||||
{% include "datacenterlight/includes/_navbar.html" %}
|
{% include "datacenterlight/includes/_navbar.html" %}
|
||||||
{% endblock navbar %}
|
{% endblock navbar %}
|
||||||
|
|
||||||
{% block content %}
|
{% block submit_btn %}
|
||||||
|
<form id="virtual_machine_create_form" action="" method="POST">
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<div class="dcl-place-order-text">{% blocktrans with vm_price=request.session.specs.price %}By clicking "Place order" this plan will charge your credit card account with the fee of {{ vm_price }}CHF/month{% endblocktrans %}.</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4 order-confirm-btn text-right">
|
||||||
|
<button class="btn choice-btn" id="btn-create-vm"
|
||||||
|
data-toggle="modal" data-target="#createvm-modal">
|
||||||
|
{% trans "Place order" %}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{% endblock submit_btn %}
|
||||||
|
|
||||||
<div class="order-detail-container">
|
|
||||||
{% if messages %}
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-xs-12 col-md-8 col-md-offset-2">
|
|
||||||
<br/>
|
|
||||||
<div class="alert alert-warning">
|
|
||||||
{% for message in messages %}
|
|
||||||
<span>{{ message }}</span>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% if not error %}
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-xs-12 col-md-8 col-md-offset-2">
|
|
||||||
<div class="invoice-title">
|
|
||||||
<h2>{% trans "Confirm Order"%}</h2>
|
|
||||||
</div>
|
|
||||||
<hr>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-xs-12 col-sm-6 pull-right order-confirm-date">
|
|
||||||
<address>
|
|
||||||
<strong>{% trans "Date"%}:</strong><br>
|
|
||||||
<span id="order-created_at">{% now "Y-m-d H:i" %}</span><br><br>
|
|
||||||
</address>
|
|
||||||
</div>
|
|
||||||
<div class="col-xs-12 col-sm-6">
|
|
||||||
<address>
|
|
||||||
<h3><b>{% trans "Billed To:"%}</b></h3>
|
|
||||||
{% with billing_address_data as billing_address %}
|
|
||||||
{{billing_address.cardholder_name}}<br> {{billing_address.street_address}}, {{billing_address.postal_code}}<br>
|
|
||||||
{{billing_address.city}}, {{billing_address.country}}.
|
|
||||||
{% endwith %}
|
|
||||||
</address>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-xs-6">
|
|
||||||
<address>
|
|
||||||
<strong>{% trans "Payment Method:"%}</strong><br>
|
|
||||||
{{cc_brand}} {% trans "ending in" %} **** {{cc_last4}}<br>
|
|
||||||
{{request.session.user.email}}
|
|
||||||
</address>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-8 col-md-offset-2">
|
|
||||||
<h3><b>{% trans "Order summary"%}</b></h3>
|
|
||||||
<hr>
|
|
||||||
<div class="content">
|
|
||||||
{% with request.session.specs as vm %}
|
|
||||||
<p><b>{% trans "Cores"%}</b> <span class="pull-right">{{vm.cpu}}</span></p>
|
|
||||||
<hr>
|
|
||||||
<p><b>{% trans "Memory"%}</b> <span class="pull-right">{{vm.memory}} GB</span></p>
|
|
||||||
<hr>
|
|
||||||
<p><b>{% trans "Disk space"%}</b> <span class="pull-right">{{vm.disk_size}} GB</span></p>
|
|
||||||
<hr>
|
|
||||||
<p><b>{% trans "Configuration"%}</b> <span class="pull-right">{{request.session.template.name}}</span></p>
|
|
||||||
<hr>
|
|
||||||
<h4>{% trans "Total"%}<p class="pull-right"><b>{{vm.price}} CHF</b><span class="dcl-price-month"> /{% trans "Month" %}</span></p></h4>
|
|
||||||
{% endwith %}
|
|
||||||
</div>
|
|
||||||
<br/>
|
|
||||||
<form method="post" id="virtual_machine_create_form">
|
|
||||||
{% csrf_token %}
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm-8">
|
|
||||||
<p class="dcl-place-order-text">{% blocktrans with vm_price=request.session.specs.price %}By clicking "Place order" this plan will charge your credit card account with the fee of {{ vm_price }}CHF/month{% endblocktrans %}.</p>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-4 content">
|
|
||||||
<button class="btn btn-info pull-right"
|
|
||||||
id="btn-create-vm"
|
|
||||||
data-href="{% url 'hosting:order-confirmation' %}"
|
|
||||||
data-toggle="modal"
|
|
||||||
data-target="#createvm-modal">
|
|
||||||
{% trans "Place order"%}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
<!-- Create VM Modal -->
|
|
||||||
<div class="modal fade" id="createvm-modal" tabindex="-1" role="dialog"
|
|
||||||
aria-hidden="true" data-backdrop="static" data-keyboard="false">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<button type="button" class="close hidden" data-dismiss="modal"
|
|
||||||
aria-label="create-vm-close">
|
|
||||||
<span aria-hidden="true">×</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<div class="modal-icon">
|
|
||||||
<i class="fa fa-cog fa-spin fa-3x fa-fw"></i>
|
|
||||||
<span class="sr-only">{% trans "Processing..." %}</span>
|
|
||||||
</div>
|
|
||||||
<h4 class="modal-title" id="createvm-modal-title">
|
|
||||||
</h4>
|
|
||||||
<div class="modal-text" id="createvm-modal-body">
|
|
||||||
{% trans "Hold tight, we are processing your request" %}
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<a id="createvm-modal-done-btn" class="btn btn-success btn-ok btn-wide hide" href="">{% trans "OK" %}</a>
|
|
||||||
<button id="createvm-modal-close-btn" type="button" class="btn btn-danger btn-ok btn-wide hide" data-dismiss="modal" aria-label="create-vm-close">{% trans "Close" %}</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- / Create VM Modal -->
|
|
||||||
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
{% trans "Some problem encountered. Please try again later." as err_msg %}
|
|
||||||
var create_vm_error_message = '{{err_msg|safe}}.';
|
|
||||||
|
|
||||||
window.onload = function () {
|
|
||||||
var locale_date = moment.utc(document.getElementById("order-created_at").textContent,'YYYY-MM-DD HH:mm').toDate();
|
|
||||||
locale_date = moment(locale_date).format("YYYY-MM-DD h:mm:ss a");
|
|
||||||
document.getElementById('order-created_at').innerHTML = locale_date;
|
|
||||||
};
|
|
||||||
|
|
||||||
</script>
|
|
||||||
{%endblock%}
|
|
||||||
|
|
|
@ -13,7 +13,6 @@ from datacenterlight.tasks import create_vm_task
|
||||||
from membership.models import StripeCustomer
|
from membership.models import StripeCustomer
|
||||||
from opennebula_api.serializers import VMTemplateSerializer
|
from opennebula_api.serializers import VMTemplateSerializer
|
||||||
from utils.hosting_utils import get_vm_price
|
from utils.hosting_utils import get_vm_price
|
||||||
from utils.models import BillingAddress
|
|
||||||
from utils.stripe_utils import StripeUtils
|
from utils.stripe_utils import StripeUtils
|
||||||
|
|
||||||
|
|
||||||
|
@ -75,21 +74,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 +115,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
|
||||||
|
|
|
@ -19,7 +19,7 @@ from hosting.forms import HostingUserLoginForm
|
||||||
from membership.models import CustomUser, StripeCustomer
|
from membership.models import CustomUser, StripeCustomer
|
||||||
from opennebula_api.serializers import VMTemplateSerializer
|
from opennebula_api.serializers import VMTemplateSerializer
|
||||||
from utils.forms import (
|
from utils.forms import (
|
||||||
BillingAddressForm, BillingAddressFormSignup, UserBillingAddressForm
|
BillingAddressForm, BillingAddressFormSignup
|
||||||
)
|
)
|
||||||
from utils.hosting_utils import get_vm_price
|
from utils.hosting_utils import get_vm_price
|
||||||
from utils.mailer import BaseEmail
|
from utils.mailer import BaseEmail
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
customer = StripeCustomer.create_stripe_api_customer(
|
try:
|
||||||
email=this_user.get('email'),
|
custom_user = CustomUser.objects.get(email=user_email)
|
||||||
token=token,
|
customer = StripeCustomer.objects.filter(
|
||||||
customer_name=form.cleaned_data.get('name'))
|
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['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(
|
||||||
|
@ -437,6 +463,8 @@ class OrderConfirmationView(DetailView):
|
||||||
'site_url': reverse('datacenterlight:index'),
|
'site_url': reverse('datacenterlight:index'),
|
||||||
'cc_last4': card_details.get('response_object').get('last4'),
|
'cc_last4': card_details.get('response_object').get('last4'),
|
||||||
'cc_brand': card_details.get('response_object').get('brand'),
|
'cc_brand': card_details.get('response_object').get('brand'),
|
||||||
|
'vm': request.session.get('specs'),
|
||||||
|
'page_header_text': _('Confirm Order'),
|
||||||
'billing_address_data': request.session.get('billing_address_data')
|
'billing_address_data': request.session.get('billing_address_data')
|
||||||
}
|
}
|
||||||
return render(request, self.template_name, context)
|
return render(request, self.template_name, context)
|
||||||
|
@ -445,15 +473,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 +519,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 +567,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 +578,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 +589,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']:
|
||||||
|
|
|
@ -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 = [
|
||||||
|
|
|
@ -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-28 18:36+0530\n"
|
"POT-Creation-Date: 2017-10-03 18:54+0530\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"
|
||||||
|
@ -308,8 +308,8 @@ msgstr "Alle Benachrichtigungen"
|
||||||
msgid "%(page_header_text)s"
|
msgid "%(page_header_text)s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Invoice Date"
|
msgid "Date"
|
||||||
msgstr "Rechnung Datum"
|
msgstr "Datum"
|
||||||
|
|
||||||
msgid "Status"
|
msgid "Status"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -332,6 +332,9 @@ msgstr "Bezahlmethode"
|
||||||
msgid "ending in"
|
msgid "ending in"
|
||||||
msgstr "endend in"
|
msgstr "endend in"
|
||||||
|
|
||||||
|
msgid "Credit Card"
|
||||||
|
msgstr "Kreditkarte"
|
||||||
|
|
||||||
msgid "Order summary"
|
msgid "Order summary"
|
||||||
msgstr "Bestellungsübersicht"
|
msgstr "Bestellungsübersicht"
|
||||||
|
|
||||||
|
@ -339,7 +342,7 @@ msgid "Product"
|
||||||
msgstr "Produkt"
|
msgstr "Produkt"
|
||||||
|
|
||||||
msgid "Period"
|
msgid "Period"
|
||||||
msgstr ""
|
msgstr "Periode"
|
||||||
|
|
||||||
msgid "Cores"
|
msgid "Cores"
|
||||||
msgstr "Prozessorkerne"
|
msgstr "Prozessorkerne"
|
||||||
|
@ -385,9 +388,6 @@ msgstr "Ein Problem ist aufgetreten. Bitte versuche es später noch einmal."
|
||||||
msgid "Order Nr."
|
msgid "Order Nr."
|
||||||
msgstr "Bestellung Nr."
|
msgstr "Bestellung Nr."
|
||||||
|
|
||||||
msgid "Date"
|
|
||||||
msgstr "Datum"
|
|
||||||
|
|
||||||
msgid "Amount"
|
msgid "Amount"
|
||||||
msgstr "Betrag"
|
msgstr "Betrag"
|
||||||
|
|
||||||
|
@ -412,9 +412,6 @@ msgstr "inkl. Mehrwertsteuer"
|
||||||
msgid "Billing Address"
|
msgid "Billing Address"
|
||||||
msgstr "Rechnungsadresse"
|
msgstr "Rechnungsadresse"
|
||||||
|
|
||||||
msgid "Credit Card"
|
|
||||||
msgstr "Kreditkarte"
|
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
" Please fill in your credit card information "
|
" Please fill in your credit card information "
|
||||||
|
@ -604,8 +601,10 @@ msgstr "Um eine neue VM zu erzeugen, klicke \"Neue VM erzeugen\""
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"To access your VM, add your SSH key <a href=\"%(create_ssh_url)s\">here</a>"
|
"To access your VM, <a href=\"%(create_ssh_url)s\">add your SSH key here</a>"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Um auf Deine VM zuzugreifen, <a href=\"%(create_ssh_url)s\">füge Deinen SSH-"
|
||||||
|
"Key hinzu</a>"
|
||||||
|
|
||||||
msgid "login"
|
msgid "login"
|
||||||
msgstr "anmelden"
|
msgstr "anmelden"
|
||||||
|
@ -661,6 +660,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."
|
||||||
|
|
||||||
|
@ -685,65 +694,29 @@ 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 ""
|
||||||
|
"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"
|
||||||
|
|
||||||
#, fuzzy, python-format
|
#, python-format
|
||||||
#| msgid "Virtual Machine Cancellation"
|
|
||||||
msgid "Virtual Machine %(vm_name)s Cancelled"
|
msgid "Virtual Machine %(vm_name)s Cancelled"
|
||||||
msgstr "VM Kündigung"
|
msgstr "Virtuelle Maschine %(vm_name)s Kündigung"
|
||||||
|
|
||||||
|
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 "My VM page"
|
#~ msgid "My VM page"
|
||||||
#~ msgstr "Meine VM page"
|
#~ msgstr "Meine VM page"
|
||||||
|
|
||||||
#~ msgid ""
|
#~ msgid "Invoice Date"
|
||||||
#~ "\n"
|
#~ msgstr "Rechnung Datum"
|
||||||
#~ "You're receiving this email because you requested a password reset for "
|
|
||||||
#~ "your user account at %(site_name)s.<br/>\n"
|
|
||||||
#~ "Please go to the following page and choose a new password: %(base_url)s"
|
|
||||||
#~ "%(password_reset_url)s<br/>\n"
|
|
||||||
#~ "If you didn't request a new password, ignore this e-mail.<br/>\n"
|
|
||||||
#~ "Thank you!\n"
|
|
||||||
#~ msgstr ""
|
|
||||||
#~ "\n"
|
|
||||||
#~ "Du erhälst diese E-Mail da Du Dein Passwort für Deinen Account bei "
|
|
||||||
#~ "%(site_name)s zurücksetzen möchtest.<br/>\n"
|
|
||||||
#~ "Bitte folge diesem Link und wähle ein neues Passwort: %(base_url)s"
|
|
||||||
#~ "%(password_reset_url)s Solltest Du kein neues Passwort angefordert haben, "
|
|
||||||
#~ "dann ignoriere diese E-Mail.<br/>\n"
|
|
||||||
#~ "Dankeschön!\n"
|
|
||||||
|
|
||||||
#~ msgid ""
|
|
||||||
#~ "You're receiving this email because you requested a password reset for "
|
|
||||||
#~ "your user account at %(site_name)s.\n"
|
|
||||||
#~ "Please go to the following page and choose a new password: %(base_url)s"
|
|
||||||
#~ "%(password_reset_url)s\n"
|
|
||||||
#~ "If you didn't request a new password, ignore this e-mail.\n"
|
|
||||||
#~ "Thank you!\n"
|
|
||||||
#~ msgstr ""
|
|
||||||
#~ "Du erhälst diese E-Mail da Du Dein Passwort für Deinen Account bei "
|
|
||||||
#~ "%(site_name)s zurücksetzen möchtest.\n"
|
|
||||||
#~ "Bitte folge diesem Link und wähle ein neues Passwort: %(base_url)s"
|
|
||||||
#~ "%(password_reset_url)s Solltest Du kein neues Passwort angefordert haben, "
|
|
||||||
#~ "dann ignoriere diese E-Mail.\n"
|
|
||||||
#~ "Dankeschön!\n"
|
|
||||||
|
|
||||||
#~ msgid ""
|
|
||||||
#~ "You're receiving this mail because your virtual machine [%(vm_name)s] has "
|
|
||||||
#~ "been cancelled.\n"
|
|
||||||
#~ "You can see your order status by clicking here\n"
|
|
||||||
#~ "%(base_url)s%(vm_order_url)s\n"
|
|
||||||
#~ "If you want to order a new virtual machine, you can do it by clicking "
|
|
||||||
#~ "this link.\n"
|
|
||||||
#~ "%(base_url)s%(my_virtual_machines_url)s\n"
|
|
||||||
#~ msgstr ""
|
|
||||||
#~ "Du erhälst diese E-Mail, da Deine virtuelle Maschine [%(vm_name)s] "
|
|
||||||
#~ "gekündigt wurde.\n"
|
|
||||||
#~ "Um Deinen Auftragsstatus zu sehen, klicke hier.\n"
|
|
||||||
#~ "%(base_url)s%(vm_order_url)s\n"
|
|
||||||
#~ "Falls Du eine neue virtuelle Maschine bestellen möchtest, kannst Du dies "
|
|
||||||
#~ "tun, indem Du diesen Link klickst.\n"
|
|
||||||
#~ "%(base_url)s%(my_virtual_machines_url)s\n"
|
|
||||||
|
|
||||||
#~ 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"
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -656,7 +656,6 @@ a.unlink:hover {
|
||||||
|
|
||||||
.card-element {
|
.card-element {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
padding: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-element label{
|
.card-element label{
|
||||||
|
|
|
@ -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) {
|
||||||
|
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) {
|
if (data.status === true) {
|
||||||
fa_icon = $('.modal-icon > .fa');
|
|
||||||
fa_icon.attr('class', 'checkmark');
|
fa_icon.attr('class', 'checkmark');
|
||||||
// $('.modal-header > .close').removeClass('hidden');
|
} else {
|
||||||
$('#createvm-modal-title').text(data.msg_title);
|
fa_icon.attr('class', 'fa fa-close');
|
||||||
$('#createvm-modal-body').text(data.msg_body);
|
modal_btn.attr('class', '').addClass('btn btn-danger btn-ok btn-wide');
|
||||||
$('#createvm-modal-done-btn')
|
|
||||||
.attr('href', data.redirect)
|
|
||||||
.removeClass('hide');
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
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');
|
||||||
|
|
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="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 %}
|
||||||
|
|
|
@ -17,10 +17,12 @@
|
||||||
<h1 class="dashboard-title-thin">
|
<h1 class="dashboard-title-thin">
|
||||||
<img src="{% static 'hosting/img/billing.svg' %}" class="un-icon">{% blocktrans with page_header_text=page_header_text|default:"Invoice" %}{{page_header_text}}{% endblocktrans %}
|
<img src="{% static 'hosting/img/billing.svg' %}" class="un-icon">{% blocktrans with page_header_text=page_header_text|default:"Invoice" %}{{page_header_text}}{% endblocktrans %}
|
||||||
</h1>
|
</h1>
|
||||||
<div class="dashboard-container-options">
|
{% if order %}
|
||||||
<button type="button" class="btn-plain btn-pdf" data-target="#order-detail{{order.pk}}"><img src="{% static 'hosting/img/icon-pdf.svg' %}" class="svg-img"></button>
|
<div class="dashboard-container-options">
|
||||||
<button type="button" class="btn-plain btn-print"><img src="{% static 'hosting/img/icon-print.svg' %}" class="svg-img"></button>
|
<button type="button" class="btn-plain btn-pdf" data-target="#order-detail{{order.pk}}"><img src="{% static 'hosting/img/icon-pdf.svg' %}" class="svg-img"></button>
|
||||||
</div>
|
<button type="button" class="btn-plain btn-print"><img src="{% static 'hosting/img/icon-print.svg' %}" class="svg-img"></button>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="order-details">
|
<div class="order-details">
|
||||||
{% if order %}
|
{% if order %}
|
||||||
|
@ -29,7 +31,7 @@
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<p>
|
<p>
|
||||||
<strong>{% trans "Invoice Date" %}:</strong>
|
<strong>{% trans "Date" %}:</strong>
|
||||||
<span id="order-created_at">
|
<span id="order-created_at">
|
||||||
{% if order %}
|
{% if order %}
|
||||||
{{order.created_at|date:'Y-m-d H:i'}}
|
{{order.created_at|date:'Y-m-d H:i'}}
|
||||||
|
@ -80,8 +82,7 @@
|
||||||
{{order.last4}}<br>
|
{{order.last4}}<br>
|
||||||
{{user.email}}
|
{{user.email}}
|
||||||
{% else %}
|
{% else %}
|
||||||
{{cc_brand|default:'Card'}} {% trans "ending in" %} ****
|
{{cc_brand|default:_('Credit Card')}} {% trans "ending in" %} ****{{cc_last4}}<br>
|
||||||
{{cc_last4}}<br>
|
|
||||||
{% if request.user.is_authenticated %}
|
{% if request.user.is_authenticated %}
|
||||||
{{request.user.email}}
|
{{request.user.email}}
|
||||||
{% else %}
|
{% else %}
|
||||||
|
@ -94,7 +95,12 @@
|
||||||
<div>
|
<div>
|
||||||
<h4>{% trans "Order summary" %}</h4>
|
<h4>{% trans "Order summary" %}</h4>
|
||||||
<p>
|
<p>
|
||||||
<strong>{% trans "Product" %}:</strong> {{vm.name}}
|
<strong>{% trans "Product" %}:</strong>
|
||||||
|
{% if vm.name %}
|
||||||
|
{{ vm.name }}
|
||||||
|
{% else %}
|
||||||
|
{{ request.session.template.name }}
|
||||||
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
|
@ -132,19 +138,21 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% if not order %}
|
{% if not order %}
|
||||||
<form method="post" id="virtual_machine_create_form">
|
{% block submit_btn %}
|
||||||
{% csrf_token %}
|
<form method="post" id="virtual_machine_create_form">
|
||||||
<div class="row">
|
{% csrf_token %}
|
||||||
<div class="col-sm-8">
|
<div class="row">
|
||||||
<div class="dcl-place-order-text">{% blocktrans with vm_price=request.session.specs.price %}By clicking "Place order" this plan will charge your credit card account with the fee of {{ vm_price }}CHF/month{% endblocktrans %}.</div>
|
<div class="col-sm-8">
|
||||||
|
<div class="dcl-place-order-text">{% blocktrans with vm_price=request.session.specs.price %}By clicking "Place order" this plan will charge your credit card account with the fee of {{ vm_price }}CHF/month{% endblocktrans %}.</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4 order-confirm-btn text-right">
|
||||||
|
<button class="btn choice-btn" id="btn-create-vm" data-href="{% url 'hosting:order-confirmation' %}" data-toggle="modal" data-target="#createvm-modal">
|
||||||
|
{% trans "Place order" %}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-4 order-confirm-btn text-right">
|
</form>
|
||||||
<button class="btn choice-btn" id="btn-create-vm" data-href="{% url 'hosting:order-confirmation' %}" data-toggle="modal" data-target="#createvm-modal">
|
{% endblock submit_btn %}
|
||||||
{% trans "Place order" %}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
@ -197,8 +205,10 @@
|
||||||
{%endblock%}
|
{%endblock%}
|
||||||
|
|
||||||
{% block js_extra %}
|
{% block js_extra %}
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.3.5/jspdf.min.js"></script>
|
{% if order %}
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/html2canvas.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.3.5/jspdf.min.js"></script>
|
||||||
<script src="{% static 'hosting/js/html2pdf.js' %}"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/html2canvas.min.js"></script>
|
||||||
<script src="{% static 'hosting/js/order.js' %}"></script>
|
<script src="{% static 'hosting/js/html2pdf.js' %}"></script>
|
||||||
|
<script src="{% static 'hosting/js/order.js' %}"></script>
|
||||||
|
{% endif %}
|
||||||
{% endblock js_extra %}
|
{% endblock js_extra %}
|
||||||
|
|
|
@ -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 %}
|
||||||
|
|
|
@ -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 %}
|
||||||
|
|
|
@ -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 %}
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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
|
||||||
|
@ -271,7 +270,8 @@ class SignupValidatedView(SignupValidateView):
|
||||||
user = CustomUser.objects.filter(
|
user = CustomUser.objects.filter(
|
||||||
validation_slug=self.kwargs['validate_slug']).first()
|
validation_slug=self.kwargs['validate_slug']).first()
|
||||||
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"),
|
||||||
|
@ -653,10 +653,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(
|
||||||
|
@ -704,7 +701,13 @@ 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'])
|
||||||
|
context['vm']['price'] = get_vm_price(
|
||||||
|
cpu=context['vm']['cores'],
|
||||||
|
disk_size=context['vm']['disk_size'],
|
||||||
|
memory=context['vm']['memory']
|
||||||
|
)
|
||||||
except VMDetail.DoesNotExist:
|
except VMDetail.DoesNotExist:
|
||||||
try:
|
try:
|
||||||
manager = OpenNebulaManager(
|
manager = OpenNebulaManager(
|
||||||
|
@ -767,7 +770,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
|
||||||
|
@ -785,8 +787,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)
|
||||||
|
@ -805,12 +806,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,
|
||||||
|
@ -821,8 +834,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',
|
||||||
|
@ -1025,6 +1037,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 = {
|
||||||
|
@ -1034,7 +1047,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)
|
||||||
|
|
||||||
|
@ -1144,3 +1161,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())
|
||||||
|
|
|
@ -184,9 +184,9 @@ class StripeCustomer(models.Model):
|
||||||
customer_name=None):
|
customer_name=None):
|
||||||
"""
|
"""
|
||||||
This method creates a Stripe API customer with the given
|
This method creates a Stripe API customer with the given
|
||||||
email, token and customer_name. This is different from
|
email, token and customer_name. This is different from
|
||||||
get_or_create method below in that it does not create a
|
get_or_create method below in that it does not create a
|
||||||
CustomUser and associate the customer created in stripe
|
CustomUser and associate the customer created in stripe
|
||||||
with it, while get_or_create does that before creating the
|
with it, while get_or_create does that before creating the
|
||||||
stripe user.
|
stripe user.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -28,28 +28,34 @@ def handleStripeError(f):
|
||||||
body = e.json_body
|
body = e.json_body
|
||||||
err = body['error']
|
err = body['error']
|
||||||
response.update({'error': err['message']})
|
response.update({'error': err['message']})
|
||||||
|
logger.error(str(e))
|
||||||
return response
|
return response
|
||||||
except stripe.error.RateLimitError as e:
|
except stripe.error.RateLimitError as e:
|
||||||
response.update(
|
response.update(
|
||||||
{'error': "Too many requests made to the API too quickly"})
|
{'error': "Too many requests made to the API too quickly"})
|
||||||
return response
|
return response
|
||||||
except stripe.error.InvalidRequestError as e:
|
except stripe.error.InvalidRequestError as e:
|
||||||
|
logger.error(str(e))
|
||||||
response.update({'error': "Invalid parameters"})
|
response.update({'error': "Invalid parameters"})
|
||||||
return response
|
return response
|
||||||
except stripe.error.AuthenticationError as e:
|
except stripe.error.AuthenticationError as e:
|
||||||
# Authentication with Stripe's API failed
|
# Authentication with Stripe's API failed
|
||||||
# (maybe you changed API keys recently)
|
# (maybe you changed API keys recently)
|
||||||
|
logger.error(str(e))
|
||||||
response.update({'error': common_message})
|
response.update({'error': common_message})
|
||||||
return response
|
return response
|
||||||
except stripe.error.APIConnectionError as e:
|
except stripe.error.APIConnectionError as e:
|
||||||
|
logger.error(str(e))
|
||||||
response.update({'error': common_message})
|
response.update({'error': common_message})
|
||||||
return response
|
return response
|
||||||
except stripe.error.StripeError as e:
|
except stripe.error.StripeError as e:
|
||||||
# maybe send email
|
# maybe send email
|
||||||
|
logger.error(str(e))
|
||||||
response.update({'error': common_message})
|
response.update({'error': common_message})
|
||||||
return response
|
return response
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# maybe send email
|
# maybe send email
|
||||||
|
logger.error(str(e))
|
||||||
response.update({'error': common_message})
|
response.update({'error': common_message})
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
|
@ -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 = {
|
||||||
|
|
Loading…
Reference in a new issue