Merged code from siarheipuhach/dynamicweb
This commit is contained in:
commit
c8cf166571
66 changed files with 372 additions and 419 deletions
|
|
@ -1,8 +1,4 @@
|
|||
from django.contrib import admin
|
||||
from django.utils.html import format_html
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
from utils.mailer import BaseEmail
|
||||
|
||||
from .models import HostingOrder, HostingBill, HostingPlan
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,11 @@
|
|||
import random
|
||||
import string
|
||||
from django import forms
|
||||
from membership.models import CustomUser
|
||||
from django.contrib.auth import authenticate
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from utils.stripe_utils import StripeUtils
|
||||
from .models import UserHostingKey
|
||||
|
||||
from .models import HostingOrder, UserHostingKey
|
||||
|
||||
class HostingUserLoginForm(forms.Form):
|
||||
|
||||
|
|
@ -62,9 +59,9 @@ class HostingUserSignupForm(forms.ModelForm):
|
|||
class UserHostingKeyForm(forms.ModelForm):
|
||||
private_key = forms.CharField(widget=forms.HiddenInput(), required=False)
|
||||
public_key = forms.CharField(widget=forms.Textarea(), required=False,
|
||||
help_text=_('Paste here your public key'))
|
||||
help_text=_('Paste here your public key'))
|
||||
user = forms.models.ModelChoiceField(queryset=CustomUser.objects.all(),
|
||||
required=False, widget=forms.HiddenInput())
|
||||
required=False, widget=forms.HiddenInput())
|
||||
name = forms.CharField(required=True)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.core.management.base import BaseCommand
|
||||
from hosting.models import VirtualMachineType
|
||||
|
||||
|
||||
|
|
@ -55,15 +55,15 @@ class Command(BaseCommand):
|
|||
},
|
||||
]
|
||||
|
||||
|
||||
hetzner = {
|
||||
'base_price': 10,
|
||||
'core_price': 5,
|
||||
'memory_price': 2,
|
||||
'disk_size_price': 0.6,
|
||||
'description': 'VM auf einzelner HW, Raid1, kein HA',
|
||||
'location': 'DE'
|
||||
}
|
||||
# not used
|
||||
# hetzner = {
|
||||
# 'base_price': 10,
|
||||
# 'core_price': 5,
|
||||
# 'memory_price': 2,
|
||||
# 'disk_size_price': 0.6,
|
||||
# 'description': 'VM auf einzelner HW, Raid1, kein HA',
|
||||
# 'location': 'DE'
|
||||
# }
|
||||
|
||||
# return {
|
||||
# # 'hetzner_nug': {
|
||||
|
|
|
|||
|
|
@ -1,22 +1,16 @@
|
|||
import os
|
||||
import socket
|
||||
import logging
|
||||
|
||||
|
||||
import oca
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.functional import cached_property
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
from Crypto.PublicKey import RSA
|
||||
from stored_messages.settings import stored_messages_settings
|
||||
|
||||
from membership.models import StripeCustomer, CustomUser
|
||||
from utils.models import BillingAddress
|
||||
from utils.mixins import AssignPermissionsMixin
|
||||
from .managers import VMPlansManager
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -29,7 +23,7 @@ class HostingPlan(models.Model):
|
|||
def serialize(self):
|
||||
return {
|
||||
'id': self.id,
|
||||
'cpu':self.cpu_cores,
|
||||
'cpu': self.cpu_cores,
|
||||
'memory': self.memory,
|
||||
'disk_size': self.disk_size,
|
||||
'price': self.price(),
|
||||
|
|
@ -46,6 +40,7 @@ class HostingPlan(models.Model):
|
|||
price += self.memory * 2
|
||||
return price
|
||||
|
||||
|
||||
class HostingOrder(AssignPermissionsMixin, models.Model):
|
||||
|
||||
ORDER_APPROVED_STATUS = 'Approved'
|
||||
|
|
@ -128,6 +123,7 @@ class UserHostingKey(models.Model):
|
|||
# self.save(update_fields=['public_key'])
|
||||
return private_key, public_key
|
||||
|
||||
|
||||
class HostingBill(AssignPermissionsMixin, models.Model):
|
||||
customer = models.ForeignKey(StripeCustomer)
|
||||
billing_address = models.ForeignKey(BillingAddress)
|
||||
|
|
@ -147,4 +143,3 @@ class HostingBill(AssignPermissionsMixin, models.Model):
|
|||
def create(cls, customer=None, billing_address=None):
|
||||
instance = cls.objects.create(customer=customer, billing_address=billing_address)
|
||||
return instance
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{% extends "hosting/base_short.html" %}
|
||||
{% load staticfiles bootstrap3 i18n %}
|
||||
{% block content %}
|
||||
{% block content %}
|
||||
<!-- Credit card form -->
|
||||
<div>
|
||||
<div class="payment-container">
|
||||
|
|
@ -32,7 +32,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="col-xs-12 col-md-4 billing">
|
||||
<h3><b>{%trans "Billing Address"%}</b></h3>
|
||||
|
|
@ -59,7 +59,7 @@
|
|||
<h5 class="membership-lead">Last 4: *****{{credit_card_data.last4}}</h5>
|
||||
<h5 class="membership-lead">Type: {{credit_card_data.cc_brand}}</h5>
|
||||
<input type="hidden" name="credit_card_needed" value="false"/>
|
||||
</form>
|
||||
</form>
|
||||
<div class="col-xs-6">
|
||||
<button id="payment_button_with_creditcard" class="btn btn-success btn-sm btn-block" type="submit">
|
||||
{% trans "Submit Payment" %}
|
||||
|
|
@ -89,7 +89,7 @@
|
|||
placeholder="{%trans "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>
|
||||
<div class="row">
|
||||
|
|
@ -131,7 +131,7 @@
|
|||
</div>
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
</form>
|
||||
{% endif %}
|
||||
|
||||
|
|
@ -146,7 +146,7 @@
|
|||
<!-- stripe key data -->
|
||||
{% if stripe_key %}
|
||||
{% get_current_language as LANGUAGE_CODE %}
|
||||
<script type="text/javascript">
|
||||
<script type="text/javascript">
|
||||
|
||||
|
||||
(function () {
|
||||
|
|
@ -157,7 +157,7 @@
|
|||
{%endif%}
|
||||
|
||||
{% if credit_card_data.last4 and credit_card_data.cc_brand %}
|
||||
<script type="text/javascript">
|
||||
<script type="text/javascript">
|
||||
(function () {window.hasCreditcard = true;})();
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from django.test import TestCase
|
|||
from django.core.urlresolvers import reverse
|
||||
from django.core.urlresolvers import resolve
|
||||
from django.contrib.auth.tokens import default_token_generator
|
||||
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
|
||||
from django.utils.http import urlsafe_base64_encode
|
||||
from django.utils.encoding import force_bytes
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
from django.test import TestCase
|
||||
# from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
|
||||
test_user_can_add_ssh_key()
|
||||
|
||||
test_user_can_delete_ssh_ke()
|
||||
# test_user_can_add_ssh_key()
|
||||
#
|
||||
# test_user_can_delete_ssh_ke()
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
from collections import namedtuple
|
||||
|
||||
from oca.pool import WrongNameError, WrongIdError
|
||||
from django.shortcuts import render
|
||||
from django.http import Http404
|
||||
from django.core.urlresolvers import reverse_lazy, reverse
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.views.generic import View, CreateView, FormView, ListView, DetailView,\
|
||||
from django.views.generic import View, CreateView, FormView, ListView, DetailView, \
|
||||
DeleteView, TemplateView, UpdateView
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.contrib.auth import authenticate, login
|
||||
from django.contrib import messages
|
||||
from django.conf import settings
|
||||
from django.shortcuts import redirect
|
||||
|
|
@ -30,14 +28,11 @@ from .forms import HostingUserSignupForm, HostingUserLoginForm, UserHostingKeyFo
|
|||
from .mixins import ProcessVMSelectionMixin
|
||||
|
||||
from opennebula_api.models import OpenNebulaManager
|
||||
from opennebula_api.serializers import VirtualMachineSerializer,\
|
||||
from opennebula_api.serializers import VirtualMachineSerializer, \
|
||||
VirtualMachineTemplateSerializer
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
||||
from oca.exceptions import OpenNebulaException
|
||||
from oca.pool import WrongNameError, WrongIdError
|
||||
|
||||
CONNECTION_ERROR = "Your VMs cannot be displayed at the moment due to a backend \
|
||||
connection error. please try again in a few minutes."
|
||||
|
||||
|
|
@ -142,7 +137,6 @@ class HostingPricingView(ProcessVMSelectionMixin, View):
|
|||
'templates': templates,
|
||||
'configuration_options': configuration_options,
|
||||
|
||||
|
||||
}
|
||||
|
||||
return context
|
||||
|
|
@ -173,7 +167,6 @@ class IndexView(View):
|
|||
return context
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
|
||||
context = self.get_context_data()
|
||||
|
||||
return render(request, self.template_name, context)
|
||||
|
|
@ -205,44 +198,48 @@ class SignupView(CreateView):
|
|||
|
||||
return HttpResponseRedirect(reverse_lazy('hosting:signup-validate'))
|
||||
|
||||
|
||||
class SignupValidateView(TemplateView):
|
||||
template_name = "hosting/signup_validate.html"
|
||||
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(SignupValidateView, self).get_context_data(**kwargs)
|
||||
login_url = '<a href="' + reverse('hosting:login') + '">' + str(_('login')) +'</a>'
|
||||
login_url = '<a href="' + reverse('hosting:login') + '">' + str(_('login')) + '</a>'
|
||||
home_url = '<a href="' + reverse('datacenterlight:index') + '">Data Center Light</a>'
|
||||
message='{signup_success_message} {lurl}</a> \
|
||||
message = '{signup_success_message} {lurl}</a> \
|
||||
<br />{go_back} {hurl}.'.format(
|
||||
signup_success_message = _('Thank you for signing up. We have sent an email to you. Please follow the instructions in it to activate your account. Once activated, you can login using'),
|
||||
go_back = _('Go back to'),
|
||||
lurl = login_url,
|
||||
hurl = home_url
|
||||
)
|
||||
signup_success_message=_(
|
||||
'Thank you for signing up. We have sent an email to you. '
|
||||
'Please follow the instructions in it to activate your account. Once activated, you can login using'),
|
||||
go_back=_('Go back to'),
|
||||
lurl=login_url,
|
||||
hurl=home_url
|
||||
)
|
||||
context['message'] = mark_safe(message)
|
||||
context['section_title'] = _('Sign up')
|
||||
return context
|
||||
|
||||
|
||||
class SignupValidatedView(SignupValidateView):
|
||||
template_name = "hosting/signup_validate.html"
|
||||
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(SignupValidateView, self).get_context_data(**kwargs)
|
||||
validated = CustomUser.validate_url(self.kwargs['validate_slug'])
|
||||
login_url = '<a href="' + reverse('hosting:login') + '">' + str(_('login')) +'</a>'
|
||||
section_title=_('Account activation')
|
||||
login_url = '<a href="' + reverse('hosting:login') + '">' + str(_('login')) + '</a>'
|
||||
section_title = _('Account activation')
|
||||
if validated:
|
||||
message='{account_activation_string} <br /> {login_string} {lurl}.'.format(
|
||||
account_activation_string = _("Your account has been activated."),
|
||||
login_string = _("You can now"),
|
||||
lurl = login_url)
|
||||
message = '{account_activation_string} <br /> {login_string} {lurl}.'.format(
|
||||
account_activation_string=_("Your account has been activated."),
|
||||
login_string=_("You can now"),
|
||||
lurl=login_url)
|
||||
else:
|
||||
home_url = '<a href="' + reverse('datacenterlight:index') + '">Data Center Light</a>'
|
||||
message = '{sorry_message} <br />{go_back_to} {hurl}'.format(
|
||||
sorry_message = _("Sorry. Your request is invalid."),
|
||||
go_back_to = _('Go back to'),
|
||||
hurl = home_url
|
||||
)
|
||||
sorry_message=_("Sorry. Your request is invalid."),
|
||||
go_back_to=_('Go back to'),
|
||||
hurl=home_url
|
||||
)
|
||||
context['message'] = mark_safe(message)
|
||||
context['section_title'] = section_title
|
||||
return context
|
||||
|
|
@ -351,6 +348,7 @@ class SSHKeyDeleteView(LoginRequiredMixin, DeleteView):
|
|||
|
||||
return super(SSHKeyDeleteView, self).delete(request, *args, **kwargs)
|
||||
|
||||
|
||||
class SSHKeyListView(LoginRequiredMixin, ListView):
|
||||
template_name = "hosting/user_keys.html"
|
||||
login_url = reverse_lazy('hosting:login')
|
||||
|
|
@ -359,7 +357,6 @@ class SSHKeyListView(LoginRequiredMixin, ListView):
|
|||
paginate_by = 10
|
||||
ordering = '-id'
|
||||
|
||||
|
||||
def get_queryset(self):
|
||||
user = self.request.user
|
||||
self.queryset = UserHostingKey.objects.filter(user=user)
|
||||
|
|
@ -379,7 +376,6 @@ class SSHKeyCreateView(LoginRequiredMixin, FormView):
|
|||
context_object_name = "virtual_machine"
|
||||
success_url = reverse_lazy('hosting:ssh_keys')
|
||||
|
||||
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super(SSHKeyCreateView, self).get_form_kwargs()
|
||||
kwargs.update({'request': self.request})
|
||||
|
|
@ -476,7 +472,7 @@ class PaymentVMView(LoginRequiredMixin, FormView):
|
|||
return context
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
if not UserHostingKey.objects.filter( user=self.request.user).exists():
|
||||
if not UserHostingKey.objects.filter(user=self.request.user).exists():
|
||||
messages.success(
|
||||
request,
|
||||
'In order to create a VM, you create/upload your SSH KEY first.'
|
||||
|
|
@ -538,7 +534,7 @@ class PaymentVMView(LoginRequiredMixin, FormView):
|
|||
manager = OpenNebulaManager(email=owner.email,
|
||||
password=owner.password)
|
||||
# Get user ssh key
|
||||
if not UserHostingKey.objects.filter( user=self.request.user).exists():
|
||||
if not UserHostingKey.objects.filter(user=self.request.user).exists():
|
||||
context.update({
|
||||
'sshError': 'error',
|
||||
'form': form
|
||||
|
|
@ -546,8 +542,8 @@ class PaymentVMView(LoginRequiredMixin, FormView):
|
|||
return render(request, self.template_name, context)
|
||||
# For now just get first one
|
||||
user_key = UserHostingKey.objects.filter(
|
||||
user=self.request.user).first()
|
||||
|
||||
user=self.request.user).first()
|
||||
|
||||
# Create a vm using logged user
|
||||
vm_id = manager.create_vm(
|
||||
template_id=vm_template_id,
|
||||
|
|
@ -565,8 +561,9 @@ class PaymentVMView(LoginRequiredMixin, FormView):
|
|||
)
|
||||
|
||||
# Create a Hosting Bill
|
||||
bill = HostingBill.create(
|
||||
customer=customer, billing_address=billing_address)
|
||||
# variable bill is not used
|
||||
# bill = HostingBill.create(
|
||||
# customer=customer, billing_address=billing_address)
|
||||
|
||||
# Create Billing Address for User if he does not have one
|
||||
if not customer.user.billing_addresses.count():
|
||||
|
|
@ -699,7 +696,7 @@ class CreateVirtualMachinesView(LoginRequiredMixin, View):
|
|||
|
||||
def get(self, request, *args, **kwargs):
|
||||
|
||||
if not UserHostingKey.objects.filter( user=self.request.user).exists():
|
||||
if not UserHostingKey.objects.filter(user=self.request.user).exists():
|
||||
messages.success(
|
||||
request,
|
||||
'In order to create a VM, you need to create/upload your SSH KEY first.'
|
||||
|
|
@ -723,7 +720,7 @@ class CreateVirtualMachinesView(LoginRequiredMixin, View):
|
|||
)
|
||||
context = {
|
||||
'error': 'connection'
|
||||
}
|
||||
}
|
||||
|
||||
return render(request, self.template_name, context)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue