diff --git a/Changelog b/Changelog index d3c2c549..1ad8f324 100644 --- a/Changelog +++ b/Changelog @@ -2,6 +2,12 @@ Next: * #3911: [dcl] Integrate resend activation link into dcl landing payment page * #3972: [hosting] Add ungleich company info to invoice footer * #3974: [hosting] Improve invoice number: Show 404 for invoice resources that do not belong to the user + * [ungleich] Add video cover to the header on ungleich.ch landing page and add corresponding cms plugin + * #3774: [hosting] Update Stripe subscription on vm delete + * [ungleich] Update text on landing page + * #3601: [dcl, hosting] Change minimum required RAM from 2GB to 1GB + * #3973: [dcl] Update datacenterlight and glasfaser contact address to Linthal and company name to "ungleich glarus ag" + * #3993: [dg] Fix new user membership payment by setting cardholder_name field for UserBillingAddressForm 1.2.13: 2017-12-09 * [cms] Introduce UngleichHeaderBackgroundImageAndTextSliderPlugin that allows to have scrolling images and texts * [cms] Remove

tag for ungleich cms customer item template diff --git a/datacenterlight/locale/de/LC_MESSAGES/django.po b/datacenterlight/locale/de/LC_MESSAGES/django.po index 1dbdd2a0..859781b6 100644 --- a/datacenterlight/locale/de/LC_MESSAGES/django.po +++ b/datacenterlight/locale/de/LC_MESSAGES/django.po @@ -56,11 +56,11 @@ msgstr "Standort: Schweiz" msgid "Please enter a value in range 1 - 48." msgstr "Bitte gib einen Wert von 1 bis 48 ein." -msgid "Please enter a value in range 2 - 200." -msgstr "Bitte gib einen Wert von 2 bis 200 ein." +msgid "Please enter a value in range 1 - 200." +msgstr "Bitte gib einen Wert von 1 bis 200 ein." msgid "Please enter a value in range 10 - 2000." -msgstr "Bitte gib einen Wert von 10 bis 200 ein." +msgstr "Bitte gib einen Wert von 10 bis 2000 ein." msgid "GB Storage (SSD)" msgstr "GB Storage (SSD)" diff --git a/datacenterlight/static/datacenterlight/js/main.js b/datacenterlight/static/datacenterlight/js/main.js index dd074397..4c50702e 100644 --- a/datacenterlight/static/datacenterlight/js/main.js +++ b/datacenterlight/static/datacenterlight/js/main.js @@ -16,7 +16,7 @@ 'ram': { 'id': 'ramValue', 'value': 2, - 'min': 2, + 'min': 1, 'max': 200, 'interval': 1 }, diff --git a/datacenterlight/templates/datacenterlight/calculator_form.html b/datacenterlight/templates/datacenterlight/calculator_form.html index 1733a719..dcab80b3 100644 --- a/datacenterlight/templates/datacenterlight/calculator_form.html +++ b/datacenterlight/templates/datacenterlight/calculator_form.html @@ -36,8 +36,8 @@

- + GB RAM
diff --git a/datacenterlight/templates/datacenterlight/index.html b/datacenterlight/templates/datacenterlight/index.html index cc3597ec..f8ac4419 100755 --- a/datacenterlight/templates/datacenterlight/index.html +++ b/datacenterlight/templates/datacenterlight/index.html @@ -160,11 +160,11 @@
-

ungleich GmbH

+

ungleich glarus ag

info@datacenterlight.ch

-

In der Au 7, Schwanden 8762

+

Bahnhofstrasse 1, 8783 Linthal

{% trans "Switzerland " %}

diff --git a/datacenterlight/views.py b/datacenterlight/views.py index bd1a7f51..fda8c9c9 100644 --- a/datacenterlight/views.py +++ b/datacenterlight/views.py @@ -209,7 +209,7 @@ class IndexView(CreateView): raise ValidationError(_('Invalid number of cores')) def validate_memory(self, value): - if (value > 200) or (value < 2): + if (value > 200) or (value < 1): raise ValidationError(_('Invalid RAM size')) def validate_storage(self, value): diff --git a/digitalglarus/views.py b/digitalglarus/views.py index 87c1ccd2..96983d9b 100644 --- a/digitalglarus/views.py +++ b/digitalglarus/views.py @@ -376,6 +376,10 @@ class MembershipPaymentView(LoginRequiredMixin, IsNotMemberMixin, FormView): return render(request, self.template_name, context) charge = charge_response.get('response_object') + if 'source' in charge: + cardholder_name = charge['source']['name'] + else: + cardholder_name = customer.user.name # Create Billing Address billing_address = form.save() @@ -383,7 +387,8 @@ class MembershipPaymentView(LoginRequiredMixin, IsNotMemberMixin, FormView): # Create Billing Address for User if he does not have one if not customer.user.billing_addresses.count(): data.update({ - 'user': customer.user.id + 'user': customer.user.id, + 'cardholder_name': cardholder_name }) billing_address_user_form = UserBillingAddressForm(data) billing_address_user_form.is_valid() diff --git a/hosting/locale/de/LC_MESSAGES/django.po b/hosting/locale/de/LC_MESSAGES/django.po index 2be2ae6d..118245e5 100644 --- a/hosting/locale/de/LC_MESSAGES/django.po +++ b/hosting/locale/de/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-10-26 03:21+0530\n" +"POT-Creation-Date: 2017-12-21 00:23+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -128,11 +128,11 @@ msgstr "MwSt. inklusive" msgid "Please enter a value in range 1 - 48." msgstr "Bitte gib einen Wert von 1 bis 48 ein." -msgid "Please enter a value in range 2 - 200." -msgstr "Bitte gib einen Wert von 2 bis 200 ein." +msgid "Please enter a value in range 1 - 200." +msgstr "Bitte gib einen Wert von 1 bis 200 ein." msgid "Please enter a value in range 10 - 2000." -msgstr "Bitte gib einen Wert von 10 bis 200 ein." +msgstr "Bitte gib einen Wert von 10 bis 2000 ein." msgid "GB Storage (SSD)" msgstr "GB Storage (SSD)" diff --git a/hosting/static/hosting/js/createvm.js b/hosting/static/hosting/js/createvm.js index 726513ad..8d525114 100644 --- a/hosting/static/hosting/js/createvm.js +++ b/hosting/static/hosting/js/createvm.js @@ -12,7 +12,7 @@ 'ram': { 'id': 'ramValue', 'value': 2, - 'min': 2, + 'min': 1, 'max': 200, 'interval': 1 }, diff --git a/hosting/templates/hosting/calculator_form.html b/hosting/templates/hosting/calculator_form.html index 18bdd3cb..02bb36ea 100644 --- a/hosting/templates/hosting/calculator_form.html +++ b/hosting/templates/hosting/calculator_form.html @@ -29,8 +29,8 @@
- + GB RAM
diff --git a/hosting/views.py b/hosting/views.py index 8a746a56..197a843d 100644 --- a/hosting/views.py +++ b/hosting/views.py @@ -41,6 +41,7 @@ from utils.forms import ( from utils.hosting_utils import get_vm_price from utils.mailer import BaseEmail from utils.stripe_utils import StripeUtils +from utils.tasks import send_plain_email_task from utils.views import ( PasswordResetViewMixin, PasswordResetConfirmViewMixin, LoginViewMixin, ResendActivationLinkViewMixin @@ -945,7 +946,7 @@ class CreateVirtualMachinesView(LoginRequiredMixin, View): raise ValidationError(_('Invalid number of cores')) def validate_memory(self, value): - if (value > 200) or (value < 2): + if (value > 200) or (value < 1): raise ValidationError(_('Invalid RAM size')) def validate_storage(self, value): @@ -1036,7 +1037,7 @@ class VirtualMachineView(LoginRequiredMixin, View): ) return None except Exception as error: - print(error) + logger.error(str(error)) raise Http404() def get_success_url(self): @@ -1079,49 +1080,88 @@ class VirtualMachineView(LoginRequiredMixin, View): def post(self, request, *args, **kwargs): response = {'status': False} + admin_email_body = {} owner = self.request.user vm = self.get_object() - opennebula_vm_id = self.kwargs.get('pk') - manager = OpenNebulaManager( email=owner.email, password=owner.password ) - try: vm_data = VirtualMachineSerializer(manager.get_vm(vm.id)).data vm_name = vm_data.get('name') - except WrongIdError: + except WrongIdError as wrong_id_err: + logger.error(str(wrong_id_err)) return redirect(reverse('hosting:virtual_machines')) + # Cancel Stripe subscription + stripe_utils = StripeUtils() + try: + hosting_order = HostingOrder.objects.get( + vm_id=vm.id + ) + result = stripe_utils.unsubscribe_customer( + subscription_id=hosting_order.subscription_id + ) + stripe_subscription_obj = result.get('response_object') + # Check if the subscription was canceled + if (stripe_subscription_obj is None or + stripe_subscription_obj.status != 'canceled'): + error_msg = result.get('error') + logger.error( + 'Error canceling subscription for {user} and vm id ' + '{vm_id}'.format(user=owner.email, vm_id=vm.id) + ) + logger.error(error_msg) + admin_email_body['stripe_error_msg'] = error_msg + except HostingOrder.DoesNotExist: + error_msg = ( + "HostingOrder corresponding to vm_id={vm_id} does" + "not exist. Hence, can not find subscription to " + "cancel ".format(vm_id=vm.id) + ) + logger.error(error_msg) + admin_email_body['stripe_error_msg'] = error_msg + terminated = manager.delete_vm(vm.id) if not terminated: - response['text'] = ugettext( - 'Error terminating VM') + opennebula_vm_id + logger.debug( + "manager.delete_vm returned False. Hence, error making " + "xml-rpc call to delete vm failed." + ) + response['text'] = ugettext('Error terminating VM') + vm.id else: for t in range(15): try: - manager.get_vm(opennebula_vm_id) + manager.get_vm(vm.id) except WrongIdError: response['status'] = True response['text'] = ugettext('Terminated') vm_detail_obj = VMDetail.objects.filter( - vm_id=opennebula_vm_id).first() + vm_id=vm.id + ).first() vm_detail_obj.terminated_at = datetime.utcnow() vm_detail_obj.save() - break - except BaseException: + except BaseException as base_exception: + logger.error( + "manager.get_vm({vm_id}) returned exception: " + "{details}.".format( + details=str(base_exception), vm_id=vm.id + ) + ) break else: sleep(2) context = { 'vm_name': vm_name, - 'base_url': "{0}://{1}".format(self.request.scheme, - self.request.get_host()), + 'base_url': "{0}://{1}".format( + self.request.scheme, self.request.get_host() + ), 'page_header': _('Virtual Machine %(vm_name)s Cancelled') % { - 'vm_name': vm_name} + 'vm_name': vm_name + } } email_data = { 'subject': context['page_header'], @@ -1133,6 +1173,18 @@ class VirtualMachineView(LoginRequiredMixin, View): } email = BaseEmail(**email_data) email.send() + admin_email_body.update(response) + email_to_admin_data = { + 'subject': "Deleted VM and Subscription for VM {vm_id} and " + "user: {user}".format( + vm_id=vm.id, user=owner.email + ), + 'from_email': settings.DCL_SUPPORT_FROM_ADDRESS, + 'to': ['info@ungleich.ch'], + 'body': "\n".join( + ["%s=%s" % (k, v) for (k, v) in admin_email_body.items()]), + } + send_plain_email_task.delay(email_to_admin_data) return HttpResponse( json.dumps(response), content_type="application/json" diff --git a/ungleich_page/locale/de/LC_MESSAGES/django.po b/ungleich_page/locale/de/LC_MESSAGES/django.po index 029137b1..9b4ef07b 100644 --- a/ungleich_page/locale/de/LC_MESSAGES/django.po +++ b/ungleich_page/locale/de/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-12-22 01:00+0530\n" +"POT-Creation-Date: 2017-12-23 05:18+0530\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -71,14 +71,14 @@ msgstr "Die Chronik von ungleich" msgid "The first incarnation of ungleich" msgstr "Die erste Inkarnation von ungleich" -msgid "in Germany" -msgstr "in Deutschland" +msgid "in Germany." +msgstr "in Deutschland." msgid "ungleich founded" msgstr "ungleich gegründet" -msgid "in Switzerland" -msgstr "in der Schweiz" +msgid "in Switzerland." +msgstr "in der Schweiz." msgid "ungleich present at various conferences" msgstr "ungleich präsent an mehreren Konferenzen" @@ -107,7 +107,7 @@ msgstr "ungleich bietet einen PC-Grundkurs für Flüchtlinge an." msgid "" "ungleich starts computer learning club for locals, \"Digitale Building " -"ungleich.\"" +"ungleich\"." msgstr "" "ungleich gründet den Verein Digitale Bildung ungleich für Ortsansässige." @@ -116,7 +116,7 @@ msgid "" "startup in canton Zürich." msgstr "" "ungleich verkauft das Projekt AlpLora an ein IoT-Startup aus dem Kanton Zürich" +"\">AlpLora an ein IoT-Startup aus dem Kanton Zürich." msgid "" "ungleich showcases the most affordable Swiss VM hosting, Data Center Light." @@ -157,8 +157,37 @@ msgstr "Copyright © ungleich GmbH" msgid "ungleich Home" msgstr "ungleich Home" -msgid "We Design, Configure & Maintain
Your Linux Infrastructure " -msgstr "Wir designen, erstellen und warten
Ihre Linux-Infrastruktur" +msgid "Hosting" +msgstr "Hosting" + +msgid "" +"Ruby on Rails. Java hosting, Django hosting, we make it everything run " +"smooth and safe." +msgstr "" +"Ruby on Rails. Java hosting, Django hosting, wir garantieren einen " +"reibungslosen Ablauf." + +msgid "Configuration as a Service" +msgstr "Konfiguration als Service" + +msgid "" +"Ruby on Rails, Django, Java, Webserver, Mailserver, any infrastructure that " +"needs to configured, we provide comprehensive solutions. Amazon, rackspace " +"or bare metal servers, we configure for you." +msgstr "" +"Ruby on Rails, Django, Java, Webserver, Mailserver, jegliche Infrastruktur " +"welche eine Konfiguration braucht, wir offerieren umfassende Lösungen, " +"Amazon, Rackspace oder Bare Metal Servers, wir konfigurieren alles." + +msgid "Linux System Engineering" +msgstr "Linux System Engineering" + +msgid "" +"Let your developers develop! We take care of your system administration. " +"Gentoo, Archlinux, Debian, Ubuntu, and many more." +msgstr "" +"Lassen sie ihre Entwickler entwickeln! Wir kümmern uns um ihre " +"Systemadministration. Gentoo, Archlinux, Debian, Ubuntu und viele mehr." msgid "Our Products" msgstr "Unsere Produkte" @@ -216,38 +245,6 @@ msgstr "" "Unser erstklassiges Konfigurationsmanagement ist erfrischend einfach und " "zuverlässig." -msgid "Hosting" -msgstr "Hosting" - -msgid "" -"Ruby on Rails. Java hosting, Django hosting, we make it everything run " -"smooth and safe." -msgstr "" -"Ruby on Rails. Java hosting, Django hosting, wir garantieren einen " -"reibungslosen Ablauf" - -msgid "Configuration as a Service" -msgstr "Konfiguration als Service" - -msgid "" -"Ruby on Rails, Django, Java, Webserver, Mailserver, any infrastructure that " -"needs to configured, we provide comprehensive solutions. Amazon, rackspace " -"or bare metal servers, we configure for you." -msgstr "" -"Ruby on Rails, Django, Java, Webserver, Mailserver, jegliche Infrastruktur " -"welche eine Konfiguration braucht, wir offerieren umfassende Lösungen, " -"Amazon, Rackspace oder Bare Metal Servers, wir konfigurieren alles." - -msgid "Linux System Engineering" -msgstr "Linux System Engineering" - -msgid "" -"Let your developers develop! We take care of your system administration. " -"Gentoo, Archlinux, Debian, Ubuntu, and many more." -msgstr "" -"Lassen sie ihre Entwickler entwickeln! Wir kümmern uns um ihre " -"Systemadministration. Gentoo, Archlinux, Debian, Ubuntu und viele mehr." - msgid "Why ungleich?*" msgstr "Warum ungleich?" @@ -363,6 +360,9 @@ msgid "If you have any question, just send us an email." msgstr "" "Wenn Sie irgendwelche Fragen haben, schicken Sie uns einfach eine E-Mail." +#~ msgid "We Design, Configure & Maintain
Your Linux Infrastructure " +#~ msgstr "Wir designen, erstellen und warten
Ihre Linux-Infrastruktur" + #~ msgid "Hosting Products " #~ msgstr "Hosting Produkte" diff --git a/ungleich_page/migrations/0017_auto_20171219_1856.py b/ungleich_page/migrations/0017_auto_20171219_1856.py index 14c137a9..f5d76c50 100644 --- a/ungleich_page/migrations/0017_auto_20171219_1856.py +++ b/ungleich_page/migrations/0017_auto_20171219_1856.py @@ -30,7 +30,7 @@ class Migration(migrations.Migration): blank=True, help_text='Text for the button, if a link is provided.', max_length=50, null=True)), ('heading', models.CharField( blank=True, help_text='An optional title for this slide.', max_length=100, null=True)), - ('video', filer.fields.file.FilerFileField(blank=True, help_text='Leavig this blank will make the image as the background.', + ('video', filer.fields.file.FilerFileField(blank=True, help_text='Leaving this blank will make the image as the background.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='ungleich_header_item_video', to='filer.File')), ], options={ diff --git a/ungleich_page/static/ungleich_page/css/agency.css b/ungleich_page/static/ungleich_page/css/agency.css index eca4036b..43a05898 100755 --- a/ungleich_page/static/ungleich_page/css/agency.css +++ b/ungleich_page/static/ungleich_page/css/agency.css @@ -372,7 +372,7 @@ section h3.section-subheading { @media(min-width:768px) { section { - padding: 125px 0; + padding: 80px 0; } section h2.section-heading { font-size: 40px; @@ -985,4 +985,4 @@ section h3.section-comment { .carousel-author { height: 72px; } -} \ No newline at end of file +} diff --git a/ungleich_page/templates/ungleich_page/glasfaser.html b/ungleich_page/templates/ungleich_page/glasfaser.html index 6bcb0746..3d8fbb76 100644 --- a/ungleich_page/templates/ungleich_page/glasfaser.html +++ b/ungleich_page/templates/ungleich_page/glasfaser.html @@ -220,11 +220,11 @@
-

ungleich GmbH

+

ungleich glarus ag

glasfaser@ungleich.ch

-

In der Au 7, Schwanden 8762

+

Bahnhofstrasse 1, 8783 Linthal

Switzerland

diff --git a/ungleich_page/templates/ungleich_page/includes/_about.html b/ungleich_page/templates/ungleich_page/includes/_about.html index 88f8a023..ba6717fc 100644 --- a/ungleich_page/templates/ungleich_page/includes/_about.html +++ b/ungleich_page/templates/ungleich_page/includes/_about.html @@ -17,7 +17,7 @@

{% trans "The first incarnation of ungleich" %}

-

{% trans "in Germany" %}

+

{% trans "in Germany." %}

@@ -31,7 +31,7 @@

{% trans "ungleich founded" %}

-

{% trans "in Switzerland" %}

+

{% trans "in Switzerland." %}

@@ -44,7 +44,7 @@

2014

-

{% trans "ungleich present at various conferences" %}:
Linuxtag, UCMS, Linux Erfa, ETH Zurich
+

{% trans "ungleich present at various conferences" %}:
Linuxtag, UCMS, Linux Erfa, ETH Zurich.

@@ -62,7 +62,7 @@

{% trans "and introduces affordable 24X7 support." %}

{% trans "ungleich launches" %} - {% trans "Digital Glarus project" %} + {% trans "Digital Glarus project" %}.

@@ -93,19 +93,6 @@ -
  • -
    - -
    -
    -
    -

    2017

    -
    -
    -

    {% trans 'ungleich starts computer learning club for locals, "Digitale Building ungleich."' %}

    -
    -
    -
  • @@ -115,6 +102,7 @@

    2017

    +

    {% trans 'ungleich starts computer learning club for locals, "Digitale Building ungleich".' %}

    {% blocktrans %}ungleich sells Alplora to an IoT startup in canton Zürich.{% endblocktrans %}

    {% trans "ungleich showcases the most affordable Swiss VM hosting, Data Center Light." %}

    diff --git a/ungleich_page/templates/ungleich_page/includes/_header.html b/ungleich_page/templates/ungleich_page/includes/_header.html index 4819ec1e..04bbce5d 100644 --- a/ungleich_page/templates/ungleich_page/includes/_header.html +++ b/ungleich_page/templates/ungleich_page/includes/_header.html @@ -18,11 +18,8 @@
    -
    - {% trans "We Design, Configure & Maintain
    Your Linux Infrastructure " %} -
    -

    Ruby on Rails, Django, Java, Webserver, Mailserver, any infrastructure that needs to configured, we provide comprehensive solutions. Amazon, rackspace or bare metal servers, we configure for you.

    - Learn More +
    {% trans "Hosting" %}
    +

    {% trans "Ruby on Rails. Java hosting, Django hosting, we make it everything run smooth and safe." %}

    @@ -33,11 +30,9 @@
    -
    - {% trans "We Design, Configure & Maintain
    Your Linux Infrastructure " %} -
    -

    Ruby on Rails, Django, Nothing else.

    - Learn More +
    {% trans "Configuration as a Service" %}
    +

    {% trans "Ruby on Rails, Django, Java, Webserver, Mailserver, any infrastructure that needs to configured, we provide comprehensive solutions. Amazon, rackspace or bare metal servers, we configure for you." %}

    +
    @@ -47,10 +42,8 @@
    -
    - {% trans "We Design, Configure & Maintain
    Your Linux Infrastructure " %} -
    - Learn More +
    {% trans "Linux System Engineering" %}
    +

    {% trans "Let your developers develop! We take care of your system administration. Gentoo, Archlinux, Debian, Ubuntu, and many more." %}

    diff --git a/utils/stripe_utils.py b/utils/stripe_utils.py index 8fcf0ab1..58840be0 100644 --- a/utils/stripe_utils.py +++ b/utils/stripe_utils.py @@ -232,6 +232,17 @@ class StripeUtils(object): ) return subscription_result + @handleStripeError + def unsubscribe_customer(self, subscription_id): + """ + Cancels a given subscription + + :param subscription_id: The Stripe subscription id string + :return: + """ + sub = stripe.Subscription.retrieve(subscription_id) + return sub.delete() + @handleStripeError def make_payment(self, customer, amount, token): charge = self.stripe.Charge.create(