Merge branch 'master' into task/3709/faq_tos_cms_template
This commit is contained in:
		
				commit
				
					
						2a76167d10
					
				
			
		
					 31 changed files with 1462 additions and 455 deletions
				
			
		| 
						 | 
				
			
			@ -8,7 +8,7 @@ msgid ""
 | 
			
		|||
msgstr ""
 | 
			
		||||
"Project-Id-Version: PACKAGE VERSION\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: \n"
 | 
			
		||||
"POT-Creation-Date: 2017-08-03 03:10+0530\n"
 | 
			
		||||
"POT-Creation-Date: 2017-08-24 11:28+0000\n"
 | 
			
		||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 | 
			
		||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 | 
			
		||||
"Language-Team: LANGUAGE <LL@li.org>\n"
 | 
			
		||||
| 
						 | 
				
			
			@ -276,6 +276,19 @@ msgstr "Konfiguration"
 | 
			
		|||
msgid "Total"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#, fuzzy
 | 
			
		||||
#| msgid "month"
 | 
			
		||||
msgid "Month"
 | 
			
		||||
msgstr "Monat"
 | 
			
		||||
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid ""
 | 
			
		||||
"By clicking \"Place order\" this plan will charge your credit card account "
 | 
			
		||||
"with the fee of %(vm_price)sCHF/month"
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Wenn Du \"bestellen\" auswählst, wird Deine Kreditkarte mit %(vm_price)sCHF "
 | 
			
		||||
"pro Monat belastet"
 | 
			
		||||
 | 
			
		||||
msgid "Place order"
 | 
			
		||||
msgstr "Bestellen"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										22
									
								
								datacenterlight/migrations/0007_stripeplan.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								datacenterlight/migrations/0007_stripeplan.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
# Generated by Django 1.9.4 on 2017-08-16 19:47
 | 
			
		||||
from __future__ import unicode_literals
 | 
			
		||||
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ('datacenterlight', '0006_vmtemplate'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.CreateModel(
 | 
			
		||||
            name='StripePlan',
 | 
			
		||||
            fields=[
 | 
			
		||||
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
 | 
			
		||||
                ('stripe_plan_id', models.CharField(max_length=100, null=True)),
 | 
			
		||||
            ],
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
							
								
								
									
										20
									
								
								datacenterlight/migrations/0008_auto_20170821_2024.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								datacenterlight/migrations/0008_auto_20170821_2024.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,20 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
# Generated by Django 1.9.4 on 2017-08-21 20:24
 | 
			
		||||
from __future__ import unicode_literals
 | 
			
		||||
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ('datacenterlight', '0007_stripeplan'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name='stripeplan',
 | 
			
		||||
            name='stripe_plan_id',
 | 
			
		||||
            field=models.CharField(max_length=256, null=True),
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
| 
						 | 
				
			
			@ -59,3 +59,15 @@ class VMTemplate(models.Model):
 | 
			
		|||
    def create(cls, name, opennebula_vm_template_id):
 | 
			
		||||
        vm_template = cls(name=name, opennebula_vm_template_id=opennebula_vm_template_id)
 | 
			
		||||
        return vm_template
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class StripePlan(models.Model):
 | 
			
		||||
    """
 | 
			
		||||
    A model to store Data Center Light's created Stripe plans
 | 
			
		||||
    """
 | 
			
		||||
    stripe_plan_id = models.CharField(max_length=256, null=True)
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def create(cls, stripe_plan_id):
 | 
			
		||||
        stripe_plan = cls(stripe_plan_id=stripe_plan_id)
 | 
			
		||||
        return stripe_plan
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -41,13 +41,15 @@ def retry_task(task, exception=None):
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
@app.task(bind=True, max_retries=settings.CELERY_MAX_RETRIES)
 | 
			
		||||
def create_vm_task(self, vm_template_id, user, specs, template, stripe_customer_id, billing_address_data,
 | 
			
		||||
def create_vm_task(self, vm_template_id, user, specs, template,
 | 
			
		||||
                   stripe_customer_id, billing_address_data,
 | 
			
		||||
                   billing_address_id,
 | 
			
		||||
                   charge):
 | 
			
		||||
                   charge, cc_details):
 | 
			
		||||
    vm_id = None
 | 
			
		||||
    try:
 | 
			
		||||
        final_price = specs.get('price')
 | 
			
		||||
        billing_address = BillingAddress.objects.filter(id=billing_address_id).first()
 | 
			
		||||
        billing_address = BillingAddress.objects.filter(
 | 
			
		||||
            id=billing_address_id).first()
 | 
			
		||||
        customer = StripeCustomer.objects.filter(id=stripe_customer_id).first()
 | 
			
		||||
        # Create OpenNebulaManager
 | 
			
		||||
        manager = OpenNebulaManager(email=settings.OPENNEBULA_USERNAME,
 | 
			
		||||
| 
						 | 
				
			
			@ -89,9 +91,9 @@ def create_vm_task(self, vm_template_id, user, specs, template, stripe_customer_
 | 
			
		|||
            billing_address_user_form.is_valid()
 | 
			
		||||
            billing_address_user_form.save()
 | 
			
		||||
 | 
			
		||||
        # Associate an order with a stripe payment
 | 
			
		||||
        # Associate an order with a stripe subscription
 | 
			
		||||
        charge_object = DictDotLookup(charge)
 | 
			
		||||
        order.set_stripe_charge(charge_object)
 | 
			
		||||
        order.set_subscription_id(charge_object, cc_details)
 | 
			
		||||
 | 
			
		||||
        # If the Stripe payment succeeds, set order status approved
 | 
			
		||||
        order.set_approved()
 | 
			
		||||
| 
						 | 
				
			
			@ -114,7 +116,8 @@ def create_vm_task(self, vm_template_id, user, specs, template, stripe_customer_
 | 
			
		|||
            'subject': settings.DCL_TEXT + " Order from %s" % context['email'],
 | 
			
		||||
            'from_email': settings.DCL_SUPPORT_FROM_ADDRESS,
 | 
			
		||||
            'to': ['info@ungleich.ch'],
 | 
			
		||||
            'body': "\n".join(["%s=%s" % (k, v) for (k, v) in context.items()]),
 | 
			
		||||
            'body': "\n".join(
 | 
			
		||||
                ["%s=%s" % (k, v) for (k, v) in context.items()]),
 | 
			
		||||
            'reply_to': [context['email']],
 | 
			
		||||
        }
 | 
			
		||||
        email = EmailMessage(**email_data)
 | 
			
		||||
| 
						 | 
				
			
			@ -124,11 +127,13 @@ def create_vm_task(self, vm_template_id, user, specs, template, stripe_customer_
 | 
			
		|||
        try:
 | 
			
		||||
            retry_task(self)
 | 
			
		||||
        except MaxRetriesExceededError:
 | 
			
		||||
            msg_text = 'Finished {} retries for create_vm_task'.format(self.request.retries)
 | 
			
		||||
            msg_text = 'Finished {} retries for create_vm_task'.format(
 | 
			
		||||
                self.request.retries)
 | 
			
		||||
            logger.error(msg_text)
 | 
			
		||||
            # Try sending email and stop
 | 
			
		||||
            email_data = {
 | 
			
		||||
                'subject': '{} CELERY TASK ERROR: {}'.format(settings.DCL_TEXT, msg_text),
 | 
			
		||||
                'subject': '{} CELERY TASK ERROR: {}'.format(settings.DCL_TEXT,
 | 
			
		||||
                                                             msg_text),
 | 
			
		||||
                'from_email': settings.DCL_SUPPORT_FROM_ADDRESS,
 | 
			
		||||
                'to': ['info@ungleich.ch'],
 | 
			
		||||
                'body': ',\n'.join(str(i) for i in self.request.args)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -67,14 +67,17 @@
 | 
			
		|||
                            <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></p></h4>
 | 
			
		||||
                            <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">
 | 
			
		||||
                    {% csrf_token %}
 | 
			
		||||
                    <div class=" content pull-right">
 | 
			
		||||
                        <a href="{{next_url}}" ><button class="btn btn-info">{% trans "Place order"%}</button></a>
 | 
			
		||||
                    <div class="col-md-8 col-xs-7 pull-left tbl-no-padding">
 | 
			
		||||
                        <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-md-4 col-xs-5 content tbl-no-padding">
 | 
			
		||||
                        <a href="{{next_url}}" ><button class="btn btn-info pull-right">{% trans "Place order"%}</button></a>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    </form>
 | 
			
		||||
                </div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,145 @@
 | 
			
		|||
# from django.test import TestCase
 | 
			
		||||
 | 
			
		||||
from time import sleep
 | 
			
		||||
 | 
			
		||||
import stripe
 | 
			
		||||
from celery.result import AsyncResult
 | 
			
		||||
from django.conf import settings
 | 
			
		||||
from django.core.management import call_command
 | 
			
		||||
# Create your tests here.
 | 
			
		||||
from django.test import TestCase, override_settings
 | 
			
		||||
from model_mommy import mommy
 | 
			
		||||
 | 
			
		||||
from datacenterlight.models import VMTemplate
 | 
			
		||||
from datacenterlight.tasks import create_vm_task
 | 
			
		||||
from membership.models import StripeCustomer
 | 
			
		||||
from opennebula_api.serializers import VMTemplateSerializer
 | 
			
		||||
from utils.models import BillingAddress
 | 
			
		||||
from utils.stripe_utils import StripeUtils
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CeleryTaskTestCase(TestCase):
 | 
			
		||||
    @override_settings(
 | 
			
		||||
        task_eager_propagates=True,
 | 
			
		||||
        task_always_eager=True,
 | 
			
		||||
    )
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        self.customer_password = 'test_password'
 | 
			
		||||
        self.customer_email = 'celery-createvm-task-test@ungleich.ch'
 | 
			
		||||
        self.customer_name = "Monty Python"
 | 
			
		||||
        self.user = {
 | 
			
		||||
            'email': self.customer_email,
 | 
			
		||||
            'name': self.customer_name
 | 
			
		||||
        }
 | 
			
		||||
        self.customer = mommy.make('membership.CustomUser')
 | 
			
		||||
        self.customer.set_password(self.customer_password)
 | 
			
		||||
        self.customer.email = self.customer_email
 | 
			
		||||
        self.customer.save()
 | 
			
		||||
        self.stripe_utils = StripeUtils()
 | 
			
		||||
        stripe.api_key = settings.STRIPE_API_PRIVATE_KEY_TEST
 | 
			
		||||
        self.token = stripe.Token.create(
 | 
			
		||||
            card={
 | 
			
		||||
                "number": '4111111111111111',
 | 
			
		||||
                "exp_month": 12,
 | 
			
		||||
                "exp_year": 2022,
 | 
			
		||||
                "cvc": '123'
 | 
			
		||||
            },
 | 
			
		||||
        )
 | 
			
		||||
        # Run fetchvmtemplates so that we have the VM templates from
 | 
			
		||||
        # OpenNebula
 | 
			
		||||
        call_command('fetchvmtemplates')
 | 
			
		||||
 | 
			
		||||
    def test_create_vm_task(self):
 | 
			
		||||
        """Tests the create vm task for monthly subscription
 | 
			
		||||
 | 
			
		||||
        This test is supposed to validate the proper execution
 | 
			
		||||
        of celery create_vm_task on production, as we have no
 | 
			
		||||
        other way to do this.
 | 
			
		||||
        """
 | 
			
		||||
 | 
			
		||||
        # We create a VM from the first template available to DCL
 | 
			
		||||
        vm_template = VMTemplate.objects.all().first()
 | 
			
		||||
        template_data = VMTemplateSerializer(vm_template).data
 | 
			
		||||
 | 
			
		||||
        # The specs of VM that we want to create
 | 
			
		||||
        specs = {
 | 
			
		||||
            'cpu': 1,
 | 
			
		||||
            'memory': 2,
 | 
			
		||||
            'disk_size': 10,
 | 
			
		||||
            'price': 15
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        stripe_customer = StripeCustomer.get_or_create(
 | 
			
		||||
            email=self.customer_email,
 | 
			
		||||
            token=self.token)
 | 
			
		||||
        card_details = self.stripe_utils.get_card_details(
 | 
			
		||||
            stripe_customer.stripe_id,
 | 
			
		||||
            self.token)
 | 
			
		||||
        card_details_dict = card_details.get('response_object')
 | 
			
		||||
        billing_address = BillingAddress(
 | 
			
		||||
            cardholder_name=self.customer_name,
 | 
			
		||||
            postal_code='1232',
 | 
			
		||||
            country='CH',
 | 
			
		||||
            street_address='Monty\'s Street',
 | 
			
		||||
            city='Hollywood')
 | 
			
		||||
        billing_address.save()
 | 
			
		||||
        billing_address_data = {'cardholder_name': self.customer_name,
 | 
			
		||||
                                'postal_code': '1231',
 | 
			
		||||
                                'country': 'CH',
 | 
			
		||||
                                'token': self.token,
 | 
			
		||||
                                'street_address': 'Monty\'s Street',
 | 
			
		||||
                                'city': 'Hollywood'}
 | 
			
		||||
 | 
			
		||||
        billing_address_id = billing_address.id
 | 
			
		||||
        vm_template_id = template_data.get('id', 1)
 | 
			
		||||
 | 
			
		||||
        cpu = specs.get('cpu')
 | 
			
		||||
        memory = specs.get('memory')
 | 
			
		||||
        disk_size = specs.get('disk_size')
 | 
			
		||||
        amount_to_be_charged = (cpu * 5) + (memory * 2) + (disk_size * 0.6)
 | 
			
		||||
        plan_name = "{cpu} Cores, {memory} GB RAM, {disk_size} GB SSD".format(
 | 
			
		||||
            cpu=cpu,
 | 
			
		||||
            memory=memory,
 | 
			
		||||
            disk_size=disk_size)
 | 
			
		||||
 | 
			
		||||
        stripe_plan_id = StripeUtils.get_stripe_plan_id(cpu=cpu,
 | 
			
		||||
                                                        ram=memory,
 | 
			
		||||
                                                        ssd=disk_size,
 | 
			
		||||
                                                        version=1,
 | 
			
		||||
                                                        app='dcl')
 | 
			
		||||
        stripe_plan = self.stripe_utils.get_or_create_stripe_plan(
 | 
			
		||||
            amount=amount_to_be_charged,
 | 
			
		||||
            name=plan_name,
 | 
			
		||||
            stripe_plan_id=stripe_plan_id)
 | 
			
		||||
        subscription_result = self.stripe_utils.subscribe_customer_to_plan(
 | 
			
		||||
            stripe_customer.stripe_id,
 | 
			
		||||
            [{"plan": stripe_plan.get(
 | 
			
		||||
                'response_object').stripe_plan_id}])
 | 
			
		||||
        stripe_subscription_obj = subscription_result.get('response_object')
 | 
			
		||||
        # Check if the subscription was approved and is active
 | 
			
		||||
        if stripe_subscription_obj is None or \
 | 
			
		||||
                        stripe_subscription_obj.status != 'active':
 | 
			
		||||
            msg = subscription_result.get('error')
 | 
			
		||||
            raise Exception("Creating subscription failed: {}".format(msg))
 | 
			
		||||
 | 
			
		||||
        async_task = create_vm_task.delay(vm_template_id, self.user,
 | 
			
		||||
                                          specs,
 | 
			
		||||
                                          template_data,
 | 
			
		||||
                                          stripe_customer.id,
 | 
			
		||||
                                          billing_address_data,
 | 
			
		||||
                                          billing_address_id,
 | 
			
		||||
                                          stripe_subscription_obj,
 | 
			
		||||
                                          card_details_dict)
 | 
			
		||||
        new_vm_id = 0
 | 
			
		||||
        res = None
 | 
			
		||||
        for i in range(0, 10):
 | 
			
		||||
            sleep(5)
 | 
			
		||||
            res = AsyncResult(async_task.task_id)
 | 
			
		||||
            if res.result is not None and res.result > 0:
 | 
			
		||||
                new_vm_id = res.result
 | 
			
		||||
                break
 | 
			
		||||
 | 
			
		||||
        # We expect a VM to be created within 50 seconds
 | 
			
		||||
        self.assertGreater(new_vm_id, 0,
 | 
			
		||||
                           "VM could not be created. res._get_task_meta() = {}"
 | 
			
		||||
                           .format(res._get_task_meta()))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,7 +18,8 @@ from hosting.models import HostingOrder
 | 
			
		|||
from utils.stripe_utils import StripeUtils
 | 
			
		||||
from membership.models import CustomUser, StripeCustomer
 | 
			
		||||
from opennebula_api.models import OpenNebulaManager
 | 
			
		||||
from opennebula_api.serializers import VirtualMachineTemplateSerializer, VMTemplateSerializer
 | 
			
		||||
from opennebula_api.serializers import VirtualMachineTemplateSerializer, \
 | 
			
		||||
    VMTemplateSerializer
 | 
			
		||||
from datacenterlight.tasks import create_vm_task
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -35,9 +36,11 @@ class SuccessView(TemplateView):
 | 
			
		|||
        elif 'token' not in request.session:
 | 
			
		||||
            return HttpResponseRedirect(reverse('datacenterlight:payment'))
 | 
			
		||||
        elif 'order_confirmation' not in request.session:
 | 
			
		||||
            return HttpResponseRedirect(reverse('datacenterlight:order_confirmation'))
 | 
			
		||||
            return HttpResponseRedirect(
 | 
			
		||||
                reverse('datacenterlight:order_confirmation'))
 | 
			
		||||
        else:
 | 
			
		||||
            for session_var in ['specs', 'user', 'template', 'billing_address', 'billing_address_data',
 | 
			
		||||
            for session_var in ['specs', 'user', 'template', 'billing_address',
 | 
			
		||||
                                'billing_address_data',
 | 
			
		||||
                                'token', 'customer']:
 | 
			
		||||
                if session_var in request.session:
 | 
			
		||||
                    del request.session[session_var]
 | 
			
		||||
| 
						 | 
				
			
			@ -53,7 +56,8 @@ class PricingView(TemplateView):
 | 
			
		|||
            templates = manager.get_templates()
 | 
			
		||||
 | 
			
		||||
            context = {
 | 
			
		||||
                'templates': VirtualMachineTemplateSerializer(templates, many=True).data,
 | 
			
		||||
                'templates': VirtualMachineTemplateSerializer(templates,
 | 
			
		||||
                                                              many=True).data,
 | 
			
		||||
            }
 | 
			
		||||
        except:
 | 
			
		||||
            messages.error(request,
 | 
			
		||||
| 
						 | 
				
			
			@ -77,7 +81,8 @@ class PricingView(TemplateView):
 | 
			
		|||
        manager = OpenNebulaManager()
 | 
			
		||||
        template = manager.get_template(template_id)
 | 
			
		||||
 | 
			
		||||
        request.session['template'] = VirtualMachineTemplateSerializer(template).data
 | 
			
		||||
        request.session['template'] = VirtualMachineTemplateSerializer(
 | 
			
		||||
            template).data
 | 
			
		||||
 | 
			
		||||
        if not request.user.is_authenticated():
 | 
			
		||||
            request.session['next'] = reverse('hosting:payment')
 | 
			
		||||
| 
						 | 
				
			
			@ -99,7 +104,8 @@ class BetaAccessView(FormView):
 | 
			
		|||
 | 
			
		||||
    def form_valid(self, form):
 | 
			
		||||
        context = {
 | 
			
		||||
            'base_url': "{0}://{1}".format(self.request.scheme, self.request.get_host())
 | 
			
		||||
            'base_url': "{0}://{1}".format(self.request.scheme,
 | 
			
		||||
                                           self.request.get_host())
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        email_data = {
 | 
			
		||||
| 
						 | 
				
			
			@ -129,7 +135,8 @@ class BetaAccessView(FormView):
 | 
			
		|||
        email = BaseEmail(**email_data)
 | 
			
		||||
        email.send()
 | 
			
		||||
 | 
			
		||||
        messages.add_message(self.request, messages.SUCCESS, self.success_message)
 | 
			
		||||
        messages.add_message(self.request, messages.SUCCESS,
 | 
			
		||||
                             self.success_message)
 | 
			
		||||
        return render(self.request, 'datacenterlight/beta_success.html', {})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -154,7 +161,8 @@ class BetaProgramView(CreateView):
 | 
			
		|||
        # data = VirtualMachineTemplateSerializer(templates, many=True).data
 | 
			
		||||
 | 
			
		||||
        context.update({
 | 
			
		||||
            'base_url': "{0}://{1}".format(self.request.scheme, self.request.get_host()),
 | 
			
		||||
            'base_url': "{0}://{1}".format(self.request.scheme,
 | 
			
		||||
                                           self.request.get_host()),
 | 
			
		||||
            'vms': vms
 | 
			
		||||
        })
 | 
			
		||||
        return context
 | 
			
		||||
| 
						 | 
				
			
			@ -164,7 +172,8 @@ class BetaProgramView(CreateView):
 | 
			
		|||
        vms = BetaAccessVM.create(data)
 | 
			
		||||
 | 
			
		||||
        context = {
 | 
			
		||||
            'base_url': "{0}://{1}".format(self.request.scheme, self.request.get_host()),
 | 
			
		||||
            'base_url': "{0}://{1}".format(self.request.scheme,
 | 
			
		||||
                                           self.request.get_host()),
 | 
			
		||||
            'email': data.get('email'),
 | 
			
		||||
            'name': data.get('name'),
 | 
			
		||||
            'vms': vms
 | 
			
		||||
| 
						 | 
				
			
			@ -181,7 +190,8 @@ class BetaProgramView(CreateView):
 | 
			
		|||
        email = BaseEmail(**email_data)
 | 
			
		||||
        email.send()
 | 
			
		||||
 | 
			
		||||
        messages.add_message(self.request, messages.SUCCESS, self.success_message)
 | 
			
		||||
        messages.add_message(self.request, messages.SUCCESS,
 | 
			
		||||
                             self.success_message)
 | 
			
		||||
        return HttpResponseRedirect(self.get_success_url())
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -225,7 +235,8 @@ class IndexView(CreateView):
 | 
			
		|||
        storage_field = forms.IntegerField(validators=[self.validate_storage])
 | 
			
		||||
        price = request.POST.get('total')
 | 
			
		||||
        template_id = int(request.POST.get('config'))
 | 
			
		||||
        template = VMTemplate.objects.filter(opennebula_vm_template_id=template_id).first()
 | 
			
		||||
        template = VMTemplate.objects.filter(
 | 
			
		||||
            opennebula_vm_template_id=template_id).first()
 | 
			
		||||
        template_data = VMTemplateSerializer(template).data
 | 
			
		||||
 | 
			
		||||
        name = request.POST.get('name')
 | 
			
		||||
| 
						 | 
				
			
			@ -237,36 +248,46 @@ class IndexView(CreateView):
 | 
			
		|||
            cores = cores_field.clean(cores)
 | 
			
		||||
        except ValidationError as err:
 | 
			
		||||
            msg = '{} : {}.'.format(cores, str(err))
 | 
			
		||||
            messages.add_message(self.request, messages.ERROR, msg, extra_tags='cores')
 | 
			
		||||
            return HttpResponseRedirect(reverse('datacenterlight:index') + "#order_form")
 | 
			
		||||
            messages.add_message(self.request, messages.ERROR, msg,
 | 
			
		||||
                                 extra_tags='cores')
 | 
			
		||||
            return HttpResponseRedirect(
 | 
			
		||||
                reverse('datacenterlight:index') + "#order_form")
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            memory = memory_field.clean(memory)
 | 
			
		||||
        except ValidationError as err:
 | 
			
		||||
            msg = '{} : {}.'.format(memory, str(err))
 | 
			
		||||
            messages.add_message(self.request, messages.ERROR, msg, extra_tags='memory')
 | 
			
		||||
            return HttpResponseRedirect(reverse('datacenterlight:index') + "#order_form")
 | 
			
		||||
            messages.add_message(self.request, messages.ERROR, msg,
 | 
			
		||||
                                 extra_tags='memory')
 | 
			
		||||
            return HttpResponseRedirect(
 | 
			
		||||
                reverse('datacenterlight:index') + "#order_form")
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            storage = storage_field.clean(storage)
 | 
			
		||||
        except ValidationError as err:
 | 
			
		||||
            msg = '{} : {}.'.format(storage, str(err))
 | 
			
		||||
            messages.add_message(self.request, messages.ERROR, msg, extra_tags='storage')
 | 
			
		||||
            return HttpResponseRedirect(reverse('datacenterlight:index') + "#order_form")
 | 
			
		||||
            messages.add_message(self.request, messages.ERROR, msg,
 | 
			
		||||
                                 extra_tags='storage')
 | 
			
		||||
            return HttpResponseRedirect(
 | 
			
		||||
                reverse('datacenterlight:index') + "#order_form")
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            name = name_field.clean(name)
 | 
			
		||||
        except ValidationError as err:
 | 
			
		||||
            msg = '{} {}.'.format(name, _('is not a proper name'))
 | 
			
		||||
            messages.add_message(self.request, messages.ERROR, msg, extra_tags='name')
 | 
			
		||||
            return HttpResponseRedirect(reverse('datacenterlight:index') + "#order_form")
 | 
			
		||||
            messages.add_message(self.request, messages.ERROR, msg,
 | 
			
		||||
                                 extra_tags='name')
 | 
			
		||||
            return HttpResponseRedirect(
 | 
			
		||||
                reverse('datacenterlight:index') + "#order_form")
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            email = email_field.clean(email)
 | 
			
		||||
        except ValidationError as err:
 | 
			
		||||
            msg = '{} {}.'.format(email, _('is not a proper email'))
 | 
			
		||||
            messages.add_message(self.request, messages.ERROR, msg, extra_tags='email')
 | 
			
		||||
            return HttpResponseRedirect(reverse('datacenterlight:index') + "#order_form")
 | 
			
		||||
            messages.add_message(self.request, messages.ERROR, msg,
 | 
			
		||||
                                 extra_tags='email')
 | 
			
		||||
            return HttpResponseRedirect(
 | 
			
		||||
                reverse('datacenterlight:index') + "#order_form")
 | 
			
		||||
 | 
			
		||||
        specs = {
 | 
			
		||||
            'cpu': cores,
 | 
			
		||||
| 
						 | 
				
			
			@ -293,14 +314,16 @@ class IndexView(CreateView):
 | 
			
		|||
    def get_context_data(self, **kwargs):
 | 
			
		||||
        context = super(IndexView, self).get_context_data(**kwargs)
 | 
			
		||||
        context.update({
 | 
			
		||||
            'base_url': "{0}://{1}".format(self.request.scheme, self.request.get_host())
 | 
			
		||||
            'base_url': "{0}://{1}".format(self.request.scheme,
 | 
			
		||||
                                           self.request.get_host())
 | 
			
		||||
        })
 | 
			
		||||
        return context
 | 
			
		||||
 | 
			
		||||
    def form_valid(self, form):
 | 
			
		||||
 | 
			
		||||
        context = {
 | 
			
		||||
            'base_url': "{0}://{1}".format(self.request.scheme, self.request.get_host())
 | 
			
		||||
            'base_url': "{0}://{1}".format(self.request.scheme,
 | 
			
		||||
                                           self.request.get_host())
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        email_data = {
 | 
			
		||||
| 
						 | 
				
			
			@ -330,7 +353,8 @@ class IndexView(CreateView):
 | 
			
		|||
        email = BaseEmail(**email_data)
 | 
			
		||||
        email.send()
 | 
			
		||||
 | 
			
		||||
        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)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -403,7 +427,8 @@ class PaymentOrderView(FormView):
 | 
			
		|||
            request.session['billing_address'] = billing_address.id
 | 
			
		||||
            request.session['token'] = token
 | 
			
		||||
            request.session['customer'] = customer.id
 | 
			
		||||
            return HttpResponseRedirect(reverse('datacenterlight:order_confirmation'))
 | 
			
		||||
            return HttpResponseRedirect(
 | 
			
		||||
                reverse('datacenterlight:order_confirmation'))
 | 
			
		||||
        else:
 | 
			
		||||
            return self.form_invalid(form)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -423,11 +448,15 @@ class OrderConfirmationView(DetailView):
 | 
			
		|||
        stripe_customer_id = request.session.get('customer')
 | 
			
		||||
        customer = StripeCustomer.objects.filter(id=stripe_customer_id).first()
 | 
			
		||||
        stripe_utils = StripeUtils()
 | 
			
		||||
        card_details = stripe_utils.get_card_details(customer.stripe_id, request.session.get('token'))
 | 
			
		||||
        if not card_details.get('response_object') and not card_details.get('paid'):
 | 
			
		||||
        card_details = stripe_utils.get_card_details(customer.stripe_id,
 | 
			
		||||
                                                     request.session.get(
 | 
			
		||||
                                                         'token'))
 | 
			
		||||
        if not card_details.get('response_object'):
 | 
			
		||||
            msg = card_details.get('error')
 | 
			
		||||
            messages.add_message(self.request, messages.ERROR, msg, extra_tags='failed_payment')
 | 
			
		||||
            return HttpResponseRedirect(reverse('datacenterlight:payment') + '#payment_error')
 | 
			
		||||
            messages.add_message(self.request, messages.ERROR, msg,
 | 
			
		||||
                                 extra_tags='failed_payment')
 | 
			
		||||
            return HttpResponseRedirect(
 | 
			
		||||
                reverse('datacenterlight:payment') + '#payment_error')
 | 
			
		||||
        context = {
 | 
			
		||||
            'site_url': reverse('datacenterlight:index'),
 | 
			
		||||
            'cc_last4': card_details.get('response_object').get('last4'),
 | 
			
		||||
| 
						 | 
				
			
			@ -444,22 +473,53 @@ class OrderConfirmationView(DetailView):
 | 
			
		|||
        billing_address_data = request.session.get('billing_address_data')
 | 
			
		||||
        billing_address_id = request.session.get('billing_address')
 | 
			
		||||
        vm_template_id = template.get('id', 1)
 | 
			
		||||
        final_price = specs.get('price')
 | 
			
		||||
 | 
			
		||||
        # Make stripe charge to a customer
 | 
			
		||||
        stripe_utils = StripeUtils()
 | 
			
		||||
        charge_response = stripe_utils.make_charge(amount=final_price,
 | 
			
		||||
                                                   customer=customer.stripe_id)
 | 
			
		||||
        card_details = stripe_utils.get_card_details(customer.stripe_id,
 | 
			
		||||
                                                     request.session.get(
 | 
			
		||||
                                                         'token'))
 | 
			
		||||
        if not card_details.get('response_object'):
 | 
			
		||||
            msg = card_details.get('error')
 | 
			
		||||
            messages.add_message(self.request, messages.ERROR, msg,
 | 
			
		||||
                                 extra_tags='failed_payment')
 | 
			
		||||
            return HttpResponseRedirect(
 | 
			
		||||
                reverse('datacenterlight:payment') + '#payment_error')
 | 
			
		||||
        card_details_dict = card_details.get('response_object')
 | 
			
		||||
        cpu = specs.get('cpu')
 | 
			
		||||
        memory = specs.get('memory')
 | 
			
		||||
        disk_size = specs.get('disk_size')
 | 
			
		||||
        amount_to_be_charged = (cpu * 5) + (memory * 2) + (disk_size * 0.6)
 | 
			
		||||
        plan_name = "{cpu} Cores, {memory} GB RAM, {disk_size} GB SSD".format(
 | 
			
		||||
            cpu=cpu,
 | 
			
		||||
            memory=memory,
 | 
			
		||||
            disk_size=disk_size)
 | 
			
		||||
 | 
			
		||||
        # Check if the payment was approved
 | 
			
		||||
        if not charge_response.get('response_object') and not charge_response.get('paid'):
 | 
			
		||||
            msg = charge_response.get('error')
 | 
			
		||||
            messages.add_message(self.request, messages.ERROR, msg, extra_tags='make_charge_error')
 | 
			
		||||
            return HttpResponseRedirect(reverse('datacenterlight:payment') + '#payment_error')
 | 
			
		||||
 | 
			
		||||
        charge = charge_response.get('response_object')
 | 
			
		||||
        create_vm_task.delay(vm_template_id, user, specs, template, stripe_customer_id, billing_address_data,
 | 
			
		||||
        stripe_plan_id = StripeUtils.get_stripe_plan_id(cpu=cpu,
 | 
			
		||||
                                                        ram=memory,
 | 
			
		||||
                                                        ssd=disk_size,
 | 
			
		||||
                                                        version=1,
 | 
			
		||||
                                                        app='dcl')
 | 
			
		||||
        stripe_plan = stripe_utils.get_or_create_stripe_plan(
 | 
			
		||||
            amount=amount_to_be_charged,
 | 
			
		||||
            name=plan_name,
 | 
			
		||||
            stripe_plan_id=stripe_plan_id)
 | 
			
		||||
        subscription_result = stripe_utils.subscribe_customer_to_plan(
 | 
			
		||||
            customer.stripe_id,
 | 
			
		||||
            [{"plan": stripe_plan.get(
 | 
			
		||||
                'response_object').stripe_plan_id}])
 | 
			
		||||
        stripe_subscription_obj = subscription_result.get('response_object')
 | 
			
		||||
        # Check if the subscription was approved and is active
 | 
			
		||||
        if stripe_subscription_obj is None or \
 | 
			
		||||
                        stripe_subscription_obj.status != 'active':
 | 
			
		||||
            msg = subscription_result.get('error')
 | 
			
		||||
            messages.add_message(self.request, messages.ERROR, msg,
 | 
			
		||||
                                 extra_tags='failed_payment')
 | 
			
		||||
            return HttpResponseRedirect(
 | 
			
		||||
                reverse('datacenterlight:payment') + '#payment_error')
 | 
			
		||||
        create_vm_task.delay(vm_template_id, user, specs, template,
 | 
			
		||||
                             stripe_customer_id, billing_address_data,
 | 
			
		||||
                             billing_address_id,
 | 
			
		||||
                             charge)
 | 
			
		||||
                             stripe_subscription_obj, card_details_dict)
 | 
			
		||||
        request.session['order_confirmation'] = True
 | 
			
		||||
        return HttpResponseRedirect(reverse('datacenterlight:order_success'))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue