Merge branch 'master' into master

This commit is contained in:
Polycarp Okock 2017-07-07 22:37:58 +03:00 committed by GitHub
commit e551ba911b
68 changed files with 420 additions and 455 deletions

View file

@ -8,4 +8,6 @@ env:
- DJANGO_SECRET_KEY=0 - DJANGO_SECRET_KEY=0
# install dependencies # install dependencies
install: "pip install -r requirements.txt" install: "pip install -r requirements.txt"
script: python manage.py test script:
- flake8
- python manage.py test

View file

@ -1,3 +1,3 @@
from django.contrib import admin # from django.contrib import admin
# Register your models here. # Register your models here.

View file

@ -1,3 +1,3 @@
from django.db import models # from django.db import models
# Create your models here. # Create your models here.

View file

@ -1,3 +1,3 @@
from django.test import TestCase # from django.test import TestCase
# Create your tests here. # Create your tests here.

View file

@ -7,6 +7,6 @@ urlpatterns = [
url(r'^/?$', IndexView.as_view(), name='index'), url(r'^/?$', IndexView.as_view(), name='index'),
url(r'/login/', LoginView.as_view(), name='login'), url(r'/login/', LoginView.as_view(), name='login'),
url(r'/contact', ContactView.as_view(), name='contact'), url(r'/contact', ContactView.as_view(), name='contact'),
# url(r'^/beta-program/?$', BetaProgramView.as_view(), name='beta'), # url(r'^/beta-program/?$', BetaProgramView.as_view(), name='beta'),
# url(r'^/landing/?$', LandingProgramView.as_view(), name='landing'), # url(r'^/landing/?$', LandingProgramView.as_view(), name='landing'),
] ]

View file

@ -4,11 +4,11 @@ from django.utils.translation import get_language, get_language_info
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.views.generic.edit import FormView from django.views.generic.edit import FormView
from django.contrib import messages from django.contrib import messages
from django.core.urlresolvers import reverse_lazy, reverse
from django.shortcuts import render from django.shortcuts import render
from utils.forms import ContactUsForm from utils.forms import ContactUsForm
class IndexView(TemplateView): class IndexView(TemplateView):
template_name = "alplora/index.html" template_name = "alplora/index.html"
@ -18,6 +18,7 @@ class IndexView(TemplateView):
context.update(languages) context.update(languages)
return context return context
class ContactView(FormView): class ContactView(FormView):
template_name = 'alplora/contact.html' template_name = 'alplora/contact.html'
form_class = ContactUsForm form_class = ContactUsForm
@ -35,6 +36,7 @@ class ContactView(FormView):
messages.add_message(self.request, messages.SUCCESS, self.success_message) messages.add_message(self.request, messages.SUCCESS, self.success_message)
return render(self.request, 'alplora/contact_success.html', {}) return render(self.request, 'alplora/contact_success.html', {})
class LoginView(TemplateView): class LoginView(TemplateView):
template_name = "alplora/login.html" template_name = "alplora/login.html"

View file

@ -1,6 +1,6 @@
from django import forms from django import forms
from .models import BetaAccess, BetaAccessVM from .models import BetaAccess
class BetaAccessForm(forms.ModelForm): class BetaAccessForm(forms.ModelForm):

View file

@ -826,6 +826,7 @@ tech-sub-sec h2 {
margin-top: 20px; margin-top: 20px;
font-size: 20px; font-size: 20px;
width: 200px; width: 200px;
border: none;
} }
.price-calc-section .card .select-configuration select{ .price-calc-section .card .select-configuration select{
outline: none; outline: none;

View file

@ -5,24 +5,23 @@ from django.utils.translation import activate, get_language
register = template.Library() register = template.Library()
@register.simple_tag(takes_context=True) @register.simple_tag(takes_context=True)
def change_lang(context, lang=None, *args, **kwargs): def change_lang(context, lang=None, *args, **kwargs):
path = context['request'].path path = context['request'].path
url_parts = resolve( path ) url_parts = resolve(path)
url = path url = path
cur_language = get_language() cur_language = get_language()
try: try:
activate(lang) activate(lang)
url = reverse( url_parts.view_name, kwargs=url_parts.kwargs ) url = reverse(url_parts.view_name, kwargs=url_parts.kwargs)
finally: finally:
activate(cur_language) activate(cur_language)
return "%s" % url return "%s" % url
@register.filter('get_value_from_dict') @register.filter('get_value_from_dict')
def get_value_from_dict(dict_data, key): def get_value_from_dict(dict_data, key):
""" """
@ -30,5 +29,5 @@ def get_value_from_dict(dict_data, key):
""" """
if key: if key:
return dict_data.get(key) return dict_data.get(key)
else : else:
return "" return ""

View file

@ -1,3 +1,3 @@
from django.test import TestCase # from django.test import TestCase
# Create your tests here. # Create your tests here.

View file

@ -1,6 +1,7 @@
from django.conf.urls import url from django.conf.urls import url
from .views import IndexView, BetaProgramView, LandingProgramView, BetaAccessView, PricingView, SuccessView, PaymentOrderView, OrderConfirmationView, WhyDataCenterLightView from .views import IndexView, BetaProgramView, LandingProgramView, BetaAccessView, PricingView, SuccessView, \
PaymentOrderView, OrderConfirmationView, WhyDataCenterLightView
urlpatterns = [ urlpatterns = [

View file

@ -3,7 +3,7 @@ from django.http import HttpResponseRedirect
from .forms import BetaAccessForm from .forms import BetaAccessForm
from .models import BetaAccess, BetaAccessVMType, BetaAccessVM from .models import BetaAccess, BetaAccessVMType, BetaAccessVM
from django.contrib import messages from django.contrib import messages
from django.core.urlresolvers import reverse_lazy, reverse from django.core.urlresolvers import reverse
from django.core.mail import EmailMessage 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
@ -15,7 +15,6 @@ 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, UserBillingAddressForm from utils.forms import BillingAddressForm, UserBillingAddressForm
from utils.models import BillingAddress from utils.models import BillingAddress
from membership.models import StripeCustomer
from hosting.models import HostingOrder, HostingBill from hosting.models import HostingOrder, HostingBill
from utils.stripe_utils import StripeUtils from utils.stripe_utils import StripeUtils
from datetime import datetime from datetime import datetime
@ -24,9 +23,11 @@ from membership.models import CustomUser, StripeCustomer
from opennebula_api.models import OpenNebulaManager from opennebula_api.models import OpenNebulaManager
from opennebula_api.serializers import VirtualMachineTemplateSerializer, VirtualMachineSerializer from opennebula_api.serializers import VirtualMachineTemplateSerializer, VirtualMachineSerializer
class LandingProgramView(TemplateView): class LandingProgramView(TemplateView):
template_name = "datacenterlight/landing.html" template_name = "datacenterlight/landing.html"
class SuccessView(TemplateView): class SuccessView(TemplateView):
template_name = "datacenterlight/success.html" template_name = "datacenterlight/success.html"
@ -38,11 +39,13 @@ class SuccessView(TemplateView):
elif 'order_confirmation' not in request.session: elif 'order_confirmation' not in request.session:
return HttpResponseRedirect(reverse('datacenterlight:order_confirmation')) return HttpResponseRedirect(reverse('datacenterlight:order_confirmation'))
else: else:
for session_var in ['specs', 'user', 'template', 'billing_address', 'billing_address_data', 'token', 'customer']: for session_var in ['specs', 'user', 'template', 'billing_address', 'billing_address_data',
'token', 'customer']:
if session_var in request.session: if session_var in request.session:
del request.session[session_var] del request.session[session_var]
return render(request, self.template_name) return render(request, self.template_name)
class PricingView(TemplateView): class PricingView(TemplateView):
template_name = "datacenterlight/pricing.html" template_name = "datacenterlight/pricing.html"
@ -55,17 +58,16 @@ class PricingView(TemplateView):
'templates': VirtualMachineTemplateSerializer(templates, many=True).data, 'templates': VirtualMachineTemplateSerializer(templates, many=True).data,
} }
except: except:
messages.error( request, messages.error(request,
'We have a temporary problem to connect to our backend. \ 'We have a temporary problem to connect to our backend. \
Please try again in a few minutes' Please try again in a few minutes'
) )
context = { context = {
'error' : 'connection' 'error': 'connection'
} }
return render(request, self.template_name, context) return render(request, self.template_name, context)
def post(self, request): def post(self, request):
cores = request.POST.get('cpu') cores = request.POST.get('cpu')
@ -74,7 +76,6 @@ class PricingView(TemplateView):
price = request.POST.get('total') price = request.POST.get('total')
template_id = int(request.POST.get('config')) template_id = int(request.POST.get('config'))
manager = OpenNebulaManager() manager = OpenNebulaManager()
template = manager.get_template(template_id) template = manager.get_template(template_id)
@ -84,7 +85,7 @@ class PricingView(TemplateView):
request.session['next'] = reverse('hosting:payment') request.session['next'] = reverse('hosting:payment')
request.session['specs'] = { request.session['specs'] = {
'cpu':cores, 'cpu': cores,
'memory': memory, 'memory': memory,
'disk_size': storage, 'disk_size': storage,
'price': price, 'price': price,
@ -99,7 +100,6 @@ class BetaAccessView(FormView):
success_message = "Thank you, we will contact you as soon as possible" success_message = "Thank you, we will contact you as soon as possible"
def form_valid(self, form): def form_valid(self, form):
context = { context = {
'base_url': "{0}://{1}".format(self.request.scheme, self.request.get_host()) 'base_url': "{0}://{1}".format(self.request.scheme, self.request.get_host())
} }
@ -134,6 +134,7 @@ class BetaAccessView(FormView):
messages.add_message(self.request, messages.SUCCESS, self.success_message) messages.add_message(self.request, messages.SUCCESS, self.success_message)
return render(self.request, 'datacenterlight/beta_success.html', {}) return render(self.request, 'datacenterlight/beta_success.html', {})
class BetaProgramView(CreateView): class BetaProgramView(CreateView):
template_name = "datacenterlight/beta.html" template_name = "datacenterlight/beta.html"
model = BetaAccessVM model = BetaAccessVM
@ -185,6 +186,7 @@ class BetaProgramView(CreateView):
messages.add_message(self.request, messages.SUCCESS, self.success_message) messages.add_message(self.request, messages.SUCCESS, self.success_message)
return HttpResponseRedirect(self.get_success_url()) return HttpResponseRedirect(self.get_success_url())
class IndexView(CreateView): class IndexView(CreateView):
template_name = "datacenterlight/index.html" template_name = "datacenterlight/index.html"
model = BetaAccess model = BetaAccess
@ -204,13 +206,13 @@ class IndexView(CreateView):
'templates': VirtualMachineTemplateSerializer(templates, many=True).data 'templates': VirtualMachineTemplateSerializer(templates, many=True).data
} }
except: except:
messages.error( request, messages.error(request,
'We have a temporary problem to connect to our backend. \ 'We have a temporary problem to connect to our backend. \
Please try again in a few minutes' Please try again in a few minutes'
) )
context = { context = {
'error' : 'connection' 'error': 'connection'
} }
return render(request, self.template_name, context) return render(request, self.template_name, context)
def post(self, request): def post(self, request):
@ -230,14 +232,14 @@ class IndexView(CreateView):
try: try:
name = name_field.clean(name) name = name_field.clean(name)
except ValidationError as err: except ValidationError as err:
msg='{} {}.'.format(name, _('is not a proper name')) msg = '{} {}.'.format(name, _('is not a proper name'))
messages.add_message(self.request, messages.ERROR, msg, extra_tags='name') messages.add_message(self.request, messages.ERROR, msg, extra_tags='name')
return HttpResponseRedirect(reverse('datacenterlight:index') + "#order_form") return HttpResponseRedirect(reverse('datacenterlight:index') + "#order_form")
try: try:
email = email_field.clean(email) email = email_field.clean(email)
except ValidationError as err: except ValidationError as err:
msg='{} {}.'.format(email, _('is not a proper email')) msg = '{} {}.'.format(email, _('is not a proper email'))
messages.add_message(self.request, messages.ERROR, msg, extra_tags='email') messages.add_message(self.request, messages.ERROR, msg, extra_tags='email')
return HttpResponseRedirect(reverse('datacenterlight:index') + "#order_form") return HttpResponseRedirect(reverse('datacenterlight:index') + "#order_form")
@ -306,6 +308,7 @@ class IndexView(CreateView):
messages.add_message(self.request, messages.SUCCESS, self.success_message) messages.add_message(self.request, messages.SUCCESS, self.success_message)
return super(IndexView, self).form_valid(form) return super(IndexView, self).form_valid(form)
class WhyDataCenterLightView(IndexView): class WhyDataCenterLightView(IndexView):
template_name = "datacenterlight/whydatacenterlight.html" template_name = "datacenterlight/whydatacenterlight.html"
model = BetaAccess model = BetaAccess
@ -319,15 +322,17 @@ class WhyDataCenterLightView(IndexView):
'templates': VirtualMachineTemplateSerializer(templates, many=True).data, 'templates': VirtualMachineTemplateSerializer(templates, many=True).data,
} }
except: except:
messages.error( request, messages.error(
request,
'We have a temporary problem to connect to our backend. \ 'We have a temporary problem to connect to our backend. \
Please try again in a few minutes' Please try again in a few minutes'
) )
context = { context = {
'error' : 'connection' 'error': 'connection'
} }
return render(request, self.template_name, context) return render(request, self.template_name, context)
class PaymentOrderView(FormView): class PaymentOrderView(FormView):
template_name = 'hosting/payment.html' template_name = 'hosting/payment.html'
form_class = BillingAddressForm form_class = BillingAddressForm
@ -346,7 +351,6 @@ class PaymentOrderView(FormView):
}) })
return form_kwargs return form_kwargs
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(PaymentOrderView, self).get_context_data(**kwargs) context = super(PaymentOrderView, self).get_context_data(**kwargs)
context.update({ context.update({
@ -368,9 +372,8 @@ class PaymentOrderView(FormView):
billing_address_data = form.cleaned_data billing_address_data = form.cleaned_data
token = form.cleaned_data.get('token') token = form.cleaned_data.get('token')
user = request.session.get('user') user = request.session.get('user')
try: try:
custom_user = CustomUser.objects.get(email=user.get('email')) CustomUser.objects.get(email=user.get('email'))
except CustomUser.DoesNotExist: except CustomUser.DoesNotExist:
password = CustomUser.get_random_password() password = CustomUser.get_random_password()
# Register the user, and do not send emails # Register the user, and do not send emails
@ -397,6 +400,7 @@ class PaymentOrderView(FormView):
else: else:
return self.form_invalid(form) return self.form_invalid(form)
class OrderConfirmationView(DetailView): class OrderConfirmationView(DetailView):
template_name = "datacenterlight/order_detail.html" template_name = "datacenterlight/order_detail.html"
payment_template_name = 'hosting/payment.html' payment_template_name = 'hosting/payment.html'
@ -415,8 +419,8 @@ class OrderConfirmationView(DetailView):
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'))
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'),
'cc_brand' : card_details.get('response_object').get('brand') 'cc_brand': card_details.get('response_object').get('brand')
} }
return render(request, self.template_name, context) return render(request, self.template_name, context)
@ -429,7 +433,6 @@ class OrderConfirmationView(DetailView):
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() billing_address = BillingAddress.objects.filter(id=billing_address_id).first()
token = request.session.get('token')
vm_template_id = template.get('id', 1) vm_template_id = template.get('id', 1)
final_price = specs.get('price') final_price = specs.get('price')
@ -441,10 +444,9 @@ class OrderConfirmationView(DetailView):
# Check if the payment was approved # Check if the payment was approved
if not charge: if not charge:
context = {}
context.update({ context.update({
'paymentError': charge_response.get('error') 'paymentError': charge_response.get('error')
# TODO add logic in payment form to autofill data
#'form': form
}) })
return render(request, self.payment_template_name, context) return render(request, self.payment_template_name, context)
@ -473,7 +475,7 @@ class OrderConfirmationView(DetailView):
) )
# Create a Hosting Bill # Create a Hosting Bill
bill = HostingBill.create( HostingBill.create(
customer=customer, billing_address=billing_address) customer=customer, billing_address=billing_address)
# Create Billing Address for User if he does not have one # Create Billing Address for User if he does not have one

