Merged master into task/3622/decouple_opennebula_dcl_flow
This commit is contained in:
commit
6b7ae88f74
19 changed files with 296 additions and 142 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -35,3 +35,4 @@ secret-key
|
||||||
|
|
||||||
.env
|
.env
|
||||||
*.mo
|
*.mo
|
||||||
|
*.log
|
||||||
|
|
23
Changelog
23
Changelog
|
@ -1,3 +1,26 @@
|
||||||
|
1.0.24: 2017-08-15
|
||||||
|
* #3699: [datacenterlight] Added oneadmin ssh key by default to the created VM via DCL landing
|
||||||
|
* #3687: [datacenterlight] Added the name of the customer as description field of the stripe metadata
|
||||||
|
[all] Added CustomUser as a parameter in get_anonymous_user function to resolve issues with tests
|
||||||
|
1.0.23: 2017-08-11
|
||||||
|
* #3629: [datacentlight] Fixed navbar changing language from DE to EN between menus bug
|
||||||
|
* #3623: [hosting] Fixed “Confirm Order” text appearing in “Invoice” place
|
||||||
|
* #3633: [datacenterlight, hosting] Translated “All Rights Reserved” for German pages
|
||||||
|
* #3627: [datacenterlight, hosting] Added border for payment warning message when the user has already submitted card information
|
||||||
|
* #3620: [hosting] Updated SSH Key page with new style: new key choice page, upload key page, added icons for downloading and deleting key on mobile
|
||||||
|
* [hosting] bug fix: added modal icon and translation back for delete SSH Key
|
||||||
|
* #3660: [datacenterlight] Rearranged desktop and mobile view for “Why Data Centre Light?” IPv6/SSD section
|
||||||
|
* #3646: Added file with VM Template hosting migration
|
||||||
|
* #3617: [hosting] Fixed Password reset confirmation page style bug
|
||||||
|
* #3408: [hosting] Changed background image of signup/login background into smaller size
|
||||||
|
* #3621: [hosting] Fixed signup/login/password reset page navbar logo overlapping with form
|
||||||
|
* #3354: [hosting] Restyled modal
|
||||||
|
* #3638: [hosting] Added “download” btn on generated key list for generated keys from upload your key page
|
||||||
|
* #3655: [hosting] Disabled deleting SSH keys from other users
|
||||||
|
* #3619: [datacenterlight, hosting] Replaced 'Lato-Light' and 'Lato-Regular' with only ‘Lato’ with appropriate font-weights
|
||||||
|
* #3677: [hosting] Added wrapping for show SSH key modal text
|
||||||
|
* #3683: [hosting] Fixed footer floating bug on VM creating page
|
||||||
|
* #3676: [datacenterlight, hosting] Added missing card holder's name field migration
|
||||||
1.0.22: 2017-07-30
|
1.0.22: 2017-07-30
|
||||||
* #3593: [datacenterlight] Removed underbars between social icons in index
|
* #3593: [datacenterlight] Removed underbars between social icons in index
|
||||||
* #3509: [datacenterlight, hosting] Made navbar transparent and removed mobile navbar bug in login/signup/reset-password
|
* #3509: [datacenterlight, hosting] Made navbar transparent and removed mobile navbar bug in login/signup/reset-password
|
||||||
|
|
|
@ -4,10 +4,10 @@
|
||||||
* For details, see http://www.apache.org/licenses/LICENSE-2.0.
|
* For details, see http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@font-face {
|
/*@font-face {
|
||||||
font-family: 'Lato-Light';
|
font-family: 'Lato-Light';
|
||||||
src: url('../fonts/Lato/Lato-Light.ttf');
|
src: url('../fonts/Lato/Lato-Light.ttf');
|
||||||
}
|
}*/
|
||||||
|
|
||||||
body,
|
body,
|
||||||
html {
|
html {
|
||||||
|
@ -22,7 +22,12 @@ h3,
|
||||||
h4,
|
h4,
|
||||||
h5,
|
h5,
|
||||||
h6 {
|
h6 {
|
||||||
font-family: 'Lato-Light', sans-serif;
|
/*font-family: 'Lato-Light', sans-serif;*/
|
||||||
|
font-family: 'Lato', sans-serif;
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
button, input, optgroup, select, textarea {
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,13 +148,15 @@ h6 {
|
||||||
|
|
||||||
.navbar-default .navbar-nav>li>a {
|
.navbar-default .navbar-nav>li>a {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-family: 'Lato-Light', sans-serif;
|
/*font-family: 'Lato-Light', sans-serif;*/
|
||||||
|
font-weight: 300;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar-transparent .navbar-nav>li>a {
|
.navbar-transparent .navbar-nav>li>a {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-family: 'Lato-Light', sans-serif;
|
/*font-family: 'Lato-Light', sans-serif;*/
|
||||||
|
font-weight: 300;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar-transparent .navbar-nav>li>a:hover {
|
.navbar-transparent .navbar-nav>li>a:hover {
|
||||||
|
@ -202,13 +209,15 @@ h6 {
|
||||||
|
|
||||||
.navbar-transparent .nav-language .select-language {
|
.navbar-transparent .nav-language .select-language {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-family: 'Lato-Light', sans-serif;
|
/*font-family: 'Lato-Light', sans-serif;*/
|
||||||
|
font-weight: 300;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-language .select-language span {
|
.nav-language .select-language span {
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
font-family: 'Lato', sans-serif;
|
/*font-family: 'Lato', sans-serif;*/
|
||||||
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
.nav-language .drop-language{
|
.nav-language .drop-language{
|
||||||
/*position: absolute;*/
|
/*position: absolute;*/
|
||||||
|
@ -237,7 +246,8 @@ h6 {
|
||||||
.nav-language .drop-language a{
|
.nav-language .drop-language a{
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding: 5px 10px !important;
|
padding: 5px 10px !important;
|
||||||
font-family: 'Lato-Light', sans-serif;
|
/*font-family: 'Lato-Light', sans-serif;*/
|
||||||
|
font-weight: 300;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Show the dropdown menu on hover */
|
/* Show the dropdown menu on hover */
|
||||||
|
@ -260,7 +270,8 @@ h6 {
|
||||||
.navbar-transparent .nav-language .drop-language a {
|
.navbar-transparent .nav-language .drop-language a {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
padding: 5px 10px !important;
|
padding: 5px 10px !important;
|
||||||
font-family: 'Lato-Light', sans-serif;
|
/*font-family: 'Lato-Light', sans-serif;*/
|
||||||
|
font-weight: 300;
|
||||||
}
|
}
|
||||||
/* .nav-language:hover .drop-language{
|
/* .nav-language:hover .drop-language{
|
||||||
display: block;
|
display: block;
|
||||||
|
@ -343,7 +354,7 @@ h6 {
|
||||||
|
|
||||||
.intro-message>h1 {
|
.intro-message>h1 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-weight: 400;
|
font-weight: 300;
|
||||||
font-size: 6em;
|
font-size: 6em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -792,7 +803,8 @@ tech-sub-sec h2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
.percent-text {
|
.percent-text {
|
||||||
font-family: 'Lato', sans-serif;
|
/*font-family: 'Lato', sans-serif;*/
|
||||||
|
/* font-weight: normal; */
|
||||||
font-size: 50px;
|
font-size: 50px;
|
||||||
color: #999;
|
color: #999;
|
||||||
}
|
}
|
||||||
|
@ -879,7 +891,7 @@ tech-sub-sec h2 {
|
||||||
.dropdown-menu>li>a {
|
.dropdown-menu>li>a {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
font-family: 'Lato-Light', sans-serif;
|
/*font-family: 'Lato-Light', sans-serif;*/
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar-default .navbar-nav>.active>a,
|
.navbar-default .navbar-nav>.active>a,
|
||||||
|
@ -898,7 +910,8 @@ tech-sub-sec h2 {
|
||||||
background: -webkit-linear-gradient(top, #f0f4f7, #fff) no-repeat;
|
background: -webkit-linear-gradient(top, #f0f4f7, #fff) no-repeat;
|
||||||
background: linear-gradient(to bottom, #f0f4f7, #fff) no-repeat;
|
background: linear-gradient(to bottom, #f0f4f7, #fff) no-repeat;
|
||||||
display: flex;
|
display: flex;
|
||||||
font-family: 'Lato', sans-serif;
|
/*font-family: 'Lato', sans-serif;*/
|
||||||
|
/* font-weight: normal; */
|
||||||
}
|
}
|
||||||
|
|
||||||
.price-calc-section .text {
|
.price-calc-section .text {
|
||||||
|
@ -963,7 +976,8 @@ tech-sub-sec h2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
.price-calc-section .card .title h3 {
|
.price-calc-section .card .title h3 {
|
||||||
font-family: 'Lato', sans-serif;
|
/*font-family: 'Lato', sans-serif;*/
|
||||||
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
.price-calc-section .card .price {
|
.price-calc-section .card .price {
|
||||||
|
@ -1050,8 +1064,9 @@ tech-sub-sec h2 {
|
||||||
|
|
||||||
.price-calc-section .card .description.input label {
|
.price-calc-section .card .description.input label {
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
font-weight: 800;
|
font-weight: 700;
|
||||||
font-family: 'Lato';
|
/*font-weight: 800;*/
|
||||||
|
/*font-family: 'Lato';*/
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
width: 40px;
|
width: 40px;
|
||||||
}
|
}
|
||||||
|
@ -1364,7 +1379,8 @@ tech-sub-sec h2 {
|
||||||
padding: 30px;
|
padding: 30px;
|
||||||
}
|
}
|
||||||
.percent-text {
|
.percent-text {
|
||||||
font-family: 'Lato';
|
/*font-family: 'Lato';*/
|
||||||
|
font-weight: normal;
|
||||||
font-size: 37px;
|
font-size: 37px;
|
||||||
/* text-align: center; */
|
/* text-align: center; */
|
||||||
}
|
}
|
||||||
|
@ -1402,7 +1418,7 @@ tech-sub-sec h2 {
|
||||||
.network-name {
|
.network-name {
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: 400;
|
font-weight: 300;
|
||||||
letter-spacing: 2px;
|
letter-spacing: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ from .forms import BetaAccessForm
|
||||||
from .models import BetaAccess, BetaAccessVMType, BetaAccessVM, VMTemplate
|
from .models import BetaAccess, BetaAccessVMType, BetaAccessVM, VMTemplate
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
|
from django.core.mail import EmailMessage
|
||||||
from utils.mailer import BaseEmail
|
from utils.mailer import BaseEmail
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
|
@ -12,12 +13,14 @@ from django.core.exceptions import ValidationError
|
||||||
from django.views.decorators.cache import cache_control
|
from django.views.decorators.cache import cache_control
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from utils.forms import BillingAddressForm
|
from utils.forms import BillingAddressForm, UserBillingAddressForm
|
||||||
from hosting.models import HostingOrder
|
from utils.models import BillingAddress
|
||||||
|
from hosting.models import HostingOrder, HostingBill
|
||||||
from utils.stripe_utils import StripeUtils
|
from utils.stripe_utils import StripeUtils
|
||||||
|
from datetime import datetime
|
||||||
from membership.models import CustomUser, StripeCustomer
|
from membership.models import CustomUser, StripeCustomer
|
||||||
from opennebula_api.models import OpenNebulaManager
|
from opennebula_api.models import OpenNebulaManager
|
||||||
from opennebula_api.serializers import VirtualMachineTemplateSerializer, VMTemplateSerializer
|
from opennebula_api.serializers import VirtualMachineTemplateSerializer, VirtualMachineSerializer, VMTemplateSerializer
|
||||||
from datacenterlight.tasks import create_vm_task
|
from datacenterlight.tasks import create_vm_task
|
||||||
|
|
||||||
|
|
||||||
|
@ -423,6 +426,10 @@ class OrderConfirmationView(DetailView):
|
||||||
customer = StripeCustomer.objects.filter(id=stripe_customer_id).first()
|
customer = StripeCustomer.objects.filter(id=stripe_customer_id).first()
|
||||||
stripe_utils = StripeUtils()
|
stripe_utils = StripeUtils()
|
||||||
card_details = stripe_utils.get_card_details(customer.stripe_id, request.session.get('token'))
|
card_details = stripe_utils.get_card_details(customer.stripe_id, request.session.get('token'))
|
||||||
|
if not card_details.get('response_object') and not card_details.get('paid'):
|
||||||
|
msg = card_details.get('error')
|
||||||
|
messages.add_message(self.request, messages.ERROR, msg, extra_tags='failed_payment')
|
||||||
|
return HttpResponseRedirect(reverse('datacenterlight:payment') + '#payment_error')
|
||||||
context = {
|
context = {
|
||||||
'site_url': reverse('datacenterlight:index'),
|
'site_url': reverse('datacenterlight:index'),
|
||||||
'cc_last4': card_details.get('response_object').get('last4'),
|
'cc_last4': card_details.get('response_object').get('last4'),
|
||||||
|
@ -438,6 +445,8 @@ class OrderConfirmationView(DetailView):
|
||||||
customer = StripeCustomer.objects.filter(id=stripe_customer_id).first()
|
customer = StripeCustomer.objects.filter(id=stripe_customer_id).first()
|
||||||
billing_address_data = request.session.get('billing_address_data')
|
billing_address_data = request.session.get('billing_address_data')
|
||||||
billing_address_id = request.session.get('billing_address')
|
billing_address_id = request.session.get('billing_address')
|
||||||
|
billing_address = BillingAddress.objects.filter(
|
||||||
|
id=billing_address_id).first()
|
||||||
vm_template_id = template.get('id', 1)
|
vm_template_id = template.get('id', 1)
|
||||||
final_price = specs.get('price')
|
final_price = specs.get('price')
|
||||||
|
|
||||||
|
@ -445,15 +454,12 @@ class OrderConfirmationView(DetailView):
|
||||||
stripe_utils = StripeUtils()
|
stripe_utils = StripeUtils()
|
||||||
charge_response = stripe_utils.make_charge(amount=final_price,
|
charge_response = stripe_utils.make_charge(amount=final_price,
|
||||||
customer=customer.stripe_id)
|
customer=customer.stripe_id)
|
||||||
charge = charge_response.get('response_object')
|
|
||||||
|
|
||||||
# Check if the payment was approved
|
# Check if the payment was approved
|
||||||
if not charge:
|
if not charge_response.get('response_object') and not charge_response.get('paid'):
|
||||||
context = {}
|
msg = charge_response.get('error')
|
||||||
context.update({
|
messages.add_message(self.request, messages.ERROR, msg, extra_tags='make_charge_error')
|
||||||
'paymentError': charge_response.get('error')
|
return HttpResponseRedirect(reverse('datacenterlight:payment') + '#payment_error')
|
||||||
})
|
|
||||||
return render(request, self.payment_template_name, context)
|
|
||||||
|
|
||||||
charge = charge_response.get('response_object')
|
charge = charge_response.get('response_object')
|
||||||
create_vm_task.delay(vm_template_id, user, specs, template, stripe_customer_id, billing_address_data,
|
create_vm_task.delay(vm_template_id, user, specs, template, stripe_customer_id, billing_address_data,
|
||||||
|
|
|
@ -523,6 +523,9 @@ OPENNEBULA_PORT = env('OPENNEBULA_PORT')
|
||||||
# default value is /RPC2
|
# default value is /RPC2
|
||||||
OPENNEBULA_ENDPOINT = env('OPENNEBULA_ENDPOINT')
|
OPENNEBULA_ENDPOINT = env('OPENNEBULA_ENDPOINT')
|
||||||
|
|
||||||
|
# The public ssh key of the oneadmin user
|
||||||
|
ONEADMIN_USER_SSH_PUBLIC_KEY = env('ONEADMIN_USER_SSH_PUBLIC_KEY')
|
||||||
|
|
||||||
# dcl email configurations
|
# dcl email configurations
|
||||||
DCL_TEXT = env('DCL_TEXT')
|
DCL_TEXT = env('DCL_TEXT')
|
||||||
DCL_SUPPORT_FROM_ADDRESS = env('DCL_SUPPORT_FROM_ADDRESS')
|
DCL_SUPPORT_FROM_ADDRESS = env('DCL_SUPPORT_FROM_ADDRESS')
|
||||||
|
|
|
@ -14,7 +14,6 @@ def generate_ssh_key_name():
|
||||||
|
|
||||||
|
|
||||||
class HostingUserLoginForm(forms.Form):
|
class HostingUserLoginForm(forms.Form):
|
||||||
|
|
||||||
email = forms.CharField(widget=forms.EmailInput())
|
email = forms.CharField(widget=forms.EmailInput())
|
||||||
password = forms.CharField(widget=forms.PasswordInput())
|
password = forms.CharField(widget=forms.PasswordInput())
|
||||||
|
|
||||||
|
@ -45,7 +44,6 @@ class HostingUserLoginForm(forms.Form):
|
||||||
|
|
||||||
|
|
||||||
class HostingUserSignupForm(forms.ModelForm):
|
class HostingUserSignupForm(forms.ModelForm):
|
||||||
|
|
||||||
confirm_password = forms.CharField(widget=forms.PasswordInput())
|
confirm_password = forms.CharField(widget=forms.PasswordInput())
|
||||||
password = forms.CharField(widget=forms.PasswordInput())
|
password = forms.CharField(widget=forms.PasswordInput())
|
||||||
|
|
||||||
|
@ -88,9 +86,8 @@ class UserHostingKeyForm(forms.ModelForm):
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
cleaned_data = self.cleaned_data
|
cleaned_data = self.cleaned_data
|
||||||
if not self.cleaned_data.get('name', ''):
|
if 'generate' in self.request.POST:
|
||||||
self.cleaned_data['name'] = generate_ssh_key_name()
|
self.cleaned_data['name'] = generate_ssh_key_name()
|
||||||
if not cleaned_data.get('public_key'):
|
|
||||||
private_key, public_key = UserHostingKey.generate_keys()
|
private_key, public_key = UserHostingKey.generate_keys()
|
||||||
cleaned_data.update({
|
cleaned_data.update({
|
||||||
'private_key': private_key,
|
'private_key': private_key,
|
||||||
|
|
|
@ -8,7 +8,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2017-08-04 18:25+0000\n"
|
"POT-Creation-Date: 2017-08-11 01:16+0530\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
@ -393,14 +393,14 @@ msgstr ""
|
||||||
msgid "Delete SSH Key"
|
msgid "Delete SSH Key"
|
||||||
msgstr "SSH Key löschen"
|
msgstr "SSH Key löschen"
|
||||||
|
|
||||||
msgid "Do You want to delete this key?"
|
msgid "Do you want to delete this key?"
|
||||||
msgstr "Möchtest Du den Schlüssel löschen?"
|
msgstr "Möchtest Du den Schlüssel löschen?"
|
||||||
|
|
||||||
msgid "Show"
|
msgid "Show"
|
||||||
msgstr "Anzeigen"
|
msgstr "Anzeigen"
|
||||||
|
|
||||||
msgid "Public ssh key"
|
msgid "Public SSH Key"
|
||||||
msgstr ""
|
msgstr "Public SSH Key"
|
||||||
|
|
||||||
msgid "Download"
|
msgid "Download"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.content-dashboard{
|
.content-dashboard{
|
||||||
min-height: calc(100vh - 120px);
|
min-height: calc(100vh - 70px);
|
||||||
width: 80%;
|
width: 80%;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
max-width: 1120px;
|
max-width: 1120px;
|
||||||
|
@ -110,12 +110,16 @@
|
||||||
font-weight: 100;
|
font-weight: 100;
|
||||||
color: #999;
|
color: #999;
|
||||||
}
|
}
|
||||||
|
.modal-body .modal-icon {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
.modal-title {
|
.modal-title {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
line-height: 1.42857143;
|
line-height: 1.42857143;
|
||||||
font-size: 25px;
|
font-size: 25px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
font-family: 'Lato', sans-serif;
|
/*font-family: 'Lato', sans-serif;*/
|
||||||
|
font-weight: 300;
|
||||||
}
|
}
|
||||||
.modal-text {
|
.modal-text {
|
||||||
padding-top: 15px;
|
padding-top: 15px;
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* For details, see http://www.apache.org/licenses/LICENSE-2.0.
|
* For details, see http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@font-face {
|
/*@font-face {
|
||||||
font-family: 'Lato-Regular';
|
font-family: 'Lato-Regular';
|
||||||
src: url('../fonts/Lato/Lato-Regular.ttf');
|
src: url('../fonts/Lato/Lato-Regular.ttf');
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Lato-Light';
|
font-family: 'Lato-Light';
|
||||||
src: url('../fonts/Lato/Lato-Light.ttf');
|
src: url('../fonts/Lato/Lato-Light.ttf');
|
||||||
}
|
}*/
|
||||||
|
|
||||||
body,
|
body,
|
||||||
html {
|
html {
|
||||||
|
@ -31,8 +31,9 @@ h3,
|
||||||
h4,
|
h4,
|
||||||
h5,
|
h5,
|
||||||
h6 {
|
h6 {
|
||||||
font-family: 'Lato-Regular', sans-serif;
|
/*font-family: 'Lato-Regular', sans-serif;*/
|
||||||
font-weight: 300;
|
font-family: 'Lato', sans-serif;
|
||||||
|
/*font-weight: 300;*/
|
||||||
}
|
}
|
||||||
|
|
||||||
.topnav {
|
.topnav {
|
||||||
|
@ -53,7 +54,8 @@ h6 {
|
||||||
.navbar-transparent .navbar-nav>li>a {
|
.navbar-transparent .navbar-nav>li>a {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-family: 'Lato-Regular', sans-serif;
|
/*font-family: 'Lato-Regular', sans-serif;*/
|
||||||
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
.navbar-transparent .navbar-nav>li>a:hover {
|
.navbar-transparent .navbar-nav>li>a:hover {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
|
@ -376,7 +378,8 @@ h6 {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
line-height: 30px;
|
line-height: 30px;
|
||||||
font-family: 'Lato' !important;
|
/*font-family: 'Lato' !important;*/
|
||||||
|
font-weight: 300 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sign-up-message a {
|
.sign-up-message a {
|
||||||
|
@ -454,16 +457,16 @@ h6 {
|
||||||
}
|
}
|
||||||
|
|
||||||
footer {
|
footer {
|
||||||
padding: 2%;
|
padding: 20px;
|
||||||
background-color: #f8f8f8;
|
background-color: #f8f8f8;
|
||||||
#position: absolute;
|
/* position: absolute */
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
p.copyright {
|
p.copyright {
|
||||||
margin: 15px 0 0;
|
margin: 14px 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
a#forgotpassword {
|
a#forgotpassword {
|
||||||
|
@ -488,7 +491,8 @@ a.unlink:hover {
|
||||||
|
|
||||||
/***** DCL payment page **********/
|
/***** DCL payment page **********/
|
||||||
.dcl-order-container {
|
.dcl-order-container {
|
||||||
font-family: Lato;
|
/*font-family: Lato;*/
|
||||||
|
font-weight: 300;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dcl-order-table-header {
|
.dcl-order-table-header {
|
||||||
|
@ -547,11 +551,16 @@ a.unlink:hover {
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-warning-content {
|
.card-warning-content {
|
||||||
font-family: Lato;
|
/*font-family: Lato;*/
|
||||||
|
font-weight: 300;
|
||||||
border: 1px solid #a1a1a1;
|
border: 1px solid #a1a1a1;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
}
|
}
|
||||||
|
.card-warning-error {
|
||||||
|
border: 1px solid #EB4D5C;
|
||||||
|
color: #EB4D5C;
|
||||||
|
}
|
||||||
|
|
||||||
.card-warning-addtional-margin {
|
.card-warning-addtional-margin {
|
||||||
margin-top: 15px;
|
margin-top: 15px;
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
font-family: 'Lato';
|
font-family: Lato, sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* ssh_keys_choice */
|
/* ssh_keys_choice */
|
||||||
.h1-thin {
|
.h1-thin {
|
||||||
font-family: Lato, sans-serif;
|
/*font-family: Lato, sans-serif;*/
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
font-size: 32px;
|
font-size: 32px;
|
||||||
}
|
}
|
||||||
|
@ -10,12 +10,12 @@
|
||||||
}
|
}
|
||||||
.dashboard-choice-container .page-header p {
|
.dashboard-choice-container .page-header p {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-family: Lato, sans-serif;
|
/*font-family: Lato, sans-serif;*/
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
}
|
}
|
||||||
.dashboard-choice-container h2 {
|
.dashboard-choice-container h2 {
|
||||||
font-family: Lato, sans-serif;
|
/*font-family: Lato, sans-serif;
|
||||||
font-weight: 400;
|
font-weight: 400;*/
|
||||||
font-size: 22px;
|
font-size: 22px;
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@
|
||||||
}
|
}
|
||||||
.choice-container p{
|
.choice-container p{
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
font-family: Lato, sans-serif;
|
/*font-family: Lato, sans-serif;*/
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
}
|
}
|
||||||
.choice-container-top {
|
.choice-container-top {
|
||||||
|
@ -119,7 +119,7 @@
|
||||||
color: #717274;
|
color: #717274;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
font-family: 'Lato';
|
/*font-family: 'Lato';*/
|
||||||
}
|
}
|
||||||
|
|
||||||
.borderless tbody:before {
|
.borderless tbody:before {
|
||||||
|
@ -195,7 +195,8 @@
|
||||||
border-bottom: 1px solid grey;
|
border-bottom: 1px solid grey;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
font-family: 'Lato-Light', sans-serif;
|
/*font-family: 'Lato-Light', sans-serif;*/
|
||||||
|
font-weight: 300;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
}
|
}
|
||||||
|
@ -203,57 +204,58 @@
|
||||||
.form_key_name::-webkit-input-placeholder{
|
.form_key_name::-webkit-input-placeholder{
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
font-weight:100;
|
font-weight:100;
|
||||||
font-family: 'Lato-Light', sans-serif;
|
/*font-family: 'Lato-Light', sans-serif;*/
|
||||||
|
font-weight: 300;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
.form_key_name::-moz-input-placeholder{
|
.form_key_name::-moz-input-placeholder{
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
font-weight:200;
|
/*font-family: 'Lato-Light', sans-serif;*/
|
||||||
font-family: 'Lato-Light', sans-serif;
|
font-weight: 300;
|
||||||
|
|
||||||
}
|
}
|
||||||
.form_key_name:-moz-input-placeholder{
|
.form_key_name:-moz-input-placeholder{
|
||||||
font-family: 'Lato-Light', sans-serif;
|
/*font-family: 'Lato-Light', sans-serif;*/
|
||||||
|
font-weight: 300;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
font-weight:200;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
.form_key_name:-ms-input-placeholder {
|
.form_key_name:-ms-input-placeholder {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
font-family: 'Lato-Light', sans-serif;
|
/*font-family: 'Lato-Light', sans-serif;*/
|
||||||
font-weight:200;
|
font-weight: 300;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form_public_key::-webkit-input-placeholder{
|
.form_public_key::-webkit-input-placeholder{
|
||||||
position: relative;
|
position: relative;
|
||||||
top: 110px;
|
top: 110px;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
font-weight: 200;
|
/*font-family: 'Lato-Light', sans-serif;*/
|
||||||
font-family: 'Lato-Light', sans-serif;
|
font-weight: 300;
|
||||||
|
|
||||||
}
|
}
|
||||||
.form_public_key::-moz-input-placeholder{
|
.form_public_key::-moz-input-placeholder{
|
||||||
position: relative;
|
position: relative;
|
||||||
top: 110px;
|
top: 110px;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
font-family: 'Lato-Light', sans-serif;
|
/*font-family: 'Lato-Light', sans-serif;*/
|
||||||
font-weight:200;
|
font-weight: 300;
|
||||||
|
|
||||||
}
|
}
|
||||||
.form_public_key:-moz-input-placeholder{
|
.form_public_key:-moz-input-placeholder{
|
||||||
position: relative;
|
position: relative;
|
||||||
top: 110px;
|
top: 110px;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
font-weight:200;
|
/*font-family: 'Lato-Light', sans-serif;*/
|
||||||
font-family: 'Lato-Light', sans-serif;
|
font-weight: 300;
|
||||||
}
|
}
|
||||||
.form_public_key:-ms-input-placeholder {
|
.form_public_key:-ms-input-placeholder {
|
||||||
position: relative;
|
position: relative;
|
||||||
top: 110px;
|
top: 110px;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
font-weight:200;
|
/*font-family: 'Lato-Light', sans-serif;*/
|
||||||
font-family: 'Lato-Light', sans-serif;
|
font-weight: 300;
|
||||||
}
|
}
|
||||||
.underform-contaner{
|
.underform-contaner{
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
|
@ -273,7 +275,8 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.underform-contaner h4{
|
.underform-contaner h4{
|
||||||
font-family: 'Lato-Light', sans-serif;
|
/*font-family: 'Lato-Light', sans-serif;*/
|
||||||
|
font-weight: 300;
|
||||||
}
|
}
|
||||||
.underform-contaner button{
|
.underform-contaner button{
|
||||||
/* font-family: Lato; */
|
/* font-family: Lato; */
|
||||||
|
@ -287,13 +290,16 @@
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
.control-label{
|
.control-label{
|
||||||
font-family: 'Lato-Light', sans-serif;
|
/*font-family: 'Lato-Light', sans-serif;*/
|
||||||
|
font-weight: 300;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
font-weight:200;
|
|
||||||
}
|
}
|
||||||
.form-ssh h3{
|
.form-ssh h3{
|
||||||
margin-bottom: 40px;
|
margin-bottom: 40px;
|
||||||
}
|
}
|
||||||
|
.key_contain {
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
.custom_form_button{
|
.custom_form_button{
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,6 @@
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{% 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'%}
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12 col-sm-7 col-md-6 creditcard-box dcl-creditcard">
|
<div class="col-xs-12 col-sm-7 col-md-6 creditcard-box dcl-creditcard">
|
||||||
|
@ -86,13 +85,29 @@
|
||||||
</form>
|
</form>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-12">
|
<div class="col-xs-12">
|
||||||
<p class="card-warning-content card-warning-addtional-margin">
|
{% if not messages and not form.non_field_errors %}
|
||||||
{% blocktrans %}
|
<p class="card-warning-content card-warning-addtional-margin">
|
||||||
You are not making any payment yet. After submitting your card
|
{% blocktrans %}
|
||||||
information, you will be taken to the Confirm Order Page.
|
You are not making any payment yet. After submitting your card
|
||||||
{% endblocktrans %}
|
information, you will be taken to the Confirm Order Page.
|
||||||
</p>
|
{% endblocktrans %}
|
||||||
</div>
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
<div id='payment_error'>
|
||||||
|
{% for message in messages %}
|
||||||
|
{% if 'failed_payment' or 'make_charge_error' in message.tags %}
|
||||||
|
<ul class="list-unstyled"><li>
|
||||||
|
<p class="card-warning-content card-warning-error">{{ message|safe }}</p>
|
||||||
|
</li></ul>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% for error in form.non_field_errors %}
|
||||||
|
<p class="card-warning-content card-warning-error">
|
||||||
|
{{ error|escape }}
|
||||||
|
</p>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="col-xs-12">
|
<div class="col-xs-12">
|
||||||
<div class="col-xs-6 pull-right">
|
<div class="col-xs-6 pull-right">
|
||||||
<button id="payment_button_with_creditcard" class="btn btn-success stripe-payment-btn"
|
<button id="payment_button_with_creditcard" class="btn btn-success stripe-payment-btn"
|
||||||
|
@ -130,12 +145,29 @@
|
||||||
<div id="card-errors" role="alert"></div>
|
<div id="card-errors" role="alert"></div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-12">
|
<div class="col-xs-12">
|
||||||
<p class="card-warning-content">
|
{% if not messages and not form.non_field_errors %}
|
||||||
{% blocktrans %}
|
<p class="card-warning-content">
|
||||||
You are not making any payment yet. After submitting your card
|
{% blocktrans %}
|
||||||
information, you will be taken to the Confirm Order Page.
|
You are not making any payment yet. After submitting your card
|
||||||
{% endblocktrans %}
|
information, you will be taken to the Confirm Order Page.
|
||||||
</p>
|
{% endblocktrans %}
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
<div id='payment_error'>
|
||||||
|
{% for message in messages %}
|
||||||
|
{% if 'failed_payment' or 'make_charge_error' in message.tags %}
|
||||||
|
<ul class="list-unstyled"><li>
|
||||||
|
<p class="card-warning-content card-warning-error">{{ message|safe }}</p>
|
||||||
|
</li></ul>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% for error in form.non_field_errors %}
|
||||||
|
<p class="card-warning-content card-warning-error">
|
||||||
|
{{ error|escape }}
|
||||||
|
</p>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12">
|
<div class="col-xs-12">
|
||||||
<div class="col-xs-6 pull-right">
|
<div class="col-xs-6 pull-right">
|
||||||
|
@ -150,15 +182,6 @@
|
||||||
<p class="payment-errors"></p>
|
<p class="payment-errors"></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% if paymentError %}
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-xs-12">
|
|
||||||
<p>
|
|
||||||
{% bootstrap_alert paymentError alert_type='danger' %}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -50,7 +50,7 @@
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div class="modal-icon"><i class="fa fa-trash" aria-hidden="true"></i></div>
|
<div class="modal-icon"><i class="fa fa-trash" aria-hidden="true"></i></div>
|
||||||
<h4 class="modal-title" id="ModalLabel">{% trans "Delete SSH Key"%}</h4>
|
<h4 class="modal-title" id="ModalLabel">{% trans "Delete SSH Key"%}</h4>
|
||||||
<p class="modal-text">{% trans "Do You want to delete this key?"%}</p>
|
<p class="modal-text">{% trans "Do you want to delete this key?"%}</p>
|
||||||
<form method="post" action="{% url 'hosting:delete_ssh_key' user_key.id %}">
|
<form method="post" action="{% url 'hosting:delete_ssh_key' user_key.id %}">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
|
@ -77,8 +77,8 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<h4 class="modal-title" id="ModalLabel_Public_Key">{% trans "Public ssh key" %}</h4>
|
<h4 class="modal-title" id="ModalLabel_Public_Key">{% trans "Public SSH key" %}</h4>
|
||||||
<p style="margin-top: 10px;">{{ user_key.public_key }}</p>
|
<p class="key_contain" style="margin-top: 10px;">{{ user_key.public_key }}</p>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
{% extends "hosting/base_short.html" %}
|
{% extends "hosting/base_short.html" %}
|
||||||
{% load staticfiles bootstrap3 i18n %}
|
{% load staticfiles bootstrap3 i18n %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div>
|
<div>
|
||||||
<div class="dashboard-container">
|
<div class="dashboard-container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-12 container-table">
|
<div class="col-xs-12 container-table">
|
||||||
<table class="table borderless table-hover">
|
<table class="table borderless table-hover">
|
||||||
<h3 class="pull-left"><i class="fa fa-server fa-separate" aria-hidden="true"></i> {% trans "Virtual Machines"%} </h3>
|
<h3 class="pull-left"><i class="fa fa-server fa-separate" aria-hidden="true"></i> {% trans "Virtual Machines"%}</h3>
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<br/>
|
<br/>
|
||||||
{% if messages %}
|
{% if messages %}
|
||||||
|
@ -19,12 +19,12 @@
|
||||||
</div>
|
</div>
|
||||||
{% if not error %}
|
{% if not error %}
|
||||||
<p class="pull-right btn-create-vm">
|
<p class="pull-right btn-create-vm">
|
||||||
<a class="btn btn-success" href="{% url 'hosting:create_virtual_machine' %}" >{% trans "Create VM"%} </a>
|
<a class="btn btn-success" href="{% url 'hosting:create_virtual_machine' %}" >{% trans "Create VM"%} </a>
|
||||||
</p>
|
</p>
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans "ID"%}</th>
|
<th>{% trans "ID"%}</th>
|
||||||
<th>{% trans "Ipv4"%}</th>
|
<th>{% trans "Ipv4"%}</th>
|
||||||
<th>{% trans "Ipv6"%}</th>
|
<th>{% trans "Ipv6"%}</th>
|
||||||
|
@ -32,36 +32,36 @@
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for vm in vms %}
|
{% for vm in vms %}
|
||||||
<tr>
|
<tr>
|
||||||
<td scope="row">{{vm.vm_id}}</td>
|
<td scope="row">{{vm.vm_id}}</td>
|
||||||
{% if vm.ipv6 %}
|
{% if vm.ipv6 %}
|
||||||
<td>{{vm.ipv4}}</td>
|
<td>{{vm.ipv4}}</td>
|
||||||
|
|
||||||
<td>{{vm.ipv6}}</td>
|
<td>{{vm.ipv6}}</td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
|
|
||||||
{% if vm.state == 'ACTIVE' %}
|
{% if vm.state == 'ACTIVE' %}
|
||||||
<span class="h3 label label-success"><strong> {{vm.state}}</strong></span>
|
<span class="h3 label label-success"><strong> {{vm.state}}</strong></span>
|
||||||
{% elif vm.state == 'FAILED' %}
|
{% elif vm.state == 'FAILED' %}
|
||||||
<span class="h3 label label-danger"><strong>{{vm.state}}</strong></span>
|
<span class="h3 label label-danger"><strong>{{vm.state}}</strong></span>
|
||||||
{% else %}
|
{% else %}
|
||||||
<span class="h3 label label-warning"><strong>{{vm.state}}</strong></span>
|
<span class="h3 label label-warning"><strong>{{vm.state}}</strong></span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<button type="button" class="btn btn-default"><a
|
<button type="button" class="btn btn-default"><a
|
||||||
href="{% url 'hosting:virtual_machines' vm.vm_id %}">{% trans "View Detail"%}</a></button>
|
href="{% url 'hosting:virtual_machines' vm.vm_id %}">{% trans "View Detail"%}</a></button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
</table>
|
||||||
|
|
||||||
{% if is_paginated %}
|
{% if is_paginated %}
|
||||||
<div class="pagination">
|
<div class="pagination">
|
||||||
|
@ -78,7 +78,7 @@
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -210,9 +210,9 @@ class SignupValidateView(TemplateView):
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(SignupValidateView, self).get_context_data(**kwargs)
|
context = super(SignupValidateView, self).get_context_data(**kwargs)
|
||||||
login_url = '<a href="' + \
|
login_url = '<a href="' + \
|
||||||
reverse('hosting:login') + '">' + str(_('login')) + '</a>'
|
reverse('hosting:login') + '">' + str(_('login')) + '</a>'
|
||||||
home_url = '<a href="' + \
|
home_url = '<a href="' + \
|
||||||
reverse('datacenterlight:index') + '">Data Center Light</a>'
|
reverse('datacenterlight:index') + '">Data Center Light</a>'
|
||||||
message = '{signup_success_message} {lurl}</a> \
|
message = '{signup_success_message} {lurl}</a> \
|
||||||
<br />{go_back} {hurl}.'.format(
|
<br />{go_back} {hurl}.'.format(
|
||||||
signup_success_message=_(
|
signup_success_message=_(
|
||||||
|
@ -234,7 +234,7 @@ class SignupValidatedView(SignupValidateView):
|
||||||
context = super(SignupValidateView, self).get_context_data(**kwargs)
|
context = super(SignupValidateView, self).get_context_data(**kwargs)
|
||||||
validated = CustomUser.validate_url(self.kwargs['validate_slug'])
|
validated = CustomUser.validate_url(self.kwargs['validate_slug'])
|
||||||
login_url = '<a href="' + \
|
login_url = '<a href="' + \
|
||||||
reverse('hosting:login') + '">' + str(_('login')) + '</a>'
|
reverse('hosting:login') + '">' + str(_('login')) + '</a>'
|
||||||
section_title = _('Account activation')
|
section_title = _('Account activation')
|
||||||
if validated:
|
if validated:
|
||||||
message = '{account_activation_string} <br /> {login_string} {lurl}.'.format(
|
message = '{account_activation_string} <br /> {login_string} {lurl}.'.format(
|
||||||
|
@ -244,7 +244,7 @@ class SignupValidatedView(SignupValidateView):
|
||||||
lurl=login_url)
|
lurl=login_url)
|
||||||
else:
|
else:
|
||||||
home_url = '<a href="' + \
|
home_url = '<a href="' + \
|
||||||
reverse('datacenterlight:index') + '">Data Center Light</a>'
|
reverse('datacenterlight:index') + '">Data Center Light</a>'
|
||||||
message = '{sorry_message} <br />{go_back_to} {hurl}'.format(
|
message = '{sorry_message} <br />{go_back_to} {hurl}'.format(
|
||||||
sorry_message=_("Sorry. Your request is invalid."),
|
sorry_message=_("Sorry. Your request is invalid."),
|
||||||
go_back_to=_('Go back to'),
|
go_back_to=_('Go back to'),
|
||||||
|
@ -342,6 +342,15 @@ class SSHKeyDeleteView(LoginRequiredMixin, DeleteView):
|
||||||
success_url = reverse_lazy('hosting:ssh_keys')
|
success_url = reverse_lazy('hosting:ssh_keys')
|
||||||
model = UserHostingKey
|
model = UserHostingKey
|
||||||
|
|
||||||
|
def get_object(self, queryset=None):
|
||||||
|
""" Hook to ensure UserHostingKey object is owned by request.user.
|
||||||
|
We reply with a Http404 if the user is not the owner of the key.
|
||||||
|
"""
|
||||||
|
obj = super(SSHKeyDeleteView, self).get_object()
|
||||||
|
if not obj.user == self.request.user:
|
||||||
|
raise Http404
|
||||||
|
return obj
|
||||||
|
|
||||||
def delete(self, request, *args, **kwargs):
|
def delete(self, request, *args, **kwargs):
|
||||||
owner = self.request.user
|
owner = self.request.user
|
||||||
manager = OpenNebulaManager()
|
manager = OpenNebulaManager()
|
||||||
|
@ -547,8 +556,9 @@ class PaymentVMView(LoginRequiredMixin, FormView):
|
||||||
customer = StripeCustomer.get_or_create(email=owner.email,
|
customer = StripeCustomer.get_or_create(email=owner.email,
|
||||||
token=token)
|
token=token)
|
||||||
if not customer:
|
if not customer:
|
||||||
form.add_error("__all__", "Invalid credit card")
|
msg = _("Invalid credit card")
|
||||||
return self.render_to_response(self.get_context_data(form=form))
|
messages.add_message(self.request, messages.ERROR, msg, extra_tags='make_charge_error')
|
||||||
|
return HttpResponseRedirect(reverse('hosting:payment') + '#payment_error')
|
||||||
|
|
||||||
# Create Billing Address
|
# Create Billing Address
|
||||||
billing_address = form.save()
|
billing_address = form.save()
|
||||||
|
@ -557,15 +567,12 @@ class PaymentVMView(LoginRequiredMixin, FormView):
|
||||||
stripe_utils = StripeUtils()
|
stripe_utils = StripeUtils()
|
||||||
charge_response = stripe_utils.make_charge(amount=final_price,
|
charge_response = stripe_utils.make_charge(amount=final_price,
|
||||||
customer=customer.stripe_id)
|
customer=customer.stripe_id)
|
||||||
charge = charge_response.get('response_object')
|
|
||||||
|
|
||||||
# Check if the payment was approved
|
# Check if the payment was approved
|
||||||
if not charge:
|
if not charge_response.get('response_object') and not charge_response.get('paid'):
|
||||||
context.update({
|
msg = charge_response.get('error')
|
||||||
'paymentError': charge_response.get('error'),
|
messages.add_message(self.request, messages.ERROR, msg, extra_tags='make_charge_error')
|
||||||
'form': form
|
return HttpResponseRedirect(reverse('hosting:payment') + '#payment_error')
|
||||||
})
|
|
||||||
return render(request, self.template_name, context)
|
|
||||||
|
|
||||||
charge = charge_response.get('response_object')
|
charge = charge_response.get('response_object')
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ REGISTRATION_MESSAGE = {'subject': "Validation mail",
|
||||||
'from': 'test@test.com'}
|
'from': 'test@test.com'}
|
||||||
|
|
||||||
|
|
||||||
def get_anonymous_user_instance():
|
def get_anonymous_user_instance(CustomUser):
|
||||||
return CustomUser(name='Anonymous', email='anonymous@ungleich.ch',
|
return CustomUser(name='Anonymous', email='anonymous@ungleich.ch',
|
||||||
validation_slug=make_password(None))
|
validation_slug=make_password(None))
|
||||||
|
|
||||||
|
@ -173,7 +173,6 @@ 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)
|
||||||
|
@ -189,7 +188,7 @@ class StripeCustomer(models.Model):
|
||||||
user = CustomUser.objects.get(email=email)
|
user = CustomUser.objects.get(email=email)
|
||||||
|
|
||||||
stripe_utils = StripeUtils()
|
stripe_utils = StripeUtils()
|
||||||
stripe_data = stripe_utils.create_customer(token, email)
|
stripe_data = stripe_utils.create_customer(token, email, user.name)
|
||||||
if stripe_data.get('response_object'):
|
if stripe_data.get('response_object'):
|
||||||
stripe_cus_id = stripe_data.get('response_object').get('id')
|
stripe_cus_id = stripe_data.get('response_object').get('id')
|
||||||
|
|
||||||
|
|
25
utils/migrations/0006_auto_20170810_1742.py
Normal file
25
utils/migrations/0006_auto_20170810_1742.py
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.9.4 on 2017-08-10 17:42
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('utils', '0005_auto_20170322_1443'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='billingaddress',
|
||||||
|
name='cardholder_name',
|
||||||
|
field=models.CharField(default='', max_length=100),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='userbillingaddress',
|
||||||
|
name='cardholder_name',
|
||||||
|
field=models.CharField(default='', max_length=100),
|
||||||
|
),
|
||||||
|
]
|
|
@ -11,7 +11,7 @@ def handleStripeError(f):
|
||||||
'error': None
|
'error': None
|
||||||
}
|
}
|
||||||
|
|
||||||
common_message = "Currently its not possible to make payments."
|
common_message = "Currently it's not possible to make payments."
|
||||||
try:
|
try:
|
||||||
response_object = f(*args, **kwargs)
|
response_object = f(*args, **kwargs)
|
||||||
response = {
|
response = {
|
||||||
|
@ -90,12 +90,12 @@ class StripeUtils(object):
|
||||||
def check_customer(self, id, user, token):
|
def check_customer(self, id, user, token):
|
||||||
customers = self.stripe.Customer.all()
|
customers = self.stripe.Customer.all()
|
||||||
if not customers.get('data'):
|
if not customers.get('data'):
|
||||||
customer = self.create_customer(token, user.email)
|
customer = self.create_customer(token, user.email, user.name)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
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.name)
|
||||||
user.stripecustomer.stripe_id = customer.get('response_object').get('id')
|
user.stripecustomer.stripe_id = customer.get('response_object').get('id')
|
||||||
user.stripecustomer.save()
|
user.stripecustomer.save()
|
||||||
return customer
|
return customer
|
||||||
|
@ -107,11 +107,12 @@ class StripeUtils(object):
|
||||||
return customer
|
return customer
|
||||||
|
|
||||||
@handleStripeError
|
@handleStripeError
|
||||||
def create_customer(self, token, email):
|
def create_customer(self, token, email, name=None):
|
||||||
|
if name is None or name.strip() == "":
|
||||||
|
name = email
|
||||||
customer = self.stripe.Customer.create(
|
customer = self.stripe.Customer.create(
|
||||||
source=token,
|
source=token,
|
||||||
description='description for testing',
|
description=name,
|
||||||
email=email
|
email=email
|
||||||
)
|
)
|
||||||
return customer
|
return customer
|
||||||
|
|
|
@ -3,6 +3,9 @@ from django.test import Client
|
||||||
from django.http.request import HttpRequest
|
from django.http.request import HttpRequest
|
||||||
|
|
||||||
from model_mommy import mommy
|
from model_mommy import mommy
|
||||||
|
from utils.stripe_utils import StripeUtils
|
||||||
|
import stripe
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
|
||||||
class BaseTestCase(TestCase):
|
class BaseTestCase(TestCase):
|
||||||
|
@ -11,7 +14,6 @@ class BaseTestCase(TestCase):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|
||||||
# Password
|
# Password
|
||||||
self.dummy_password = 'test_password'
|
self.dummy_password = 'test_password'
|
||||||
|
|
||||||
|
@ -83,3 +85,35 @@ class BaseTestCase(TestCase):
|
||||||
view.kwargs = kwargs
|
view.kwargs = kwargs
|
||||||
view.config = None
|
view.config = None
|
||||||
return view
|
return view
|
||||||
|
|
||||||
|
|
||||||
|
class TestStripeCustomerDescription(TestCase):
|
||||||
|
"""
|
||||||
|
A class to test setting the description field of the stripe customer
|
||||||
|
https://stripe.com/docs/api#metadata
|
||||||
|
"""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.dummy_password = 'test_password'
|
||||||
|
self.dummy_email = 'test@ungleich.ch'
|
||||||
|
self.customer = mommy.make('membership.CustomUser')
|
||||||
|
self.customer.set_password(self.dummy_password)
|
||||||
|
self.customer.email = self.dummy_email
|
||||||
|
self.customer.save()
|
||||||
|
stripe.api_key = settings.STRIPE_API_PRIVATE_KEY
|
||||||
|
|
||||||
|
def test_creating_stripe_customer(self):
|
||||||
|
test_name = "Monty Python"
|
||||||
|
token = stripe.Token.create(
|
||||||
|
card={
|
||||||
|
"number": '4111111111111111',
|
||||||
|
"exp_month": 12,
|
||||||
|
"exp_year": 2022,
|
||||||
|
"cvc": '123'
|
||||||
|
},
|
||||||
|
)
|
||||||
|
stripe_utils = StripeUtils()
|
||||||
|
stripe_data = stripe_utils.create_customer(token.id, self.customer.email, test_name)
|
||||||
|
self.assertEqual(stripe_data.get('error'), None)
|
||||||
|
customer_data = stripe_data.get('response_object')
|
||||||
|
self.assertEqual(customer_data.description, test_name)
|
||||||
|
|
Loading…
Reference in a new issue