Merge branch 'pcoder-new_flow'

This commit is contained in:
M.Ravi 2017-06-23 04:54:15 +05:30
commit ed9e5c591c
6 changed files with 320 additions and 44 deletions

View file

@ -0,0 +1,79 @@
{% extends "hosting/base_short.html" %}
{% load staticfiles bootstrap3 %}
{% load i18n %}
{% block content %}
<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><h3 class="pull-right">{% trans "Order #"%} {{order.id}}</h3>
</div>
<hr>
<div class="row">
<div class="col-xs-6">
<address>
<h3><b>{% trans "Billed To:"%}</b></h3>
{{user.name}}<br>
{{order.billing_address.street_address}},{{order.billing_address.postal_code}}<br>
{{order.billing_address.city}}, {{order.billing_address.country}}.
</address>
</div>
<div class="col-xs-6 text-right">
<address>
<strong>{% trans "Date"%}:</strong><br>
{{order.created_at}}<br><br>
</address>
</div>
</div>
<div class="row">
<div class="col-xs-6">
<address>
<strong>{% trans "Payment Method:"%}</strong><br>
{{order.cc_brand}} ending **** {{order.last4}}<br>
{{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">
<p><b>{% trans "Cores"%}</b> <span class="pull-right">{{vm.cores}}</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>
<h4>{% trans "Total"%}<p class="pull-right"><b>{{vm.price}} CHF</b></p></h4>
</div>
<br/>
{% url 'datacenterlight:payment' as payment_url %}
{% if payment_url in request.META.HTTP_REFERER %}
<div class=" content pull-right">
<a href="{{next_url}}" ><button class="btn btn-info">{% trans "Finish Configuration"%}</button></a>
</div>
{% endif %}
</div>
</div>
{% endif %}
</div>
{%endblock%}

View file

@ -1,6 +1,6 @@
from django.conf.urls import url from django.conf.urls import url
from .views import IndexView, BetaProgramView, LandingProgramView, BetaAccessView, PricingView, SuccessView from .views import IndexView, BetaProgramView, LandingProgramView, BetaAccessView, PricingView, SuccessView, PaymentOrderView, OrderConfirmationView
urlpatterns = [ urlpatterns = [
@ -8,6 +8,8 @@ urlpatterns = [
url(r'^/beta-program/?$', BetaProgramView.as_view(), name='beta'), url(r'^/beta-program/?$', BetaProgramView.as_view(), name='beta'),
url(r'^/landing/?$', LandingProgramView.as_view(), name='landing'), url(r'^/landing/?$', LandingProgramView.as_view(), name='landing'),
url(r'^/pricing/?$', PricingView.as_view(), name='pricing'), url(r'^/pricing/?$', PricingView.as_view(), name='pricing'),
url(r'^/payment/?$', PaymentOrderView.as_view(), name='payment'),
url(r'^/order-confirmation/(?P<pk>\d+)/?$', OrderConfirmationView.as_view(), name='order_confirmation'),
url(r'^/order-success/?$', SuccessView.as_view(), name='order_success'), url(r'^/order-success/?$', SuccessView.as_view(), name='order_success'),
url(r'^/beta_access?$', BetaAccessView.as_view(), name='beta_access'), url(r'^/beta_access?$', BetaAccessView.as_view(), name='beta_access'),
] ]

View file

@ -1,4 +1,4 @@
from django.views.generic import FormView, CreateView, TemplateView from django.views.generic import FormView, CreateView, TemplateView, DetailView
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from .forms import BetaAccessForm from .forms import BetaAccessForm
from .models import BetaAccess, BetaAccessVMType, BetaAccessVM from .models import BetaAccess, BetaAccessVMType, BetaAccessVM
@ -10,9 +10,17 @@ from django.shortcuts import render
from django.shortcuts import redirect from django.shortcuts import redirect
from django import forms from django import forms
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.views.decorators.cache import cache_control
from django.conf import settings
from utils.forms import BillingAddressForm, UserBillingAddressForm
from membership.models import StripeCustomer
from hosting.models import HostingOrder, HostingBill
from utils.stripe_utils import StripeUtils
from datetime import datetime
from membership.models import CustomUser, StripeCustomer
from opennebula_api.models import OpenNebulaManager from opennebula_api.models import OpenNebulaManager
from opennebula_api.serializers import VirtualMachineTemplateSerializer from opennebula_api.serializers import VirtualMachineTemplateSerializer, VirtualMachineSerializer
class LandingProgramView(TemplateView): class LandingProgramView(TemplateView):
template_name = "datacenterlight/landing.html" template_name = "datacenterlight/landing.html"
@ -20,6 +28,14 @@ class LandingProgramView(TemplateView):
class SuccessView(TemplateView): class SuccessView(TemplateView):
template_name = "datacenterlight/success.html" template_name = "datacenterlight/success.html"
def get(self, request, *args, **kwargs):
if 'specs' not in request.session or 'user' not in request.session:
return HttpResponseRedirect(reverse('datacenterlight:index'))
else :
del request.session['specs']
del request.session['user']
return render(request, self.template_name)
class PricingView(TemplateView): class PricingView(TemplateView):
template_name = "datacenterlight/pricing.html" template_name = "datacenterlight/pricing.html"
@ -170,7 +186,12 @@ class IndexView(CreateView):
success_url = "/datacenterlight#requestform" success_url = "/datacenterlight#requestform"
success_message = "Thank you, we will contact you as soon as possible" success_message = "Thank you, we will contact you as soon as possible"
@cache_control(no_cache=True, must_revalidate=True, no_store=True)
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
if 'specs' in request.session :
del request.session['specs']
if 'user' in request.session :
del request.session['user']
try: try:
manager = OpenNebulaManager() manager = OpenNebulaManager()
templates = manager.get_templates() templates = manager.get_templates()
@ -213,26 +234,22 @@ class IndexView(CreateView):
messages.add_message(self.request, messages.ERROR, '%(value) is not a proper email.'.format(email)) messages.add_message(self.request, messages.ERROR, '%(value) is not a proper email.'.format(email))
return HttpResponseRedirect(reverse('datacenterlight:index')) return HttpResponseRedirect(reverse('datacenterlight:index'))
context = { specs = {
'name': name, 'cpu': cores,
'email': email,
'cores': cores,
'memory': memory, 'memory': memory,
'storage': storage, 'disk_size': storage,
'price': price, 'price': price
'template': template_data['name'],
} }
email_data = {
'subject': "Data Center Light Order from %s" % context['email'],
'from_email': '(datacenterlight) datacenterlight Support <support@datacenterlight.ch>',
'to': ['info@ungleich.ch'],
'body': "\n".join(["%s=%s" % (k, v) for (k, v) in context.items()]),
'reply_to': [context['email']],
}
email = EmailMessage(**email_data)
email.send()
return HttpResponseRedirect(reverse('datacenterlight:order_success')) this_user = {
'name': name,
'email': email
}
request.session['specs'] = specs
request.session['template'] = template_data
request.session['user'] = this_user
return HttpResponseRedirect(reverse('datacenterlight:payment'))
def get_success_url(self): def get_success_url(self):
success_url = reverse('datacenterlight:index') success_url = reverse('datacenterlight:index')
@ -281,3 +298,167 @@ class IndexView(CreateView):
messages.add_message(self.request, messages.SUCCESS, self.success_message) messages.add_message(self.request, messages.SUCCESS, self.success_message)
return super(IndexView, self).form_valid(form) return super(IndexView, self).form_valid(form)
class PaymentOrderView(FormView):
template_name = 'hosting/payment.html'
form_class = BillingAddressForm
def get_context_data(self, **kwargs):
context = super(PaymentOrderView, self).get_context_data(**kwargs)
context.update({
'stripe_key': settings.STRIPE_API_PUBLIC_KEY
})
return context
@cache_control(no_cache=True, must_revalidate=True, no_store=True)
def get(self, request, *args, **kwargs):
if 'specs' not in request.session or 'user' not in request.session:
return HttpResponseRedirect(reverse('datacenterlight:index'))
return self.render_to_response(self.get_context_data())
def post(self, request, *args, **kwargs):
form = self.get_form()
if form.is_valid():
# Get billing address data
billing_address_data = form.cleaned_data
context = self.get_context_data()
template = request.session.get('template')
specs = request.session.get('specs')
user = request.session.get('user')
vm_template_id = template.get('id', 1)
final_price = specs.get('price')
token = form.cleaned_data.get('token')
try:
custom_user = CustomUser.objects.get(email=user.get('email'))
except CustomUser.DoesNotExist:
password = CustomUser.get_random_password()
# Register the user, and do not send emails
CustomUser.register(user.get('name'),
password,
user.get('email'),
app='dcl',
base_url=None, send_email=False)
# Get or create stripe customer
customer = StripeCustomer.get_or_create(email=user.get('email'),
token=token)
if not customer:
form.add_error("__all__", "Invalid credit card")
return self.render_to_response(self.get_context_data(form=form))
# Create Billing Address
billing_address = form.save()
# Make stripe charge to a customer
stripe_utils = StripeUtils()
charge_response = stripe_utils.make_charge(amount=final_price,
customer=customer.stripe_id)
charge = charge_response.get('response_object')
# Check if the payment was approved
if not charge:
context.update({
'paymentError': charge_response.get('error'),
'form': form
})
return render(request, self.template_name, context)
charge = charge_response.get('response_object')
# Create OpenNebulaManager
manager = OpenNebulaManager(email=settings.OPENNEBULA_USERNAME,
password=settings.OPENNEBULA_PASSWORD)
# Create a vm using logged user
vm_id = manager.create_vm(
template_id=vm_template_id,
specs=specs,
vm_name="{email}-{template_name}-{date}".format(
email=user.get('email'),
template_name=template.get('name'),
date=int(datetime.now().strftime("%s")))
)
# Create a Hosting Order
order = HostingOrder.create(
price=final_price,
vm_id=vm_id,
customer=customer,
billing_address=billing_address
)
# Create a Hosting Bill
bill = HostingBill.create(
customer=customer, billing_address=billing_address)
# Create Billing Address for User if he does not have one
if not customer.user.billing_addresses.count():
billing_address_data.update({
'user': customer.user.id
})
billing_address_user_form = UserBillingAddressForm(
billing_address_data)
billing_address_user_form.is_valid()
billing_address_user_form.save()
# Associate an order with a stripe payment
order.set_stripe_charge(charge)
# If the Stripe payment was successed, set order status approved
order.set_approved()
vm = VirtualMachineSerializer(manager.get_vm(vm_id)).data
context = {
'name': user.get('name'),
'email': user.get('email'),
'cores': specs.get('cpu'),
'memory': specs.get('memory'),
'storage': specs.get('disk_size'),
'price': specs.get('price'),
'template': template.get('name'),
'vm.name': vm['name'],
'vm.id': vm['vm_id'],
'order.id': order.id
}
email_data = {
'subject': "Data Center Light Order from %s" % context['email'],
'from_email': '(Data Center Light) Data Center Light Support <support@datacenterlight.ch>',
'to': ['info@ungleich.ch'],
'body': "\n".join(["%s=%s" % (k, v) for (k, v) in context.items()]),
'reply_to': [context['email']],
}
email = EmailMessage(**email_data)
email.send()
return HttpResponseRedirect(reverse('datacenterlight:order_confirmation', kwargs={'pk': order.id}))
else:
return self.form_invalid(form)
class OrderConfirmationView(DetailView):
template_name = "datacenterlight/order_detail.html"
context_object_name = "order"
model = HostingOrder
def get_context_data(self, **kwargs):
# Get context
context = super(DetailView, self).get_context_data(**kwargs)
obj = self.get_object()
manager = OpenNebulaManager(email=settings.OPENNEBULA_USERNAME,
password=settings.OPENNEBULA_PASSWORD)
try:
vm = manager.get_vm(obj.vm_id)
context['vm'] = VirtualMachineSerializer(vm).data
context['next_url'] = reverse('datacenterlight:order_success')
except WrongIdError:
messages.error(self.request,
'The VM you are looking for is unavailable at the moment. \
Please contact Data Center Light support.'
)
self.kwargs['error'] = 'WrongIdError'
context['error'] = 'WrongIdError'
except ConnectionRefusedError:
messages.error(self.request,
'In order to create a VM, you need to create/upload your SSH KEY first.'
)
return context

View file

@ -46,7 +46,7 @@
<!-- Navigation --> <!-- Navigation -->
{% if request.user.is_authenticated %}
<nav class="navbar navbar-default navbar-fixed-top topnav" role="navigation"> <nav class="navbar navbar-default navbar-fixed-top topnav" role="navigation">
<div class="container topnav"> <div class="container topnav">
<!-- Brand and toggle get grouped for better mobile display --> <!-- Brand and toggle get grouped for better mobile display -->
@ -59,6 +59,7 @@
</button> </button>
<a class="navbar-brand topnav" href="{{ request.session.hosting_url}}"><img src="{% static 'datacenterlight/img/logo_black.svg' %}"></a> <a class="navbar-brand topnav" href="{{ request.session.hosting_url}}"><img src="{% static 'datacenterlight/img/logo_black.svg' %}"></a>
</div> </div>
{% if request.user.is_authenticated %}
<!-- Collect the nav links, forms, and other content for toggling --> <!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav navbar-right"> <ul class="nav navbar-nav navbar-right">
@ -110,12 +111,13 @@
</li> --> </li> -->
</ul> </ul>
</div> </div>
{% endif %}
<!-- /.navbar-collapse --> <!-- /.navbar-collapse -->
</div> </div>
<!-- /.container --> <!-- /.container -->
</nav> </nav>
{% endif %}
<div class="content-dashboard"> <div class="content-dashboard">
{% block content %} {% block content %}

View file

@ -7,6 +7,7 @@ from django.core.validators import RegexValidator
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.contrib.sites.models import Site from django.contrib.sites.models import Site
from django.conf import settings from django.conf import settings
from django.utils.crypto import get_random_string
from utils.stripe_utils import StripeUtils from utils.stripe_utils import StripeUtils
from utils.mailer import DigitalGlarusRegistrationMailer from utils.mailer import DigitalGlarusRegistrationMailer
@ -74,7 +75,7 @@ class CustomUser(AbstractBaseUser, PermissionsMixin):
REQUIRED_FIELDS = ['name', 'password'] REQUIRED_FIELDS = ['name', 'password']
@classmethod @classmethod
def register(cls, name, password, email, app='digital_glarus', base_url=None): def register(cls, name, password, email, app='digital_glarus', base_url=None, send_email=True):
user = cls.objects.filter(email=email).first() user = cls.objects.filter(email=email).first()
if not user: if not user:
user = cls.objects.create_user(name=name, email=email, password=password) user = cls.objects.create_user(name=name, email=email, password=password)
@ -86,19 +87,20 @@ class CustomUser(AbstractBaseUser, PermissionsMixin):
dcl_text = settings.DCL_TEXT dcl_text = settings.DCL_TEXT
dcl_from_address = settings.DCL_SUPPORT_FROM_ADDRESS dcl_from_address = settings.DCL_SUPPORT_FROM_ADDRESS
user.is_active = False user.is_active = False
email_data = { if send_email is True:
'subject': str(_('Activate your ')) + dcl_text + str(_(' account')), email_data = {
'from_address': settings.DCL_SUPPORT_FROM_ADDRESS, 'subject': str(_('Activate your ')) + dcl_text + str(_(' account')),
'to': user.email, 'from_address': settings.DCL_SUPPORT_FROM_ADDRESS,
'context': {'base_url' : base_url, 'to': user.email,
'activation_link' : reverse('hosting:validate', kwargs={'validate_slug': user.validation_slug}), 'context': {'base_url' : base_url,
'dcl_text' : dcl_text 'activation_link' : reverse('hosting:validate', kwargs={'validate_slug': user.validation_slug}),
}, 'dcl_text' : dcl_text
'template_name': 'user_activation', },
'template_path': 'datacenterlight/emails/' 'template_name': 'user_activation',
} 'template_path': 'datacenterlight/emails/'
email = BaseEmail(**email_data) }
email.send() email = BaseEmail(**email_data)
email.send()
return user return user
else: else:
return None return None
@ -118,6 +120,10 @@ class CustomUser(AbstractBaseUser, PermissionsMixin):
return True return True
return False return False
@classmethod
def get_random_password(cls):
return get_random_string(24)
def is_superuser(self): def is_superuser(self):
return False return False

View file

@ -239,7 +239,7 @@ class OpenNebulaManager():
) )
) )
def create_vm(self, template_id, specs, ssh_key=None): def create_vm(self, template_id, specs, ssh_key=None, vm_name=None):
template = self.get_template(template_id) template = self.get_template(template_id)
vm_specs_formatter = """<TEMPLATE> vm_specs_formatter = """<TEMPLATE>
@ -287,14 +287,13 @@ class OpenNebulaManager():
image=image, image=image,
image_uname=image_uname) image_uname=image_uname)
vm_specs += "<CONTEXT>"
if ssh_key: if ssh_key:
vm_specs += """<CONTEXT> vm_specs += "<SSH_PUBLIC_KEY>{ssh}</SSH_PUBLIC_KEY>".format(ssh=ssh_key)
<SSH_PUBLIC_KEY>{ssh}</SSH_PUBLIC_KEY> vm_specs += """<NETWORK>YES</NETWORK>
<NETWORK>YES</NETWORK>
</CONTEXT> </CONTEXT>
</TEMPLATE> </TEMPLATE>
""".format(ssh=ssh_key) """
vm_id = self.client.call(oca.VmTemplate.METHODS['instantiate'], vm_id = self.client.call(oca.VmTemplate.METHODS['instantiate'],
template.id, template.id,
'', '',
@ -307,6 +306,13 @@ class OpenNebulaManager():
'release', 'release',
vm_id vm_id
) )
if vm_name is not None:
self.oneadmin_client.call(
'vm.rename',
vm_id,
vm_name
)
return vm_id return vm_id
def delete_vm(self, vm_id): def delete_vm(self, vm_id):