Added View to render payment page, Added Payment and summary forms, Added Payment.js library to request stripe token , Added jQuery validator for handling payment form errors
This commit is contained in:
		
					parent
					
						
							
								4e23adcea6
							
						
					
				
			
			
				commit
				
					
						38801abed7
					
				
			
		
					 13 changed files with 480 additions and 71 deletions
				
			
		|  | @ -30,6 +30,7 @@ dotenv.read_dotenv("{0}/.env".format(PROJECT_DIR)) | ||||||
| SITE_ID = 1 | SITE_ID = 1 | ||||||
| 
 | 
 | ||||||
| APP_ROOT_ENDPOINT = "/" | APP_ROOT_ENDPOINT = "/" | ||||||
|  | APPEND_SLASH=True | ||||||
| 
 | 
 | ||||||
| LOGIN_URL = None | LOGIN_URL = None | ||||||
| LOGOUT_URL = None | LOGOUT_URL = None | ||||||
|  |  | ||||||
							
								
								
									
										20
									
								
								hosting/mixins.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								hosting/mixins.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,20 @@ | ||||||
|  | from django.shortcuts import redirect | ||||||
|  | from django.core.urlresolvers import reverse | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class ProcessVMSelectionMixin(object): | ||||||
|  | 
 | ||||||
|  |     def post(self, request, *args, **kwargs): | ||||||
|  |         vm_specs = { | ||||||
|  |             'cores': request.POST.get('cores'), | ||||||
|  |             'memory': request.POST.get('memory'), | ||||||
|  |             'disk_size': request.POST.get('disk_space'), | ||||||
|  |             'hosting_company': request.POST.get('hosting_company'), | ||||||
|  |             'hosting_company_name': request.POST.get('hosting_company_name'), | ||||||
|  |             'final_price': request.POST.get('final_price') | ||||||
|  |         } | ||||||
|  |         request.session['vm_specs'] = vm_specs | ||||||
|  |         if not request.user.is_authenticated(): | ||||||
|  |             request.session['vm_specs'] = vm_specs | ||||||
|  |             return redirect(reverse('hosting:login')) | ||||||
|  |         return redirect(reverse('hosting:payment')) | ||||||
|  | @ -31,8 +31,7 @@ h6 { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .intro-header { | .intro-header { | ||||||
|     height: 85%; |     padding-top: 50px; /* If you're making other pages, make sure there is 50px of padding to make sure the navbar doesn't overlap content! */ | ||||||
|     padding-top: 10%; /* If you're making other pages, make sure there is 50px of padding to make sure the navbar doesn't overlap content! */ |  | ||||||
|     padding-bottom: 50px; |     padding-bottom: 50px; | ||||||
|     text-align: center; |     text-align: center; | ||||||
|     color: #f8f8f8; |     color: #f8f8f8; | ||||||
|  | @ -48,8 +47,7 @@ h6 { | ||||||
|     background-size: cover; |     background-size: cover; | ||||||
| } | } | ||||||
| .intro-header-2 { | .intro-header-2 { | ||||||
|     height: 85%; |     padding-top: 50px; /* If you're making other pages, make sure there is 50px of padding to make sure the navbar doesn't overlap content! */ | ||||||
|     padding-top: 100px; /* If you're making other pages, make sure there is 50px of padding to make sure the navbar doesn't overlap content! */ |  | ||||||
|     padding-bottom: 50px; |     padding-bottom: 50px; | ||||||
|     text-align: center; |     text-align: center; | ||||||
|     color: #f8f8f8; |     color: #f8f8f8; | ||||||
|  |  | ||||||
							
								
								
									
										33
									
								
								hosting/static/hosting/css/payment.css
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								hosting/static/hosting/css/payment.css
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,33 @@ | ||||||
|  | .creditcard-box {padding-top:17%; padding-bottom: 11%;} | ||||||
|  | .creditcard-box .panel-title {display: inline;font-weight: bold; font-size:17px;} | ||||||
|  | .creditcard-box .checkbox.pull-right { margin: 0; } | ||||||
|  | .creditcard-box .pl-ziro { padding-left: 0px; } | ||||||
|  | .creditcard-box .form-control.error { | ||||||
|  |     border-color: red; | ||||||
|  |     outline: 0; | ||||||
|  |     box-shadow: inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(255,0,0,0.6); | ||||||
|  | } | ||||||
|  | .creditcard-box label.error { | ||||||
|  |   font-weight: bold; | ||||||
|  |   color: red; | ||||||
|  |   padding: 2px 8px; | ||||||
|  |   margin-top: 2px; | ||||||
|  | } | ||||||
|  | .creditcard-box .payment-errors { | ||||||
|  |   font-weight: bold; | ||||||
|  |   color: red; | ||||||
|  |   padding: 2px 8px; | ||||||
|  |   margin-top: 2px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .summary-box { | ||||||
|  | 
 | ||||||
|  |   padding-top:17%; | ||||||
|  |   padding-bottom: 11%; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .summary-box .content { | ||||||
|  | 
 | ||||||
|  | 	padding-top: 15px; | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										110
									
								
								hosting/static/hosting/js/payment.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								hosting/static/hosting/js/payment.js
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,110 @@ | ||||||
|  | $( document ).ready(function() { | ||||||
|  | 
 | ||||||
|  |     var $form = $('#payment-form'); | ||||||
|  |     $form.submit(payWithStripe); | ||||||
|  | 
 | ||||||
|  |     /* If you're using Stripe for payments */ | ||||||
|  |     function payWithStripe(e) { | ||||||
|  |         e.preventDefault(); | ||||||
|  | 
 | ||||||
|  |         /* Visual feedback */ | ||||||
|  |         $form.find('[type=submit]').html('Validating <i class="fa fa-spinner fa-pulse"></i>'); | ||||||
|  | 
 | ||||||
|  |         var PublishableKey = 'pk_test_6pRNASCoBOKtIshFeQd4XMUh'; // Replace with your API publishable key
 | ||||||
|  |         Stripe.setPublishableKey(PublishableKey); | ||||||
|  |         Stripe.card.createToken($form, function stripeResponseHandler(status, response) { | ||||||
|  |             console.log | ||||||
|  |             if (response.error) { | ||||||
|  |                 /* Visual feedback */ | ||||||
|  |                 $form.find('[type=submit]').html('Try again'); | ||||||
|  |                 /* Show Stripe errors on the form */ | ||||||
|  |                 $form.find('.payment-errors').text(response.error.message); | ||||||
|  |                 $form.find('.payment-errors').closest('.row').show(); | ||||||
|  |             } else { | ||||||
|  |                 /* Visual feedback */ | ||||||
|  |                 $form.find('[type=submit]').html('Processing <i class="fa fa-spinner fa-pulse"></i>'); | ||||||
|  |                 /* Hide Stripe errors on the form */ | ||||||
|  |                 $form.find('.payment-errors').closest('.row').hide(); | ||||||
|  |                 $form.find('.payment-errors').text(""); | ||||||
|  |                 // response contains id and card, which contains additional card details
 | ||||||
|  |                 var token = response.id; | ||||||
|  |                 console.log(token); | ||||||
|  |                 // AJAX
 | ||||||
|  |                 $.post('/account/stripe_card_token', { | ||||||
|  |                         token: token | ||||||
|  |                     }) | ||||||
|  |                     // Assign handlers immediately after making the request,
 | ||||||
|  |                     .done(function(data, textStatus, jqXHR) { | ||||||
|  |                         $form.find('[type=submit]').html('Payment successful <i class="fa fa-check"></i>').prop('disabled', true); | ||||||
|  |                     }) | ||||||
|  |                     .fail(function(jqXHR, textStatus, errorThrown) { | ||||||
|  |                         $form.find('[type=submit]').html('There was a problem').removeClass('success').addClass('error'); | ||||||
|  |                         /* Show Stripe errors on the form */ | ||||||
|  |                         $form.find('.payment-errors').text('Try refreshing the page and trying again.'); | ||||||
|  |                         $form.find('.payment-errors').closest('.row').show(); | ||||||
|  |                     }); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* Form validation */ | ||||||
|  |     $.validator.addMethod("month", function(value, element) { | ||||||
|  |       return this.optional(element) || /^(01|02|03|04|05|06|07|08|09|10|11|12)$/.test(value); | ||||||
|  |     }, "Please specify a valid 2-digit month."); | ||||||
|  | 
 | ||||||
|  |     $.validator.addMethod("year", function(value, element) { | ||||||
|  |       return this.optional(element) || /^[0-9]{2}$/.test(value); | ||||||
|  |     }, "Please specify a valid 2-digit year."); | ||||||
|  | 
 | ||||||
|  |     validator = $form.validate({ | ||||||
|  |         rules: { | ||||||
|  |             cardNumber: { | ||||||
|  |                 required: true, | ||||||
|  |                 creditcard: true, | ||||||
|  |                 digits: true | ||||||
|  |             }, | ||||||
|  |             expMonth: { | ||||||
|  |                 required: true, | ||||||
|  |                 month: true | ||||||
|  |             }, | ||||||
|  |             expYear: { | ||||||
|  |                 required: true, | ||||||
|  |                 year: true | ||||||
|  |             }, | ||||||
|  |             cvCode: { | ||||||
|  |                 required: true, | ||||||
|  |                 digits: true | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         highlight: function(element) { | ||||||
|  |             $(element).closest('.form-control').removeClass('success').addClass('error'); | ||||||
|  |         }, | ||||||
|  |         unhighlight: function(element) { | ||||||
|  |             $(element).closest('.form-control').removeClass('error').addClass('success'); | ||||||
|  |         }, | ||||||
|  |         errorPlacement: function(error, element) { | ||||||
|  |             $(element).closest('.form-group').append(error); | ||||||
|  |         } | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     paymentFormReady = function() { | ||||||
|  |         if ($form.find('[name=cardNumber]').hasClass("success") && | ||||||
|  |             $form.find('[name=expMonth]').hasClass("success") && | ||||||
|  |             $form.find('[name=expYear]').hasClass("success") && | ||||||
|  |             $form.find('[name=cvCode]').val().length > 1) { | ||||||
|  |             return true; | ||||||
|  |         } else { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     $form.find('[type=submit]').prop('disabled', true); | ||||||
|  |     var readyInterval = setInterval(function() { | ||||||
|  |         if (paymentFormReady()) { | ||||||
|  |             $form.find('[type=submit]').prop('disabled', false); | ||||||
|  |             clearInterval(readyInterval); | ||||||
|  |         } | ||||||
|  |     }, 250); | ||||||
|  | 
 | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | @ -8,7 +8,7 @@ $( document ).ready(function() { | ||||||
| 	function calculate_price(vm_type){ | 	function calculate_price(vm_type){ | ||||||
| 
 | 
 | ||||||
| 		var ID_SELECTOR = "#"; | 		var ID_SELECTOR = "#"; | ||||||
| 		var CURRENCY = "$"; | 		var CURRENCY = "CHF"; | ||||||
| 		var final_price_selector = ID_SELECTOR.concat(vm_type.concat('-final-price')); | 		var final_price_selector = ID_SELECTOR.concat(vm_type.concat('-final-price')); | ||||||
| 		var core_selector = ID_SELECTOR.concat(vm_type.concat('-cores')); | 		var core_selector = ID_SELECTOR.concat(vm_type.concat('-cores')); | ||||||
| 		var memory_selector = ID_SELECTOR.concat(vm_type.concat('-memory')); | 		var memory_selector = ID_SELECTOR.concat(vm_type.concat('-memory')); | ||||||
|  |  | ||||||
							
								
								
									
										135
									
								
								hosting/templates/hosting/base_short.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								hosting/templates/hosting/base_short.html
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,135 @@ | ||||||
|  | {% load staticfiles bootstrap3%} | ||||||
|  | <!DOCTYPE html> | ||||||
|  | <html lang="en"> | ||||||
|  | 
 | ||||||
|  | <head> | ||||||
|  | 
 | ||||||
|  |     <meta charset="utf-8"> | ||||||
|  |     <meta http-equiv="X-UA-Compatible" content="IE=edge"> | ||||||
|  |     <meta name="viewport" content="width=device-width, initial-scale=1"> | ||||||
|  |     <meta name="description" content=""> | ||||||
|  |     <meta name="author" content=""> | ||||||
|  | 
 | ||||||
|  |     <title>Payment</title> | ||||||
|  | 
 | ||||||
|  |     <!-- Bootstrap Core CSS --> | ||||||
|  |     <link href="{% static 'hosting/css/bootstrap.min.css' %}" rel="stylesheet"> | ||||||
|  | 
 | ||||||
|  |     <!-- Custom CSS --> | ||||||
|  |     <link href="{% static 'hosting/css/landing-page.css' %}" rel="stylesheet"> | ||||||
|  |     <link href="{% static 'hosting/css/payment.css' %}" rel="stylesheet"> | ||||||
|  | 
 | ||||||
|  |     <!-- Custom Fonts --> | ||||||
|  |     <link href='http://fonts.googleapis.com/css?family=Raleway' rel='stylesheet' type='text/css'> | ||||||
|  |     <link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css"> | ||||||
|  |     <link href="http://fonts.googleapis.com/css?family=Lato:300,400,700,300italic,400italic,700italic" rel="stylesheet" type="text/css"> | ||||||
|  |     <link rel="shortcut icon" href="img/favicon.ico" type="image/x-icon" /> | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries --> | ||||||
|  |     <!-- WARNING: Respond.js doesn't work if you view the page via file:// --> | ||||||
|  |     <!--[if lt IE 9]> | ||||||
|  |         <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script> | ||||||
|  |         <script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script> | ||||||
|  |     <![endif]--> | ||||||
|  | 
 | ||||||
|  | </head> | ||||||
|  | 
 | ||||||
|  | <body> | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     <!-- Navigation --> | ||||||
|  |     <nav class="navbar navbar-default  navbar-fixed-top topnav" role="navigation"> | ||||||
|  |         <div class="container topnav"> | ||||||
|  |             <!-- Brand and toggle get grouped for better mobile display --> | ||||||
|  |             <div class="navbar-header"> | ||||||
|  |                 <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1"> | ||||||
|  |                     <span class="sr-only">Toggle navigation</span> | ||||||
|  |                     <span class="icon-bar"></span> | ||||||
|  |                     <span class="icon-bar"></span> | ||||||
|  |                     <span class="icon-bar"></span> | ||||||
|  |                 </button> | ||||||
|  |                 <a class="navbar-brand topnav" href="#"><img src="img/logo_black.svg"></a> | ||||||
|  |             </div> | ||||||
|  |             <!-- Collect the nav links, forms, and other content for toggling --> | ||||||
|  |             <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> | ||||||
|  |                 <ul class="nav navbar-nav navbar-right"> | ||||||
|  |                     <li> | ||||||
|  |                         <a href="#how">How it works</a> | ||||||
|  |                     </li> | ||||||
|  |                     <li> | ||||||
|  |                         <a href="#your">Your infrastructure</a> | ||||||
|  |                     </li> | ||||||
|  |                    <li> | ||||||
|  |                         <a href="#our">Our inftrastructure</a> | ||||||
|  |                     </li> | ||||||
|  |                     <li> | ||||||
|  |                         <a href="#price">Pricing</a> | ||||||
|  |                     </li> | ||||||
|  |                     <li> | ||||||
|  |                         <a href="#contact">Contact</a> | ||||||
|  |                     </li> | ||||||
|  |                 </ul> | ||||||
|  |             </div> | ||||||
|  |             <!-- /.navbar-collapse --> | ||||||
|  |         </div> | ||||||
|  |         <!-- /.container --> | ||||||
|  |     </nav> | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     <!-- Header --> | ||||||
|  |     <a name="about"></a> | ||||||
|  |     {% block content %} | ||||||
|  |     {% endblock %} | ||||||
|  | 
 | ||||||
|  |     <!-- Footer --> | ||||||
|  |     <footer> | ||||||
|  |         <div class="container"> | ||||||
|  |             <div class="row"> | ||||||
|  |                 <div class="col-lg-12"> | ||||||
|  |                     <ul class="list-inline"> | ||||||
|  |                         <li> | ||||||
|  |                             <a href="#">Home</a> | ||||||
|  |                         </li> | ||||||
|  |                         <li class="footer-menu-divider">⋅</li> | ||||||
|  |                         <li> | ||||||
|  |                             <a href="#about">How it works</a></li> | ||||||
|  |                         <li class="footer-menu-divider">⋅</li> | ||||||
|  |                         <li> | ||||||
|  |                             <a href="#about">Your infrastructure</a></li> | ||||||
|  |                         <li>⋅</li> | ||||||
|  |                         <li> | ||||||
|  |                             <a href="#about">Our infrastructure</a></li> | ||||||
|  |                         <li class="footer-menu-divider">⋅</li> | ||||||
|  |                         <li> | ||||||
|  |                             <a href="#services">Pricing</a> | ||||||
|  |                         </li> | ||||||
|  |                         <li class="footer-menu-divider">⋅</li> | ||||||
|  |                         <li> | ||||||
|  |                             <a href="#contact">Contact</a> | ||||||
|  |                         </li> | ||||||
|  |                     </ul> | ||||||
|  |                     <p class="copyright text-muted small">Copyright © ungleich GmbH {% now "Y" %}. All Rights Reserved</p> | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |     </footer> | ||||||
|  | 
 | ||||||
|  |     <!-- jQuery --> | ||||||
|  |     <script src="{% static 'hosting/js/jquery.js' %}"></script> | ||||||
|  |     <script type="text/javascript" src="http://cdn.jsdelivr.net/jquery.validation/1.13.1/jquery.validate.min.js"></script> | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     <!-- Bootstrap Core JavaScript --> | ||||||
|  |     <script src="{% static 'hosting/js/bootstrap.min.js' %}"></script> | ||||||
|  | 
 | ||||||
|  |     <!-- Stripe Lib --> | ||||||
|  |     <script type="text/javascript" src="https://js.stripe.com/v2/"></script> | ||||||
|  | 
 | ||||||
|  |     <!-- Proccess payment lib --> | ||||||
|  |     <script type="text/javascript" src="{% static 'hosting/js/payment.js' %}"></script> | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | </body> | ||||||
|  | 
 | ||||||
|  | </html> | ||||||
|  | @ -1,5 +1,4 @@ | ||||||
| {% load staticfiles %} | {% load staticfiles %} | ||||||
| 
 |  | ||||||
| <a name="about"></a> | <a name="about"></a> | ||||||
| <div class="intro-header"> | <div class="intro-header"> | ||||||
|     <div class="container"> |     <div class="container"> | ||||||
|  |  | ||||||
|  | @ -80,7 +80,10 @@ | ||||||
|           {% endfor %} |           {% endfor %} | ||||||
|           {% for vm in vm_types %} |           {% for vm in vm_types %} | ||||||
|             <div class="col-xs-12 col-sm-6 col-md-3"> |             <div class="col-xs-12 col-sm-6 col-md-3"> | ||||||
|               <form class="form-inline"> |               <form class="form-inline" method="POST" action="{{request.path}}"> | ||||||
|  |                 {% csrf_token %} | ||||||
|  |                 <input type="hidden" name="hosting_company" value="{{vm.hosting_company}}"> | ||||||
|  |                 <input type="hidden" name="hosting_company_name" value="{{vm.hosting_company_name}}"> | ||||||
|                 <ul class="pricing {% cycle 'p-green' 'p-yel' 'p-red' 'p-blue' %}"> |                 <ul class="pricing {% cycle 'p-green' 'p-yel' 'p-red' 'p-blue' %}"> | ||||||
|                   <li style="height:200px;"> |                   <li style="height:200px;"> | ||||||
|                     <!-- <img src="http://bread.pp.ua/n/settings_g.svg" alt=""> --> |                     <!-- <img src="http://bread.pp.ua/n/settings_g.svg" alt=""> --> | ||||||
|  | @ -91,7 +94,7 @@ | ||||||
|                     <div class="btn-group"> |                     <div class="btn-group"> | ||||||
|                       <div class="form-group"> |                       <div class="form-group"> | ||||||
|                         <label for="cores">Cores: </label> |                         <label for="cores">Cores: </label> | ||||||
|                         <select class="form-control cores-selector" id="{{vm.hosting_company}}-cores" data-vm-type="{{vm.hosting_company}}"> |                         <select class="form-control cores-selector" name="cores" id="{{vm.hosting_company}}-cores" data-vm-type="{{vm.hosting_company}}"> | ||||||
|                         {% with ''|center:10 as range %} |                         {% with ''|center:10 as range %} | ||||||
|                         {% for _ in range %} |                         {% for _ in range %} | ||||||
|                             <option>{{ forloop.counter }}</option> |                             <option>{{ forloop.counter }}</option> | ||||||
|  | @ -106,7 +109,7 @@ | ||||||
|                     <div class="btn-group"> |                     <div class="btn-group"> | ||||||
|                       <div class="form-group"> |                       <div class="form-group"> | ||||||
|                         <label for="memory">Memory: </label> |                         <label for="memory">Memory: </label> | ||||||
|                         <select class="form-control memory-selector" id="{{vm.hosting_company}}-memory" data-vm-type="{{vm.hosting_company}}"> |                         <select class="form-control memory-selector" name="memory" id="{{vm.hosting_company}}-memory" data-vm-type="{{vm.hosting_company}}"> | ||||||
|                         {% with ''|center:50 as range %} |                         {% with ''|center:50 as range %} | ||||||
|                         {% for _ in range %} |                         {% for _ in range %} | ||||||
|                             <option>{{ forloop.counter }}</option> |                             <option>{{ forloop.counter }}</option> | ||||||
|  | @ -120,12 +123,13 @@ | ||||||
|                   <li class="row"> |                   <li class="row"> | ||||||
|                     <div class="form-group"> |                     <div class="form-group"> | ||||||
|                       <label for="Disk Size">Disk Size: </label> |                       <label for="Disk Size">Disk Size: </label> | ||||||
|                       <input class="form-control short-input disk-space-selector" type="number" id="{{vm.hosting_company}}-disk_space" min="10" value="10" data-vm-type="{{vm.hosting_company}}"/> |                       <input class="form-control short-input disk-space-selector" name="disk_space" type="number" id="{{vm.hosting_company}}-disk_space" min="10" value="10" data-vm-type="{{vm.hosting_company}}"/> | ||||||
|                       <span>GiB</span> |                       <span>GiB</span> | ||||||
|                     </div> |                     </div> | ||||||
|                   </li> |                   </li> | ||||||
|                   <li> |                   <li> | ||||||
|                     <h3 id="{{vm.hosting_company}}-final-price">{{vm.default_price|floatformat}}$</h3> |                     <input id="{{vm.hosting_company}}-final-price" type="hidden" name="final_price" value="{{vm.default_price|floatformat}}"> | ||||||
|  |                     <h3 id="{{vm.hosting_company}}-final-price">{{vm.default_price|floatformat}}CHF</h3> | ||||||
|                     <span>per month</span> |                     <span>per month</span> | ||||||
|                   </li> |                   </li> | ||||||
|                   <li> |                   <li> | ||||||
|  |  | ||||||
|  | @ -36,7 +36,7 @@ | ||||||
| <body> | <body> | ||||||
| 
 | 
 | ||||||
|     <!-- Navigation --> |     <!-- Navigation --> | ||||||
|     <nav class="navbar navbar-default navbar-fixed-top topnav" role="navigation"> |     <nav class="navbar navbar-default  topnav" role="navigation"> | ||||||
|         <div class="container topnav"> |         <div class="container topnav"> | ||||||
|             <!-- Brand and toggle get grouped for better mobile display --> |             <!-- Brand and toggle get grouped for better mobile display --> | ||||||
|             <div class="navbar-header"> |             <div class="navbar-header"> | ||||||
|  | @ -78,25 +78,25 @@ | ||||||
|     <a name="about"></a> |     <a name="about"></a> | ||||||
|     <div class="intro-header"> |     <div class="intro-header"> | ||||||
|         <div class="container"> |         <div class="container"> | ||||||
|             <div class="col-md-4"> </div><div class="col-md-4"> |                 <div class="col-md-4 col-md-offset-4"> | ||||||
|               <div class="intro-message"> |                     <div class="intro-message"> | ||||||
|                 <h2>Login</h2> |                         <h2>Login</h2> | ||||||
|                 <form action="{% url 'hosting:login' %}" method="post" class="form" novalidate> |                         <form action="{% url 'hosting:login' %}" method="post" class="form" novalidate> | ||||||
|                     {% csrf_token %} |                             {% csrf_token %} | ||||||
|                     {% for field in form %} |                             {% for field in form %} | ||||||
|                         {% bootstrap_field field show_label=False type='fields'%} |                                 {% bootstrap_field field show_label=False type='fields'%} | ||||||
|                     {% endfor %} |                             {% endfor %} | ||||||
|                     {% bootstrap_form_errors form type='non_fields'%} |                             {% bootstrap_form_errors form type='non_fields'%} | ||||||
|                     {% buttons %} |                             {% buttons %} | ||||||
|                         <button type="submit" class="btn btn-default"> |                                 <button type="submit" class="btn btn-default"> | ||||||
|                             Login |                                     Login | ||||||
|                         </button> |                                 </button> | ||||||
|                     {% endbuttons %} |                             {% endbuttons %} | ||||||
|                 </form> |                         </form> | ||||||
|                 <ul class="list-inline intro-social-buttons"> |                         <ul class="list-inline intro-social-buttons"> | ||||||
|                              |                              | ||||||
|                 </ul> |                         </ul> | ||||||
|               </div> |                     </div> | ||||||
|             </div> |             </div> | ||||||
|         </div> |         </div> | ||||||
|         <!-- /.container --> |         <!-- /.container --> | ||||||
|  |  | ||||||
							
								
								
									
										90
									
								
								hosting/templates/hosting/payment.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								hosting/templates/hosting/payment.html
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,90 @@ | ||||||
|  | {% extends "hosting/base_short.html" %} | ||||||
|  | {% load staticfiles bootstrap3 %} | ||||||
|  | {%block content %}  | ||||||
|  | <!-- Credit card form --> | ||||||
|  | <div> | ||||||
|  | 	<div class="container"> | ||||||
|  | 	    <div class="row"> | ||||||
|  | 	        <div class="col-xs-12 col-md-4 col-md-offset-2 creditcard-box"> | ||||||
|  | 				<h3><b>Payment Details</b></h3> | ||||||
|  | 				<hr> | ||||||
|  | 	            <div> | ||||||
|  | 	                <div class="panel-body"> | ||||||
|  | 	                    <form role="form" id="payment-form" novalidate> | ||||||
|  | 	                        <div class="row"> | ||||||
|  | 	                            <div class="col-xs-12"> | ||||||
|  | 	                                <div class="form-group"> | ||||||
|  | 	                                    <label class="control-label" for="cardNumber">CARD NUMBER</label> | ||||||
|  | 	                                    <div class="input-group"> | ||||||
|  | 	                                        <input type="text" class="form-control" name="cardNumber" placeholder="Valid Card Number" required autofocus data-stripe="number" /> | ||||||
|  | 	                                        <span class="input-group-addon"><i class="fa fa-credit-card"></i></span> | ||||||
|  | 	                                    </div> | ||||||
|  | 	                                </div>                             | ||||||
|  | 	                            </div> | ||||||
|  | 	                        </div> | ||||||
|  | 	                        <div class="row"> | ||||||
|  | 	                            <div class="col-xs-7 col-md-7"> | ||||||
|  | 	                                <div class="form-group"> | ||||||
|  | 	                                    <label for="expMonth">EXPIRATION DATE</label> | ||||||
|  | 	                                    <div class="col-xs-6 col-lg-6 pl-ziro"> | ||||||
|  | 	                                        <input type="text" class="form-control" name="expMonth" placeholder="MM" required data-stripe="exp_month" /> | ||||||
|  | 	                                    </div> | ||||||
|  | 	                                    <div class="col-xs-6 col-lg-6 pl-ziro"> | ||||||
|  | 	                                        <input type="text" class="form-control" name="expYear" placeholder="YY" required data-stripe="exp_year" /> | ||||||
|  | 	                                    </div> | ||||||
|  | 	                                </div> | ||||||
|  | 	                            </div> | ||||||
|  | 	                            <div class="col-xs-5 col-md-5 pull-right"> | ||||||
|  | 	                                <div class="form-group"> | ||||||
|  | 	                                    <label for="cvCode">CV CODE</label> | ||||||
|  | 	                                    <input type="password" class="form-control" name="cvCode" placeholder="CV" required data-stripe="cvc" /> | ||||||
|  | 	                                </div> | ||||||
|  | 	                            </div> | ||||||
|  | 	                        </div> | ||||||
|  | 	                        <div class="row"> | ||||||
|  | 	                            <div class="col-xs-12"> | ||||||
|  | 	                                <button class="btn btn-success btn-lg btn-block" type="submit">Submit Payment</button> | ||||||
|  | 	                            </div> | ||||||
|  | 	                        </div> | ||||||
|  | 	                        <div class="row" style="display:none;"> | ||||||
|  | 	                            <div class="col-xs-12"> | ||||||
|  | 	                                <p class="payment-errors"></p> | ||||||
|  | 	                            </div> | ||||||
|  | 	                        </div> | ||||||
|  | 	                    </form> | ||||||
|  | 	                </div> | ||||||
|  | 	            </div> | ||||||
|  | 	        </div> | ||||||
|  |             <div class="col-xs-12 col-md-3 col-md-offset-1 summary-box"> | ||||||
|  |             	<form role="form" novalidate> | ||||||
|  |             		<div class="row"> | ||||||
|  |             			<div class="col-xs-12"> | ||||||
|  | 							<h3><b>Billing Amount</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.memory}} GiB</span></p> | ||||||
|  | 								<hr> | ||||||
|  | 								<h4>Total<p class="pull-right"><b>{{request.session.vm_specs.final_price}} CHF</b></p></h4> | ||||||
|  | 							</div> | ||||||
|  | 						</div> | ||||||
|  | 					</div> | ||||||
|  | 				</form> | ||||||
|  | 			</div> | ||||||
|  | 	         | ||||||
|  | 	              | ||||||
|  | 	         | ||||||
|  | 	    </div> | ||||||
|  | 	</div> | ||||||
|  | 
 | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | {%endblock%} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @ -1,14 +1,14 @@ | ||||||
| from django.conf.urls import url | from django.conf.urls import url | ||||||
| 
 | 
 | ||||||
| from .views import VMPricingView, DjangoHostingView, RailsHostingView, \ | from .views import DjangoHostingView, RailsHostingView, PaymentVMView, \ | ||||||
|                     NodeJSHostingView, LoginView, SignupView, IndexView |                     NodeJSHostingView, LoginView, SignupView, IndexView | ||||||
| 
 | 
 | ||||||
| urlpatterns = [ | urlpatterns = [ | ||||||
|     url(r'index/?$', IndexView.as_view(), name='index'), |     url(r'index/?$', IndexView.as_view(), name='index'), | ||||||
|     url(r'pricing/?$', VMPricingView.as_view(), name='pricing'), |  | ||||||
|     url(r'django/?$', DjangoHostingView.as_view(), name='djangohosting'), |     url(r'django/?$', DjangoHostingView.as_view(), name='djangohosting'), | ||||||
|     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'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'payment/?$', PaymentVMView.as_view(), name='payment'), | ||||||
| ] | ] | ||||||
|  |  | ||||||
|  | @ -3,32 +3,32 @@ 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.views.generic import View, CreateView, FormView | from django.views.generic import View, CreateView, FormView | ||||||
|  | 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 membership.forms import PaymentForm | ||||||
| from membership.models import CustomUser | from membership.models import CustomUser | ||||||
| from .models import RailsBetaUser, VirtualMachineType | from .models import RailsBetaUser, VirtualMachineType | ||||||
| from .forms import HostingUserSignupForm, HostingUserLoginForm | from .forms import HostingUserSignupForm, HostingUserLoginForm | ||||||
|  | from .mixins import ProcessVMSelectionMixin | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class VMPricingView(View): | class DjangoHostingView(ProcessVMSelectionMixin, View): | ||||||
|     template_name = "hosting/pricing.html" |  | ||||||
| 
 |  | ||||||
|     def get(self, request, *args, **kwargs): |  | ||||||
|         return render(request, self.template_name, request) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class DjangoHostingView(View): |  | ||||||
|     template_name = "hosting/django.html" |     template_name = "hosting/django.html" | ||||||
| 
 | 
 | ||||||
|     def get_context_data(self, **kwargs): |     def get_context_data(self, **kwargs): | ||||||
|         context = {} |         context = { | ||||||
|         context["hosting"] = "django" |             'hosting': "django", | ||||||
|         context["hosting_long"] = "Django" |             'hosting_long': "Django", | ||||||
|         context["domain"] = "django-hosting.ch" |             'domain': "django-hosting.ch", | ||||||
|         context["google_analytics"] = "UA-62285904-6" |             'google_analytics': "UA-62285904-6", | ||||||
|         context["email"] = "info@django-hosting.ch" |             'email': "info@django-hosting.ch", | ||||||
|         context["vm_types"] = VirtualMachineType.get_serialized_vm_types() |             'vm_types': VirtualMachineType.get_serialized_vm_types(), | ||||||
|  |         } | ||||||
|         return context |         return context | ||||||
| 
 | 
 | ||||||
|     def get(self, request, *args, **kwargs): |     def get(self, request, *args, **kwargs): | ||||||
|  | @ -36,17 +36,18 @@ class DjangoHostingView(View): | ||||||
|         return render(request, self.template_name, context) |         return render(request, self.template_name, context) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class RailsHostingView(View): | class RailsHostingView(ProcessVMSelectionMixin, View): | ||||||
|     template_name = "hosting/rails.html" |     template_name = "hosting/rails.html" | ||||||
| 
 | 
 | ||||||
|     def get_context_data(self, **kwargs): |     def get_context_data(self, **kwargs): | ||||||
|         context = {} |         context = { | ||||||
|         context["hosting"] = "rails" |             'hosting': "rails", | ||||||
|         context["hosting_long"] = "Ruby On Rails" |             'hosting_long': "Ruby On Rails", | ||||||
|         context["domain"] = "rails-hosting.ch" |             'domain': "rails-hosting.ch", | ||||||
|         context["google_analytics"] = "UA-62285904-5" |             'google_analytics': "UA-62285904-5", | ||||||
|         context["email"] = "info@rails-hosting.ch" |             'email': "info@rails-hosting.ch", | ||||||
|         context["vm_types"] = VirtualMachineType.get_serialized_vm_types() |             'vm_types': VirtualMachineType.get_serialized_vm_types(), | ||||||
|  |         } | ||||||
|         return context |         return context | ||||||
| 
 | 
 | ||||||
|     def get(self, request, *args, **kwargs): |     def get(self, request, *args, **kwargs): | ||||||
|  | @ -54,17 +55,18 @@ class RailsHostingView(View): | ||||||
|         return render(request, self.template_name, context) |         return render(request, self.template_name, context) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class NodeJSHostingView(View): | class NodeJSHostingView(ProcessVMSelectionMixin, View): | ||||||
|     template_name = "hosting/nodejs.html" |     template_name = "hosting/nodejs.html" | ||||||
| 
 | 
 | ||||||
|     def get_context_data(self, **kwargs): |     def get_context_data(self, **kwargs): | ||||||
|         context = {} |         context = { | ||||||
|         context["hosting"] = "nodejs" |             'hosting': "nodejs", | ||||||
|         context["hosting_long"] = "NodeJS" |             'hosting_long': "NodeJS", | ||||||
|         context["domain"] = "node-hosting.ch" |             'domain': "node-hosting.ch", | ||||||
|         context["google_analytics"] = "UA-62285904-7" |             'google_analytics': "UA-62285904-7", | ||||||
|         context["email"] = "info@node-hosting.ch" |             'email': "info@node-hosting.ch", | ||||||
|         context["vm_types"] = VirtualMachineType.get_serialized_vm_types() |             'vm_types': VirtualMachineType.get_serialized_vm_types(), | ||||||
|  |         } | ||||||
|         return context |         return context | ||||||
| 
 | 
 | ||||||
|     def get(self, request, *args, **kwargs): |     def get(self, request, *args, **kwargs): | ||||||
|  | @ -76,13 +78,14 @@ class IndexView(View): | ||||||
|     template_name = "hosting/index.html" |     template_name = "hosting/index.html" | ||||||
| 
 | 
 | ||||||
|     def get_context_data(self, **kwargs): |     def get_context_data(self, **kwargs): | ||||||
|         context = {} |         context = { | ||||||
|         context["hosting"] = "nodejs" |             'hosting': "nodejs", | ||||||
|         context["hosting_long"] = "NodeJS" |             'hosting_long': "NodeJS", | ||||||
|         context["domain"] = "node-hosting.ch" |             'domain': "node-hosting.ch", | ||||||
|         context["google_analytics"] = "UA-62285904-7" |             'google_analytics': "UA-62285904-7", | ||||||
|         context["email"] = "info@node-hosting.ch" |             'email': "info@node-hosting.ch", | ||||||
|         context["vm_types"] = VirtualMachineType.get_serialized_vm_types() |             'vm_types': VirtualMachineType.get_serialized_vm_types(), | ||||||
|  |         } | ||||||
|         return context |         return context | ||||||
| 
 | 
 | ||||||
|     def get(self, request, *args, **kwargs): |     def get(self, request, *args, **kwargs): | ||||||
|  | @ -124,6 +127,22 @@ class SignupView(CreateView): | ||||||
|         return HttpResponseRedirect(self.get_success_url()) |         return HttpResponseRedirect(self.get_success_url()) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | class PaymentVMView(FormView): | ||||||
|  |     template_name = 'hosting/payment.html' | ||||||
|  |     form_class = PaymentForm | ||||||
|  | 
 | ||||||
|  |     def get_context_data(self, **kwargs): | ||||||
|  |         context = super(PaymentVMView, self).get_context_data(**kwargs) | ||||||
|  |         context.update({ | ||||||
|  |             'stripe_key': settings.STRIPE_API_PUBLIC_KEY | ||||||
|  |         }) | ||||||
|  |         return context | ||||||
|  | 
 | ||||||
|  |     # moodel = CustomUser | ||||||
|  | 
 | ||||||
|  |     # def get(self, request, *args, **kwargs): | ||||||
|  | 
 | ||||||
|  |     #     return render(request, self.template_name, self.context) | ||||||
| 
 | 
 | ||||||
| # class RailsBetaUserForm(ModelForm): | # class RailsBetaUserForm(ModelForm): | ||||||
| #     required_css_class = 'form-control' | #     required_css_class = 'form-control' | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue