Merged code from siarheipuhach/dynamicweb

This commit is contained in:
M.Ravi 2017-07-01 15:18:44 +02:00
commit c8cf166571
66 changed files with 372 additions and 419 deletions

View file

@ -4,8 +4,10 @@ python:
- "3.6" - "3.6"
env: env:
# Set a dummy secret key # Set a dummy secret key
- 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
@ -33,7 +34,8 @@ class ContactView(FormView):
form.save() form.save()
form.send_email(email_to='info@alplora.ch') form.send_email(email_to='info@alplora.ch')
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

@ -5,22 +5,20 @@ 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')

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 from .views import IndexView, BetaProgramView, LandingProgramView, \
BetaAccessView, PricingView, SuccessView, PaymentOrderView, OrderConfirmationView
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
@ -19,13 +19,15 @@ 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
from membership.models import CustomUser, StripeCustomer from membership.models import CustomUser, StripeCustomer
from oca.pool import WrongIdError
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"
@ -54,17 +56,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')
@ -83,7 +84,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,
@ -98,7 +99,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())
} }
@ -133,6 +133,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
@ -191,12 +192,12 @@ class IndexView(CreateView):
form_class = BetaAccessForm form_class = BetaAccessForm
success_url = "/datacenterlight#requestform" success_url = "/datacenterlight#requestform"
success_message = "Thank you, we will contact you as soon as possible" success_message = "Thank you, we will contact you as soon as possible"
@cache_control(no_cache=True, must_revalidate=True, no_store=True) @cache_control(no_cache=True, must_revalidate=True, no_store=True)
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
if 'specs' in request.session : if 'specs' in request.session:
del request.session['specs'] del request.session['specs']
if 'user' in request.session : if 'user' in request.session:
del request.session['user'] del request.session['user']
if 'billing_address_data' in request.session : if 'billing_address_data' in request.session :
del request.session['billing_address_data'] del request.session['billing_address_data']
@ -204,16 +205,16 @@ class IndexView(CreateView):
manager = OpenNebulaManager() manager = OpenNebulaManager()
templates = manager.get_templates() templates = manager.get_templates()
context = { context = {
'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):
@ -225,7 +226,7 @@ class IndexView(CreateView):
manager = OpenNebulaManager() manager = OpenNebulaManager()
template = manager.get_template(template_id) template = manager.get_template(template_id)
template_data = VirtualMachineTemplateSerializer(template).data template_data = VirtualMachineTemplateSerializer(template).data
name = request.POST.get('name') name = request.POST.get('name')
email = request.POST.get('email') email = request.POST.get('email')
name_field = forms.CharField() name_field = forms.CharField()
@ -236,7 +237,7 @@ class IndexView(CreateView):
messages.add_message(self.request, messages.ERROR, '%(value) is not a proper name.'.format(name)) messages.add_message(self.request, messages.ERROR, '%(value) is not a proper name.'.format(name))
return HttpResponseRedirect(reverse('datacenterlight:index')) return HttpResponseRedirect(reverse('datacenterlight:index'))
try: try:
email = email_field.clean(email) email = email_field.clean(email)
except ValidationError as err: except ValidationError as err:
messages.add_message(self.request, messages.ERROR, '%(value) is not a proper email.'.format(email)) messages.add_message(self.request, messages.ERROR, '%(value) is not a proper email.'.format(email))
@ -248,12 +249,12 @@ class IndexView(CreateView):
'disk_size': storage, 'disk_size': storage,
'price': price 'price': price
} }
this_user = { this_user = {
'name': name, 'name': name,
'email': email 'email': email
} }
request.session['specs'] = specs request.session['specs'] = specs
request.session['template'] = template_data request.session['template'] = template_data
request.session['user'] = this_user request.session['user'] = this_user
@ -354,10 +355,10 @@ class PaymentOrderView(FormView):
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
CustomUser.register(user.get('name'), CustomUser.register(user.get('name'),
password, password,
user.get('email'), user.get('email'),
app='dcl', app='dcl',
base_url=None, send_email=False) base_url=None, send_email=False)
# Get or create stripe customer # Get or create stripe customer
@ -377,6 +378,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'

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 *

View file

@ -11,7 +11,9 @@ 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):
@ -186,7 +188,11 @@ CMS_TEMPLATES = (
DATABASES = { DATABASES = {
'default': { 'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2', 'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'app' 'NAME': 'app',
'HOST': 'localhost',
'USER': 'ubuntu',
'PASSWORD': 'Qwerty123',
} }
} }
@ -462,17 +468,20 @@ 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 DEBUG = True
if DEBUG: # not used
from .local import * # if DEBUG:
else: # from .local import *
from .prod import * # # else:
# # from .prod import *
ANONYMOUS_USER_NAME = 'anonymous@ungleich.ch' ANONYMOUS_USER_NAME = 'anonymous@ungleich.ch'

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,16 @@
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 # MANAGERS = ADMINS
REGISTRATION_MESSAGE['message'] = REGISTRATION_MESSAGE['message'].format(host='digitalglarus.ungleich.ch',slug='{slug}') 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,30 +12,31 @@ 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'),
@ -50,4 +51,4 @@ if settings.DEBUG:
'document_root': settings.MEDIA_ROOT, 'document_root': settings.MEDIA_ROOT,
}), }),
) )
urlpatterns += patterns('',url(r'^__debug__/', include(debug_toolbar.urls))) 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

@ -1,6 +1,6 @@
{% extends "hosting/base_short.html" %} {% extends "hosting/base_short.html" %}
{% load staticfiles bootstrap3 i18n %} {% load staticfiles bootstrap3 i18n %}
{% block content %} {% block content %}
<!-- Credit card form --> <!-- Credit card form -->
<div> <div>
<div class="payment-container"> <div class="payment-container">
@ -32,7 +32,7 @@
</div> </div>
</div> </div>
</form> </form>
</div> </div>
<div class="col-xs-12 col-md-4 billing"> <div class="col-xs-12 col-md-4 billing">
<h3><b>{%trans "Billing Address"%}</b></h3> <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">Last 4: *****{{credit_card_data.last4}}</h5>
<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="col-xs-6"> <div class="col-xs-6">
<button id="payment_button_with_creditcard" class="btn btn-success btn-sm btn-block" type="submit"> <button id="payment_button_with_creditcard" class="btn btn-success btn-sm btn-block" type="submit">
{% trans "Submit Payment" %} {% trans "Submit Payment" %}
@ -89,7 +89,7 @@
placeholder="{%trans "Valid Card Number"%}" required autofocus data-stripe="number" /> placeholder="{%trans "Valid Card Number"%}" required autofocus data-stripe="number" />
<span class="input-group-addon"><i class="fa fa-credit-card"></i></span> <span class="input-group-addon"><i class="fa fa-credit-card"></i></span>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
@ -131,7 +131,7 @@
</div> </div>
{% endif %} {% endif %}
</form> </form>
{% endif %} {% endif %}
@ -146,7 +146,7 @@
<!-- stripe key data --> <!-- stripe key data -->
{% if stripe_key %} {% if stripe_key %}
{% get_current_language as LANGUAGE_CODE %} {% get_current_language as LANGUAGE_CODE %}
<script type="text/javascript"> <script type="text/javascript">
(function () { (function () {
@ -157,7 +157,7 @@
{%endif%} {%endif%}
{% if credit_card_data.last4 and credit_card_data.cc_brand %} {% if credit_card_data.last4 and credit_card_data.cc_brand %}
<script type="text/javascript"> <script type="text/javascript">
(function () {window.hasCreditcard = true;})(); (function () {window.hasCreditcard = true;})();
</script> </script>

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,8 +542,8 @@ 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(
template_id=vm_template_id, template_id=vm_template_id,
@ -565,8 +561,9 @@ class PaymentVMView(LoginRequiredMixin, FormView):
) )
# Create a Hosting Bill # Create a Hosting Bill
bill = HostingBill.create( # variable bill is not used
customer=customer, billing_address=billing_address) # bill = HostingBill.create(
# 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 +696,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.'
@ -723,7 +720,7 @@ class CreateVirtualMachinesView(LoginRequiredMixin, View):
) )
context = { context = {
'error': 'connection' 'error': 'connection'
} }
return render(request, self.template_name, context) return render(request, self.template_name, context)

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,9 +37,10 @@ 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
Args: Args:
user (CustomUser): dynamicweb CustomUser object user (CustomUser): dynamicweb CustomUser object
@ -49,7 +49,7 @@ class OpenNebulaManager():
Raise: Raise:
ConnectionError: If the connection to the opennebula server can't be ConnectionError: If the connection to the opennebula server can't be
established established
""" """
return oca.Client("{0}:{1}".format( return oca.Client("{0}:{1}".format(
user.email, user.email,
@ -74,8 +74,8 @@ class OpenNebulaManager():
)) ))
def _get_user(self, user): def _get_user(self, user):
"""Get the corresponding opennebula user for a CustomUser object """Get the corresponding opennebula user for a CustomUser object
Args: Args:
user (CustomUser): dynamicweb CustomUser object user (CustomUser): dynamicweb CustomUser object
@ -85,7 +85,7 @@ class OpenNebulaManager():
Raise: Raise:
WrongNameError: If no openebula user with this credentials exists WrongNameError: If no openebula user with this credentials exists
ConnectionError: If the connection to the opennebula server can't be ConnectionError: If the connection to the opennebula server can't be
established established
""" """
user_pool = self._get_user_pool() user_pool = self._get_user_pool()
return user_pool.get_by_name(user.email) return user_pool.get_by_name(user.email)
@ -93,16 +93,16 @@ class OpenNebulaManager():
def create_user(self, user: CustomUser): def create_user(self, user: CustomUser):
"""Create a new opennebula user or a corresponding CustomUser object """Create a new opennebula user or a corresponding CustomUser object
Args: Args:
user (CustomUser): dynamicweb CustomUser object user (CustomUser): dynamicweb CustomUser object
Returns: Returns:
int: Return the opennebula user id int: Return the opennebula user id
Raises: Raises:
ConnectionError: If the connection to the opennebula server can't be ConnectionError: If the connection to the opennebula server can't be
established established
UserExistsError: If a user with this credeintals already exits on the UserExistsError: If a user with this credeintals already exits on the
server server
UserCredentialError: If a user with this email exists but the UserCredentialError: If a user with this email exists but the
@ -111,7 +111,7 @@ class OpenNebulaManager():
""" """
try: try:
self._get_user(user) self._get_user(user)
try: try:
self._get_client(self, user) self._get_client(self, user)
logger.debug('User already exists') logger.debug('User already exists')
raise UserExistsError() raise UserExistsError()
@ -122,19 +122,18 @@ 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(
host=settings.OPENNEBULA_DOMAIN, host=settings.OPENNEBULA_DOMAIN,
protocol=settings.OPENNEBULA_PROTOCOL) protocol=settings.OPENNEBULA_PROTOCOL)
) )
raise ConnectionRefusedError raise ConnectionRefusedError
def _get_or_create_user(self, email, password): def _get_or_create_user(self, email, password):
try: try:
@ -166,7 +165,7 @@ class OpenNebulaManager():
host=settings.OPENNEBULA_DOMAIN, host=settings.OPENNEBULA_DOMAIN,
protocol=settings.OPENNEBULA_PROTOCOL) protocol=settings.OPENNEBULA_PROTOCOL)
) )
raise raise
return user_pool return user_pool
def _get_vm_pool(self): def _get_vm_pool(self):
@ -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)
@ -306,7 +275,7 @@ class OpenNebulaManager():
'release', 'release',
vm_id vm_id
) )
if vm_name is not None: if vm_name is not None:
self.oneadmin_client.call( self.oneadmin_client.call(
'vm.rename', 'vm.rename',
@ -437,30 +406,30 @@ class OpenNebulaManager():
) )
def add_public_key(self, user, public_key='', merge=False): def add_public_key(self, user, public_key='', merge=False):
""" """
Args: Args:
user (CustomUser): Dynamicweb user user (CustomUser): Dynamicweb user
public_key (string): Public key to add to the user public_key (string): Public key to add to the user
merge (bool): Optional if True the new public key replaces the old merge (bool): Optional if True the new public key replaces the old
Raises: Raises:
KeyExistsError: If replace is False and the user already has a KeyExistsError: If replace is False and the user already has a
public key public key
WrongNameError: If no openebula user with this credentials exists WrongNameError: If no openebula user with this credentials exists
ConnectionError: If the connection to the opennebula server can't be ConnectionError: If the connection to the opennebula server can't be
established established
Returns: Returns:
True if public_key was added True if public_key was added
""" """
# TODO: Check if we can remove this first try because we basically just # TODO: Check if we can remove this first try because we basically just
# raise the possible Errors # raise the possible Errors
try: try:
open_user = self._get_user(user) open_user = self._get_user(user)
try: try:
old_key = open_user.template.ssh_public_key old_key = open_user.template.ssh_public_key
if not merge: if not merge:
raise KeyExistsError() raise KeyExistsError()
public_key += '\n{key}'.format(key=old_key) public_key += '\n{key}'.format(key=old_key)
@ -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
@ -477,18 +447,18 @@ class OpenNebulaManager():
raise raise
def remove_public_key(self, user, public_key=''): def remove_public_key(self, user, public_key=''):
""" """
Args: Args:
user (CustomUser): Dynamicweb user user (CustomUser): Dynamicweb user
public_key (string): Public key to be removed to the user public_key (string): Public key to be removed to the user
Raises: Raises:
KeyDoesNotExistsError: If replace is False and the user already has a KeyDoesNotExistsError: If replace is False and the user already has a
public key public key
WrongNameError: If no openebula user with this credentials exists WrongNameError: If no openebula user with this credentials exists
ConnectionError: If the connection to the opennebula server can't be ConnectionError: If the connection to the opennebula server can't be
established established
Returns: Returns:
True if public_key was removed True if public_key was removed
@ -498,21 +468,22 @@ class OpenNebulaManager():
try: try:
open_user = self._get_user(user) open_user = self._get_user(user)
try: try:
old_key = open_user.template.ssh_public_key old_key = open_user.template.ssh_public_key
if public_key not in old_key: if public_key not in old_key:
return False return False
# raise KeyDoesNotExistsError() # raise KeyDoesNotExistsError()
if '\n{}'.format(public_key) in old_key: if '\n{}'.format(public_key) in old_key:
public_key = old_key.replace('\n{}'.format(public_key), '') public_key = old_key.replace('\n{}'.format(public_key), '')
else: else:
public_key = old_key.replace(public_key, '') public_key = old_key.replace(public_key, '')
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'):
@ -28,7 +27,7 @@ class VirtualMachineTemplateSerializer(serializers.Serializer):
try: try:
for disk in template.disks: for disk in template.disks:
disk_size += int(disk.size) disk_size += int(disk.size)
return disk_size / 1024 return disk_size / 1024
except: except:
return 0 return 0
@ -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,
@ -92,7 +88,7 @@ class VirtualMachineSerializer(serializers.Serializer):
specs=specs) specs=specs)
except OpenNebulaException as err: except OpenNebulaException as err:
raise serializers.ValidationError("OpenNebulaException occured. {0}".format(err)) raise serializers.ValidationError("OpenNebulaException occured. {0}".format(err))
return manager.get_vm(opennebula_id) return manager.get_vm(opennebula_id)
def get_memory(self, obj): def get_memory(self, obj):
@ -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)
@ -123,7 +120,7 @@ class VirtualMachineSerializer(serializers.Serializer):
return str(v4_from_mac(nic.mac)) return str(v4_from_mac(nic.mac))
else: else:
return '-' return '-'
def get_ipv6(self, obj): def get_ipv6(self, obj):
nic = obj.template.nics[0] nic = obj.template.nics[0]
return nic.ip6_global return nic.ip6_global
@ -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,32 +7,30 @@ 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
self.vm_specs['memory'] = 2 self.vm_specs['memory'] = 2
self.vm_specs['disk_size'] = 10 self.vm_specs['disk_size'] = 10
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:
ver = self.manager.oneadmin_client.version() ver = self.manager.oneadmin_client.version()
except: except:
ver = None ver = None
self.assertTrue(ver is not None) self.assertTrue(ver is not None)
@ -54,7 +51,7 @@ class OpenNebulaManagerTestCases(TestCase):
# Remove the user afterwards # Remove the user afterwards
user = user_pool.get_by_name(self.email) user = user_pool.get_by_name(self.email)
user.delete() user.delete()
self.assertNotEqual(old_count, new_count) self.assertNotEqual(old_count, new_count)
def test_user_can_login(self): def test_user_can_login(self):
@ -64,7 +61,7 @@ class OpenNebulaManagerTestCases(TestCase):
client = self.manager._get_client(self.user) client = self.manager._get_client(self.user)
version = client.version() version = client.version()
# Cleanup # Cleanup
user.delete() user.delete()
self.assertNotEqual(version, None) self.assertNotEqual(version, None)
@ -77,11 +74,11 @@ class OpenNebulaManagerTestCases(TestCase):
# Fetch new user information from opennebula # Fetch new user information from opennebula
user.info() user.info()
user_public_key = user.template.ssh_public_key user_public_key = user.template.ssh_public_key
# Cleanup # Cleanup
user.delete() user.delete()
self.assertEqual(user_public_key, public_key) self.assertEqual(user_public_key, public_key)
def test_append_public_key_to_user(self): def test_append_public_key_to_user(self):
""" Test the manager can append a new public key to an user """ """ Test the manager can append a new public key to an user """
self.manager.create_user(self.user) self.manager.create_user(self.user)
@ -94,11 +91,11 @@ class OpenNebulaManagerTestCases(TestCase):
self.manager.add_public_key(self.user, public_key, merge=True) self.manager.add_public_key(self.user, public_key, merge=True)
user.info() user.info()
new_public_key = user.template.ssh_public_key new_public_key = user.template.ssh_public_key
# Cleanup # Cleanup
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 """
@ -112,12 +109,11 @@ class OpenNebulaManagerTestCases(TestCase):
self.manager.remove_public_key(self.user, public_key) self.manager.remove_public_key(self.user, public_key)
user.info() user.info()
new_public_key = user.template.ssh_public_key new_public_key = user.template.ssh_public_key
# Cleanup # Cleanup
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
@ -128,14 +124,11 @@ class VirtualMachineSerializerTestCase(TestCase):
def setUp(self): def setUp(self):
"""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-'."""
for vm in self.manager.get_vms(): for vm in self.manager.get_vms():
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.'
@ -29,7 +21,7 @@ class VmCreateView(generics.ListCreateAPIView):
owner = self.request.user owner = self.request.user
manager = OpenNebulaManager(email=owner.email, manager = OpenNebulaManager(email=owner.email,
password=owner.password) password=owner.password)
# We may have ConnectionRefusedError if we don't have a # We may have ConnectionRefusedError if we don't have a
# connection to OpenNebula. For now, we raise ServiceUnavailable # connection to OpenNebula. For now, we raise ServiceUnavailable
try: try:
vms = manager.get_vms() vms = manager.get_vms()
@ -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, )
@ -51,7 +44,7 @@ class VmDetailsView(generics.RetrieveUpdateDestroyAPIView):
owner = self.request.user owner = self.request.user
manager = OpenNebulaManager(email=owner.email, manager = OpenNebulaManager(email=owner.email,
password=owner.password) password=owner.password)
# We may have ConnectionRefusedError if we don't have a # We may have ConnectionRefusedError if we don't have a
# connection to OpenNebula. For now, we raise ServiceUnavailable # connection to OpenNebula. For now, we raise ServiceUnavailable
try: try:
vms = manager.get_vms() vms = manager.get_vms()
@ -63,22 +56,21 @@ class VmDetailsView(generics.RetrieveUpdateDestroyAPIView):
owner = self.request.user owner = self.request.user
manager = OpenNebulaManager(email=owner.email, manager = OpenNebulaManager(email=owner.email,
password=owner.password) password=owner.password)
# We may have ConnectionRefusedError if we don't have a # We may have ConnectionRefusedError if we don't have a
# connection to OpenNebula. For now, we raise ServiceUnavailable # connection to OpenNebula. For now, we raise ServiceUnavailable
try: try:
vm = manager.get_vm(self.kwargs.get('pk')) vm = manager.get_vm(self.kwargs.get('pk'))
except ConnectionRefusedError: except ConnectionRefusedError:
raise ServiceUnavailable raise ServiceUnavailable
return vm return vm
def perform_destroy(self, instance): def perform_destroy(self, instance):
owner = self.request.user owner = self.request.user
manager = OpenNebulaManager(email=owner.email, manager = OpenNebulaManager(email=owner.email,
password=owner.password) password=owner.password)
# We may have ConnectionRefusedError if we don't have a # We may have ConnectionRefusedError if we don't have a
# connection to OpenNebula. For now, we raise ServiceUnavailable # connection to OpenNebula. For now, we raise ServiceUnavailable
try: try:
manager.delete_vm(instance.id) manager.delete_vm(instance.id)
except ConnectionRefusedError: except ConnectionRefusedError:
raise ServiceUnavailable raise ServiceUnavailable

View file

@ -84,5 +84,4 @@ 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

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 = (
@ -255,4 +254,4 @@ class CountryField(models.CharField):
super(CountryField, self).__init__(*args, **kwargs) super(CountryField, self).__init__(*args, **kwargs)
def get_internal_type(self): def get_internal_type(self):
return "CharField" return "CharField"

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)