fix merge conflict

This commit is contained in:
Tomislav R 2016-04-28 19:47:44 +02:00
commit e0fc542673
28 changed files with 1244 additions and 438 deletions

View file

@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-04-23 07:10
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('hosting', '0007_auto_20160418_0103'),
]
operations = [
migrations.CreateModel(
name='VirtualMachinePlan',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('cores', models.IntegerField()),
('memory', models.IntegerField()),
('disk_size', models.IntegerField()),
('price', models.FloatField()),
('client', models.ManyToManyField(to=settings.AUTH_USER_MODEL)),
('vm_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='hosting.VirtualMachineType')),
],
),
]

View file

@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-04-26 04:44
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('utils', '0002_billingaddress'),
('membership', '0004_stripecustomer'),
('hosting', '0008_virtualmachineplan'),
]
operations = [
migrations.CreateModel(
name='HostingOrder',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True)),
],
),
migrations.RemoveField(
model_name='virtualmachineplan',
name='client',
),
migrations.AddField(
model_name='hostingorder',
name='VMPlan',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='hosting.VirtualMachinePlan'),
),
migrations.AddField(
model_name='hostingorder',
name='billing_address',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='utils.BillingAddress'),
),
migrations.AddField(
model_name='hostingorder',
name='customer',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='membership.StripeCustomer'),
),
]

View file

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-04-26 05:30
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('hosting', '0009_auto_20160426_0444'),
]
operations = [
migrations.AddField(
model_name='hostingorder',
name='approved',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='hostingorder',
name='stripe_charge_id',
field=models.CharField(max_length=100, null=True),
),
]

View file

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-04-26 05:55
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('hosting', '0010_auto_20160426_0530'),
]
operations = [
migrations.AlterField(
model_name='hostingorder',
name='VMPlan',
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='hosting.VirtualMachinePlan'),
),
]

20
hosting/mixins.py Normal file
View 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'))

View file

@ -1,7 +1,10 @@
import json
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.core import serializers
import json
from membership.models import StripeCustomer
from utils.models import BillingAddress
class RailsBetaUser(models.Model):
@ -42,7 +45,13 @@ class VirtualMachineType(models.Model):
def get_serialized_vm_types(cls):
return [vm.get_serialized_data()
for vm in cls.objects.all()]
# return serializers.serialize("json",)
def calculate_price(self, specifications):
price = float(specifications['cores']) * self.core_price
price += float(specifications['memory']) * self.memory_price
price += float(specifications['disk_size']) * self.disk_size_price
price += self.base_price
return price
def defeault_price(self):
price = self.base_price
@ -63,3 +72,51 @@ class VirtualMachineType(models.Model):
'default_price': self.defeault_price(),
'id': self.id,
}
class VirtualMachinePlan(models.Model):
cores = models.IntegerField()
memory = models.IntegerField()
disk_size = models.IntegerField()
vm_type = models.ForeignKey(VirtualMachineType)
price = models.FloatField()
@classmethod
def create(cls, data, user):
instance = cls.objects.create(**data)
return instance
class HostingOrder(models.Model):
VMPlan = models.OneToOneField(VirtualMachinePlan)
customer = models.ForeignKey(StripeCustomer)
billing_address = models.ForeignKey(BillingAddress)
created_at = models.DateTimeField(auto_now_add=True)
approved = models.BooleanField(default=False)
stripe_charge_id = models.CharField(max_length=100, null=True)
@classmethod
def create(cls, VMPlan=None, customer=None, billing_address=None):
instance = cls.objects.create(VMPlan=VMPlan, customer=customer,
billing_address=billing_address)
return instance
def set_approved(self):
self.approved = True
self.save()
def set_stripe_charge(self, stripe_charge):
self.stripe_charge_id = stripe_charge.id
self.save()

View file

@ -31,8 +31,7 @@ h6 {
}
.intro-header {
height: 85%;
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-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-bottom: 50px;
text-align: center;
color: #f8f8f8;
@ -48,8 +47,7 @@ h6 {
background-size: cover;
}
.intro-header-2 {
height: 85%;
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-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-bottom: 50px;
text-align: center;
color: #f8f8f8;
@ -61,10 +59,23 @@ h6 {
padding-top: 20%;
padding-bottom: 20%;
}
.intro-signup {
.intro-auth {
text-align: center;
color: #f8f8f8;
position: relative;
padding-top: 20%;
padding-bottom: 20%;
padding-bottom: 25%;
padding-top: 10%;
}
.intro-login {
background: url(../img/intro-bg.jpg) no-repeat center center;
background-size: cover;
}
.intro-signup {
background: url(../img/configure.jpg) no-repeat center center;
background-size: cover;
}
.intro-message > h1 {
@ -202,4 +213,12 @@ a#forgotpassword {
line-height: 1;
font-weight: 700;
color: #6db97c;
}
a.unlink {
color: inherit;
}
a.unlink:hover {
color: inherit;
}

View file

@ -0,0 +1,28 @@
.payment-container {padding-top:5%; 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 .content {
padding-top: 15px;
}

View file

@ -0,0 +1,124 @@
$( document ).ready(function() {
$.ajaxSetup({
beforeSend: function(xhr, settings) {
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) {
// Only send the token to relative URLs i.e. locally.
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
}
}
});
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 = window.stripeKey;
Stripe.setPublishableKey(PublishableKey);
Stripe.card.createToken($form, function stripeResponseHandler(status, response) {
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;
// AJAX
//set token on a hidden input
$('#id_token').val(token);
$('#billing-form').submit();
}
});
}
/* 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);
});

View file

@ -8,8 +8,9 @@ $( document ).ready(function() {
function calculate_price(vm_type){
var ID_SELECTOR = "#";
var CURRENCY = "$";
var CURRENCY = "CHF";
var final_price_selector = ID_SELECTOR.concat(vm_type.concat('-final-price'));
var final_price_input_selector = final_price_selector.concat('-input');
var core_selector = ID_SELECTOR.concat(vm_type.concat('-cores'));
var memory_selector = ID_SELECTOR.concat(vm_type.concat('-memory'));
var disk_size_selector = ID_SELECTOR.concat(vm_type.concat('-disk_space'));
@ -27,8 +28,9 @@ $( document ).ready(function() {
price += company_prices.memory_price*memory;
price += company_prices.disk_size_price*disk_size;
console.log(final_price_selector);
console.log(final_price_input_selector);
$(final_price_selector).text(price.toString().concat(CURRENCY));
$(final_price_input_selector).attr('value', price);
}
@ -47,7 +49,5 @@ $( document ).ready(function() {
$('.disk-space-selector').on('change',change_attribute);
console.log("mirame",window.VMTypesData);
});

View file

@ -0,0 +1,134 @@
{% 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">&sdot;</li>
<li>
<a href="#about">How it works</a></li>
<li class="footer-menu-divider">&sdot;</li>
<li>
<a href="#about">Your infrastructure</a></li>
<li>&sdot;</li>
<li>
<a href="#about">Our infrastructure</a></li>
<li class="footer-menu-divider">&sdot;</li>
<li>
<a href="#services">Pricing</a>
</li>
<li class="footer-menu-divider">&sdot;</li>
<li>
<a href="#contact">Contact</a>
</li>
</ul>
<p class="copyright text-muted small">Copyright &copy; 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>

View file

@ -1,5 +1,4 @@
{% load staticfiles %}
<a name="about"></a>
<div class="intro-header">
<div class="container">

View file

@ -17,70 +17,12 @@
<div class="row text-center">
<div class="block">
{% for vm in vm_types %}
<div class="row well pricing">
<form class="form-inline p-green" role="form">
<div class="btn-group col-md-3">
<div class="form-group">
<big>
{{vm.hosting_company_name}}
</big>
<p>
{{vm.description}}
</p>
</div>
</div>
<div class="btn-group col-md-2">
<div class="form-group">
<label for="cores">Cores:</label>
<select class="form-control" id="cores">
{% with ''|center:10 as range %}
{% for _ in range %}
<option>{{ forloop.counter }}</option>
{% endfor %}
{% endwith %}
</select>
</div>
</div>
<div class="btn-group col-md-2">
<label for="memory">Memory: </label>
<div class="form-group">
<select class="form-control short-input" id="memory">
{% with ''|center:50 as range %}
{% for _ in range %}
<option>{{ forloop.counter }}</option>
{% endfor %}
{% endwith %}
</select>
<span>GiB</span>
</div>
</div>
<div class="form-group col-md-2">
<label for="Disk Size">Disk Size: </label>
<input class="form-control short-input" type="number" id="disk_space" min="0" value="0"/>
<span>GiB</span>
</div>
<div class="col-md-2">
<h3>$199</h3>
</div>
<div class="col-md-1">
<button type="submit" class="btn btn-default">Buy it</button>
</div>
<!-- <button type="submit" class="btn btn-default">Submit</button> -->
</form>
</div>
{% endfor %}
{% for vm in vm_types %}
<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' %}">
<li style="height:200px;">
<!-- <img src="http://bread.pp.ua/n/settings_g.svg" alt=""> -->
@ -91,7 +33,7 @@
<div class="btn-group">
<div class="form-group">
<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 %}
{% for _ in range %}
<option>{{ forloop.counter }}</option>
@ -106,7 +48,7 @@
<div class="btn-group">
<div class="form-group">
<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 %}
{% for _ in range %}
<option>{{ forloop.counter }}</option>
@ -120,12 +62,13 @@
<li class="row">
<div class="form-group">
<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>
</div>
</li>
<li>
<h3 id="{{vm.hosting_company}}-final-price">{{vm.default_price|floatformat}}$</h3>
<input id="{{vm.hosting_company}}-final-price-input" 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>
</li>
<li>

View file

@ -1,148 +1,33 @@
{% extends "hosting/base_short.html" %}
{% load staticfiles bootstrap3%}
<!DOCTYPE html>
<html lang="en">
{% block content %}
<head>
<div class="intro-auth intro-login">
<div class="container">
<div class="col-md-4 col-md-offset-4">
<div class="intro-message">
<h2 class="section-heading">Login</h2>
<form action="{% url 'hosting:login' %}" method="post" class="form" novalidate>
{% csrf_token %}
{% for field in form %}
{% bootstrap_field field show_label=False type='fields'%}
{% endfor %}
{% bootstrap_form_errors form type='non_fields'%}
{% buttons %}
<button type="submit" class="btn btn-default">
Login
</button>
{% endbuttons %}
</form>
<span>Doesn't have an account ? <a class="unlink" href="{% url 'hosting:signup' %}">Sign up</a></span>
<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>Rails Hosting.ch - Ruby on Rails as easy as possible</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">
<!-- Custom Fonts -->
<link href='http://fonts.googleapis.com/css?family=Raleway' rel='stylesheet' type='text/css'>
<link href="font-awesome/css/font-awesome.min.css" rel="stylesheet" type="text/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>
<div class="intro-header">
<div class="container">
<div class="col-md-4">&nbsp;</div><div class="col-md-4">
<div class="intro-message">
<h2>Login</h2>
<form action="{% url 'hosting:login' %}" method="post" class="form" novalidate>
{% csrf_token %}
{% for field in form %}
{% bootstrap_field field show_label=False type='fields'%}
{% endfor %}
{% bootstrap_form_errors form type='non_fields'%}
{% buttons %}
<button type="submit" class="btn btn-default">
Login
</button>
{% endbuttons %}
</form>
<ul class="list-inline intro-social-buttons">
</ul>
</div>
</div>
</div>
<!-- /.container -->
</div>
<!-- /.intro-header -->
<!-- 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">&sdot;</li>
<li>
<a href="#about">How it works</a></li>
<li class="footer-menu-divider">&sdot;</li>
<li>
<a href="#about">Your infrastructure</a></li>
<li>&sdot;</li>
<li>
<a href="#about">Our infrastructure</a></li>
<li class="footer-menu-divider">&sdot;</li>
<li>
<a href="#services">Pricing</a>
</li>
<li class="footer-menu-divider">&sdot;</li>
<li>
<a href="#contact">Contact</a>
</li>
<ul class="list-inline intro-social-buttons">
</ul>
<p class="copyright text-muted small">Copyright &copy; ungleich GmbH {% now "Y" %}. All Rights Reserved</p>
</div>
</div>
</div>
</footer>
</div>
<!-- /.container -->
<!-- jQuery -->
<script src="js/jquery.js"></script>
<!-- Bootstrap Core JavaScript -->
<script src="js/bootstrap.min.js"></script>
</body>
</html>
</div>
{% endblock %}

View file

@ -0,0 +1,110 @@
{% extends "hosting/base_short.html" %}
{% load staticfiles bootstrap3 %}
{%block content %}
<!-- Credit card form -->
<div>
<div class="container payment-container">
<div class="row">
<div class="col-xs-12 col-md-4 col-md-offset-2 billing">
<h3><b>Billing Address</b></h3>
<hr>
<form role="form" id="billing-form" method="post" action="{% url 'hosting:payment' %}" novalidate>
{% for field in form %}
{% csrf_token %}
{% bootstrap_field field show_label=False type='fields'%}
{% endfor %}
{% bootstrap_form_errors form type='non_fields'%}
</form>
</div>
</div>
<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>
<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.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>
</form>
</div>
</div>
</div>
</div>
<!-- stripe key data -->
{% if stripe_key %}
<script type="text/javascript">
(function () {window.stripeKey = "{{stripe_key}}";})();
</script>
{%endif%}
{%endblock%}

View file

@ -1,149 +1,29 @@
{% extends "hosting/base_short.html" %}
{% 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>Signup</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">
<!-- Custom Fonts -->
<link href='http://fonts.googleapis.com/css?family=Raleway' rel='stylesheet' type='text/css'>
<link href="font-awesome/css/font-awesome.min.css" rel="stylesheet" type="text/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="{% static 'hosting/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>
<div class="intro-header-2">
{% block content %}
<div class="intro-auth intro-signup">
<div class="container">
<div class="col-md-4">&nbsp;</div><div class="col-md-4">
<div class="intro-message">
<h2>Sign up</h2>
<form action="{% url 'hosting:signup' %}" method="post" class="form" novalidate>
{% csrf_token %}
{% for field in form %}
{% bootstrap_field field show_label=False %}
{% endfor %}
{% buttons %}
<button type="submit" class="btn btn-default">
Signup
</button>
{% endbuttons %}
</form>
<ul class="list-inline intro-social-buttons">
</ul>
<div class="col-md-4">&nbsp;</div>
<div class="col-md-4">
<div class="intro-message">
<h2 class="section-heading">Sign up</h2>
<form action="{% url 'hosting:signup' %}" method="post" class="form" novalidate>
{% csrf_token %}
{% for field in form %}
{% bootstrap_field field show_label=False %}
{% endfor %}
{% buttons %}
<button type="submit" class="btn btn-default">
Sign up
</button>
{% endbuttons %}
</form>
<span>Already have an account ? <a class="unlink" href="{% url 'hosting:login' %}">Log in</a></span>
<ul class="list-inline intro-social-buttons">
</ul>
</div>
</div>
</div>
</div>
<!-- /.container -->
</div>
<!-- /.intro-header -->
<!-- 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">&sdot;</li>
<li>
<a href="#about">How it works</a></li>
<li class="footer-menu-divider">&sdot;</li>
<li>
<a href="#about">Your infrastructure</a></li>
<li>&sdot;</li>
<li>
<a href="#about">Our infrastructure</a></li>
<li class="footer-menu-divider">&sdot;</li>
<li>
<a href="#services">Pricing</a>
</li>
<li class="footer-menu-divider">&sdot;</li>
<li>
<a href="#contact">Contact</a>
</li>
</ul>
<p class="copyright text-muted small">Copyright &copy; ungleich GmbH {% now "Y" %}. All Rights Reserved</p>
</div>
</div>
</div>
</footer>
<!-- jQuery -->
<script src="js/jquery.js"></script>
<!-- Bootstrap Core JavaScript -->
<script src="js/bootstrap.min.js"></script>
</body>
</html>
{% endblock %}

View file

@ -1,14 +1,15 @@
from django.conf.urls import url
from .views import VMPricingView, DjangoHostingView, RailsHostingView, \
from .views import DjangoHostingView, RailsHostingView, PaymentVMView, \
NodeJSHostingView, LoginView, SignupView, IndexView
urlpatterns = [
url(r'index/$', IndexView.as_view(), name='index'),
url(r'pricing/?$', VMPricingView.as_view(), name='pricing'),
url(r'index/?$', IndexView.as_view(), name='index'),
url(r'django/?$', DjangoHostingView.as_view(), name='djangohosting'),
url(r'nodejs/?$', NodeJSHostingView.as_view(), name='nodejshosting'),
url(r'rails/?$', RailsHostingView.as_view(), name='railshosting'),
url(r'login/?$', LoginView.as_view(), name='login'),
url(r'signup/?$', SignupView.as_view(), name='signup'),
url(r'payment/?$', PaymentVMView.as_view(), name='payment'),
]

View file

@ -3,50 +3,54 @@ from django.shortcuts import get_object_or_404, render
from django.core.urlresolvers import reverse_lazy, reverse
from django.views.generic import View, CreateView, FormView
from django.shortcuts import redirect
from django.http import HttpResponseRedirect
from django.contrib.auth import authenticate, login
from django.conf import settings
from membership.models import CustomUser
from .models import RailsBetaUser, VirtualMachineType
from membership.forms import PaymentForm
from membership.models import CustomUser, StripeCustomer
from utils.stripe_utils import StripeUtils
from utils.forms import BillingAddressForm
from .models import VirtualMachineType, VirtualMachinePlan, HostingOrder
from .forms import HostingUserSignupForm, HostingUserLoginForm
from .mixins import ProcessVMSelectionMixin
class VMPricingView(View):
template_name = "hosting/pricing.html"
def get(self, request, *args, **kwargs):
return render(request, self.template_name, request)
class DjangoHostingView(View):
class DjangoHostingView(ProcessVMSelectionMixin, View):
template_name = "hosting/django.html"
def get_context_data(self, **kwargs):
context = {}
context["hosting"] = "django"
context["hosting_long"] = "Django"
context["domain"] = "django-hosting.ch"
context["google_analytics"] = "UA-62285904-6"
context["email"] = "info@django-hosting.ch"
context["vm_types"] = VirtualMachineType.get_serialized_vm_types()
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(),
}
return context
def get(self, request, *args, **kwargs):
context = self.get_context_data()
return render(request, self.template_name, context)
class RailsHostingView(View):
class RailsHostingView(ProcessVMSelectionMixin, View):
template_name = "hosting/rails.html"
def get_context_data(self, **kwargs):
context = {}
context["hosting"] = "rails"
context["hosting_long"] = "Ruby On Rails"
context["domain"] = "rails-hosting.ch"
context["google_analytics"] = "UA-62285904-5"
context["email"] = "info@rails-hosting.ch"
context["vm_types"] = VirtualMachineType.get_serialized_vm_types()
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(),
}
return context
def get(self, request, *args, **kwargs):
@ -54,21 +58,24 @@ class RailsHostingView(View):
return render(request, self.template_name, context)
class NodeJSHostingView(View):
class NodeJSHostingView(ProcessVMSelectionMixin, View):
template_name = "hosting/nodejs.html"
def get_context_data(self, **kwargs):
context = {}
context["hosting"] = "nodejs"
context["hosting_long"] = "NodeJS"
context["domain"] = "node-hosting.ch"
context["google_analytics"] = "UA-62285904-7"
context["email"] = "info@node-hosting.ch"
context["vm_types"] = VirtualMachineType.get_serialized_vm_types()
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(),
}
return context
def get(self, request, *args, **kwargs):
context = self.get_context_data()
return render(request, self.template_name, context)
@ -76,33 +83,39 @@ class IndexView(View):
template_name = "hosting/index.html"
def get_context_data(self, **kwargs):
context = {}
context["hosting"] = "nodejs"
context["hosting_long"] = "NodeJS"
context["domain"] = "node-hosting.ch"
context["google_analytics"] = "UA-62285904-7"
context["email"] = "info@node-hosting.ch"
context["vm_types"] = VirtualMachineType.get_serialized_vm_types()
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(),
}
return context
def get(self, request, *args, **kwargs):
context = self.get_context_data()
return render(request, self.template_name, context)
class LoginView(FormView):
template_name = 'hosting/login.html'
success_url = reverse_lazy('hosting:login')
form_class = HostingUserLoginForm
moodel = CustomUser
success_url = reverse_lazy('hosting:login')
def form_valid(self, form):
email = form.cleaned_data.get('email')
password = form.cleaned_data.get('password')
auth_user = authenticate(email=email, password=password)
if auth_user:
login(self.request, auth_user)
return HttpResponseRedirect(self.get_success_url())
return HttpResponseRedirect(self.get_success_url())
@ -115,43 +128,77 @@ class SignupView(CreateView):
return reverse_lazy('hosting:signup')
def form_valid(self, form):
name = form.cleaned_data.get('name')
email = form.cleaned_data.get('email')
password = form.cleaned_data.get('password')
CustomUser.register(name, password, email)
auth_user = authenticate(email=email, password=password)
login(self.request, auth_user)
return HttpResponseRedirect(self.get_success_url())
class PaymentVMView(FormView):
template_name = 'hosting/payment.html'
form_class = BillingAddressForm
# class RailsBetaUserForm(ModelForm):
# required_css_class = 'form-control'
# class Meta:
# model = RailsBetaUser
# fields = [ 'email' ]
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
# def hosting(request, context):
# email = RailsBetaUser(received_date=datetime.datetime.now())
def post(self, request, *args, **kwargs):
form = self.get_form()
# if request.method == 'POST':
# context['form'] = RailsBetaUserForm(request.POST, instance=email)
# if context['form'].is_valid():
# context['form'].save()
# email = context['form'].cleaned_data['email']
# subject = "%shosting request" % context['hosting']
# message = "Request for beta by: %s" % email
if form.is_valid():
# mail_managers(subject, message)
specifications = request.session.get('vm_specs')
vm_type = specifications.get('hosting_company')
vm = VirtualMachineType.objects.get(hosting_company=vm_type)
final_price = vm.calculate_price(specifications)
# return HttpResponseRedirect(reverse("hosting:beta"))
# else:
# context['form'] = RailsBetaUserForm()
# context['error_message'] = "a problem"
plan_data = {
'vm_type': vm,
'cores': specifications.get('cores'),
'memory': specifications.get('memory'),
'disk_size': specifications.get('disk_size'),
'price': final_price
}
token = form.cleaned_data.get('token')
# page = "hosting/%s.html" % context['hosting']
# Get or create stripe customer
customer = StripeCustomer.get_or_create(email=self.request.user.email,
token=token)
# Create Virtual Machine Plan
plan = VirtualMachinePlan.create(plan_data, request.user)
# return render(request, page, context)
# Create Billing Address
billing_address = form.save()
# def beta(request):
# return render(request, 'hosting/beta.html')
# Create a Hosting Order
order = HostingOrder.create(VMPlan=plan, customer=customer,
billing_address=billing_address)
# Make stripe charge to a customer
stripe_utils = StripeUtils()
charge = stripe_utils.make_charge(amount=final_price,
customer=customer.stripe_id)
order.set_stripe_charge(charge)
if not charge.paid:
# raise an error
pass
# If the Stripe payment was successed, set order status approved
order.set_approved()
# order.charge =
# Billing Address should be store here
return HttpResponseRedirect(reverse('hosting:payment'))
else:
return self.form_invalid(form)