commit
				
					
						99b16b09fb
					
				
			
		
					 21 changed files with 661 additions and 170 deletions
				
			
		|  | @ -446,8 +446,8 @@ AUTH_USER_MODEL = 'membership.CustomUser' | ||||||
| 
 | 
 | ||||||
| # PAYMENT | # PAYMENT | ||||||
| 
 | 
 | ||||||
| STRIPE_API_PUBLIC_KEY = 'pk_test_ZRg6P8g5ybiHE6l2RW5pSaYV'  # used in frontend to call from user browser | STRIPE_API_PUBLIC_KEY = 'pk_test_QqBZ50Am8KOxaAlOxbcm9Psl'  # used in frontend to call from user browser | ||||||
| STRIPE_API_PRIVATE_KEY = 'sk_test_uIPMdgXoRGydrcD7fkwcn7dj'  # used in backend payment | STRIPE_API_PRIVATE_KEY = 'sk_test_dqAmbKAij12QCGfkYZ3poGt2'  # used in backend payment | ||||||
| STRIPE_DESCRIPTION_ON_PAYMENT = "Payment for ungleich GmbH services" | STRIPE_DESCRIPTION_ON_PAYMENT = "Payment for ungleich GmbH services" | ||||||
| 
 | 
 | ||||||
| # EMAIL MESSAGES | # EMAIL MESSAGES | ||||||
|  |  | ||||||
							
								
								
									
										9
									
								
								hosting/managers.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								hosting/managers.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,9 @@ | ||||||
|  | from django.db import models | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class VMPlansManager(models.Manager): | ||||||
|  | 
 | ||||||
|  |     def active(self, user, **kwargs): | ||||||
|  |         return self.prefetch_related('hosting_orders__customer__user').\ | ||||||
|  |             filter(hosting_orders__customer__user=user, hosting_orders__approved=True, **kwargs)\ | ||||||
|  |             .distinct() | ||||||
							
								
								
									
										27
									
								
								hosting/migrations/0012_auto_20160501_1850.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								hosting/migrations/0012_auto_20160501_1850.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,27 @@ | ||||||
|  | # -*- coding: utf-8 -*- | ||||||
|  | # Generated by Django 1.9.4 on 2016-05-01 18:50 | ||||||
|  | from __future__ import unicode_literals | ||||||
|  | 
 | ||||||
|  | from django.db import migrations, models | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Migration(migrations.Migration): | ||||||
|  | 
 | ||||||
|  |     dependencies = [ | ||||||
|  |         ('hosting', '0011_auto_20160426_0555'), | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     operations = [ | ||||||
|  |         migrations.AddField( | ||||||
|  |             model_name='hostingorder', | ||||||
|  |             name='cc_brand', | ||||||
|  |             field=models.CharField(default='Visa', max_length=10), | ||||||
|  |             preserve_default=False, | ||||||
|  |         ), | ||||||
|  |         migrations.AddField( | ||||||
|  |             model_name='hostingorder', | ||||||
|  |             name='last4', | ||||||
|  |             field=models.CharField(default=1111, max_length=4), | ||||||
|  |             preserve_default=False, | ||||||
|  |         ), | ||||||
|  |     ] | ||||||
							
								
								
									
										21
									
								
								hosting/migrations/0013_auto_20160505_0302.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								hosting/migrations/0013_auto_20160505_0302.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,21 @@ | ||||||
|  | # -*- coding: utf-8 -*- | ||||||
|  | # Generated by Django 1.9.4 on 2016-05-05 03:02 | ||||||
|  | from __future__ import unicode_literals | ||||||
|  | 
 | ||||||
|  | from django.db import migrations, models | ||||||
|  | import django.db.models.deletion | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Migration(migrations.Migration): | ||||||
|  | 
 | ||||||
|  |     dependencies = [ | ||||||
|  |         ('hosting', '0012_auto_20160501_1850'), | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     operations = [ | ||||||
|  |         migrations.AlterField( | ||||||
|  |             model_name='hostingorder', | ||||||
|  |             name='VMPlan', | ||||||
|  |             field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='hosting.VirtualMachinePlan'), | ||||||
|  |         ), | ||||||
|  |     ] | ||||||
							
								
								
									
										21
									
								
								hosting/migrations/0014_auto_20160505_0541.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								hosting/migrations/0014_auto_20160505_0541.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,21 @@ | ||||||
|  | # -*- coding: utf-8 -*- | ||||||
|  | # Generated by Django 1.9.4 on 2016-05-05 05:41 | ||||||
|  | from __future__ import unicode_literals | ||||||
|  | 
 | ||||||
|  | from django.db import migrations, models | ||||||
|  | import django.db.models.deletion | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Migration(migrations.Migration): | ||||||
|  | 
 | ||||||
|  |     dependencies = [ | ||||||
|  |         ('hosting', '0013_auto_20160505_0302'), | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     operations = [ | ||||||
|  |         migrations.AlterField( | ||||||
|  |             model_name='hostingorder', | ||||||
|  |             name='VMPlan', | ||||||
|  |             field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='hosting_orders', to='hosting.VirtualMachinePlan'), | ||||||
|  |         ), | ||||||
|  |     ] | ||||||
|  | @ -2,10 +2,13 @@ import json | ||||||
| 
 | 
 | ||||||
| from django.db import models | from django.db import models | ||||||
| from django.utils.translation import ugettext_lazy as _ | from django.utils.translation import ugettext_lazy as _ | ||||||
|  | from django.utils.functional import cached_property | ||||||
| from django.core import serializers | from django.core import serializers | ||||||
| from membership.models import StripeCustomer | from membership.models import StripeCustomer | ||||||
| from utils.models import BillingAddress | from utils.models import BillingAddress | ||||||
| 
 | 
 | ||||||
|  | from .managers import VMPlansManager | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| class RailsBetaUser(models.Model): | class RailsBetaUser(models.Model): | ||||||
|     email = models.EmailField(unique=True) |     email = models.EmailField(unique=True) | ||||||
|  | @ -81,6 +84,17 @@ class VirtualMachinePlan(models.Model): | ||||||
|     vm_type = models.ForeignKey(VirtualMachineType) |     vm_type = models.ForeignKey(VirtualMachineType) | ||||||
|     price = models.FloatField() |     price = models.FloatField() | ||||||
| 
 | 
 | ||||||
|  |     objects = VMPlansManager() | ||||||
|  | 
 | ||||||
|  |     @cached_property | ||||||
|  |     def hosting_company_name(self): | ||||||
|  |         return self.vm_type.get_hosting_company_display() | ||||||
|  | 
 | ||||||
|  |     @cached_property | ||||||
|  |     def name(self): | ||||||
|  |         name = 'vm-%s' % self.id | ||||||
|  |         return name | ||||||
|  | 
 | ||||||
|     @classmethod |     @classmethod | ||||||
|     def create(cls, data, user): |     def create(cls, data, user): | ||||||
|         instance = cls.objects.create(**data) |         instance = cls.objects.create(**data) | ||||||
|  | @ -88,13 +102,23 @@ class VirtualMachinePlan(models.Model): | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class HostingOrder(models.Model): | class HostingOrder(models.Model): | ||||||
|     VMPlan = models.OneToOneField(VirtualMachinePlan) | 
 | ||||||
|  |     ORDER_APPROVED_STATUS = 'Approved' | ||||||
|  |     ORDER_DECLINED_STATUS = 'Declined' | ||||||
|  | 
 | ||||||
|  |     VMPlan = models.ForeignKey(VirtualMachinePlan, related_name='hosting_orders') | ||||||
|     customer = models.ForeignKey(StripeCustomer) |     customer = models.ForeignKey(StripeCustomer) | ||||||
|     billing_address = models.ForeignKey(BillingAddress) |     billing_address = models.ForeignKey(BillingAddress) | ||||||
|     created_at = models.DateTimeField(auto_now_add=True) |     created_at = models.DateTimeField(auto_now_add=True) | ||||||
|     approved = models.BooleanField(default=False) |     approved = models.BooleanField(default=False) | ||||||
|  |     last4 = models.CharField(max_length=4) | ||||||
|  |     cc_brand = models.CharField(max_length=10) | ||||||
|     stripe_charge_id = models.CharField(max_length=100, null=True) |     stripe_charge_id = models.CharField(max_length=100, null=True) | ||||||
| 
 | 
 | ||||||
|  |     @cached_property | ||||||
|  |     def status(self): | ||||||
|  |         return self.ORDER_APPROVED_STATUS if self.approved else self.ORDER_DECLINED_STATUS | ||||||
|  | 
 | ||||||
|     @classmethod |     @classmethod | ||||||
|     def create(cls, VMPlan=None, customer=None, billing_address=None): |     def create(cls, VMPlan=None, customer=None, billing_address=None): | ||||||
|         instance = cls.objects.create(VMPlan=VMPlan, customer=customer, |         instance = cls.objects.create(VMPlan=VMPlan, customer=customer, | ||||||
|  | @ -107,6 +131,8 @@ class HostingOrder(models.Model): | ||||||
| 
 | 
 | ||||||
|     def set_stripe_charge(self, stripe_charge): |     def set_stripe_charge(self, stripe_charge): | ||||||
|         self.stripe_charge_id = stripe_charge.id |         self.stripe_charge_id = stripe_charge.id | ||||||
|  |         self.last4 = stripe_charge.source.last4 | ||||||
|  |         self.cc_brand = stripe_charge.source.brand | ||||||
|         self.save() |         self.save() | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										20
									
								
								hosting/static/hosting/css/commons.css
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								hosting/static/hosting/css/commons.css
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,20 @@ | ||||||
|  | .dashboard-container { | ||||||
|  | 	padding-top:5%; padding-bottom: 11%; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .borderless td { | ||||||
|  |     border: none !important; | ||||||
|  | } | ||||||
|  | .borderless thead { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .borderless tbody:before { | ||||||
|  |     content: "-"; | ||||||
|  |     display: block; | ||||||
|  |     color: transparent; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .inline-headers h3, .inline-headers h4 { | ||||||
|  |   display: inline-block; | ||||||
|  |   vertical-align: baseline; | ||||||
|  | } | ||||||
							
								
								
									
										17
									
								
								hosting/static/hosting/css/order.css
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								hosting/static/hosting/css/order.css
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,17 @@ | ||||||
|  | .order-detail-container {padding-top:5%; padding-bottom: 11%;} | ||||||
|  | 
 | ||||||
|  | .order-detail-container .invoice-title h2, .invoice-title h3 { | ||||||
|  |     display: inline-block; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .order-detail-container .table > tbody > tr > .no-line { | ||||||
|  |     border-top: none; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .order-detail-container .table > thead > tr > .no-line { | ||||||
|  |     border-bottom: none; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .order-detail-container .table > tbody > tr > .thick-line { | ||||||
|  |     border-top: 2px solid; | ||||||
|  | } | ||||||
							
								
								
									
										5
									
								
								hosting/static/hosting/css/orders.css
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								hosting/static/hosting/css/orders.css
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,5 @@ | ||||||
|  | .orders-container {padding-top:5%; padding-bottom: 11%;} | ||||||
|  | 
 | ||||||
|  | .orders-container .table > tbody > tr > td { | ||||||
|  |      vertical-align: middle; | ||||||
|  | } | ||||||
							
								
								
									
										42
									
								
								hosting/static/hosting/css/virtual-machine.css
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								hosting/static/hosting/css/virtual-machine.css
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,42 @@ | ||||||
|  | .virtual-machine-container .tabs-left, .virtual-machine-container .tabs-right { | ||||||
|  |   border-bottom: none; | ||||||
|  |   padding-top: 2px; | ||||||
|  | } | ||||||
|  | .virtual-machine-container .tabs-left { | ||||||
|  |   border-right: 1px solid #ddd; | ||||||
|  | } | ||||||
|  | .virtual-machine-container .tabs-right { | ||||||
|  |   border-left: 1px solid #ddd; | ||||||
|  | } | ||||||
|  | .virtual-machine-container .tabs-left>li, .virtual-machine-container .tabs-right>li { | ||||||
|  |   float: none; | ||||||
|  |   margin-bottom: 2px; | ||||||
|  | } | ||||||
|  | .virtual-machine-container .tabs-left>li { | ||||||
|  |   margin-right: -1px; | ||||||
|  | } | ||||||
|  | .virtual-machine-container .tabs-right>li { | ||||||
|  |   margin-left: -1px; | ||||||
|  | } | ||||||
|  | .virtual-machine-container .tabs-left>li.active>a, | ||||||
|  | .virtual-machine-container .tabs-left>li.active>a:hover, | ||||||
|  | .virtual-machine-container .tabs-left>li.active>a:focus { | ||||||
|  |   border-bottom-color: #ddd; | ||||||
|  |   border-right-color: transparent; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .virtual-machine-container .tabs-right>li.active>a, | ||||||
|  | .virtual-machine-container .tabs-right>li.active>a:hover, | ||||||
|  | .virtual-machine-container .tabs-right>li.active>a:focus { | ||||||
|  |   border-bottom: 1px solid #ddd; | ||||||
|  |   border-left-color: transparent; | ||||||
|  | } | ||||||
|  | .virtual-machine-container .tabs-left>li>a { | ||||||
|  |   border-radius: 4px 0 0 4px; | ||||||
|  |   margin-right: 0; | ||||||
|  |   display:block; | ||||||
|  | } | ||||||
|  | .virtual-machine-container .tabs-right>li>a { | ||||||
|  |   border-radius: 0 4px 4px 0; | ||||||
|  |   margin-right: 0; | ||||||
|  | } | ||||||
|  | @ -18,6 +18,10 @@ | ||||||
|     <!-- Custom CSS --> |     <!-- Custom CSS --> | ||||||
|     <link href="{% static 'hosting/css/landing-page.css' %}" rel="stylesheet"> |     <link href="{% static 'hosting/css/landing-page.css' %}" rel="stylesheet"> | ||||||
|     <link href="{% static 'hosting/css/payment.css' %}" rel="stylesheet"> |     <link href="{% static 'hosting/css/payment.css' %}" rel="stylesheet"> | ||||||
|  |     <link href="{% static 'hosting/css/order.css' %}" rel="stylesheet"> | ||||||
|  |     <link href="{% static 'hosting/css/orders.css' %}" rel="stylesheet"> | ||||||
|  |     <link href="{% static 'hosting/css/commons.css' %}" rel="stylesheet"> | ||||||
|  |     <link href="{% static 'hosting/css/virtual-machine.css' %}" rel="stylesheet"> | ||||||
| 
 | 
 | ||||||
|     <!-- Custom Fonts --> |     <!-- Custom Fonts --> | ||||||
|     <link href='http://fonts.googleapis.com/css?family=Raleway' rel='stylesheet' type='text/css'> |     <link href='http://fonts.googleapis.com/css?family=Raleway' rel='stylesheet' type='text/css'> | ||||||
|  | @ -49,11 +53,33 @@ | ||||||
|                     <span class="icon-bar"></span> |                     <span class="icon-bar"></span> | ||||||
|                     <span class="icon-bar"></span> |                     <span class="icon-bar"></span> | ||||||
|                 </button> |                 </button> | ||||||
|                 <a class="navbar-brand topnav" href="#"><img src="img/logo_black.svg"></a> |                 <a class="navbar-brand topnav" href="#"><img src="{% static 'hosting/img/logo_black.svg' %}"></a> | ||||||
|             </div> |             </div> | ||||||
|             <!-- 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"> | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |                     {% if request.user.is_authenticated %} | ||||||
|  |                         <li> | ||||||
|  |                             <a href="{% url 'hosting:virtual_machines' %}"> | ||||||
|  |                                 <i class="fa fa-server" aria-hidden="true"></i> My Virtual Machines | ||||||
|  |                             </a> | ||||||
|  |                         </li> | ||||||
|  |                         <li> | ||||||
|  |                             <a href="{% url 'hosting:orders' %}"> | ||||||
|  |                                 <i class="fa fa-credit-card"></i> My Orders | ||||||
|  |                             </a> | ||||||
|  |                         </li> | ||||||
|  | 
 | ||||||
|  |                         <li class="dropdown"> | ||||||
|  |                           <a class="dropdown-toggle" role="button" data-toggle="dropdown" href="#"> | ||||||
|  |                             <i class="glyphicon glyphicon-user"></i> {{request.user.name}} <span class="caret"></span></a> | ||||||
|  |                           <ul id="g-account-menu" class="dropdown-menu" role="menu"> | ||||||
|  |                             <li><a href="{% url 'hosting:logout' %}"><i class="glyphicon glyphicon-lock"></i> Logout</a></li> | ||||||
|  |                           </ul> | ||||||
|  |                         </li> | ||||||
|  |                     {% else %} | ||||||
|                         <li> |                         <li> | ||||||
|                             <a href="{{ request.META.HTTP_REFERER }}#how">How it works</a> |                             <a href="{{ request.META.HTTP_REFERER }}#how">How it works</a> | ||||||
|                         </li> |                         </li> | ||||||
|  | @ -69,9 +95,8 @@ | ||||||
|                         <li> |                         <li> | ||||||
|                             <a href="{{ request.META.HTTP_REFERER }}#contact">Contact</a> |                             <a href="{{ request.META.HTTP_REFERER }}#contact">Contact</a> | ||||||
|                         </li>   |                         </li>   | ||||||
|                     {% if request.user.is_authenticated %} |  | ||||||
|                         <li> |                         <li> | ||||||
|                         <a href="{% url 'hosting:logout' %}"> Logout</a> |                             <a href="{% url 'hosting:login' %}?next={{request.current_path}}">Login</a> | ||||||
|                         </li>    |                         </li>    | ||||||
|                     {% endif %} |                     {% endif %} | ||||||
|                 </ul> |                 </ul> | ||||||
|  |  | ||||||
|  | @ -1,79 +0,0 @@ | ||||||
| {% extends "hosting/base_short.html" %} |  | ||||||
| {% load staticfiles bootstrap3 %} |  | ||||||
| {% block content %}  |  | ||||||
| 
 |  | ||||||
| <style type="text/css"> |  | ||||||
| .invoice-title h2, .invoice-title h3 { |  | ||||||
|     display: inline-block; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .table > tbody > tr > .no-line { |  | ||||||
|     border-top: none; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .table > thead > tr > .no-line { |  | ||||||
|     border-bottom: none; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .table > tbody > tr > .thick-line { |  | ||||||
|     border-top: 2px solid; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| </style> |  | ||||||
| 
 |  | ||||||
| <div class="container  payment-container"> |  | ||||||
|     <div class="row"> |  | ||||||
|         <div class="col-xs-8 col-xs-offset-2"> |  | ||||||
|     		<div class="invoice-title"> |  | ||||||
|     			<h2>Invoice</h2><h3 class="pull-right">Order # {{order.id}}</h3> |  | ||||||
|     		</div> |  | ||||||
|     		<hr> |  | ||||||
|     		<div class="row"> |  | ||||||
|     			<div class="col-xs-6"> |  | ||||||
|     				<address> |  | ||||||
|                     <h3><b>Billed To:</b></h3> |  | ||||||
|     					John Smith<br> |  | ||||||
|     					1234 Main<br> |  | ||||||
|     					Apt. 4B<br> |  | ||||||
|     					Springfield, ST 54321 |  | ||||||
|     				</address> |  | ||||||
|     			</div> |  | ||||||
|                 <div class="col-xs-6 text-right"> |  | ||||||
|                     <address> |  | ||||||
|                         <strong>Order Date:</strong><br> |  | ||||||
|                         {{order.created_at}}<br><br> |  | ||||||
|                     </address> |  | ||||||
|                 </div> |  | ||||||
|     		</div> |  | ||||||
|     		<div class="row"> |  | ||||||
|     			<div class="col-xs-6"> |  | ||||||
|     				<address> |  | ||||||
|     					<strong>Payment Method:</strong><br> |  | ||||||
|     					{{brand}} ending **** {{last4}}<br> |  | ||||||
|     					{{user.email}} |  | ||||||
|     				</address> |  | ||||||
|     			</div> |  | ||||||
|     		</div> |  | ||||||
|     	</div> |  | ||||||
|     </div> |  | ||||||
|      |  | ||||||
|     <div class="row"> |  | ||||||
|         <div class="col-md-8 col-md-offset-2"> |  | ||||||
|             <h3><b>Order summary</b></h3> |  | ||||||
|             <hr> |  | ||||||
|             <div class="content"> |  | ||||||
|                 <p><b>Type</b> <span class="pull-right">{{request.session.vm_specs.hosting_company_name}}</span></p> |  | ||||||
|                 <hr> |  | ||||||
|                 <p><b>Cores</b> <span class="pull-right">{{request.session.vm_specs.cores}}</span></p> |  | ||||||
|                 <hr> |  | ||||||
|                 <p><b>Memory</b> <span class="pull-right">{{request.session.vm_specs.memory}} GiB</span></p> |  | ||||||
|                 <hr> |  | ||||||
|                 <p><b>Disk space</b> <span class="pull-right">{{request.session.vm_specs.disk_size}} GiB</span></p> |  | ||||||
|                 <hr> |  | ||||||
|                 <h4>Total<p class="pull-right"><b>{{request.session.vm_specs.final_price}} CHF</b></p></h4> |  | ||||||
|             </div> |  | ||||||
|         </div> |  | ||||||
|     </div> |  | ||||||
| </div> |  | ||||||
| {%endblock%} |  | ||||||
							
								
								
									
										64
									
								
								hosting/templates/hosting/order_detail.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								hosting/templates/hosting/order_detail.html
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,64 @@ | ||||||
|  | {% extends "hosting/base_short.html" %} | ||||||
|  | {% load staticfiles bootstrap3 %} | ||||||
|  | {% block content %}  | ||||||
|  | 
 | ||||||
|  | <div class="container  order-detail-container"> | ||||||
|  |     <div class="row"> | ||||||
|  |         <div class="col-xs-8 col-xs-offset-2"> | ||||||
|  |     		<div class="invoice-title"> | ||||||
|  |     			<h2>Invoice</h2><h3 class="pull-right">Order # {{object.id}}</h3> | ||||||
|  |     		</div> | ||||||
|  |     		<hr> | ||||||
|  |     		<div class="row"> | ||||||
|  |     			<div class="col-xs-6"> | ||||||
|  |     				<address> | ||||||
|  |                     <h3><b>Billed To:</b></h3> | ||||||
|  |     					{{user.name}}<br> | ||||||
|  |                         {{object.billing_address.street_address}},{{order.billing_address.postal_code}}<br> | ||||||
|  |                         {{object.billing_address.city}}, {{object.billing_address.country}}. | ||||||
|  |     				</address> | ||||||
|  |     			</div> | ||||||
|  |                 <div class="col-xs-6 text-right"> | ||||||
|  |                     <address> | ||||||
|  |                         <strong>Order Date:</strong><br> | ||||||
|  |                         {{object.created_at}}<br><br> | ||||||
|  |                         <strong>Status:</strong><br> | ||||||
|  |                         <strong class="{% if object.status == 'Approved' %}text-success | ||||||
|  |                                        {%else%} text-danger | ||||||
|  |                                        {% endif %}">{{object.status}}</strong> | ||||||
|  |                         <br><br> | ||||||
|  |                     </address> | ||||||
|  | 
 | ||||||
|  |                 </div> | ||||||
|  |     		</div> | ||||||
|  |     		<div class="row"> | ||||||
|  |     			<div class="col-xs-6"> | ||||||
|  |     				<address> | ||||||
|  |     					<strong>Payment Method:</strong><br> | ||||||
|  |     					{{object.cc_brand}} ending **** {{object.last4}}<br> | ||||||
|  |     					{{user.email}} | ||||||
|  |     				</address> | ||||||
|  |     			</div> | ||||||
|  |     		</div> | ||||||
|  |     	</div> | ||||||
|  |     </div> | ||||||
|  |      | ||||||
|  |     <div class="row"> | ||||||
|  |         <div class="col-md-8 col-md-offset-2"> | ||||||
|  |             <h3><b>Order summary</b></h3> | ||||||
|  |             <hr> | ||||||
|  |             <div class="content"> | ||||||
|  |                 <p><b>Type</b> <span class="pull-right">{{object.VMPlan.hosting_company_name}}</span></p> | ||||||
|  |                 <hr> | ||||||
|  |                 <p><b>Cores</b> <span class="pull-right">{{object.VMPlan.cores}}</span></p> | ||||||
|  |                 <hr> | ||||||
|  |                 <p><b>Memory</b> <span class="pull-right">{{object.VMPlan.memory}} GiB</span></p> | ||||||
|  |                 <hr> | ||||||
|  |                 <p><b>Disk space</b> <span class="pull-right">{{object.VMPlan.disk_size}} GiB</span></p> | ||||||
|  |                 <hr> | ||||||
|  |                 <h4>Total<p class="pull-right"><b>{{object.VMPlan.price}} CHF</b></p></h4> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  | </div> | ||||||
|  | {%endblock%} | ||||||
|  | @ -1,31 +1,59 @@ | ||||||
| {% extends "hosting/base_short.html" %} | {% extends "hosting/base_short.html" %} | ||||||
| {% load staticfiles bootstrap3 %} | {% load staticfiles bootstrap3 %} | ||||||
| {% block content %}  | {% block content %}  | ||||||
|  | 
 | ||||||
| <div> | <div> | ||||||
| 	<div class="container payment-container"> | 	<div class="container orders-container"> | ||||||
| 		<div class="row"> | 		<div class="row"> | ||||||
| 			<div class="col-md-8 col-md-offset-2"> | 			<div class="col-md-8 col-md-offset-2"> | ||||||
| 				<table class="table">  | 				<table class="table borderless table-hover">  | ||||||
| 				<caption>My orders.</caption>  | 				<h3><i class="fa fa-credit-card"></i> My Orders</h3>  | ||||||
|  | 				<br/> | ||||||
| 				<thead>  | 				<thead>  | ||||||
| 				<tr>  | 				<tr>  | ||||||
| 					<th>#</th> | 					<th>#</th> | ||||||
| 					<th>Date</th> | 					<th>Date</th> | ||||||
| 					<th>Amount</th> | 					<th>Amount</th> | ||||||
| 					<th>Status</th> | 					<th>Status</th> | ||||||
|  | 					<th></th> | ||||||
| 				</tr>  | 				</tr>  | ||||||
| 				</thead>  | 				</thead>  | ||||||
| 				<tbody>  | 				<tbody>  | ||||||
| 					{% for order in orders %} | 					{% for order in orders %} | ||||||
| 					<tr>  | 					<tr>  | ||||||
| 						<th scope="row">{{order.id}}</th>  | 						<td scope="row">{{order.id}}</td>  | ||||||
| 						<td>{{order.created_at}}</td>  | 						<td>{{order.created_at}}</td>  | ||||||
| 						<td>{{order.VMPlan.price}}</td>  | 						<td>{{order.VMPlan.price}} CHF</td>  | ||||||
| 						<td>{{order.approved}}</td>  | 						<td>{% if order.approved %} | ||||||
|  | 								<span class="text-success strong">Approved</span> | ||||||
|  | 							{% else%}  | ||||||
|  | 								<span class="text-danger strong">Declined</span> | ||||||
|  | 							{% endif%} | ||||||
|  | 						</td>  | ||||||
|  | 						<td> | ||||||
|  | 							<button type="button" class="btn btn-default"><a href="{% url 'hosting:orders' order.id %}">View Detail</a></button> | ||||||
|  | 						</td> | ||||||
| 					</tr> | 					</tr> | ||||||
| 					{% endfor %} | 					{% endfor %} | ||||||
| 				</tbody>  | 				</tbody>  | ||||||
| 				</table> | 				</table> | ||||||
|  | 
 | ||||||
|  | 			    {% if is_paginated %} | ||||||
|  | 			        <div class="pagination"> | ||||||
|  | 			            <span class="page-links"> | ||||||
|  | 			                {% if page_obj.has_previous %} | ||||||
|  | 			                    <a href="{{request.path}}?page={{ page_obj.previous_page_number }}">previous</a> | ||||||
|  | 			                {% endif %} | ||||||
|  | 			                <span class="page-current"> | ||||||
|  | 			                    Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}. | ||||||
|  | 			                </span> | ||||||
|  | 			                {% if page_obj.has_next %} | ||||||
|  | 			                    <a href="{{request.path}}?page={{ page_obj.next_page_number }}">next</a> | ||||||
|  | 			                {% endif %} | ||||||
|  | 			            </span> | ||||||
|  | 			        </div> | ||||||
|  | 			    {% endif %} | ||||||
|  | 
 | ||||||
| 			</div> | 			</div> | ||||||
| 
 | 
 | ||||||
| 	    </div> | 	    </div> | ||||||
|  |  | ||||||
							
								
								
									
										155
									
								
								hosting/templates/hosting/virtual_machine_detail.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								hosting/templates/hosting/virtual_machine_detail.html
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,155 @@ | ||||||
|  | {% extends "hosting/base_short.html" %} | ||||||
|  | {% load staticfiles bootstrap3 %} | ||||||
|  | {% block content %}  | ||||||
|  | <div> | ||||||
|  | 	<div class="container virtual-machine-container dashboard-container "> | ||||||
|  | 		<div class="row"> | ||||||
|  | 			<div class="col-md-9 col-md-offset-2"> | ||||||
|  | 				 <div  class="col-sm-12"> | ||||||
|  | 				        <h3><i class="fa fa-cloud" aria-hidden="true"></i> {{virtual_machine.name}}</h3> | ||||||
|  | 				        <hr/> | ||||||
|  | 				        <div class="col-md-3"> <!-- required for floating --> | ||||||
|  | 				          <!-- Nav tabs --> | ||||||
|  | 				          <ul class="nav nav-tabs tabs-left sideways"> | ||||||
|  | 				            <li class="active"> | ||||||
|  | 				            	<a href="#settings-v" data-toggle="tab"> | ||||||
|  | 				            		<i class="fa fa-cogs" aria-hidden="true"></i> | ||||||
|  | 				            		Settings | ||||||
|  | 				            	</a> | ||||||
|  | 				            </li> | ||||||
|  | 				            <li> | ||||||
|  | 				            	<a href="#billing-v" data-toggle="tab"> | ||||||
|  | 				            		<i class="fa fa-money" aria-hidden="true"></i> | ||||||
|  | 				            		Billing | ||||||
|  | 				            	</a> | ||||||
|  | 				            </li> | ||||||
|  | 				            <li> | ||||||
|  | 				            	<a href="#orders-v" data-toggle="tab"> | ||||||
|  | 				            		<i class="fa fa-credit-card"></i>  | ||||||
|  | 				            		Orders | ||||||
|  | 				            	</a> | ||||||
|  | 				            </li> | ||||||
|  | 				            <li> | ||||||
|  | 				            	<a href="#status-v" data-toggle="tab"> | ||||||
|  | 				            		<i class="fa fa-signal" aria-hidden="true"></i> Status | ||||||
|  | 				            	</a> | ||||||
|  | 				            </li> | ||||||
|  | 				          </ul> | ||||||
|  | 				        </div> | ||||||
|  | 
 | ||||||
|  | 				        <div class="col-md-9"> | ||||||
|  | 				          <!-- Tab panes --> | ||||||
|  | 				          <div class="tab-content"> | ||||||
|  | 				            <div class="tab-pane active" id="settings-v"> | ||||||
|  | 				            	<div class="row"> | ||||||
|  | 									<div class="col-md-12"> | ||||||
|  | 									<h3>{{virtual_machine.hosting_company_name}}</h3> | ||||||
|  | 									<hr> | ||||||
|  | 									</div> | ||||||
|  | 				            	</div> | ||||||
|  | 								<div class="row"> | ||||||
|  | 								  <div class="col-md-12"> | ||||||
|  | 								    <div class="row"> | ||||||
|  | 								      <div class="col-md-3"> | ||||||
|  | 								        <div class="well text-center"> | ||||||
|  | 								        	<i class="fa fa-cubes" aria-hidden="true"></i> Cores <br/> | ||||||
|  | 								        	<span class="label label-success">{{virtual_machine.cores}}</span> | ||||||
|  | 								        </div> | ||||||
|  | 								      </div> | ||||||
|  | 								      <div class="col-md-3"> | ||||||
|  | 								        <div class="well text-center"> | ||||||
|  | 								        	<i class="fa fa-tachometer" aria-hidden="true"></i> Memory <br/> | ||||||
|  | 								        	<span class="label label-success">{{virtual_machine.memory}} GiB</span> | ||||||
|  | 								        </div> | ||||||
|  | 								      </div> | ||||||
|  | 								      <div class="col-md-3"> | ||||||
|  | 								        <div class="well text-center"> | ||||||
|  | 								        	<i class="fa fa-hdd-o" aria-hidden="true"></i> Disk <br/> | ||||||
|  | 								        	<span class="label label-success">{{virtual_machine.disk_size}} GiB</span> | ||||||
|  | 								        </div> | ||||||
|  | 								      </div> | ||||||
|  | 								    </div><!--/row-->     | ||||||
|  | 								  </div><!--/col-12--> | ||||||
|  | 								</div><!--/row--> | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 				            </div> | ||||||
|  | 				            <div class="tab-pane" id="billing-v"> | ||||||
|  | 
 | ||||||
|  | 				            	<div class="row "> | ||||||
|  | 									<div class="col-md-12 inline-headers"> | ||||||
|  | 										<h3>Current pricing</h3> | ||||||
|  | 										<span class="h3 pull-right"><strong>{{virtual_machine.price|floatformat}} CHF</strong>/mo</span>  | ||||||
|  | 										<hr> | ||||||
|  | 									</div> | ||||||
|  | 				            	</div> | ||||||
|  | 				            </div> | ||||||
|  | 				            <div class="tab-pane" id="orders-v"> | ||||||
|  | 								<div class="row"> | ||||||
|  | 								  <div class="col-md-12"> | ||||||
|  | 									<table class="table borderless table-hover">  | ||||||
|  | 										<h3>Orders</h3>  | ||||||
|  | 										<br/> | ||||||
|  | 										<thead>  | ||||||
|  | 										<tr>  | ||||||
|  | 											<th>#</th> | ||||||
|  | 											<th>Date</th> | ||||||
|  | 											<th>Amount</th> | ||||||
|  | 											<th>Status</th> | ||||||
|  | 											<th></th> | ||||||
|  | 										</tr>  | ||||||
|  | 										</thead>  | ||||||
|  | 										<tbody>  | ||||||
|  | 											{% for order in virtual_machine.hosting_orders.all %} | ||||||
|  | 											<tr>  | ||||||
|  | 												<td scope="row">{{order.id}}</td>  | ||||||
|  | 												<td>{{order.created_at}}</td>  | ||||||
|  | 												<td>{{order.VMPlan.price}} CHF</td>  | ||||||
|  | 												<td>{% if order.approved %} | ||||||
|  | 														<span class="text-success strong">Approved</span> | ||||||
|  | 													{% else%}  | ||||||
|  | 														<span class="text-danger strong">Declined</span> | ||||||
|  | 													{% endif%} | ||||||
|  | 												</td>  | ||||||
|  | 												<td> | ||||||
|  | 													<button type="button" class="btn btn-default"><a href="{% url 'hosting:orders' order.id %}">View Detail</a></button> | ||||||
|  | 												</td> | ||||||
|  | 											</tr> | ||||||
|  | 											{% endfor %} | ||||||
|  | 										</tbody>  | ||||||
|  | 									</table> | ||||||
|  | 								  </div><!--/col-12--> | ||||||
|  | 								</div><!--/row--> | ||||||
|  | 				            </div> | ||||||
|  | 				            <div class="tab-pane" id="status-v"> | ||||||
|  | 
 | ||||||
|  | 				            	<div class="row "> | ||||||
|  | 									<div class="col-md-12 inline-headers"> | ||||||
|  | 										<h3>Current status</h3> | ||||||
|  | 										<span class="h3 pull-right label label-success"><strong>Online</strong></span>  | ||||||
|  | 										<hr> | ||||||
|  | 									</div> | ||||||
|  | 				            	</div> | ||||||
|  | 				            </div> | ||||||
|  | 				          </div> | ||||||
|  | 				        </div> | ||||||
|  | 
 | ||||||
|  | 				        <div class="clearfix"></div> | ||||||
|  | 				</div> | ||||||
|  | 			</div> | ||||||
|  | 
 | ||||||
|  | 	    </div> | ||||||
|  | 	</div> | ||||||
|  | 
 | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | {%endblock%} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
							
								
								
									
										56
									
								
								hosting/templates/hosting/virtual_machines.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								hosting/templates/hosting/virtual_machines.html
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,56 @@ | ||||||
|  | {% extends "hosting/base_short.html" %} | ||||||
|  | {% load staticfiles bootstrap3 %} | ||||||
|  | {% block content %}  | ||||||
|  | <div> | ||||||
|  | 	<div class="container dashboard-container"> | ||||||
|  | 		<div class="row"> | ||||||
|  | 			<div class="col-md-8 col-md-offset-2"> | ||||||
|  | 				<table class="table borderless table-hover">  | ||||||
|  | 				<h3><i class="fa fa-server" aria-hidden="true"></i> Virtual Machines</h3>  | ||||||
|  | 				<br/> | ||||||
|  | 				<thead>  | ||||||
|  | 				<tr>  | ||||||
|  | 					<th>ID</th> | ||||||
|  | 					<th>Type</th> | ||||||
|  | 					<th>Amount</th> | ||||||
|  | 					<th></th> | ||||||
|  | 				</tr> | ||||||
|  | 				</thead> | ||||||
|  | 				<tbody>  | ||||||
|  | 					{% for vm in vms %} | ||||||
|  | 					<tr>  | ||||||
|  | 						<td scope="row">{{vm.name}}</td>  | ||||||
|  | 						<td>{{vm.hosting_company_name}}</td>  | ||||||
|  | 						<td>{{vm.price}} CHF</td>  | ||||||
|  | 						<td> | ||||||
|  | 							<button type="button" class="btn btn-default"><a href="{% url 'hosting:virtual_machines' vm.id %}">View Detail</a></button> | ||||||
|  | 						</td> | ||||||
|  | 					</tr> | ||||||
|  | 					{% endfor %} | ||||||
|  | 				</tbody>  | ||||||
|  | 				</table> | ||||||
|  | 
 | ||||||
|  | 			    {% if is_paginated %} | ||||||
|  | 			        <div class="pagination"> | ||||||
|  | 			            <span class="page-links"> | ||||||
|  | 			                {% if page_obj.has_previous %} | ||||||
|  | 			                    <a href="{{request.path}}?page={{ page_obj.previous_page_number }}">previous</a> | ||||||
|  | 			                {% endif %} | ||||||
|  | 			                <span class="page-current"> | ||||||
|  | 			                    Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}. | ||||||
|  | 			                </span> | ||||||
|  | 			                {% if page_obj.has_next %} | ||||||
|  | 			                    <a href="{{request.path}}?page={{ page_obj.next_page_number }}">next</a> | ||||||
|  | 			                {% endif %} | ||||||
|  | 			            </span> | ||||||
|  | 			        </div> | ||||||
|  | 			    {% endif %} | ||||||
|  | 				 | ||||||
|  | 			</div> | ||||||
|  | 
 | ||||||
|  | 	    </div> | ||||||
|  | 	</div> | ||||||
|  | 
 | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | {%endblock%} | ||||||
							
								
								
									
										72
									
								
								hosting/test_views.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								hosting/test_views.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,72 @@ | ||||||
|  | from django.test import TestCase | ||||||
|  | from django.core.urlresolvers import reverse | ||||||
|  | from django.core.urlresolvers import resolve | ||||||
|  | from .models import VirtualMachineType | ||||||
|  | from .views import DjangoHostingView, RailsHostingView, NodeJSHostingView | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class ProcessVMSelectionTestMixin(object): | ||||||
|  | 
 | ||||||
|  |     def url_resolve_to_view_correctly(self): | ||||||
|  |         found = resolve(self.url) | ||||||
|  |         self.assertEqual(found.func.__name__, self.view.__name__) | ||||||
|  | 
 | ||||||
|  |     def test_get(self): | ||||||
|  |         response = self.client.get(self.url) | ||||||
|  |         self.assertEqual(response.status_code, 200) | ||||||
|  |         self.assertEqual(self.view.get_context_data(), self.expected_context) | ||||||
|  |         self.assertEqual(response.context['hosting'], self.expected_context['hosting']) | ||||||
|  |         self.assertTemplateUsed(response, self.expected_template) | ||||||
|  | 
 | ||||||
|  |     def test_anonymous_post(self): | ||||||
|  |         response = self.client.post(self.url) | ||||||
|  |         self.assertRedirects(response, expected_url=reverse('hosting:login'), | ||||||
|  |                              status_code=302, target_status_code=200) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class DjangoHostingViewTest(TestCase, ProcessVMSelectionTestMixin): | ||||||
|  | 
 | ||||||
|  |     def setUp(self): | ||||||
|  |         self.url = reverse('django.hosting') | ||||||
|  |         self.view = DjangoHostingView() | ||||||
|  |         self.expected_template = 'hosting/django.html' | ||||||
|  |         self.expected_context = { | ||||||
|  |             'hosting': "django", | ||||||
|  |             'hosting_long': "Django", | ||||||
|  |             'domain': "django-hosting.ch", | ||||||
|  |             'google_analytics': "UA-62285904-6", | ||||||
|  |             'email': "info@django-hosting.ch", | ||||||
|  |             'vm_types': VirtualMachineType.get_serialized_vm_types(), | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class RailsHostingViewTest(TestCase, ProcessVMSelectionTestMixin): | ||||||
|  | 
 | ||||||
|  |     def setUp(self): | ||||||
|  |         self.url = reverse('rails.hosting') | ||||||
|  |         self.view = RailsHostingView() | ||||||
|  |         self.expected_template = 'hosting/rails.html' | ||||||
|  |         self.expected_context = { | ||||||
|  |             'hosting': "rails", | ||||||
|  |             'hosting_long': "Ruby On Rails", | ||||||
|  |             'domain': "rails-hosting.ch", | ||||||
|  |             'google_analytics': "UA-62285904-5", | ||||||
|  |             'email': "info@rails-hosting.ch", | ||||||
|  |             'vm_types': VirtualMachineType.get_serialized_vm_types(), | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class NodeJSHostingViewTest(TestCase, ProcessVMSelectionTestMixin): | ||||||
|  | 
 | ||||||
|  |     def setUp(self): | ||||||
|  |         self.url = reverse('node.hosting') | ||||||
|  |         self.view = NodeJSHostingView() | ||||||
|  |         self.expected_template = 'hosting/nodejs.html' | ||||||
|  |         self.expected_context = { | ||||||
|  |             'hosting': "nodejs", | ||||||
|  |             'hosting_long': "NodeJS", | ||||||
|  |             'domain': "node-hosting.ch", | ||||||
|  |             'google_analytics': "UA-62285904-7", | ||||||
|  |             'email': "info@node-hosting.ch", | ||||||
|  |             'vm_types': VirtualMachineType.get_serialized_vm_types(), | ||||||
|  |         } | ||||||
|  | @ -2,7 +2,8 @@ from django.conf.urls import url | ||||||
| 
 | 
 | ||||||
| from .views import DjangoHostingView, RailsHostingView, PaymentVMView, \ | from .views import DjangoHostingView, RailsHostingView, PaymentVMView, \ | ||||||
|     NodeJSHostingView, LoginView, SignupView, IndexView, \ |     NodeJSHostingView, LoginView, SignupView, IndexView, \ | ||||||
|                     InvoiceVMView, OrdersHostingView |     OrdersHostingListView, OrdersHostingDetailView, VirtualMachinesPlanListView,\ | ||||||
|  |     VirtualMachineDetailListView | ||||||
| 
 | 
 | ||||||
| urlpatterns = [ | urlpatterns = [ | ||||||
|     # url(r'pricing/?$', VMPricingView.as_view(), name='pricing'), |     # url(r'pricing/?$', VMPricingView.as_view(), name='pricing'), | ||||||
|  | @ -11,8 +12,11 @@ urlpatterns = [ | ||||||
|     url(r'nodejs/?$', NodeJSHostingView.as_view(), name='nodejshosting'), |     url(r'nodejs/?$', NodeJSHostingView.as_view(), name='nodejshosting'), | ||||||
|     url(r'rails/?$', RailsHostingView.as_view(), name='railshosting'), |     url(r'rails/?$', RailsHostingView.as_view(), name='railshosting'), | ||||||
|     url(r'payment/?$', PaymentVMView.as_view(), name='payment'), |     url(r'payment/?$', PaymentVMView.as_view(), name='payment'), | ||||||
|     url(r'invoice/?$', InvoiceVMView.as_view(), name='invoice'), |     url(r'orders/?$', OrdersHostingListView.as_view(), name='orders'), | ||||||
|     url(r'orders/?$', OrdersHostingView.as_view(), name='orders'), |     url(r'orders/(?P<pk>\d+)/?$', OrdersHostingDetailView.as_view(), name='orders'), | ||||||
|  |     url(r'my-virtual-machines/?$', VirtualMachinesPlanListView.as_view(), name='virtual_machines'), | ||||||
|  |     url(r'my-virtual-machines/(?P<pk>\d+)/?$', VirtualMachineDetailListView.as_view(), | ||||||
|  |         name='virtual_machines'), | ||||||
|     url(r'login/?$', LoginView.as_view(), name='login'), |     url(r'login/?$', LoginView.as_view(), name='login'), | ||||||
|     url(r'signup/?$', SignupView.as_view(), name='signup'), |     url(r'signup/?$', SignupView.as_view(), name='signup'), | ||||||
|     url(r'^logout/?$', 'django.contrib.auth.views.logout', |     url(r'^logout/?$', 'django.contrib.auth.views.logout', | ||||||
|  |  | ||||||
|  | @ -2,16 +2,12 @@ | ||||||
| from django.shortcuts import get_object_or_404, render | from django.shortcuts import get_object_or_404, render | ||||||
| from django.core.urlresolvers import reverse_lazy, reverse | from django.core.urlresolvers import reverse_lazy, reverse | ||||||
| from django.contrib.auth.mixins import LoginRequiredMixin | from django.contrib.auth.mixins import LoginRequiredMixin | ||||||
| from django.contrib.auth.decorators import login_required |  | ||||||
| from django.utils.decorators import method_decorator |  | ||||||
| 
 | 
 | ||||||
| from django.views.generic import View, CreateView, FormView | from django.views.generic import View, CreateView, FormView, ListView, DetailView | ||||||
| from django.shortcuts import redirect |  | ||||||
| from django.http import HttpResponseRedirect | from django.http import HttpResponseRedirect | ||||||
| from django.contrib.auth import authenticate, login | from django.contrib.auth import authenticate, login | ||||||
| from django.conf import settings | from django.conf import settings | ||||||
| 
 | 
 | ||||||
| from membership.forms import PaymentForm |  | ||||||
| from membership.models import CustomUser, StripeCustomer | from membership.models import CustomUser, StripeCustomer | ||||||
| from utils.stripe_utils import StripeUtils | from utils.stripe_utils import StripeUtils | ||||||
| from utils.forms import BillingAddressForm | from utils.forms import BillingAddressForm | ||||||
|  | @ -21,7 +17,6 @@ from .forms import HostingUserSignupForm, HostingUserLoginForm | ||||||
| from .mixins import ProcessVMSelectionMixin | from .mixins import ProcessVMSelectionMixin | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| class DjangoHostingView(ProcessVMSelectionMixin, View): | class DjangoHostingView(ProcessVMSelectionMixin, View): | ||||||
|     template_name = "hosting/django.html" |     template_name = "hosting/django.html" | ||||||
| 
 | 
 | ||||||
|  | @ -106,7 +101,7 @@ class IndexView(View): | ||||||
| 
 | 
 | ||||||
| class LoginView(FormView): | class LoginView(FormView): | ||||||
|     template_name = 'hosting/login.html' |     template_name = 'hosting/login.html' | ||||||
|     success_url = reverse_lazy('hosting:login') |     success_url = reverse_lazy('hosting:orders') | ||||||
|     form_class = HostingUserLoginForm |     form_class = HostingUserLoginForm | ||||||
|     moodel = CustomUser |     moodel = CustomUser | ||||||
| 
 | 
 | ||||||
|  | @ -217,60 +212,45 @@ class PaymentVMView(FormView): | ||||||
|                 'order': order.id, |                 'order': order.id, | ||||||
|                 'billing_address': billing_address.id |                 'billing_address': billing_address.id | ||||||
|             }) |             }) | ||||||
|             return HttpResponseRedirect(reverse('hosting:invoice')) |             return HttpResponseRedirect(reverse('hosting:orders', kwargs={'pk': order.id})) | ||||||
|         else: |         else: | ||||||
|             return self.form_invalid(form) |             return self.form_invalid(form) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class InvoiceVMView(LoginRequiredMixin, View): | class OrdersHostingDetailView(LoginRequiredMixin, DetailView): | ||||||
|     template_name = "hosting/invoice.html" |     template_name = "hosting/order_detail.html" | ||||||
|     login_url = reverse_lazy('hosting:login') |     login_url = reverse_lazy('hosting:login') | ||||||
| 
 |     model = HostingOrder | ||||||
|     def get_context_data(self, **kwargs): |  | ||||||
|         charge = self.request.session.get('charge') |  | ||||||
|         order_id = self.request.session.get('order') |  | ||||||
|         billing_address_id = self.request.session.get('billing_address') |  | ||||||
|         last4 = charge.get('source').get('last4') |  | ||||||
|         brand = charge.get('source').get('brand') |  | ||||||
| 
 |  | ||||||
|         order = get_object_or_404(HostingOrder, pk=order_id) |  | ||||||
|         billing_address = get_object_or_404(BillingAddress, pk=billing_address_id) |  | ||||||
| 
 |  | ||||||
|         if not charge: |  | ||||||
|             return |  | ||||||
| 
 |  | ||||||
|         context = { |  | ||||||
|             'last4': last4, |  | ||||||
|             'brand': brand, |  | ||||||
|             'order': order, |  | ||||||
|             'billing_address': billing_address, |  | ||||||
|         } |  | ||||||
|         return context |  | ||||||
| 
 |  | ||||||
|     def get(self, request, *args, **kwargs): |  | ||||||
| 
 |  | ||||||
|         context = self.get_context_data() |  | ||||||
| 
 |  | ||||||
|         return render(request, self.template_name, context) |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class OrdersHostingView(LoginRequiredMixin, View): | class OrdersHostingListView(LoginRequiredMixin, ListView): | ||||||
|     template_name = "hosting/orders.html" |     template_name = "hosting/orders.html" | ||||||
|     login_url = reverse_lazy('hosting:login') |     login_url = reverse_lazy('hosting:login') | ||||||
|  |     context_object_name = "orders" | ||||||
|  |     model = HostingOrder | ||||||
|  |     paginate_by = 10 | ||||||
| 
 | 
 | ||||||
|     def get_context_data(self, **kwargs): |     def get_queryset(self): | ||||||
|         user = self.request.user |         user = self.request.user | ||||||
|         orders = HostingOrder.objects.filter(customer__user=user) |         self.queryset = HostingOrder.objects.filter(customer__user=user) | ||||||
|         context = { |         return super(OrdersHostingListView, self).get_queryset() | ||||||
|             'orders':orders |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return context |  | ||||||
| 
 |  | ||||||
|     def get(self, request, *args, **kwargs): |  | ||||||
| 
 |  | ||||||
|         context = self.get_context_data() |  | ||||||
| 
 |  | ||||||
|         return render(request, self.template_name, context) |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | class VirtualMachinesPlanListView(LoginRequiredMixin, ListView): | ||||||
|  |     template_name = "hosting/virtual_machines.html" | ||||||
|  |     login_url = reverse_lazy('hosting:login') | ||||||
|  |     context_object_name = "vms" | ||||||
|  |     model = VirtualMachinePlan | ||||||
|  |     paginate_by = 10 | ||||||
|  | 
 | ||||||
|  |     def get_queryset(self): | ||||||
|  |         user = self.request.user | ||||||
|  |         self.queryset = VirtualMachinePlan.objects.active(user) | ||||||
|  |         return super(VirtualMachinesPlanListView, self).get_queryset() | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class VirtualMachineDetailListView(LoginRequiredMixin, DetailView): | ||||||
|  |     template_name = "hosting/virtual_machine_detail.html" | ||||||
|  |     login_url = reverse_lazy('hosting:login') | ||||||
|  |     model = VirtualMachinePlan | ||||||
|  |     context_object_name = "virtual_machine" | ||||||
|  |  | ||||||
|  | @ -131,7 +131,7 @@ class StripeCustomer(models.Model): | ||||||
|             Check if there is a registered stripe customer with that email |             Check if there is a registered stripe customer with that email | ||||||
|             or create a new one |             or create a new one | ||||||
|         """ |         """ | ||||||
| 
 |         stripe_customer = None | ||||||
|         try: |         try: | ||||||
|             stripe_utils = StripeUtils() |             stripe_utils = StripeUtils() | ||||||
|             stripe_customer = cls.objects.get(user__email=email) |             stripe_customer = cls.objects.get(user__email=email) | ||||||
|  |  | ||||||
|  | @ -52,8 +52,6 @@ def handleStripeError(f): | ||||||
|     return handleProblems |     return handleProblems | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class StripeUtils(object): | class StripeUtils(object): | ||||||
|     CURRENCY = 'chf' |     CURRENCY = 'chf' | ||||||
|     INTERVAL = 'month' |     INTERVAL = 'month' | ||||||
|  | @ -71,7 +69,7 @@ class StripeUtils(object): | ||||||
|                 customer = stripe.Customer.retrieve(id) |                 customer = stripe.Customer.retrieve(id) | ||||||
|             except stripe.InvalidRequestError: |             except stripe.InvalidRequestError: | ||||||
|                 customer = self.create_customer(token, user.email) |                 customer = self.create_customer(token, user.email) | ||||||
|                 user.stripecustomer.stripe_id = customer.get('id') |                 user.stripecustomer.stripe_id = customer.get('response_object').get('id') | ||||||
|                 user.stripecustomer.save() |                 user.stripecustomer.save() | ||||||
|         return customer |         return customer | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue