diff --git a/alplora/static/alplora/js/form.js b/alplora/static/alplora/js/form.js new file mode 100644 index 00000000..0e91b172 --- /dev/null +++ b/alplora/static/alplora/js/form.js @@ -0,0 +1,12 @@ +/*! + * jQuery Form Plugin + * version: 4.2.1 + * Requires jQuery v1.7 or later + * Copyright 2017 Kevin Morris + * Copyright 2006 M. Alsup + * Project repository: https://github.com/jquery-form/form + * Dual licensed under the MIT and LGPLv3 licenses. + * https://github.com/jquery-form/form#license + */ +!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof module&&module.exports?module.exports=function(b,c){return void 0===c&&(c="undefined"!=typeof window?require("jquery"):require("jquery")(b)),a(c),c}:a(jQuery)}(function(a){"use strict";function b(b){var c=b.data;b.isDefaultPrevented()||(b.preventDefault(),a(b.target).closest("form").ajaxSubmit(c))}function c(b){var c=b.target,d=a(c);if(!d.is("[type=submit],[type=image]")){var e=d.closest("[type=submit]");if(0===e.length)return;c=e[0]}var f=c.form;if(f.clk=c,"image"===c.type)if(void 0!==b.offsetX)f.clk_x=b.offsetX,f.clk_y=b.offsetY;else if("function"==typeof a.fn.offset){var g=d.offset();f.clk_x=b.pageX-g.left,f.clk_y=b.pageY-g.top}else f.clk_x=b.pageX-c.offsetLeft,f.clk_y=b.pageY-c.offsetTop;setTimeout(function(){f.clk=f.clk_x=f.clk_y=null},100)}function d(){if(a.fn.ajaxSubmit.debug){var b="[jquery.form] "+Array.prototype.join.call(arguments,"");window.console&&window.console.log?window.console.log(b):window.opera&&window.opera.postError&&window.opera.postError(b)}}var e={};e.fileapi=void 0!==a('').get(0).files,e.formdata=void 0!==window.FormData;var f=!!a.fn.prop;a.fn.attr2=function(){if(!f)return this.attr.apply(this,arguments);var a=this.prop.apply(this,arguments);return a&&a.jquery||"string"==typeof a?a:this.attr.apply(this,arguments)},a.fn.ajaxSubmit=function(b,c,g,h){function i(c){var d,e,f=a.param(c,b.traditional).split("&"),g=f.length,h=[];for(d=0;d',z).val(k.extraData[j].value).appendTo(x)[0]):i.push(a('',z).val(k.extraData[j]).appendTo(x)[0]));k.iframeTarget||p.appendTo(A),q.attachEvent?q.attachEvent("onload",h):q.addEventListener("load",h,!1),setTimeout(b,15);try{x.submit()}catch(a){var m=document.createElement("form").submit;m.apply(x)}}finally{x.setAttribute("action",f),x.setAttribute("enctype",g),c?x.setAttribute("target",c):o.removeAttr("target"),a(i).remove()}}function h(b){if(!r.aborted&&!F){if(E=e(q),E||(d("cannot access response document"),b=2),1===b&&r)return r.abort("timeout"),void y.reject(r,"timeout");if(2===b&&r)return r.abort("server abort"),void y.reject(r,"error","server abort");if(E&&E.location.href!==k.iframeSrc||v){q.detachEvent?q.detachEvent("onload",h):q.removeEventListener("load",h,!1);var c,f="success";try{if(v)throw"timeout";var g="xml"===k.dataType||E.XMLDocument||a.isXMLDoc(E);if(d("isXml="+g),!g&&window.opera&&(null===E.body||!E.body.innerHTML)&&--G)return d("requeing onLoad callback, DOM not available"),void setTimeout(h,250);var i=E.body?E.body:E.documentElement;r.responseText=i?i.innerHTML:null,r.responseXML=E.XMLDocument?E.XMLDocument:E,g&&(k.dataType="xml"),r.getResponseHeader=function(a){return{"content-type":k.dataType}[a.toLowerCase()]},i&&(r.status=Number(i.getAttribute("status"))||r.status,r.statusText=i.getAttribute("statusText")||r.statusText);var j=(k.dataType||"").toLowerCase(),l=/(json|script|text)/.test(j);if(l||k.textarea){var n=E.getElementsByTagName("textarea")[0];if(n)r.responseText=n.value,r.status=Number(n.getAttribute("status"))||r.status,r.statusText=n.getAttribute("statusText")||r.statusText;else if(l){var o=E.getElementsByTagName("pre")[0],s=E.getElementsByTagName("body")[0];o?r.responseText=o.textContent?o.textContent:o.innerText:s&&(r.responseText=s.textContent?s.textContent:s.innerText)}}else"xml"===j&&!r.responseXML&&r.responseText&&(r.responseXML=H(r.responseText));try{D=J(r,j,k)}catch(a){f="parsererror",r.error=c=a||f}}catch(a){d("error caught: ",a),f="error",r.error=c=a||f}r.aborted&&(d("upload aborted"),f=null),r.status&&(f=r.status>=200&&r.status<300||304===r.status?"success":"error"),"success"===f?(k.success&&k.success.call(k.context,D,"success",r),y.resolve(r.responseText,"success",r),m&&a.event.trigger("ajaxSuccess",[r,k])):f&&(void 0===c&&(c=r.statusText),k.error&&k.error.call(k.context,r,f,c),y.reject(r,"error",c),m&&a.event.trigger("ajaxError",[r,k,c])),m&&a.event.trigger("ajaxComplete",[r,k]),m&&!--a.active&&a.event.trigger("ajaxStop"),k.complete&&k.complete.call(k.context,r,f),F=!0,k.timeout&&clearTimeout(w),setTimeout(function(){k.iframeTarget?p.attr("src",k.iframeSrc):p.remove(),r.responseXML=null},100)}}}var i,j,k,m,n,p,q,r,t,u,v,w,x=o[0],y=a.Deferred();if(y.abort=function(a){r.abort(a)},c)for(j=0;j',z),p.css({position:"absolute",top:"-1000px",left:"-1000px"})),q=p[0],r={aborted:0,responseText:null,responseXML:null,status:0,statusText:"n/a",getAllResponseHeaders:function(){},getResponseHeader:function(){},setRequestHeader:function(){},abort:function(b){var c="timeout"===b?"timeout":"aborted";d("aborting upload... "+c),this.aborted=1;try{q.contentWindow.document.execCommand&&q.contentWindow.document.execCommand("Stop")}catch(a){}p.attr("src",k.iframeSrc),r.error=c,k.error&&k.error.call(k.context,r,c,b),m&&a.event.trigger("ajaxError",[r,k,c]),k.complete&&k.complete.call(k.context,r,c)}},m=k.global,m&&0==a.active++&&a.event.trigger("ajaxStart"),m&&a.event.trigger("ajaxSend",[r,k]),k.beforeSend&&k.beforeSend.call(k.context,r,k)===!1)return k.global&&a.active--,y.reject(),y;if(r.aborted)return y.reject(),y;(t=x.clk)&&(u=t.name)&&!t.disabled&&(k.extraData=k.extraData||{},k.extraData[u]=t.value,"image"===t.type&&(k.extraData[u+".x"]=x.clk_x,k.extraData[u+".y"]=x.clk_y));var B=a("meta[name=csrf-token]").attr("content"),C=a("meta[name=csrf-param]").attr("content");C&&B&&(k.extraData=k.extraData||{},k.extraData[C]=B),k.forceSync?g():setTimeout(g,10);var D,E,F,G=50,H=a.parseXML||function(a,b){return window.ActiveXObject?(b=new ActiveXObject("Microsoft.XMLDOM"),b.async="false",b.loadXML(a)):b=(new DOMParser).parseFromString(a,"text/xml"),b&&b.documentElement&&"parsererror"!==b.documentElement.nodeName?b:null},I=a.parseJSON||function(a){return window.eval("("+a+")")},J=function(b,c,d){var e=b.getResponseHeader("content-type")||"",f=("xml"===c||!c)&&e.indexOf("xml")>=0,g=f?b.responseXML:b.responseText;return f&&"parsererror"===g.documentElement.nodeName&&a.error&&a.error("parsererror"),d&&d.dataFilter&&(g=d.dataFilter(g,c)),"string"==typeof g&&(("json"===c||!c)&&e.indexOf("json")>=0?g=I(g):("script"===c||!c)&&e.indexOf("javascript")>=0&&a.globalEval(g)),g};return y}if(!this.length)return d("ajaxSubmit: skipping submit process - no element selected"),this;var l,m,n,o=this;"function"==typeof b?b={success:b}:"string"==typeof b||b===!1&&arguments.length>0?(b={url:b,data:c,dataType:g},"function"==typeof h&&(b.success=h)):void 0===b&&(b={}),l=b.method||b.type||this.attr2("method"),m=b.url||this.attr2("action"),n="string"==typeof m?a.trim(m):"",n=n||window.location.href||"",n&&(n=(n.match(/^([^#]+)/)||[])[1]),b=a.extend(!0,{url:n,success:a.ajaxSettings.success,type:l||a.ajaxSettings.type,iframeSrc:/^https/i.test(window.location.href||"")?"javascript:false":"about:blank"},b);var p={};if(this.trigger("form-pre-serialize",[this,b,p]),p.veto)return d("ajaxSubmit: submit vetoed via form-pre-serialize trigger"),this;if(b.beforeSerialize&&b.beforeSerialize(this,b)===!1)return d("ajaxSubmit: submit aborted via beforeSerialize callback"),this;var q=b.traditional;void 0===q&&(q=a.ajaxSettings.traditional);var r,s=[],t=this.formToArray(b.semantic,s,b.filtering);if(b.data){var u=a.isFunction(b.data)?b.data(t):b.data;b.extraData=u,r=a.param(u,q)}if(b.beforeSubmit&&b.beforeSubmit(t,this,b)===!1)return d("ajaxSubmit: submit aborted via beforeSubmit callback"),this;if(this.trigger("form-submit-validate",[t,this,b,p]),p.veto)return d("ajaxSubmit: submit vetoed via form-submit-validate trigger"),this;var v=a.param(t,q);r&&(v=v?v+"&"+r:r),"GET"===b.type.toUpperCase()?(b.url+=(b.url.indexOf("?")>=0?"&":"?")+v,b.data=null):b.data=v;var w=[];if(b.resetForm&&w.push(function(){o.resetForm()}),b.clearForm&&w.push(function(){o.clearForm(b.includeHidden)}),!b.dataType&&b.target){var x=b.success||function(){};w.push(function(c,d,e){var f=arguments,g=b.replaceTarget?"replaceWith":"html";a(b.target)[g](c).each(function(){x.apply(this,f)})})}else b.success&&(a.isArray(b.success)?a.merge(w,b.success):w.push(b.success));if(b.success=function(a,c,d){for(var e=b.context||this,f=0,g=w.length;f0,C="multipart/form-data",D=o.attr("enctype")===C||o.attr("encoding")===C,E=e.fileapi&&e.formdata;d("fileAPI :"+E);var F,G=(B||D)&&!E;b.iframe!==!1&&(b.iframe||G)?b.closeKeepAlive?a.get(b.closeKeepAlive,function(){F=k(t)}):F=k(t):F=(B||D)&&E?j(t):a.ajax(b),o.removeData("jqxhr").data("jqxhr",F);for(var H=0;H0)&&(e={url:e,data:f,dataType:g},"function"==typeof h&&(e.success=h)),e=e||{},e.delegation=e.delegation&&a.isFunction(a.fn.on),!e.delegation&&0===this.length){var i={s:this.selector,c:this.context};return!a.isReady&&i.s?(d("DOM not ready, queuing ajaxForm"),a(function(){a(i.s,i.c).ajaxForm(e)}),this):(d("terminating; zero elements found by selector"+(a.isReady?"":" (DOM not ready)")),this)}return e.delegation?(a(document).off("submit.form-plugin",this.selector,b).off("click.form-plugin",this.selector,c).on("submit.form-plugin",this.selector,e,b).on("click.form-plugin",this.selector,e,c),this):this.ajaxFormUnbind().on("submit.form-plugin",e,b).on("click.form-plugin",e,c)},a.fn.ajaxFormUnbind=function(){return this.off("submit.form-plugin click.form-plugin")},a.fn.formToArray=function(b,c,d){var f=[];if(0===this.length)return f;var g,h=this[0],i=this.attr("id"),j=b||void 0===h.elements?h.getElementsByTagName("*"):h.elements;if(j&&(j=a.makeArray(j)),i&&(b||/(Edge|Trident)\//.test(navigator.userAgent))&&(g=a(':input[form="'+i+'"]').get(),g.length&&(j=(j||[]).concat(g))),!j||!j.length)return f;a.isFunction(d)&&(j=a.map(j,d));var k,l,m,n,o,p,q;for(k=0,p=j.length;k + + + diff --git a/alplora/templates/alplora/contact_success.html b/alplora/templates/alplora/contact_success.html new file mode 100644 index 00000000..563b2e89 --- /dev/null +++ b/alplora/templates/alplora/contact_success.html @@ -0,0 +1,21 @@ +{% load i18n %} + + diff --git a/alplora/templates/alplora/index.html b/alplora/templates/alplora/index.html index 495961a4..ae388459 100644 --- a/alplora/templates/alplora/index.html +++ b/alplora/templates/alplora/index.html @@ -53,7 +53,6 @@ -
@@ -419,7 +418,9 @@

{% trans 'How do I get Alplora?'%}

{% trans 'Click the button below and leave us your contact.'%}

{% trans 'Team Alplora will contact you and visit you with a tracking device.'%}


- {% trans 'Contact'%} + {% trans 'Contact'%}
@@ -429,60 +430,9 @@
- @@ -560,6 +510,7 @@ + @@ -572,14 +523,15 @@ - diff --git a/alplora/urls.py b/alplora/urls.py index a84884c4..f792f13f 100644 --- a/alplora/urls.py +++ b/alplora/urls.py @@ -1,11 +1,12 @@ from django.conf.urls import url -from .views import IndexView, LoginView +from .views import IndexView, LoginView, ContactView urlpatterns = [ url(r'^/?$', IndexView.as_view(), name='index'), url(r'/login/', LoginView.as_view(), name='login'), + url(r'/contact', ContactView.as_view(), name='contact'), # url(r'^/beta-program/?$', BetaProgramView.as_view(), name='beta'), # url(r'^/landing/?$', LandingProgramView.as_view(), name='landing'), ] diff --git a/alplora/views.py b/alplora/views.py index 5c6bacd2..ba249887 100644 --- a/alplora/views.py +++ b/alplora/views.py @@ -5,13 +5,12 @@ from django.utils.translation import ugettext_lazy as _ from django.views.generic.edit import FormView from django.contrib import messages from django.core.urlresolvers import reverse_lazy, reverse +from django.shortcuts import render from utils.forms import ContactUsForm -class IndexView(FormView): +class IndexView(TemplateView): template_name = "alplora/index.html" - form_class = ContactUsForm - success_message = _('Message Successfully Sent') def get_context_data(self, *args, **kwargs): context = super(IndexView, self).get_context_data(**kwargs) @@ -19,17 +18,22 @@ class IndexView(FormView): context.update(languages) return context - def get_success_url(self): - success_url = reverse('alplora:index') - success_url += "#requestformsuccess" - return success_url +class ContactView(FormView): + template_name = 'alplora/contact.html' + form_class = ContactUsForm + success_message = _('Message Successfully Sent') + + def get_context_data(self, *args, **kwargs): + context = super(ContactView, self).get_context_data(**kwargs) + languages = getlanguages() + context.update(languages) + return context def form_valid(self, form): form.save() form.send_email(email_to='info@alplora.ch') messages.add_message(self.request, messages.SUCCESS, self.success_message) - return super(IndexView, self).form_valid(form) - + return render(self.request, 'alplora/contact_success.html', {}) class LoginView(TemplateView): template_name = "alplora/login.html" diff --git a/cms_templates/djangocms_blog/_header_post_detail.html b/cms_templates/djangocms_blog/_header_post_detail.html index 669de5bc..2fa8697e 100644 --- a/cms_templates/djangocms_blog/_header_post_detail.html +++ b/cms_templates/djangocms_blog/_header_post_detail.html @@ -17,21 +17,10 @@ {% render_model post "abstract" "" "" 'truncatewords_html:10' %} - Posted - {% if post.author %} - by - - {% if post.author.get_full_name %} - {{ post.author.get_full_name }} - {% else %} - {{ post.author }} - {% endif %} - - {% endif %} - on {{ post.date_published|date:"DATE_FORMAT" }} + Posted on {{ post.date_published|date:"DATE_FORMAT" }} - \ No newline at end of file + diff --git a/digitalglarus/templates/digitalglarus/post_detail.html b/digitalglarus/templates/digitalglarus/post_detail.html index f59cec48..90ba0384 100644 --- a/digitalglarus/templates/digitalglarus/post_detail.html +++ b/digitalglarus/templates/digitalglarus/post_detail.html @@ -16,18 +16,7 @@

diff --git a/hosting/models.py b/hosting/models.py index 3b096d92..fe40ff3f 100644 --- a/hosting/models.py +++ b/hosting/models.py @@ -15,7 +15,10 @@ from membership.models import StripeCustomer, CustomUser from utils.models import BillingAddress from utils.mixins import AssignPermissionsMixin from .managers import VMPlansManager +from oca.pool import WrongNameError +import logging +logger = logging.getLogger(__name__) class VirtualMachineType(models.Model): @@ -290,3 +293,12 @@ class ManageVM(models.Model): class Meta: managed = False + +def get_user_opennebula_password(): + ''' + TODO: Implement the way we obtain the user's opennebula password + ''' + pw = os.environ.get('OPENNEBULA_USER_PW') + if pw is None: + raise Exception("Define OPENNEBULA_USER_PW env variable") + return pw diff --git a/hosting/opennebula_functions.py b/hosting/opennebula_functions.py index f043270b..b0d0e13b 100644 --- a/hosting/opennebula_functions.py +++ b/hosting/opennebula_functions.py @@ -14,6 +14,7 @@ from django.utils.translation import ugettext_lazy as _ from oca.exceptions import OpenNebulaException from oca.pool import WrongNameError +from django import forms # Get an instance of a logger logger = logging.getLogger(__name__) @@ -135,9 +136,9 @@ class HostingManageVMAdmin(admin.ModelAdmin): port=settings.OPENNEBULA_PORT, endpoint=settings.OPENNEBULA_ENDPOINT )) - print("{0}:{1}".format(settings.OPENNEBULA_USERNAME, + logger.debug("{0}:{1}".format(settings.OPENNEBULA_USERNAME, settings.OPENNEBULA_PASSWORD)) - print("{protocol}://{domain}:{port}{endpoint}".format( + logger.debug("{protocol}://{domain}:{port}{endpoint}".format( protocol=settings.OPENNEBULA_PROTOCOL, domain=settings.OPENNEBULA_DOMAIN, port=settings.OPENNEBULA_PORT, @@ -146,6 +147,7 @@ class HostingManageVMAdmin(admin.ModelAdmin): self.create_opennebula_user(request) if self.client is None: opennebula_user = request.user.email + # TODO: get the password stored in django opennebula_user_password ='19737450' self.client = oca.Client("{0}:{1}".format(opennebula_user, opennebula_user_password), "{protocol}://{domain}:{port}{endpoint}".format( @@ -172,6 +174,7 @@ class HostingManageVMAdmin(admin.ModelAdmin): # Include common variables for rendering the admin template. self.admin_site.each_context(request), vms=vm_pool, + form=HostingManageVMForm ) return TemplateResponse(request, "hosting/managevms.html", context) @@ -259,22 +262,30 @@ class HostingManageVMAdmin(admin.ModelAdmin): vm_template_int = int(vm_template) if 1 <= vm_template_int <= 8: vm_string_formatter = """ + + + {ssh_key} + + {memory} {vcpu} {cpu} {disk_type} {size} + {dev_prefix} """ vm_id = oca.VirtualMachine.allocate(self.client, - vm_string_formatter.format( - memory=1024 * vm_template_int, - vcpu=vm_template_int, - cpu=0.1 * vm_template_int, - disk_type='fs', - size=10000 * vm_template_int)) + vm_string_formatter.format( + ssh_key='', # public key of the user + memory=1024 * vm_template_int, # memory in MB + vcpu=vm_template_int, # vpcu + cpu=0.1 * vm_template_int, # cpu + disk_type='fs', + size=10000 * vm_template_int, + dev_prefix='vd')) # We need KVM virtual disk message = _("Created with id = " + str(vm_id)) messages.add_message(request, messages.SUCCESS, message) else: @@ -372,14 +383,60 @@ class HostingManageVMAdmin(admin.ModelAdmin): opennebula_user = user_pool.get_by_name(request.user.email) logger.debug("User {0} exists. User id = {1}".format(request.user.email, opennebula_user.id)) except WrongNameError as wrong_name_err: - user_id = self.oneadmin_client.call('user.allocate', request.user.email, get_random_password(), - 'dummy') + # TODO: Store this password so that we can use it later to + # connect to opennebula + password = get_random_password() + oca.User.allocate(self.oneadmin_client, request.user.email, password) logger.debug("User {0} does not exist. Created the user. User id = {1}", request.user.email, user_id) except OpenNebulaException as err: messages.add_message(request, messages.ERROR, "Error : {0}".format(err)) logger.error("Error : {0}".format(err)) +def set_field_html_name(cls, new_name): + """ + This creates wrapper around the normal widget rendering, + allowing for a custom field name (new_name). + """ + old_render = cls.widget.render + def _widget_render_wrapper(name, value, attrs=None): + return old_render(new_name, value, attrs) + cls.widget.render = _widget_render_wrapper + +class HostingManageVMForm(forms.Form): + vm_templates = [] + VM_CHOICES = (('1', 'disk = 10GB, vcpu=1, ram=1GB'), + ('2', 'disk = 20GB, vcpu=2, ram=2GB'), + ('3', 'disk = 40GB, vcpu=4, ram=4GB'), + ('4', 'disk = 80GB, vcpu=8, ram=8GB'), + ('5', 'disk = 160GB, vcpu=16, ram=16GB'), + ('6', 'disk = 320GB, vcpu=32, ram=32GB'), + ('7', 'disk = 640GB, vcpu=64, ram=64GB'), + ('8', 'disk = 1280GB, vcpu=128, ram=128GB')) + #for i in range(0,8): + # factor = pow(2, i) + # vm_templates.append(VMTemplate(i, VM_CHOICES[i], 10000 * factor, factor , 0.1 * factor, 1024 * factor)) + field = forms.ChoiceField(label="Choose a VM Template ", choices=VM_CHOICES, widget=forms.Select(attrs={"id": "vm_template"})) + set_field_html_name(field, 'vm_template') + + + +class VMTemplate: + """A simple representation of a VM template. + + :param template_id: The id of the template + :param label: A string representation describing the template. Used as the label in view + :param disk: VM disk space in MB + :param vcpu: Virtual cpu for the VM + :param cpu: CPU for the VM + :param ram: The RAM for the VM + """ + def __init__(self, template_id, label, disk, vcpu, cpu, ram): + self.template_id = template_id + self.label = label + self.disk = disk + self.vcpu = vcpu + self.cpu = cpu # Returns random password that is needed by OpenNebula def get_random_password(): diff --git a/hosting/templates/hosting/managevms.html b/hosting/templates/hosting/managevms.html index f8c7e873..54270316 100644 --- a/hosting/templates/hosting/managevms.html +++ b/hosting/templates/hosting/managevms.html @@ -2,13 +2,9 @@ {% block content %}

- {% csrf_token %} - - + {% csrf_token %} + {{ form }} +
{% if vms %}