View file

@ -1,5 +1,5 @@
from django.contrib import admin from django.contrib import admin
from .models import Supporter, DGGallery, DGPicture, Booking, BookingPrice,\ from .models import DGGallery, DGPicture, Booking, BookingPrice,\
MembershipOrder, Membership, MembershipType, BookingOrder, BookingCancellation MembershipOrder, Membership, MembershipType, BookingOrder, BookingCancellation
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse

View file

@ -1,9 +1,9 @@
from cms.plugin_base import CMSPluginBase from cms.plugin_base import CMSPluginBase
from cms.plugin_pool import plugin_pool from cms.plugin_pool import plugin_pool
from cms.wizards import wizard_base
from .models import DGGalleryPlugin, DGSupportersPlugin, Supporter from .models import DGGalleryPlugin, DGSupportersPlugin, Supporter
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
#
class CMSGalleryPlugin(CMSPluginBase): class CMSGalleryPlugin(CMSPluginBase):
model = DGGalleryPlugin model = DGGalleryPlugin
name = _("Digital Glarus Gallery") name = _("Digital Glarus Gallery")
@ -11,12 +11,13 @@ class CMSGalleryPlugin(CMSPluginBase):
def render(self, context, instance, placeholder): def render(self, context, instance, placeholder):
context.update({ context.update({
'gallery':instance.dgGallery, 'gallery': instance.dgGallery,
'object':instance, 'object': instance,
'placeholder':placeholder 'placeholder': placeholder
}) })
return context return context
class CMSSupportersPlugin(CMSPluginBase): class CMSSupportersPlugin(CMSPluginBase):
name = _("Digital Glarus Supporters") name = _("Digital Glarus Supporters")
model = DGSupportersPlugin model = DGSupportersPlugin
@ -26,11 +27,10 @@ class CMSSupportersPlugin(CMSPluginBase):
context.update({ context.update({
'supporters': Supporter.objects.all().order_by('name'), 'supporters': Supporter.objects.all().order_by('name'),
'object': instance, 'object': instance,
'placeholder':placeholder 'placeholder': placeholder
}) })
return context return context
#
#
#
plugin_pool.register_plugin(CMSGalleryPlugin) plugin_pool.register_plugin(CMSGalleryPlugin)
plugin_pool.register_plugin(CMSSupportersPlugin) plugin_pool.register_plugin(CMSSupportersPlugin)

View file

@ -1,7 +1,6 @@
from django import forms from django import forms
from django.db.models import Q from django.db.models import Q
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from datetime import datetime
from utils.models import BillingAddress from utils.models import BillingAddress
@ -92,7 +91,7 @@ class CancelBookingForm(forms.ModelForm):
class BookingDateForm(forms.Form): class BookingDateForm(forms.Form):
start_date = forms.DateField(required=False, start_date = forms.DateField(required=False,
widget=forms.TextInput(attrs={'id': 'booking-date-1', widget=forms.TextInput(attrs={'id': 'booking-date-1',
'value': 'Select your date'})) 'value': 'Select your date'}))
end_date = forms.DateField(required=False, end_date = forms.DateField(required=False,
widget=forms.TextInput(attrs={'id': 'booking-date-2'})) widget=forms.TextInput(attrs={'id': 'booking-date-2'}))

View file

@ -3,6 +3,7 @@ from django.conf import settings
import stripe import stripe
stripe.api_key = settings.STRIPE_API_PRIVATE_KEY stripe.api_key = settings.STRIPE_API_PRIVATE_KEY
class Command(BaseCommand): class Command(BaseCommand):
help = "Record payment plans for Digital Glarus on stripe" help = "Record payment plans for Digital Glarus on stripe"
@ -10,5 +11,3 @@ class Command(BaseCommand):
print("Available plans:") print("Available plans:")
for plan in stripe.Plan.all(): for plan in stripe.Plan.all():
print(plan) print(plan)

View file

@ -11,11 +11,11 @@ PAYMENT_PLANS = [
'id': "spontaneus" 'id': "spontaneus"
}), }),
('committed', { ('committed', {
'amount':36000, 'amount': 36000,
'interval':'year', 'interval': 'year',
'name':'The Committed', 'name': 'The Committed',
'currency':'chf', 'currency': 'chf',
'id':'committed' 'id': 'committed'
}) })
] ]
@ -26,8 +26,6 @@ class Command(BaseCommand):
def handle(self, *args, **options): def handle(self, *args, **options):
for payment_plan, data in PAYMENT_PLANS: for payment_plan, data in PAYMENT_PLANS:
try: try:
res = stripe.Plan.create(**data) stripe.Plan.create(**data)
except stripe.InvalidRequestError as e: except stripe.InvalidRequestError as e:
print(e) print(e)

View file

@ -105,7 +105,7 @@ class Membership(models.Model):
has_order_current_month = Q(membershiporder__customer__user=user, has_order_current_month = Q(membershiporder__customer__user=user,
membershiporder__created_at__month=datetime.today().month) membershiporder__created_at__month=datetime.today().month)
# has_order_past_month = Q(membershiporder__customer__user=user, # has_order_past_month = Q(membershiporder__customer__user=user,
# membershiporder__created_at__month=past_month) # membershiporder__created_at__month=past_month)
active_membership = Q(active=True) active_membership = Q(active=True)
# return cls.objects.filter(has_order_past_month | has_order_current_month).\ # return cls.objects.filter(has_order_past_month | has_order_current_month).\
return cls.objects.filter(has_order_current_month).\ return cls.objects.filter(has_order_current_month).\
@ -316,17 +316,20 @@ class DGGallery(models.Model):
class Meta: class Meta:
verbose_name_plural = 'dgGallery' verbose_name_plural = 'dgGallery'
#
class DGPicture(models.Model): class DGPicture(models.Model):
gallery = models.ForeignKey(DGGallery) gallery = models.ForeignKey(DGGallery)
image = FilerImageField(related_name='dg_gallery') image = FilerImageField(related_name='dg_gallery')
description = models.CharField(max_length=60) description = models.CharField(max_length=60)
def __str__(self): def __str__(self):
return "%s" % (self.image.name) return "%s" % (self.image.name)
class DGGalleryPlugin(CMSPlugin): class DGGalleryPlugin(CMSPlugin):
dgGallery = models.ForeignKey(DGGallery) dgGallery = models.ForeignKey(DGGallery)
class DGSupportersPlugin(CMSPlugin): class DGSupportersPlugin(CMSPlugin):
pass pass

View file

@ -1,4 +1,3 @@
import json
from model_mommy import mommy from model_mommy import mommy
from unittest import mock from unittest import mock
@ -150,7 +149,7 @@ class MembershipPaymentViewTest(BaseTestCase):
# self.assertTrue(HostingOrder.objects.filter(customer=stripe_customer).exists()) # self.assertTrue(HostingOrder.objects.filter(customer=stripe_customer).exists())
# hosting_order = HostingOrder.objects.filter(customer=stripe_customer)[0] # hosting_order = HostingOrder.objects.filter(customer=stripe_customer)[0]
# vm_plan = { # vm_plan = {
# 'cores': hosting_order.vm_plan.cores, # 'cores': hosting_order.vm_plan.cores,
# 'memory': hosting_order.vm_plan.memory, # 'memory': hosting_order.vm_plan.memory,
# 'disk_size': hosting_order.vm_plan.disk_size, # 'disk_size': hosting_order.vm_plan.disk_size,
# 'price': hosting_order.vm_plan.price, # 'price': hosting_order.vm_plan.price,

View file

@ -720,7 +720,9 @@ class ContactView(FormView):
messages.add_message(self.request, messages.SUCCESS, self.success_message) messages.add_message(self.request, messages.SUCCESS, self.success_message)
return super(ContactView, self).form_valid(form) return super(ContactView, self).form_valid(form)
############## OLD VIEWS
# OLD VIEWS
def blog(request): def blog(request):
tags = ["digitalglarus"] tags = ["digitalglarus"]
@ -751,6 +753,3 @@ def supporters(request):
'supporters': Supporter.objects.order_by('name') 'supporters': Supporter.objects.order_by('name')
} }
return render(request, 'supporters.html', context) return render(request, 'supporters.html', context)

View file

@ -9,12 +9,15 @@ from django.utils.translation import ugettext_lazy as _
# dotenv # dotenv
import dotenv import dotenv
gettext = lambda s: s
def gettext(s):
return s
def env(env_name): def env(env_name):
return os.environ.get(env_name) return os.environ.get(env_name)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
PROJECT_DIR = os.path.abspath( PROJECT_DIR = os.path.abspath(
@ -83,7 +86,7 @@ INSTALLED_APPS = (
'django_select2', 'django_select2',
'meta', 'meta',
'meta_mixin', 'meta_mixin',
# 'admin_enhancer', # 'admin_enhancer',
'djangocms_blog', 'djangocms_blog',
'bootstrap3', 'bootstrap3',
'compressor', 'compressor',
@ -433,5 +436,5 @@ MANAGERS = ADMINS
ALLOWED_HOSTS = [ ALLOWED_HOSTS = [
".ungleich.ch", ".ungleich.ch",
"digital.glarus.ungleich.ch" , "digital.glarus.ungleich.ch",
] ]

View file

@ -1 +1 @@
from .base import * from .base import * # flake8: noqa

View file

@ -11,13 +11,20 @@ from django.utils.translation import ugettext_lazy as _
# dotenv # dotenv
import dotenv import dotenv
gettext = lambda s: s
def gettext(s):
return s
def env(env_name): def env(env_name):
return os.environ.get(env_name) return os.environ.get(env_name)
def bool_env(val):
"""Replaces string based environment values with Python booleans"""
return True if os.environ.get(val, False) == 'True' else False
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
PROJECT_DIR = os.path.abspath( PROJECT_DIR = os.path.abspath(
@ -465,19 +472,13 @@ STRIPE_DESCRIPTION_ON_PAYMENT = "Payment for ungleich GmbH services"
# EMAIL MESSAGES # EMAIL MESSAGES
REGISTRATION_MESSAGE = {'subject': "Validation mail", REGISTRATION_MESSAGE = {'subject': "Validation mail",
'message': 'Thank You for registering for account on Digital Glarus.\nPlease verify Your account under following link http://{host}/en-us/digitalglarus/login/validate/{slug}', 'message': 'Thank You for registering for account on Digital Glarus.\n'
'Please verify Your account under following link '
'http://{host}/en-us/digitalglarus/login/validate/{slug}',
} }
STRIPE_API_PRIVATE_KEY = env('STRIPE_API_PRIVATE_KEY') STRIPE_API_PRIVATE_KEY = env('STRIPE_API_PRIVATE_KEY')
STRIPE_API_PUBLIC_KEY = env('STRIPE_API_PUBLIC_KEY') STRIPE_API_PUBLIC_KEY = env('STRIPE_API_PUBLIC_KEY')
DEBUG = True
if DEBUG:
from .local import *
else:
from .prod import *
ANONYMOUS_USER_NAME = 'anonymous@ungleich.ch' ANONYMOUS_USER_NAME = 'anonymous@ungleich.ch'
GUARDIAN_GET_INIT_ANONYMOUS_USER = 'membership.models.get_anonymous_user_instance' GUARDIAN_GET_INIT_ANONYMOUS_USER = 'membership.models.get_anonymous_user_instance'
@ -521,3 +522,10 @@ GOOGLE_ANALYTICS_PROPERTY_IDS = {
'dynamicweb-development.ungleich.ch': 'development', 'dynamicweb-development.ungleich.ch': 'development',
'dynamicweb-staging.ungleich.ch': 'staging' 'dynamicweb-staging.ungleich.ch': 'staging'
} }
DEBUG = bool_env('DEBUG')
if DEBUG:
from .local import * # flake8: noqa
else:
from .prod import * # flake8: noqa

View file

@ -1,5 +1,7 @@
from .base import * from .base import * # flake8: noqa
REGISTRATION_MESSAGE['message'] = REGISTRATION_MESSAGE['message'].format(host='dynamicweb-development.ungleich.ch',slug='{slug}')
REGISTRATION_MESSAGE['message'] = REGISTRATION_MESSAGE['message'].format(host='dynamicweb-development.ungleich.ch',
slug='{slug}')
ALLOWED_HOSTS = [ ALLOWED_HOSTS = [
"*" "*"
] ]
@ -13,9 +15,9 @@ CACHES = {
} }
} }
MIDDLEWARE_CLASSES+=("debug_toolbar.middleware.DebugToolbarMiddleware",) MIDDLEWARE_CLASSES += ("debug_toolbar.middleware.DebugToolbarMiddleware",)
INSTALLED_APPS+=( INSTALLED_APPS += (
'django_extensions', 'django_extensions',
'debug_toolbar' 'debug_toolbar'
) )

View file

@ -1,15 +1,23 @@
from .base import * from .base import * # flake8: noqa
# List of people that get admin messages # List of people that get admin messages
ADMINS = ( (x, x + "@ungleich.ch") for x in ["web-team"] ) ADMINS = ((x, x + "@ungleich.ch") for x in ["web-team"])
DEBUG=False DEBUG = False
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
#MANAGERS = ADMINS CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
}
}
REGISTRATION_MESSAGE['message'] = REGISTRATION_MESSAGE['message'].format(host='digitalglarus.ungleich.ch',slug='{slug}') # MANAGERS = ADMINS
REGISTRATION_MESSAGE['message'] = REGISTRATION_MESSAGE['message'].format(host='digitalglarus.ungleich.ch',
slug='{slug}') # flake8: noqa
ALLOWED_HOSTS = [ ALLOWED_HOSTS = [
".ungleich.ch", ".ungleich.ch",

View file

@ -12,42 +12,42 @@ from django.views.generic import RedirectView
from django.core.urlresolvers import reverse_lazy from django.core.urlresolvers import reverse_lazy
import debug_toolbar import debug_toolbar
urlpatterns = [ url(r'^index.html$', LandingView.as_view()), urlpatterns = [url(r'^index.html$', LandingView.as_view()),
url(r'^hosting/', include('hosting.urls', namespace="hosting")), url(r'^hosting/', include('hosting.urls', namespace="hosting")),
url(r'^open_api/', include('opennebula_api.urls', url(r'^open_api/', include('opennebula_api.urls',
namespace='opennebula_api')), namespace='opennebula_api')),
url(r'^railshosting/', RailsHostingView.as_view(), name="rails.hosting"), url(r'^railshosting/', RailsHostingView.as_view(), name="rails.hosting"),
url(r'^nodehosting/', NodeJSHostingView.as_view(), name="node.hosting"), url(r'^nodehosting/', NodeJSHostingView.as_view(), name="node.hosting"),
url(r'^djangohosting/', DjangoHostingView.as_view(), name="django.hosting"), url(r'^djangohosting/', DjangoHostingView.as_view(), name="django.hosting"),
url(r'^nosystemd/', include('nosystemd.urls', namespace="nosystemd")), url(r'^nosystemd/', include('nosystemd.urls', namespace="nosystemd")),
url(r'^taggit_autosuggest/', include('taggit_autosuggest.urls')), url(r'^taggit_autosuggest/', include('taggit_autosuggest.urls')),
url(r'^jsi18n/(?P<packages>\S+?)/$', url(r'^jsi18n/(?P<packages>\S+?)/$',
'django.views.i18n.javascript_catalog'), 'django.views.i18n.javascript_catalog'),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
# note the django CMS URLs included via i18n_patterns # note the django CMS URLs included via i18n_patterns
urlpatterns += i18n_patterns('', urlpatterns += i18n_patterns('',
url(r'^/?$', LandingView.as_view()), url(r'^/?$', LandingView.as_view()),
url(r'^admin/', include(admin.site.urls)), url(r'^admin/', include(admin.site.urls)),
url(r'^datacenterlight', include('datacenterlight.urls', namespace="datacenterlight")), url(r'^datacenterlight', include('datacenterlight.urls', namespace="datacenterlight")),
url(r'^hosting/', RedirectView.as_view(url=reverse_lazy('hosting:login')), name='redirect_hosting_login'), url(r'^hosting/', RedirectView.as_view(
url=reverse_lazy('hosting:login')), name='redirect_hosting_login'),
url(r'^alplora', include('alplora.urls', namespace="alplora")), url(r'^alplora', include('alplora.urls', namespace="alplora")),
url(r'^membership/', include(membership_urls)), url(r'^membership/', include(membership_urls)),
url(r'^digitalglarus/', include('digitalglarus.urls', url(r'^digitalglarus/', include('digitalglarus.urls',
namespace="digitalglarus")), namespace="digitalglarus")),
#url(r'^blog/', include('ungleich.urls', namespace='ungleich')), # url(r'^blog/', include('ungleich.urls', namespace='ungleich')),
url(r'^', url(r'^',
include('ungleich_page.urls', namespace='ungleich_page'), include('ungleich_page.urls', namespace='ungleich_page'),
name='ungleich_page'), name='ungleich_page'),
url(r'^blog/', include('ungleich.urls', namespace='ungleich')), url(r'^blog/', include('ungleich.urls', namespace='ungleich')),
url(r'^', include('cms.urls')) url(r'^', include('cms.urls'))
) )
urlpatterns += patterns('',
url(r'^media/(?P<path>.*)$',
'django.views.static.serve', {
'document_root': settings.MEDIA_ROOT,
}),
)
if settings.DEBUG: if settings.DEBUG:
urlpatterns += patterns('', urlpatterns += patterns('', url(r'^__debug__/', include(debug_toolbar.urls)))
url(r'^media/(?P<path>.*)$',
'django.views.static.serve', {
'document_root': settings.MEDIA_ROOT,
}),
)
urlpatterns += patterns('',url(r'^__debug__/', include(debug_toolbar.urls)))

View file

@ -7,13 +7,13 @@ For more information on this file, see
https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/ https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/
""" """
import os,sys import os
#sys.path.append(os.path.dirname(__file__)) import sys
from django.core.wsgi import get_wsgi_application
# sys.path.append(os.path.dirname(__file__))
sys.path.append('/home/app/pyvenv/lib/python3.4/site-packages/') sys.path.append('/home/app/pyvenv/lib/python3.4/site-packages/')
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dynamicweb.settings.prod") os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dynamicweb.settings.prod")
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application() application = get_wsgi_application()

View file

@ -1,8 +1,4 @@
from django.contrib import admin 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 from .models import HostingOrder, HostingBill, HostingPlan

View file

@ -1,14 +1,11 @@
import random
import string
from django import forms from django import forms
from membership.models import CustomUser from membership.models import CustomUser
from django.contrib.auth import authenticate from django.contrib.auth import authenticate
from django.utils.translation import ugettext_lazy as _ 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): class HostingUserLoginForm(forms.Form):
@ -62,9 +59,9 @@ class HostingUserSignupForm(forms.ModelForm):
class UserHostingKeyForm(forms.ModelForm): class UserHostingKeyForm(forms.ModelForm):
private_key = forms.CharField(widget=forms.HiddenInput(), required=False) private_key = forms.CharField(widget=forms.HiddenInput(), required=False)
public_key = forms.CharField(widget=forms.Textarea(), 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(), user = forms.models.ModelChoiceField(queryset=CustomUser.objects.all(),
required=False, widget=forms.HiddenInput()) required=False, widget=forms.HiddenInput())
name = forms.CharField(required=True) name = forms.CharField(required=True)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):

View file

@ -1,4 +1,4 @@
from django.core.management.base import BaseCommand, CommandError from django.core.management.base import BaseCommand
from hosting.models import VirtualMachineType from hosting.models import VirtualMachineType
@ -55,15 +55,15 @@ class Command(BaseCommand):
}, },
] ]
# not used
hetzner = { # hetzner = {
'base_price': 10, # 'base_price': 10,
'core_price': 5, # 'core_price': 5,
'memory_price': 2, # 'memory_price': 2,
'disk_size_price': 0.6, # 'disk_size_price': 0.6,
'description': 'VM auf einzelner HW, Raid1, kein HA', # 'description': 'VM auf einzelner HW, Raid1, kein HA',
'location': 'DE' # 'location': 'DE'
} # }
# return { # return {
# # 'hetzner_nug': { # # 'hetzner_nug': {

View file

@ -1,22 +1,16 @@
import os import os
import socket
import logging import logging
import oca
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.conf import settings
from Crypto.PublicKey import RSA from Crypto.PublicKey import RSA
from stored_messages.settings import stored_messages_settings
from membership.models import StripeCustomer, CustomUser from membership.models import StripeCustomer, CustomUser
from utils.models import BillingAddress from utils.models import BillingAddress
from utils.mixins import AssignPermissionsMixin from utils.mixins import AssignPermissionsMixin
from .managers import VMPlansManager
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -29,7 +23,7 @@ class HostingPlan(models.Model):
def serialize(self): def serialize(self):
return { return {
'id': self.id, 'id': self.id,
'cpu':self.cpu_cores, 'cpu': self.cpu_cores,
'memory': self.memory, 'memory': self.memory,
'disk_size': self.disk_size, 'disk_size': self.disk_size,
'price': self.price(), 'price': self.price(),
@ -46,6 +40,7 @@ class HostingPlan(models.Model):
price += self.memory * 2 price += self.memory * 2
return price return price
class HostingOrder(AssignPermissionsMixin, models.Model): class HostingOrder(AssignPermissionsMixin, models.Model):
ORDER_APPROVED_STATUS = 'Approved' ORDER_APPROVED_STATUS = 'Approved'
@ -128,6 +123,7 @@ class UserHostingKey(models.Model):
# self.save(update_fields=['public_key']) # self.save(update_fields=['public_key'])
return private_key, public_key return private_key, public_key
class HostingBill(AssignPermissionsMixin, models.Model): class HostingBill(AssignPermissionsMixin, models.Model):
customer = models.ForeignKey(StripeCustomer) customer = models.ForeignKey(StripeCustomer)
billing_address = models.ForeignKey(BillingAddress) billing_address = models.ForeignKey(BillingAddress)
@ -147,4 +143,3 @@ class HostingBill(AssignPermissionsMixin, models.Model):
def create(cls, customer=None, billing_address=None): def create(cls, customer=None, billing_address=None):
instance = cls.objects.create(customer=customer, billing_address=billing_address) instance = cls.objects.create(customer=customer, billing_address=billing_address)
return instance return instance

View file

@ -64,6 +64,7 @@
<h5 class="membership-lead">Type: {{credit_card_data.cc_brand}}</h5> <h5 class="membership-lead">Type: {{credit_card_data.cc_brand}}</h5>
<input type="hidden" name="credit_card_needed" value="false"/> <input type="hidden" name="credit_card_needed" value="false"/>
</form> </form>
<div class="row"> <div class="row">
<br> <br>
<div> <div>
@ -72,6 +73,10 @@
<div class="col-xs-6 pull-right"> <div class="col-xs-6 pull-right">
<button style="width: 100px; float: right; font-style: normal; font-weight: bold; position: absolute; right: 0;" id="payment_button_with_creditcard" class="btn btn-success" type="submit"> <button style="width: 100px; float: right; font-style: normal; font-weight: bold; position: absolute; right: 0;" id="payment_button_with_creditcard" class="btn btn-success" type="submit">
{% trans "Place Order" %} {% trans "Place Order" %}
<div class="col-xs-6">
<button id="payment_button_with_creditcard" class="btn btn-success btn-sm btn-block" type="submit">
{% trans "Submit Payment" %}
</button> </button>
</div> </div>
</div> </div>

View file

@ -4,7 +4,7 @@ from django.test import TestCase
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.core.urlresolvers import resolve from django.core.urlresolvers import resolve
from django.contrib.auth.tokens import default_token_generator 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 from django.utils.encoding import force_bytes

View file

@ -1,7 +1,7 @@
from django.test import TestCase # from django.test import TestCase
# Create your tests here. # Create your tests here.
test_user_can_add_ssh_key() # test_user_can_add_ssh_key()
#
test_user_can_delete_ssh_ke() # test_user_can_delete_ssh_ke()

View file

@ -1,13 +1,11 @@
from collections import namedtuple from oca.pool import WrongNameError, WrongIdError
from django.shortcuts import render from django.shortcuts import render
from django.http import Http404 from django.http import Http404
from django.core.urlresolvers import reverse_lazy, reverse from django.core.urlresolvers import reverse_lazy, reverse
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import View, CreateView, FormView, ListView, DetailView,\ from django.views.generic import View, CreateView, FormView, ListView, DetailView, \
DeleteView, TemplateView, UpdateView DeleteView, TemplateView, UpdateView
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.contrib.auth import authenticate, login
from django.contrib import messages from django.contrib import messages
from django.conf import settings from django.conf import settings
from django.shortcuts import redirect from django.shortcuts import redirect
@ -30,14 +28,11 @@ from .forms import HostingUserSignupForm, HostingUserLoginForm, UserHostingKeyFo
from .mixins import ProcessVMSelectionMixin from .mixins import ProcessVMSelectionMixin
from opennebula_api.models import OpenNebulaManager from opennebula_api.models import OpenNebulaManager
from opennebula_api.serializers import VirtualMachineSerializer,\ from opennebula_api.serializers import VirtualMachineSerializer, \
VirtualMachineTemplateSerializer VirtualMachineTemplateSerializer
from django.utils.translation import ugettext_lazy as _ 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 = "Your VMs cannot be displayed at the moment due to a backend \
connection error. please try again in a few minutes." connection error. please try again in a few minutes."
@ -142,7 +137,6 @@ class HostingPricingView(ProcessVMSelectionMixin, View):
'templates': templates, 'templates': templates,
'configuration_options': configuration_options, 'configuration_options': configuration_options,
} }
return context return context
@ -173,7 +167,6 @@ class IndexView(View):
return context return context
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
context = self.get_context_data() context = self.get_context_data()
return render(request, self.template_name, context) return render(request, self.template_name, context)
@ -205,44 +198,48 @@ class SignupView(CreateView):
return HttpResponseRedirect(reverse_lazy('hosting:signup-validate')) return HttpResponseRedirect(reverse_lazy('hosting:signup-validate'))
class SignupValidateView(TemplateView): class SignupValidateView(TemplateView):
template_name = "hosting/signup_validate.html" template_name = "hosting/signup_validate.html"
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="' + 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>' 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( <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'), signup_success_message=_(
go_back = _('Go back to'), 'Thank you for signing up. We have sent an email to you. '
lurl = login_url, 'Please follow the instructions in it to activate your account. Once activated, you can login using'),
hurl = home_url go_back=_('Go back to'),
) lurl=login_url,
hurl=home_url
)
context['message'] = mark_safe(message) context['message'] = mark_safe(message)
context['section_title'] = _('Sign up') context['section_title'] = _('Sign up')
return context return context
class SignupValidatedView(SignupValidateView): class SignupValidatedView(SignupValidateView):
template_name = "hosting/signup_validate.html" template_name = "hosting/signup_validate.html"
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)
validated = CustomUser.validate_url(self.kwargs['validate_slug']) validated = CustomUser.validate_url(self.kwargs['validate_slug'])
login_url = '<a href="' + reverse('hosting:login') + '">' + str(_('login')) +'</a>' login_url = '<a href="' + 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(
account_activation_string = _("Your account has been activated."), account_activation_string=_("Your account has been activated."),
login_string = _("You can now"), login_string=_("You can now"),
lurl = login_url) lurl=login_url)
else: else:
home_url = '<a href="' + reverse('datacenterlight:index') + '">Data Center Light</a>' home_url = '<a href="' + 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'),
hurl = home_url hurl=home_url
) )
context['message'] = mark_safe(message) context['message'] = mark_safe(message)
context['section_title'] = section_title context['section_title'] = section_title
return context return context
@ -351,6 +348,7 @@ class SSHKeyDeleteView(LoginRequiredMixin, DeleteView):
return super(SSHKeyDeleteView, self).delete(request, *args, **kwargs) return super(SSHKeyDeleteView, self).delete(request, *args, **kwargs)
class SSHKeyListView(LoginRequiredMixin, ListView): class SSHKeyListView(LoginRequiredMixin, ListView):
template_name = "hosting/user_keys.html" template_name = "hosting/user_keys.html"
login_url = reverse_lazy('hosting:login') login_url = reverse_lazy('hosting:login')
@ -359,7 +357,6 @@ class SSHKeyListView(LoginRequiredMixin, ListView):
paginate_by = 10 paginate_by = 10
ordering = '-id' ordering = '-id'
def get_queryset(self): def get_queryset(self):
user = self.request.user user = self.request.user
self.queryset = UserHostingKey.objects.filter(user=user) self.queryset = UserHostingKey.objects.filter(user=user)
@ -379,7 +376,6 @@ class SSHKeyCreateView(LoginRequiredMixin, FormView):
context_object_name = "virtual_machine" context_object_name = "virtual_machine"
success_url = reverse_lazy('hosting:ssh_keys') success_url = reverse_lazy('hosting:ssh_keys')
def get_form_kwargs(self): def get_form_kwargs(self):
kwargs = super(SSHKeyCreateView, self).get_form_kwargs() kwargs = super(SSHKeyCreateView, self).get_form_kwargs()
kwargs.update({'request': self.request}) kwargs.update({'request': self.request})
@ -476,7 +472,7 @@ class PaymentVMView(LoginRequiredMixin, FormView):
return context return context
def get(self, request, *args, **kwargs): 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( messages.success(
request, request,
'In order to create a VM, you create/upload your SSH KEY first.' '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, manager = OpenNebulaManager(email=owner.email,
password=owner.password) password=owner.password)
# Get user ssh key # 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({ context.update({
'sshError': 'error', 'sshError': 'error',
'form': form 'form': form
@ -546,7 +542,7 @@ class PaymentVMView(LoginRequiredMixin, FormView):
return render(request, self.template_name, context) return render(request, self.template_name, context)
# For now just get first one # For now just get first one
user_key = UserHostingKey.objects.filter( user_key = UserHostingKey.objects.filter(
user=self.request.user).first() user=self.request.user).first()
# Create a vm using logged user # Create a vm using logged user
vm_id = manager.create_vm( vm_id = manager.create_vm(
@ -565,8 +561,8 @@ class PaymentVMView(LoginRequiredMixin, FormView):
) )
# Create a Hosting Bill # Create a Hosting Bill
bill = HostingBill.create( HostingBill.create(
customer=customer, billing_address=billing_address) customer=customer, billing_address=billing_address)
# Create Billing Address for User if he does not have one # Create Billing Address for User if he does not have one
if not customer.user.billing_addresses.count(): if not customer.user.billing_addresses.count():
@ -699,7 +695,7 @@ class CreateVirtualMachinesView(LoginRequiredMixin, View):
def get(self, request, *args, **kwargs): 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( messages.success(
request, request,
'In order to create a VM, you need to create/upload your SSH KEY first.' 'In order to create a VM, you need to create/upload your SSH KEY first.'

View file

@ -38,26 +38,26 @@ class CustomHTMLCalendar(CustomCalendar):
self.requested_month = requested_month self.requested_month = requested_month
super(CustomHTMLCalendar, self).__init__() super(CustomHTMLCalendar, self).__init__()
def formatday(self, day, weekday, month=None,year=None): def formatday(self, day, weekday, month=None, year=None):
""" """
Return a day as a table cell. Return a day as a table cell.
""" """
booked = CalendarModel.objects.filter(user_id=self.user.id) booked = CalendarModel.objects.filter(user_id=self.user.id)
is_booked= booked.filter(datebooked=datetime.date(day=day,month=month,year=year)) is_booked = booked.filter(datebooked=datetime.date(day=day, month=month, year=year))
if month < int(self.requested_month): if month < int(self.requested_month):
return '<td class="prev-month %s">%d</td>' % ("selected" if is_booked else "",day) return '<td class="prev-month %s">%d</td>' % ("selected" if is_booked else "", day)
elif month > int(self.requested_month): elif month > int(self.requested_month):
return '<td class="next-month %s">%d</td>' % ("selected" if is_booked else "",day) return '<td class="next-month %s">%d</td>' % ("selected" if is_booked else "", day)
else: else:
return '<td class="%s">%d</td>' % ("selected" if is_booked else "",day) return '<td class="%s">%d</td>' % ("selected" if is_booked else "", day)
def formatweek(self, theweek,year): def formatweek(self, theweek, year):
""" """
Return a complete week as a table row. Return a complete week as a table row.
""" """
s = ''.join(self.formatday(d, wd, month,year) for (d, wd, month) in theweek) s = ''.join(self.formatday(d, wd, month, year) for (d, wd, month) in theweek)
return '<tr>%s</tr>' % s return '<tr>%s</tr>' % s
def formatmonthname(self, theyear, themonth, withyear=True): def formatmonthname(self, theyear, themonth, withyear=True):
@ -93,7 +93,7 @@ class CustomHTMLCalendar(CustomCalendar):
a(self.formatweekheader()) a(self.formatweekheader())
a('\n') a('\n')
for week in self.monthdays2calendar(theyear, themonth): for week in self.monthdays2calendar(theyear, themonth):
a(self.formatweek(week,theyear)) a(self.formatweek(week, theyear))
a('\n') a('\n')
a('</table>') a('</table>')
a('\n') a('\n')
@ -102,8 +102,8 @@ class CustomHTMLCalendar(CustomCalendar):
class BookCalendar(CustomHTMLCalendar): class BookCalendar(CustomHTMLCalendar):
def __init__(self, user,requested_month): def __init__(self, user, requested_month):
self.user=user self.user = user
super(BookCalendar, self).__init__(requested_month) super(BookCalendar, self).__init__(requested_month)
def formatmonth(self, year, month): def formatmonth(self, year, month):
@ -111,7 +111,7 @@ class BookCalendar(CustomHTMLCalendar):
return super(BookCalendar, self).formatmonth(year, month) return super(BookCalendar, self).formatmonth(year, month)
def day_cell(self, cssclass, body): def day_cell(self, cssclass, body):
return '<td>%s</td>' % body return '<td>%s</td>' % body
def formatmonthname(self, theyear, themonth, withyear): def formatmonthname(self, theyear, themonth, withyear):
""" """

View file

@ -1,7 +1,7 @@
__author__ = 'tomislav' __author__ = 'tomislav'
from django import forms from django import forms
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.contrib.auth import authenticate,login from django.contrib.auth import authenticate
from .models import CreditCards from .models import CreditCards
@ -25,7 +25,7 @@ class LoginForm(forms.Form):
raise forms.ValidationError("Sorry, that login was invalid. Please try again.") raise forms.ValidationError("Sorry, that login was invalid. Please try again.")
return self.cleaned_data return self.cleaned_data
def login(self,request): def login(self, request):
username = self.cleaned_data.get('email') username = self.cleaned_data.get('email')
password = self.cleaned_data.get('password') password = self.cleaned_data.get('password')
user = authenticate(email=username, password=password) user = authenticate(email=username, password=password)
@ -36,6 +36,7 @@ class RegisterForm(SignupFormMixin):
password = forms.CharField(widget=forms.PasswordInput()) password = forms.CharField(widget=forms.PasswordInput())
confirm_password = forms.CharField(widget=forms.PasswordInput()) confirm_password = forms.CharField(widget=forms.PasswordInput())
class PaymentForm(forms.ModelForm): class PaymentForm(forms.ModelForm):
class Meta: class Meta:
model = CreditCards model = CreditCards
@ -58,7 +59,7 @@ class PaymentForm(forms.ModelForm):
# if CreditCards.objects.filter(card_number=data.get("card_number")): # if CreditCards.objects.filter(card_number=data.get("card_number")):
# raise forms.ValidationError({'card_number': _('Credit card is used before.')}) # raise forms.ValidationError({'card_number': _('Credit card is used before.')})
return self.cleaned_data return data
def save(self, user_id): def save(self, user_id):
self.instance.user_id = user_id self.instance.user_id = user_id

View file

@ -1,10 +1,9 @@
from datetime import datetime from datetime import datetime
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.models import User, AbstractBaseUser, BaseUserManager, AbstractUser, PermissionsMixin from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
from django.contrib.auth.hashers import make_password from django.contrib.auth.hashers import make_password
from django.core.validators import RegexValidator from django.core.validators import RegexValidator
from django.contrib.auth.models import User
from django.contrib.sites.models import Site from django.contrib.sites.models import Site
from django.conf import settings from django.conf import settings
from django.utils.crypto import get_random_string from django.utils.crypto import get_random_string
@ -15,11 +14,12 @@ from django.core.urlresolvers import reverse
from utils.mailer import BaseEmail from utils.mailer import BaseEmail
REGISTRATION_MESSAGE = {'subject': "Validation mail", REGISTRATION_MESSAGE = {'subject': "Validation mail",
'message': 'Please validate Your account under this link http://localhost:8000/en-us/digitalglarus/login/validate/{}', 'message': 'Please validate Your account under this link '
'http://localhost:8000/en-us/digitalglarus/login/validate/{}',
'from': 'test@test.com'} 'from': 'test@test.com'}
def get_anonymous_user_instance(User): def get_anonymous_user_instance():
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))
@ -85,16 +85,19 @@ class CustomUser(AbstractBaseUser, PermissionsMixin):
dg.send_mail(to=user.email) dg.send_mail(to=user.email)
elif app == 'dcl': elif app == 'dcl':
dcl_text = settings.DCL_TEXT dcl_text = settings.DCL_TEXT
dcl_from_address = settings.DCL_SUPPORT_FROM_ADDRESS # not used
# dcl_from_address = settings.DCL_SUPPORT_FROM_ADDRESS
user.is_active = False user.is_active = False
if send_email is True: if send_email is True:
email_data = { email_data = {
'subject': str(_('Activate your ')) + dcl_text + str(_(' account')), 'subject': str(_('Activate your ')) + dcl_text + str(_(' account')),
'from_address': settings.DCL_SUPPORT_FROM_ADDRESS, 'from_address': settings.DCL_SUPPORT_FROM_ADDRESS,
'to': user.email, 'to': user.email,
'context': {'base_url' : base_url, 'context': {'base_url': base_url,
'activation_link' : reverse('hosting:validate', kwargs={'validate_slug': user.validation_slug}), 'activation_link': reverse('hosting:validate',
'dcl_text' : dcl_text kwargs={'validate_slug': user.validation_slug}),
'dcl_text': dcl_text
}, },
'template_name': 'user_activation', 'template_name': 'user_activation',
'template_path': 'datacenterlight/emails/' 'template_path': 'datacenterlight/emails/'
@ -188,7 +191,7 @@ class StripeCustomer(models.Model):
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')
stripe_customer = StripeCustomer.objects.\ stripe_customer = StripeCustomer.objects. \
create(user=user, stripe_id=stripe_cus_id) create(user=user, stripe_id=stripe_cus_id)
return stripe_customer return stripe_customer

View file

@ -7,7 +7,7 @@ stripe.api_key = settings.STRIPE_API_PRIVATE_KEY
class StripePayment(object): class StripePayment(object):
@classmethod @classmethod
def make_payment(cls,user,amount,token,time): def make_payment(cls, user, amount, token, time):
try: try:
print(amount) print(amount)
print(amount) print(amount)
@ -19,7 +19,7 @@ class StripePayment(object):
source=token, source=token,
description=settings.STRIPE_DESCRIPTION_ON_PAYMENT description=settings.STRIPE_DESCRIPTION_ON_PAYMENT
) )
if charge['status'] =='succeeded': if charge['status'] == 'succeeded':
obj = CreditCards.objects.filter(user_id=user.id).first() obj = CreditCards.objects.filter(user_id=user.id).first()
obj.payment_type = time obj.payment_type = time
obj.save() obj.save()
@ -42,7 +42,7 @@ class StripePayment(object):
return "Currently its not possible to make payments." return "Currently its not possible to make payments."
except stripe.error.StripeError as e: except stripe.error.StripeError as e:
return "Currently its not possible to make payments." return "Currently its not possible to make payments."
#maybe send email # maybe send email
except Exception as e: except Exception as e:
return "Currently its not possible to make payments." return "Currently its not possible to make payments."
#maybe send email # maybe send email

View file

@ -26,6 +26,4 @@ class LoginTestCase(TestCase):
# check fail login # check fail login
res4 = self.client.post(url, data={'email': 'test@gmail.com', 'password': 'falsepassword'}) res4 = self.client.post(url, data={'email': 'test@gmail.com', 'password': 'falsepassword'})
self.assertContains(res4,'Sorry, that login was invalid.',1,200) self.assertContains(res4, 'Sorry, that login was invalid.', 1, 200)

View file

@ -8,7 +8,7 @@ urlpatterns = (
url(r"^$", views.LoginRegistrationView.as_view(), name='login_glarus'), url(r"^$", views.LoginRegistrationView.as_view(), name='login_glarus'),
url(r"^validate/(?P<validate_slug>.*)/$", views.validate_email), url(r"^validate/(?P<validate_slug>.*)/$", views.validate_email),
url(r"^membership/$", login_required(views.MembershipView.as_view()), name='membership'), url(r"^membership/$", login_required(views.MembershipView.as_view()), name='membership'),
url(r'logout/?$',views.logout_glarus,name='logout_glarus'), url(r'logout/?$', views.logout_glarus, name='logout_glarus'),
url(r"^buy/(?P<time>\w+)/$", login_required(views.CreditCardView.as_view()), name='payment'), url(r"^buy/(?P<time>\w+)/$", login_required(views.CreditCardView.as_view()), name='payment'),
url(r'^buy/(?P<time>\w+)/reset',login_required(views.reset),name='reset') url(r'^buy/(?P<time>\w+)/reset', login_required(views.reset), name='reset')
) )

View file

@ -8,22 +8,23 @@ from django.contrib.auth import logout
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.contrib.auth import login from django.contrib.auth import login
from .models import CustomUser,StripeCustomer from .models import CustomUser, StripeCustomer
from .forms import LoginForm, RegisterForm, PaymentForm from .forms import LoginForm, RegisterForm, PaymentForm
from utils.stripe_utils import StripeUtils from utils.stripe_utils import StripeUtils
def validate_email(request, validate_slug): def validate_email(request, validate_slug):
validated = CustomUser.validate_url(validate_slug) validated = CustomUser.validate_url(validate_slug)
if validated: if validated:
return render(request, 'templates/validated_email.html',{'msg':True}) return render(request, 'templates/validated_email.html', {'msg': True})
else: else:
return render(request, 'templates/error.html',{'msg':'Validation failed.'}) return render(request, 'templates/error.html', {'msg': 'Validation failed.'})
def reset(request, time):
request.session['next'] = 0
return redirect('payment', time=time)
def reset(request,time):
request.session['next']=0
return redirect('payment',time=time)
class CreditCardView(View): class CreditCardView(View):
def _get_context(self, request, time): def _get_context(self, request, time):
@ -42,20 +43,20 @@ class CreditCardView(View):
context['form'] = PaymentForm() context['form'] = PaymentForm()
return context return context
@cache_control(no_cache=True,must_revalidate=True) @cache_control(no_cache=True, must_revalidate=True)
def get(self, request, time=None): def get(self, request, time=None):
context = self._get_context(request, time) context = self._get_context(request, time)
next = request.session.get('next') next = request.session.get('next')
if next == 1 or next ==0: if next == 1 or next == 0:
template = 'templates/creditcard.html' template = 'templates/creditcard.html'
request.session['next'] +=1 request.session['next'] += 1
elif next == 2: elif next == 2:
customer = StripeCustomer.get_or_create(email=request.user.email,token=request.session['token']) customer = StripeCustomer.get_or_create(email=request.user.email, token=request.session['token'])
stripe_utils = StripeUtils() stripe_utils = StripeUtils()
charge = stripe_utils.make_charge(request.session['amount'],customer=customer.stripe_id) charge = stripe_utils.make_charge(request.session['amount'], customer=customer.stripe_id)
template = 'templates/validated.html' template = 'templates/validated.html'
resp = charge.get('response_object') resp = charge.get('response_object')
context['msg'] = resp.get('status',None) context['msg'] = resp.get('status', None)
request.session['next'] = None request.session['next'] = None
return render(request, template, context) return render(request, template, context)
@ -64,11 +65,11 @@ class CreditCardView(View):
stripe_token = request.POST['stripeToken'] stripe_token = request.POST['stripeToken']
if form.is_valid(): if form.is_valid():
ret = form.save(request.user) form.save(request.user)
amount = 35 if time == 'month' else 360 amount = 35 if time == 'month' else 360
request.session['token'] = stripe_token request.session['token'] = stripe_token
request.session['amount'] = amount request.session['amount'] = amount
request.session['next'] +=1 request.session['next'] += 1
return render(request, 'templates/confirm.html', return render(request, 'templates/confirm.html',
context={'name': request.user.name, 'email': request.user.email}) context={'name': request.user.name, 'email': request.user.email})
else: else:
@ -121,13 +122,14 @@ class LoginRegistrationView(View):
class MembershipView(View): class MembershipView(View):
def get(self, request): def get(self, request):
#if the user has payed already # if the user has payed already
member_payed = request.user.creditcards_set.filter(Q(payment_type='month') | Q(payment_type='year')) member_payed = request.user.creditcards_set.filter(Q(payment_type='month') | Q(payment_type='year'))
if member_payed: if member_payed:
return redirect('/') return redirect('/')
request.session['next'] = 0 request.session['next'] = 0
language = get_language() language = get_language()
return render(request, 'templates/membership.html',context={'language_code':language}) return render(request, 'templates/membership.html', context={'language_code': language})
def logout_glarus(request): def logout_glarus(request):
logout(request) logout(request)

View file

@ -1,3 +1,3 @@
from django.test import TestCase # from django.test import TestCase
# Create your tests here. # Create your tests here.

View file

@ -1,3 +1,3 @@
from django.contrib import admin # from django.contrib import admin
# Register your models here. # Register your models here.

View file

@ -1,9 +1,10 @@
class KeyExistsError(Exception): class KeyExistsError(Exception):
pass pass
class UserExistsError(Exception): class UserExistsError(Exception):
pass pass
class UserCredentialError(Exception): class UserCredentialError(Exception):
pass pass

View file

@ -6,7 +6,6 @@ from oca.pool import WrongNameError, WrongIdError
from oca.exceptions import OpenNebulaException from oca.exceptions import OpenNebulaException
from django.conf import settings from django.conf import settings
from django.utils.functional import cached_property
from utils.models import CustomUser from utils.models import CustomUser
from .exceptions import KeyExistsError, UserExistsError, UserCredentialError from .exceptions import KeyExistsError, UserExistsError, UserCredentialError
@ -38,6 +37,7 @@ class OpenNebulaManager():
) )
except: except:
pass pass
def _get_client(self, user): def _get_client(self, user):
"""Get a opennebula client object for a CustomUser object """Get a opennebula client object for a CustomUser object
@ -122,11 +122,11 @@ class OpenNebulaManager():
except WrongNameError: except WrongNameError:
user_id = self.oneadmin_client.call(oca.User.METHODS['allocate'], user_id = self.oneadmin_client.call(oca.User.METHODS['allocate'],
user.email, user.password, 'core') user.email, user.password, 'core')
logger.debug('Created a user for CustomObject: {user} with user id = {u_id}', logger.debug('Created a user for CustomObject: {user} with user id = {u_id}',
user=user, user=user,
u_id=user_id u_id=user_id
) )
return user_id return user_id
except ConnectionRefusedError: except ConnectionRefusedError:
logger.error('Could not connect to host: {host} via protocol {protocol}'.format( logger.error('Could not connect to host: {host} via protocol {protocol}'.format(
@ -135,7 +135,6 @@ class OpenNebulaManager():
) )
raise ConnectionRefusedError raise ConnectionRefusedError
def _get_or_create_user(self, email, password): def _get_or_create_user(self, email, password):
try: try:
user_pool = self._get_user_pool() user_pool = self._get_user_pool()
@ -209,36 +208,6 @@ class OpenNebulaManager():
except: except:
raise ConnectionRefusedError raise ConnectionRefusedError
def create_template(self, name, cores, memory, disk_size, core_price, memory_price,
disk_size_price, ssh=''):
"""Create and add a new template to opennebula.
:param name: A string representation describing the template.
Used as label in view.
:param cores: Amount of virtual cpu cores for the VM.
:param memory: Amount of RAM for the VM (GB)
:param disk_size: Amount of disk space for VM (GB)
:param core_price: Price of virtual cpu for the VM per core.
:param memory_price: Price of RAM for the VM per GB
:param disk_size_price: Price of disk space for VM per GB
:param ssh: User public ssh key
"""
template_id = oca.VmTemplate.allocate(
self.oneadmin_client,
template_string_formatter.format(
name=name,
vcpu=cores,
cpu=0.1 * cores,
size=1024 * disk_size,
memory=1024 * memory,
# * 10 because we set cpu to *0.1
cpu_cost=10 * core_price,
memory_cost=memory_price,
disk_cost=disk_size_price,
ssh=ssh
)
)
def create_vm(self, template_id, specs, ssh_key=None, vm_name=None): def create_vm(self, template_id, specs, ssh_key=None, vm_name=None):
template = self.get_template(template_id) template = self.get_template(template_id)
@ -468,7 +437,8 @@ class OpenNebulaManager():
except AttributeError: except AttributeError:
pass pass
self.oneadmin_client.call('user.update', open_user.id, self.oneadmin_client.call('user.update', open_user.id,
'<CONTEXT><SSH_PUBLIC_KEY>{key}</SSH_PUBLIC_KEY></CONTEXT>'.format(key=public_key)) '<CONTEXT><SSH_PUBLIC_KEY>{key}</SSH_PUBLIC_KEY></CONTEXT>'
.format(key=public_key))
return True return True
except WrongNameError: except WrongNameError:
raise raise
@ -509,10 +479,11 @@ class OpenNebulaManager():
except AttributeError: except AttributeError:
return False return False
#raise KeyDoesNotExistsError() # raise KeyDoesNotExistsError()
self.oneadmin_client.call('user.update', open_user.id, self.oneadmin_client.call('user.update', open_user.id,
'<CONTEXT><SSH_PUBLIC_KEY>{key}</SSH_PUBLIC_KEY></CONTEXT>'.format(key=public_key)) '<CONTEXT><SSH_PUBLIC_KEY>{key}</SSH_PUBLIC_KEY></CONTEXT>'
.format(key=public_key))
return True return True
except WrongNameError: except WrongNameError:
raise raise

View file

@ -1,20 +1,19 @@
import oca
import ipaddress import ipaddress
from rest_framework import serializers from rest_framework import serializers
from oca import OpenNebulaException from oca import OpenNebulaException
from oca.template import VmTemplate
from .models import OpenNebulaManager from .models import OpenNebulaManager
class VirtualMachineTemplateSerializer(serializers.Serializer): class VirtualMachineTemplateSerializer(serializers.Serializer):
"""Serializer to map the virtual machine template instance into JSON format.""" """Serializer to map the virtual machine template instance into JSON format."""
id = serializers.IntegerField(read_only=True) id = serializers.IntegerField(read_only=True)
name = serializers.SerializerMethodField() name = serializers.SerializerMethodField()
cores = serializers.SerializerMethodField() cores = serializers.SerializerMethodField()
disk_size = serializers.SerializerMethodField() disk_size = serializers.SerializerMethodField()
memory = serializers.SerializerMethodField() memory = serializers.SerializerMethodField()
def get_cores(self, obj): def get_cores(self, obj):
if hasattr(obj.template, 'vcpu'): if hasattr(obj.template, 'vcpu'):
@ -39,30 +38,28 @@ class VirtualMachineTemplateSerializer(serializers.Serializer):
return obj.name.strip('public-') return obj.name.strip('public-')
class VirtualMachineSerializer(serializers.Serializer): class VirtualMachineSerializer(serializers.Serializer):
"""Serializer to map the virtual machine instance into JSON format.""" """Serializer to map the virtual machine instance into JSON format."""
name = serializers.SerializerMethodField() name = serializers.SerializerMethodField()
cores = serializers.IntegerField(source='template.vcpu') cores = serializers.IntegerField(source='template.vcpu')
disk = serializers.IntegerField(write_only=True) disk = serializers.IntegerField(write_only=True)
set_memory = serializers.IntegerField(write_only=True, label='Memory') set_memory = serializers.IntegerField(write_only=True, label='Memory')
memory = serializers.SerializerMethodField() memory = serializers.SerializerMethodField()
disk_size = serializers.SerializerMethodField()
disk_size = serializers.SerializerMethodField() ipv4 = serializers.SerializerMethodField()
ipv4 = serializers.SerializerMethodField() ipv6 = serializers.SerializerMethodField()
ipv6 = serializers.SerializerMethodField() vm_id = serializers.IntegerField(read_only=True, source='id')
vm_id = serializers.IntegerField(read_only=True, source='id') state = serializers.CharField(read_only=True, source='str_state')
state = serializers.CharField(read_only=True, source='str_state') price = serializers.SerializerMethodField()
price = serializers.SerializerMethodField() ssh_key = serializers.CharField(write_only=True)
ssh_key = serializers.CharField(write_only=True)
configuration = serializers.SerializerMethodField() configuration = serializers.SerializerMethodField()
template_id = serializers.ChoiceField( template_id = serializers.ChoiceField(
choices=[(key.id, key.name) for key in choices=[(key.id, key.name) for key in
OpenNebulaManager().try_get_templates() OpenNebulaManager().try_get_templates()
], ],
source='template.template_id', source='template.template_id',
write_only=True, write_only=True,
default=[] default=[]
@ -77,12 +74,11 @@ class VirtualMachineSerializer(serializers.Serializer):
template_id = validated_data['template']['template_id'] template_id = validated_data['template']['template_id']
specs = { specs = {
'cpu' : cores, 'cpu': cores,
'disk_size' : disk, 'disk_size': disk,
'memory' : memory, 'memory': memory,
} }
try: try:
manager = OpenNebulaManager(email=owner.email, manager = OpenNebulaManager(email=owner.email,
password=owner.password, password=owner.password,
@ -112,6 +108,7 @@ class VirtualMachineSerializer(serializers.Serializer):
for disk in template.disks: for disk in template.disks:
price += int(disk.size)/1024 * 0.6 price += int(disk.size)/1024 * 0.6
return price return price
def get_configuration(self, obj): def get_configuration(self, obj):
template_id = obj.template.template_id template_id = obj.template.template_id
template = OpenNebulaManager().get_template(template_id) template = OpenNebulaManager().get_template(template_id)
@ -131,12 +128,15 @@ class VirtualMachineSerializer(serializers.Serializer):
def get_name(self, obj): def get_name(self, obj):
return obj.name.strip('public-') return obj.name.strip('public-')
def hexstr2int(string): def hexstr2int(string):
return int(string.replace(':', ''), 16) return int(string.replace(':', ''), 16)
FIRST_MAC = hexstr2int('02:00:b3:39:79:4d') FIRST_MAC = hexstr2int('02:00:b3:39:79:4d')
FIRST_V4 = ipaddress.ip_address('185.203.112.2') FIRST_V4 = ipaddress.ip_address('185.203.112.2')
COUNT = 1000 COUNT = 1000
def v4_from_mac(mac): def v4_from_mac(mac):
"""Calculates the IPv4 address from a MAC address. """Calculates the IPv4 address from a MAC address.
@ -146,5 +146,6 @@ def v4_from_mac(mac):
""" """
return FIRST_V4 + (hexstr2int(mac) - FIRST_MAC) return FIRST_V4 + (hexstr2int(mac) - FIRST_MAC)
def is_in_v4_range(mac): def is_in_v4_range(mac):
return FIRST_MAC <= hexstr2int(mac) < FIRST_MAC + 1000 return FIRST_MAC <= hexstr2int(mac) < FIRST_MAC + 1000

View file

@ -1,4 +1,3 @@
import socket
import random import random
import string import string
@ -8,18 +7,17 @@ from .models import OpenNebulaManager
from .serializers import VirtualMachineSerializer from .serializers import VirtualMachineSerializer
from utils.models import CustomUser from utils.models import CustomUser
class OpenNebulaManagerTestCases(TestCase): class OpenNebulaManagerTestCases(TestCase):
"""This class defines the test suite for the opennebula manager model.""" """This class defines the test suite for the opennebula manager model."""
def setUp(self): def setUp(self):
"""Define the test client and other test variables.""" """Define the test client and other test variables."""
self.email = '{}@ungleich.ch'.format(''.join(random.choices(string.ascii_uppercase, k=10))) self.email = '{}@ungleich.ch'.format(''.join(random.choices(string.ascii_uppercase, k=10)))
self.password = ''.join(random.choices(string.ascii_uppercase + string.digits, k=20)) self.password = ''.join(random.choices(string.ascii_uppercase + string.digits, k=20))
self.user = CustomUser.objects.create(name='test', email=self.email, self.user = CustomUser.objects.create(name='test', email=self.email,
password=self.password) password=self.password)
self.vm_specs = {} self.vm_specs = {}
self.vm_specs['cpu'] = 1 self.vm_specs['cpu'] = 1
@ -28,7 +26,6 @@ class OpenNebulaManagerTestCases(TestCase):
self.manager = OpenNebulaManager() self.manager = OpenNebulaManager()
def test_connect_to_server(self): def test_connect_to_server(self):
"""Test the opennebula manager can connect to a server.""" """Test the opennebula manager can connect to a server."""
try: try:
@ -98,7 +95,7 @@ class OpenNebulaManagerTestCases(TestCase):
user.delete() user.delete()
self.assertEqual(new_public_key, '{}\n{}'.format(old_public_key, self.assertEqual(new_public_key, '{}\n{}'.format(old_public_key,
public_key)) public_key))
def test_remove_public_key_to_user(self): def test_remove_public_key_to_user(self):
""" Test the manager can remove a public key from an user """ """ Test the manager can remove a public key from an user """
@ -116,8 +113,7 @@ class OpenNebulaManagerTestCases(TestCase):
user.delete() user.delete()
self.assertEqual(new_public_key, self.assertEqual(new_public_key,
old_public_key.replace('{}\n'.format(public_key), '', 1)) old_public_key.replace('{}\n'.format(public_key), '', 1))
def test_requires_ssh_key_for_new_vm(self): def test_requires_ssh_key_for_new_vm(self):
"""Test the opennebula manager requires the user to have a ssh key when """Test the opennebula manager requires the user to have a ssh key when
@ -129,7 +125,6 @@ class VirtualMachineSerializerTestCase(TestCase):
"""Define the test client and other test variables.""" """Define the test client and other test variables."""
self.manager = OpenNebulaManager(email=None, password=None) self.manager = OpenNebulaManager(email=None, password=None)
def test_serializer_strips_of_public(self): def test_serializer_strips_of_public(self):
""" Test the serialized virtual machine object contains no 'public-'.""" """ Test the serialized virtual machine object contains no 'public-'."""
@ -137,5 +132,3 @@ class VirtualMachineSerializerTestCase(TestCase):
serialized = VirtualMachineSerializer(vm) serialized = VirtualMachineSerializer(vm)
self.assertEqual(serialized.data.get('name'), vm.name.strip('public-')) self.assertEqual(serialized.data.get('name'), vm.name.strip('public-'))
break break

View file

@ -1,19 +1,11 @@
from rest_framework import generics from rest_framework import generics
from rest_framework import permissions from rest_framework import permissions
from django.contrib.auth.mixins import LoginRequiredMixin from .serializers import VirtualMachineSerializer
from django.contrib.auth import authenticate, login
from utils.views import LoginViewMixin
from membership.models import CustomUser, StripeCustomer
from guardian.mixins import PermissionRequiredMixin
from .serializers import VirtualMachineTemplateSerializer, \
VirtualMachineSerializer
from .models import OpenNebulaManager from .models import OpenNebulaManager
from rest_framework.exceptions import APIException from rest_framework.exceptions import APIException
class ServiceUnavailable(APIException): class ServiceUnavailable(APIException):
status_code = 503 status_code = 503
default_detail = 'Service temporarily unavailable, try again later.' default_detail = 'Service temporarily unavailable, try again later.'
@ -41,6 +33,7 @@ class VmCreateView(generics.ListCreateAPIView):
"""Save the post data when creating a new template.""" """Save the post data when creating a new template."""
serializer.save(owner=self.request.user) serializer.save(owner=self.request.user)
class VmDetailsView(generics.RetrieveUpdateDestroyAPIView): class VmDetailsView(generics.RetrieveUpdateDestroyAPIView):
"""This class handles the http GET, PUT and DELETE requests.""" """This class handles the http GET, PUT and DELETE requests."""
permission_classes = (permissions.IsAuthenticated, ) permission_classes = (permissions.IsAuthenticated, )
@ -81,4 +74,3 @@ class VmDetailsView(generics.RetrieveUpdateDestroyAPIView):
manager.delete_vm(instance.id) manager.delete_vm(instance.id)
except ConnectionRefusedError: except ConnectionRefusedError:
raise ServiceUnavailable raise ServiceUnavailable

View file

@ -84,5 +84,5 @@ django-admin-honeypot==1.0.0
coverage==4.3.4 coverage==4.3.4
git+https://github.com/ungleich/python-oca.git#egg=python-oca git+https://github.com/ungleich/python-oca.git#egg=python-oca
djangorestframework djangorestframework
flake8==3.3.0
python-memcached==1.58

3
setup.cfg Executable file
View file

@ -0,0 +1,3 @@
[flake8]
max-line-length = 120
exclude = .tox,.git,*/migrations/*,*/static/*,docs,venv,node_modules/*

View file

@ -9,4 +9,5 @@ from .models import UngleichPage
class UngleichPageAdmin(PageExtensionAdmin): class UngleichPageAdmin(PageExtensionAdmin):
pass pass
admin.site.register(UngleichPage, UngleichPageAdmin) admin.site.register(UngleichPage, UngleichPageAdmin)

View file

@ -2,7 +2,6 @@ from cms.extensions.toolbar import ExtensionToolbar
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from cms.toolbar_pool import toolbar_pool from cms.toolbar_pool import toolbar_pool
from cms.toolbar_base import CMSToolbar
from .models import UngleichPage from .models import UngleichPage
@ -22,4 +21,4 @@ class UngleichPageToolbar(ExtensionToolbar):
if url: if url:
# adds a toolbar item # adds a toolbar item
current_page_menu.add_modal_item(_('Page Header'), url=url, current_page_menu.add_modal_item(_('Page Header'), url=url,
disabled=not self.toolbar.edit_mode) disabled=not self.toolbar.edit_mode)

View file

@ -1,5 +1,3 @@
from django.db import models
from cms.extensions import PageExtension from cms.extensions import PageExtension
from cms.extensions.extension_pool import extension_pool from cms.extensions.extension_pool import extension_pool
from filer.fields.image import FilerImageField from filer.fields.image import FilerImageField
@ -9,11 +7,12 @@ from filer.fields.image import FilerImageField
class UngleichPage(PageExtension): class UngleichPage(PageExtension):
#image_header = models.ImageField(upload_to='image_header') # image_header = models.ImageField(upload_to='image_header')
image = FilerImageField(null=True, blank=True, image = FilerImageField(null=True, blank=True,
related_name="ungleinch_page_image") related_name="ungleinch_page_image")
class Meta: class Meta:
app_label = 'ungleich' app_label = 'ungleich'
extension_pool.register(UngleichPage) extension_pool.register(UngleichPage)

View file

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from django.utils.translation import ugettext_lazy as _ # from django.utils.translation import ugettext_lazy as _
# TEMPLATES = { # TEMPLATES = {
# 'blog_u.html': _('Blog'), # 'blog_u.html': _('Blog'),
# 'page.html': _('Page'), # 'page.html': _('Page'),

View file

@ -1,3 +1,3 @@
from django.test import TestCase # from django.test import TestCase
# Create your tests here. # Create your tests here.

View file

@ -6,6 +6,7 @@ from django.utils.translation import get_language
from djangocms_blog.models import Post from djangocms_blog.models import Post
from djangocms_blog.views import PostListView from djangocms_blog.views import PostListView
from djangocms_blog.settings import get_setting from djangocms_blog.settings import get_setting
from django.utils.translation import ugettext_lazy as _
def blog(request): def blog(request):

View file

@ -1,3 +1,3 @@
from django.contrib import admin # from django.contrib import admin
# Register your models here. # Register your models here.

View file

@ -1,3 +1,3 @@
from django.db import models # from django.db import models
# Create your models here. # Create your models here.

View file

@ -1,3 +1,3 @@
from django.test import TestCase # from django.test import TestCase
# Create your tests here. # Create your tests here.

View file

@ -2,10 +2,9 @@ from django.contrib import messages
from django.views.generic.edit import FormView from django.views.generic.edit import FormView
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.core.urlresolvers import reverse_lazy,reverse from django.core.urlresolvers import reverse_lazy
from django.views.generic import View from django.views.generic import View
from django.shortcuts import render,redirect,render_to_response from django.shortcuts import render
from django.http import HttpResponseRedirect
from utils.forms import ContactUsForm from utils.forms import ContactUsForm

View file

@ -1,5 +1,5 @@
from django.contrib import admin from django.contrib import admin
from .models import BillingAddress, UserBillingAddress from .models import UserBillingAddress
# Register your models here. # Register your models here.

View file

@ -1,6 +1,5 @@
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.db import models from django.db import models
from django import forms
# http://xml.coverpages.org/country3166.html # http://xml.coverpages.org/country3166.html
COUNTRIES = ( COUNTRIES = (

View file

@ -115,7 +115,8 @@ class BillingAddressForm(forms.ModelForm):
class UserBillingAddressForm(forms.ModelForm): class UserBillingAddressForm(forms.ModelForm):
user = forms.ModelChoiceField(queryset=CustomUser.objects.all(), user = forms.ModelChoiceField(queryset=CustomUser.objects.all(),
widget=forms.HiddenInput()) widget=forms.HiddenInput())
class Meta: class Meta:
model = UserBillingAddress model = UserBillingAddress
fields = ['street_address', 'city', 'postal_code', 'country', 'user'] fields = ['street_address', 'city', 'postal_code', 'country', 'user']
@ -126,6 +127,7 @@ class UserBillingAddressForm(forms.ModelForm):
'Country': _('Country'), 'Country': _('Country'),
} }
class ContactUsForm(forms.ModelForm): class ContactUsForm(forms.ModelForm):
error_css_class = 'autofocus' error_css_class = 'autofocus'

View file

@ -77,4 +77,3 @@ class DigitalGlarusRegistrationMailer(BaseMailer):
self.registration = self.message self.registration = self.message
self._message = self._message.format(slug=self._slug) self._message = self._message.format(slug=self._slug)
super().__init__() super().__init__()

View file

@ -1,6 +1,4 @@
from django.db import models from django.db import models
from django.core import serializers
from django.forms.models import model_to_dict
from membership.models import CustomUser from membership.models import CustomUser
@ -18,6 +16,7 @@ class BaseBillingAddress(models.Model):
class Meta: class Meta:
abstract = True abstract = True
class BillingAddress(BaseBillingAddress): class BillingAddress(BaseBillingAddress):
def __str__(self): def __str__(self):

View file

@ -137,22 +137,10 @@ class StripeUtils(object):
id=id) id=id)
@handleStripeError @handleStripeError
def make_payment(self, user, amount, token): def make_payment(self, customer, amount, token):
charge = self.stripe.Charge.create( charge = self.stripe.Charge.create(
amount=amount, # in cents amount=amount, # in cents
currency=self.CURRENCY, currency=self.CURRENCY,
customer=customer customer=customer
) )
return charge return charge
@handleStripeError
def create_plan(self, amount, name, id):
self.stripe.Plan.create(
amount=amount,
interval=self.INTERVAL,
name=name,
currency=self.CURRENCY,
id=id)