Merge branch 'master' into task/3554/remove_beta_url

This commit is contained in:
M.Ravi 2018-02-22 13:58:02 +01:00
commit 488d259ec5
17 changed files with 359 additions and 20 deletions

View file

@ -4,7 +4,7 @@ python:
# - "3.6" # - "3.6"
env: env:
- DJANGO_SECRET_KEY=0 OPENNEBULA_USERNAME='test' OPENNEBULA_PASSWORD='test' OPENNEBULA_PROTOCOL='http' OPENNEBULA_DOMAIN='test_domain' OPENNEBULA_PORT='2633' OPENNEBULA_ENDPOINT='/RPC2' DCL_TEXT='Data Center Light' CELERY_MAX_RETRIES=0 - DJANGO_SECRET_KEY=0 OPENNEBULA_USERNAME='test' OPENNEBULA_PASSWORD='test' OPENNEBULA_PROTOCOL='http' OPENNEBULA_DOMAIN='test_domain' OPENNEBULA_PORT='2633' OPENNEBULA_ENDPOINT='/RPC2' DCL_TEXT='Data Center Light' CELERY_MAX_RETRIES=0 UNGLEICH_SITE_CONFIGS='{"localhost":{"MULTISITE_CMS_URL":"dynamicweb.urls"}}'
# install dependencies # install dependencies
install: "pip install -r requirements.txt" install: "pip install -r requirements.txt"
script: script:

View file

@ -1,4 +1,8 @@
Next: 1.4: 2018-02-22
* #4104: [cms, nuglarus] Multisite and access control of cms pages per user
1.3.3: 2018-02-21
* Add ALLOWED_HOST nüglarus.ch IDN
* #4105: [cms] Add cms footer plugin
* #4049: [blog] Replace header background image * #4049: [blog] Replace header background image
* #3670: [hosting] Shorten ssh key name * #3670: [hosting] Shorten ssh key name
* #4046: [hosting] Add sdd_size, hdd_size to VirtualMachineSerializer (No visual change) * #4046: [hosting] Add sdd_size, hdd_size to VirtualMachineSerializer (No visual change)

View file

@ -5,6 +5,7 @@ Copyright 2015 ungleich.
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Build paths inside the project like this: os.path.join(BASE_DIR, ...) # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os import os
import json
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -54,7 +55,8 @@ PROJECT_DIR = os.path.abspath(
# load .env file # load .env file
dotenv.read_dotenv("{0}/.env".format(PROJECT_DIR)) dotenv.read_dotenv("{0}/.env".format(PROJECT_DIR))
SITE_ID = 1 from multisite import SiteID
SITE_ID = SiteID(default=1)
APP_ROOT_ENDPOINT = "/" APP_ROOT_ENDPOINT = "/"
APPEND_SLASH = True APPEND_SLASH = True
@ -76,6 +78,7 @@ SECRET_KEY = env('DJANGO_SECRET_KEY')
INSTALLED_APPS = ( INSTALLED_APPS = (
# 1st migrate # 1st migrate
'membership', 'membership',
'djangocms_admin_style',
'django.contrib.admin', 'django.contrib.admin',
'django.contrib.auth', 'django.contrib.auth',
'django.contrib.contenttypes', 'django.contrib.contenttypes',
@ -83,6 +86,8 @@ INSTALLED_APPS = (
'django.contrib.messages', 'django.contrib.messages',
'django.contrib.staticfiles', 'django.contrib.staticfiles',
'django.contrib.sites', 'django.contrib.sites',
'multisite',
'djangocms_multisite',
'easy_thumbnails', 'easy_thumbnails',
'utils', 'utils',
'stored_messages', 'stored_messages',
@ -124,7 +129,6 @@ INSTALLED_APPS = (
# 'djangocms_teaser', # 'djangocms_teaser',
'djangocms_page_meta', 'djangocms_page_meta',
'djangocms_text_ckeditor', 'djangocms_text_ckeditor',
'djangocms_admin_style',
'cmsplugin_filer_file', 'cmsplugin_filer_file',
'cmsplugin_filer_folder', 'cmsplugin_filer_folder',
'cmsplugin_filer_link', 'cmsplugin_filer_link',
@ -163,6 +167,8 @@ MIDDLEWARE_CLASSES = (
'cms.middleware.page.CurrentPageMiddleware', 'cms.middleware.page.CurrentPageMiddleware',
'cms.middleware.toolbar.ToolbarMiddleware', 'cms.middleware.toolbar.ToolbarMiddleware',
'cms.middleware.language.LanguageCookieMiddleware', 'cms.middleware.language.LanguageCookieMiddleware',
'multisite.middleware.DynamicSiteMiddleware',
'djangocms_multisite.middleware.CMSMultiSiteMiddleware',
) )
CSRF_FAILURE_VIEW = 'hosting.views.forbidden_view' CSRF_FAILURE_VIEW = 'hosting.views.forbidden_view'
@ -328,6 +334,8 @@ CMS_PLACEHOLDER_CONF = {
}, },
} }
CMS_PERMISSION=True
CACHES = { CACHES = {
'default': { 'default': {
'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache', 'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
@ -507,6 +515,36 @@ STRIPE_API_PRIVATE_KEY_TEST = env('STRIPE_API_PRIVATE_KEY_TEST')
ANONYMOUS_USER_NAME = 'anonymous@ungleich.ch' ANONYMOUS_USER_NAME = 'anonymous@ungleich.ch'
GUARDIAN_GET_INIT_ANONYMOUS_USER = 'membership.models.get_anonymous_user_instance' GUARDIAN_GET_INIT_ANONYMOUS_USER = 'membership.models.get_anonymous_user_instance'
UNGLEICH_SITE_CONFIGS = env('UNGLEICH_SITE_CONFIGS')
MULTISITE_CMS_URLS = {}
if UNGLEICH_SITE_CONFIGS == "":
raise Exception("Please define UNGLEICH_SITE_CONFIGS in your .env")
else:
try:
configs_dict=json.loads(UNGLEICH_SITE_CONFIGS)
except ValueError as verr:
raise Exception("UNGLEICH_SITE_CONFIGS is not a valid JSON: {}".format(
str(verr)
))
else:
MULTISITE_CMS_URLS = {
k:v['MULTISITE_CMS_URL'] for (k,v) in configs_dict.items()
}
MULTISITE_CMS_ALIASES = {
}
MULTISITE_CMS_FALLBACK = env('MULTISITE_CMS_FALLBACK')
if MULTISITE_CMS_FALLBACK == '':
MULTISITE_CMS_FALLBACK = 'datacenterlight.ch'
MULTISITE_FALLBACK = 'django.views.generic.base.RedirectView'
MULTISITE_FALLBACK_KWARGS = {
'url': 'https://{}/'.format(MULTISITE_CMS_FALLBACK), 'permanent': False
}
FILER_ENABLE_PERMISSIONS = True
############################################# #############################################
# configurations for opennebula-integration # # configurations for opennebula-integration #
############################################# #############################################

View file

@ -19,5 +19,6 @@ MIDDLEWARE_CLASSES += ("debug_toolbar.middleware.DebugToolbarMiddleware",)
INSTALLED_APPS += ( INSTALLED_APPS += (
'django_extensions', 'django_extensions',
'debug_toolbar' # debug_toolbar seems to conflict with multisite (and djangocms_multisite)
# 'debug_toolbar'
) )

View file

@ -31,5 +31,6 @@ ALLOWED_HOSTS = [
".ipv6onlyhosting.com", ".ipv6onlyhosting.com",
".ipv6onlyhosting.net", ".ipv6onlyhosting.net",
".digitalglarus.ch", ".digitalglarus.ch",
".hack4glarus.ch" ".hack4glarus.ch",
".xn--nglarus-n2a.ch"
] ]

17
dynamicweb/urls_multi.py Normal file
View file

@ -0,0 +1,17 @@
from django.conf import settings
from django.conf.urls import include, url
from django.conf.urls.i18n import i18n_patterns
from django.contrib import admin
from django.views import static as static_view
urlpatterns = i18n_patterns(
url(r'^admin/', include(admin.site.urls)),
url(r'^cms/', include('cms.urls')),
)
urlpatterns += [
url(r'^media/(?P<path>.*)$',
static_view.serve, {
'document_root': settings.MEDIA_ROOT,
}),
]

View file

@ -1,20 +1,103 @@
from django import forms
from django.contrib import admin from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from .models import CustomUser, StripeCustomer from .models import CustomUser, StripeCustomer
from django.contrib.auth.hashers import make_password
class CustomUserAdmin(admin.ModelAdmin): # Refer https://docs.djangoproject.com/en/2.0/topics/auth/customizing/
fields = ('password', 'user_permissions', 'email', 'is_admin') # for understanding custom auth user model
def save_model(self, request, obj, form, change):
password = form.cleaned_data.get('password')
if not change: class UserCreationForm(forms.ModelForm):
obj.validation_slug = make_password(None) """A form for creating new users. Includes all the required
fields, plus a repeated password."""
password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
password2 = forms.CharField(label='Password confirmation',
widget=forms.PasswordInput)
obj.set_password(password) class Meta:
obj.save() model = CustomUser
return obj fields = ('email', 'user_permissions', 'email', 'is_admin')
def clean_password2(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password2
def save(self, commit=True):
# Save the provided password in hashed format
user = super().save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
class UserChangeForm(forms.ModelForm):
"""A form for updating users. Includes all the fields on
the user, but replaces the password field with admin's
password hash display field.
"""
password = ReadOnlyPasswordHashField(
label="Password",
help_text=(
"Raw passwords are not stored, so there is no way to see "
"this user's password, but you can change the password "
"using <a href=\"../password/\">this form</a>.")
)
class Meta:
model = CustomUser
fields = ('email', 'password', 'is_admin')
def clean_password(self):
# Regardless of what the user provides, return the initial value.
# This is done here, rather than on the field, because the
# field does not have access to the initial value
return self.initial["password"]
class CustomUserAdmin(BaseUserAdmin):
# The forms to add and change user instances
form = UserChangeForm
add_form = UserCreationForm
# The fields to be used in displaying the User model.
# These override the definitions on the base UserAdmin
# that reference specific fields on auth.User.
list_display = (
'email', 'is_admin', 'is_superuser'
)
list_filter = ()
fieldsets = (
(None, {'fields': ('email',)}),
('Change Password',
{'fields': ('password',),
'description': "Raw passwords are not stored, so there is no way to "
"see this user's password, but you can change the "
"password using <a href=\"../password/\">this "
"form</a>."
}
),
('Permissions', {'fields': ('is_admin', 'user_permissions',
'groups')}),
)
# add_fieldsets is not a standard ModelAdmin attribute. UserAdmin
# overrides get_fieldsets to use this attribute when creating a user.
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'password1', 'password2')}
),
)
search_fields = ('email',)
ordering = ('email',)
filter_horizontal = ()
admin.site.register(CustomUser, CustomUserAdmin) admin.site.register(CustomUser, CustomUserAdmin)

View file

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2018-02-13 01:28
from __future__ import unicode_literals
from django.db import migrations, models
import membership.models
class Migration(migrations.Migration):
dependencies = [
('membership', '0006_auto_20160526_0445'),
]
operations = [
migrations.AlterField(
model_name='customuser',
name='validation_slug',
field=models.CharField(db_index=True, default=membership.models.get_validation_slug, max_length=50, unique=True),
),
]

View file

@ -59,6 +59,10 @@ class MyUserManager(BaseUserManager):
return user return user
def get_validation_slug():
return make_password(None)
class CustomUser(AbstractBaseUser, PermissionsMixin): class CustomUser(AbstractBaseUser, PermissionsMixin):
VALIDATED_CHOICES = ((0, 'Not validated'), (1, 'Validated')) VALIDATED_CHOICES = ((0, 'Not validated'), (1, 'Validated'))
site = models.ForeignKey(Site, default=1) site = models.ForeignKey(Site, default=1)
@ -66,8 +70,12 @@ class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True) email = models.EmailField(unique=True)
validated = models.IntegerField(choices=VALIDATED_CHOICES, default=0) validated = models.IntegerField(choices=VALIDATED_CHOICES, default=0)
validation_slug = models.CharField(db_index=True, unique=True, # By default, we initialize the validation_slug with appropriate value
max_length=50) # This is required for User(page) admin
validation_slug = models.CharField(
db_index=True, unique=True, max_length=50,
default=get_validation_slug
)
is_admin = models.BooleanField( is_admin = models.BooleanField(
_('staff status'), _('staff status'),
default=False, default=False,
@ -171,6 +179,10 @@ class CustomUser(AbstractBaseUser, PermissionsMixin):
# Simplest possible answer: All admins are staff # Simplest possible answer: All admins are staff
return self.is_admin return self.is_admin
@is_staff.setter
def is_staff(self, value):
self._is_staff = value
class StripeCustomer(models.Model): class StripeCustomer(models.Model):
user = models.OneToOneField(CustomUser) user = models.OneToOneField(CustomUser)

View file

@ -104,7 +104,7 @@ class VirtualMachineSerializer(serializers.Serializer):
disk_size += int(disk.size) disk_size += int(disk.size)
return disk_size / 1024 return disk_size / 1024
def get_sdd_size(self, obj): def get_ssd_size(self, obj):
template = obj.template template = obj.template
disk_size = 0 disk_size = 0
for disk in template.disks: for disk in template.disks:

View file

@ -34,6 +34,7 @@ django-meta==1.2
django-meta-mixin==0.3.0 django-meta-mixin==0.3.0
django-model-utils==2.5 django-model-utils==2.5
django-mptt==0.8.4 django-mptt==0.8.4
django-multisite==1.4.1
django-parler==1.6.3 django-parler==1.6.3
django-phonenumber-field==1.1.0 django-phonenumber-field==1.1.0
django-polymorphic==0.9.2 django-polymorphic==0.9.2
@ -97,3 +98,4 @@ billiard==3.5.0.3
amqp==2.2.1 amqp==2.2.1
vine==1.1.4 vine==1.1.4
cdist==4.7.0 cdist==4.7.0
git+https://github.com/ungleich/djangocms-multisite.git#egg=djangocms_multisite

View file

@ -8,6 +8,7 @@ from .models import (
UngleichCustomerItem, UngleichHTMLOnly, UngleichCustomerItem, UngleichHTMLOnly,
UngleichHeaderWithBackgroundImageSlider, UngleichHeaderWithBackgroundImageSlider,
UngleichHeaderWithBackgroundVideoSliderItem, UngleichHeaderWithBackgroundVideoSliderItem,
UngleichFooter
) )
@ -295,3 +296,18 @@ class UngleichHTMLPlugin(CMSPluginBase):
) )
context['instance'] = instance context['instance'] = instance
return context return context
@plugin_pool.register_plugin
class UngleichFooterPlugin(CMSPluginBase):
name = "ungleich Footer Plugin"
model = UngleichFooter
render_template = "ungleich_page/ungleich/_footer.html"
cache = False
def render(self, context, instance, placeholder):
context = super(UngleichFooterPlugin, self).render(
context, instance, placeholder
)
context['instance'] = instance
return context

View file

@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2018-02-08 15:49
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('ungleich_page', '0017_auto_20171219_1856'),
('cms', '0014_auto_20160404_1908'),
]
operations = [
migrations.CreateModel(
name='UngleichFooter',
fields=[
('cmsplugin_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE,
parent_link=True, primary_key=True, serialize=False, to='cms.CMSPlugin')),
('copyright_label', models.CharField(blank=True, default='',
help_text='Name of the company alongside the copyright year', max_length=100)),
('link_text', models.CharField(
blank=True, help_text='Text for the link on the right part of footer', max_length=100, null=True)),
('link_url', models.URLField(blank=True,
help_text='Url to the link in footer', null=True)),
('twitter_url', models.URLField(
blank=True, help_text='If empty, twitter btn will not be visible', null=True)),
('linkedin_url', models.URLField(
blank=True, help_text='If empty, linkedin btn will not be visible', null=True)),
('github_url', models.URLField(
blank=True, help_text='If empty, github btn will not be visible', null=True)),
('facebook_url', models.URLField(
blank=True, help_text='If empty, facebook btn will not be visible', null=True)),
('youtube_url', models.URLField(
blank=True, help_text='If empty, youtube btn will not be visible', null=True)),
],
options={
'abstract': False,
},
bases=('cms.cmsplugin',),
),
]

View file

@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2018-02-08 20:10
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('ungleich_page', '0018_ungleichfooter'),
('ungleich_page', '0018_auto_20180105_1826'),
]
operations = [
]

View file

@ -169,3 +169,38 @@ class UngleichHTMLOnly(CMSPlugin):
def __str__(self): def __str__(self):
return self.name return self.name
class UngleichFooter(CMSPlugin):
copyright_label = models.CharField(
max_length=100, default='', blank=True,
help_text='Name of the company alongside the copyright year'
)
link_text = models.CharField(
max_length=100, blank=True, null=True,
help_text='Text for the link on the right part of footer'
)
link_url = models.URLField(
blank=True, null=True,
help_text='Url to the link in footer'
)
twitter_url = models.URLField(
blank=True, null=True,
help_text='If empty, twitter btn will not be visible'
)
linkedin_url = models.URLField(
blank=True, null=True,
help_text='If empty, linkedin btn will not be visible'
)
github_url = models.URLField(
blank=True, null=True,
help_text='If empty, github btn will not be visible'
)
facebook_url = models.URLField(
blank=True, null=True,
help_text='If empty, facebook btn will not be visible'
)
youtube_url = models.URLField(
blank=True, null=True,
help_text='If empty, youtube btn will not be visible'
)

View file

@ -0,0 +1,47 @@
<footer>
<div class="container">
<div class="row">
<div class="col-md-4">
<span class="copyright">Copyright © {{instance.copyright_label}} {% now "Y" %}</span>
</div>
<div class="col-md-4">
<ul class="list-inline social-buttons">
{% if instance.twitter_url %}
<li>
<a href="{{instance.twitter_url}}"><i class="fa fa-twitter"></i></a>
</li>
{% endif %}
{% if instance.github_url %}
<li>
<a href="{{instance.github_url}}"><i class="fa fa-github"></i></a>
</li>
{% endif %}
{% if instance.linkedin_url %}
<li>
<a href="{{instance.linkedin_url}}"><i class="fa fa-linkedin"></i></a>
</li>
{% endif %}
{% if instance.facebook_url %}
<li>
<a href="{{instance.facebook_url}}"><i class="fa fa-facebook"></i></a>
</li>
{% endif %}
{% if instance.youtube_url %}
<li>
<a href="{{instance.youtube_url}}"><i class="fa fa-youtube-play"></i></a>
</li>
{% endif %}
</ul>
</div>
<div class="col-md-4">
{% if instance.link_text %}
<ul class="list-inline quicklinks">
<li>
<a href="{{instance.link_url}}">{{instance.link_text}}</a>
</li>
</ul>
{% endif %}
</div>
</div>
</div>
</footer>

View file

@ -41,7 +41,9 @@
{% placeholder 'Ungleich Page Contents' %} {% placeholder 'Ungleich Page Contents' %}
<!-- Footer --> <!-- Footer -->
{% include "ungleich_page/includes/_footer.html" %} {% placeholder 'Footer' or %}
{% include "ungleich_page/includes/_footer.html" %}
{% endplaceholder %}
<!-- jQuery --> <!-- jQuery -->
<script src="{% static 'ungleich_page/js/jquery.js' %}" type="text/javascript"></script> <script src="{% static 'ungleich_page/js/jquery.js' %}" type="text/javascript"></script>