Commit 53dbd80b by Czémán Arnold

Merge branch 'issue_494' into 'master'

Upgrade to Django 1.11

See merge request !395
parents 4565cf03 df34da69
"""
Creates Levels for all installed apps that have levels.
"""
from django.db.models import get_models, signals
from django.db.models import signals
from django.apps import apps
from django.db import DEFAULT_DB_ALIAS
from django.core.exceptions import ImproperlyConfigured
from ..models import Level, AclBase
def create_levels(app, created_models, verbosity, db=DEFAULT_DB_ALIAS,
def create_levels(app_config, verbosity=False, using=DEFAULT_DB_ALIAS,
**kwargs):
"""Create and set the weights of the configured Levels.
Based on django.contrib.auth.management.__init__.create_permissions"""
# if not router.allow_migrate(db, auth_app.Permission):
# if not router.allow_migrate(using, auth_app.Permission):
# return
from django.contrib.contenttypes.models import ContentType
app_models = [k for k in get_models(app) if AclBase in k.__bases__]
app_models = [k for k in apps.get_models(app_config)
if AclBase in k.__bases__]
print "Creating levels for models: %s." % ", ".join(
[m.__name__ for m in app_models])
......@@ -31,7 +33,7 @@ def create_levels(app, created_models, verbosity, db=DEFAULT_DB_ALIAS,
for klass in app_models:
# Force looking up the content types in the current database
# before creating foreign keys to them.
ctype1 = ContentType.objects.db_manager(db).get_for_model(klass)
ctype1 = ContentType.objects.db_manager(using).get_for_model(klass)
ctypes.add(ctype1)
weight = 0
try:
......@@ -46,7 +48,7 @@ def create_levels(app, created_models, verbosity, db=DEFAULT_DB_ALIAS,
# Find all the Levels that have a content_type for a model we're
# looking for. We don't need to check for codenames since we already have
# a list of the ones we're going to create.
all_levels = set(Level.objects.using(db).filter(
all_levels = set(Level.objects.using(using).filter(
content_type__in=ctypes,
).values_list(
"content_type", "codename"
......@@ -57,7 +59,7 @@ def create_levels(app, created_models, verbosity, db=DEFAULT_DB_ALIAS,
for ctype, (codename, name) in searched_levels
if (ctype.pk, codename) not in all_levels
]
Level.objects.using(db).bulk_create(levels)
Level.objects.using(using).bulk_create(levels)
if verbosity >= 2:
print("Adding levels [%s]." % ", ".join(unicode(l) for l in levels))
print("Searched: [%s]." % ", ".join(
......@@ -70,5 +72,5 @@ def create_levels(app, created_models, verbosity, db=DEFAULT_DB_ALIAS,
content_type=ctype).update(weight=weight)
signals.post_syncdb.connect(
signals.post_migrate.connect(
create_levels, dispatch_uid="circle.acl.management.create_levels")
......@@ -18,7 +18,7 @@
import logging
from django.contrib.auth.models import User, Group
from django.contrib.contenttypes.generic import (
from django.contrib.contenttypes.fields import (
GenericForeignKey, GenericRelation
)
from django.contrib.contenttypes.models import ContentType
......
......@@ -12,9 +12,10 @@ def update_permissions_after_migration(sender, **kwargs):
"""
from django.conf import settings
from django.db.models import get_models
from django.apps import apps
from django.contrib.auth.management import create_permissions
create_permissions(sender, get_models(), 2 if settings.DEBUG else 0)
create_permissions(sender, apps.get_models(), 2 if settings.DEBUG else 0)
post_migrate.connect(update_permissions_after_migration)
......@@ -166,96 +166,95 @@ if exists(p):
STATICFILES_DIRS.append(p)
STATICFILES_STORAGE = 'pipeline.storage.PipelineCachedStorage'
PIPELINE_COMPILERS = (
'pipeline.compilers.less.LessCompiler',
)
PIPELINE_CSS_COMPRESSOR = 'pipeline.compressors.yuglify.YuglifyCompressor'
# PIPELINE_JS_COMPRESSOR = 'pipeline.compressors.slimit.SlimItCompressor'
PIPELINE_JS_COMPRESSOR = None
PIPELINE_DISABLE_WRAPPER = True
PIPELINE_LESS_ARGUMENTS = u'--include-path={}'.format(':'.join(STATICFILES_DIRS))
PIPELINE_CSS = {
"all": {"source_filenames": (
"compile_bootstrap.less",
"bootstrap/dist/css/bootstrap-theme.css",
"fontawesome/css/font-awesome.css",
"jquery-simple-slider/css/simple-slider.css",
"intro.js/introjs.css",
"template.less",
"dashboard/dashboard.less",
"network/network.less",
"autocomplete_light/style.css",
),
"output_filename": "all.css",
}
}
PIPELINE_JS = {
"all": {"source_filenames": (
# "jquery/dist/jquery.js", # included separately
"bootbox/bootbox.js",
"bootstrap/dist/js/bootstrap.js",
"intro.js/intro.js",
"jquery-knob/dist/jquery.knob.min.js",
"jquery-simple-slider/js/simple-slider.js",
"favico.js/favico.js",
"datatables/media/js/jquery.dataTables.js",
"dashboard/dashboard.js",
"dashboard/activity.js",
"dashboard/group-details.js",
"dashboard/group-list.js",
"dashboard/js/stupidtable.min.js", # no bower file
"dashboard/node-create.js",
"dashboard/node-details.js",
"dashboard/node-list.js",
"dashboard/profile.js",
"dashboard/store.js",
"dashboard/template-list.js",
"dashboard/vm-common.js",
"dashboard/vm-create.js",
"dashboard/vm-list.js",
"dashboard/help.js",
"js/host.js",
"js/network.js",
"js/switch-port.js",
"js/host-list.js",
"autocomplete_light/autocomplete.js",
"autocomplete_light/widget.js",
"autocomplete_light/addanother.js",
"autocomplete_light/text_widget.js",
"autocomplete_light/remote.js",
),
"output_filename": "all.js",
},
"vm-detail": {"source_filenames": (
"clipboard/dist/clipboard.min.js",
"dashboard/vm-details.js",
"no-vnc/include/util.js",
"no-vnc/include/webutil.js",
"no-vnc/include/base64.js",
"no-vnc/include/websock.js",
"no-vnc/include/des.js",
"no-vnc/include/keysym.js",
"no-vnc/include/keysymdef.js",
"no-vnc/include/keyboard.js",
"no-vnc/include/input.js",
"no-vnc/include/display.js",
"no-vnc/include/jsunzip.js",
"no-vnc/include/rfb.js",
"dashboard/vm-console.js",
"dashboard/vm-tour.js",
),
"output_filename": "vm-detail.js",
PIPELINE = {
'COMPILERS' : ('pipeline.compilers.less.LessCompiler',),
'LESS_ARGUMENTS': u'--include-path={}'.format(':'.join(STATICFILES_DIRS)),
'CSS_COMPRESSOR': 'pipeline.compressors.yuglify.YuglifyCompressor',
'JS_COMPRESSOR': None,
'DISABLE_WRAPPER': True,
'STYLESHEETS': {
"all": {"source_filenames": (
"compile_bootstrap.less",
"bootstrap/dist/css/bootstrap-theme.css",
"fontawesome/css/font-awesome.css",
"jquery-simple-slider/css/simple-slider.css",
"intro.js/introjs.css",
"template.less",
"dashboard/dashboard.less",
"network/network.less",
"autocomplete_light/vendor/select2/dist/css/select2.css",
"autocomplete_light/select2.css",
),
"output_filename": "all.css",
}
},
"datastore": {"source_filenames": (
"chart.js/dist/Chart.min.js",
"dashboard/datastore-details.js"
),
"output_filename": "datastore.js",
'JAVASCRIPT': {
"all": {"source_filenames": (
# "jquery/dist/jquery.js", # included separately
"bootbox/bootbox.js",
"bootstrap/dist/js/bootstrap.js",
"intro.js/intro.js",
"jquery-knob/dist/jquery.knob.min.js",
"jquery-simple-slider/js/simple-slider.js",
"favico.js/favico.js",
"datatables/media/js/jquery.dataTables.js",
"autocomplete_light/jquery.init.js",
"autocomplete_light/autocomplete.init.js",
"autocomplete_light/vendor/select2/dist/js/select2.js",
"autocomplete_light/select2.js",
"dashboard/dashboard.js",
"dashboard/activity.js",
"dashboard/group-details.js",
"dashboard/group-list.js",
"dashboard/js/stupidtable.min.js", # no bower file
"dashboard/node-create.js",
"dashboard/node-details.js",
"dashboard/node-list.js",
"dashboard/profile.js",
"dashboard/store.js",
"dashboard/template-list.js",
"dashboard/vm-common.js",
"dashboard/vm-create.js",
"dashboard/vm-list.js",
"dashboard/help.js",
"js/host.js",
"js/network.js",
"js/switch-port.js",
"js/host-list.js",
),
"output_filename": "all.js",
},
"vm-detail": {"source_filenames": (
"clipboard/dist/clipboard.min.js",
"dashboard/vm-details.js",
"no-vnc/include/util.js",
"no-vnc/include/webutil.js",
"no-vnc/include/base64.js",
"no-vnc/include/websock.js",
"no-vnc/include/des.js",
"no-vnc/include/keysym.js",
"no-vnc/include/keysymdef.js",
"no-vnc/include/keyboard.js",
"no-vnc/include/input.js",
"no-vnc/include/display.js",
"no-vnc/include/jsunzip.js",
"no-vnc/include/rfb.js",
"dashboard/vm-console.js",
"dashboard/vm-tour.js",
),
"output_filename": "vm-detail.js",
},
"datastore": {"source_filenames": (
"chart.js/dist/Chart.min.js",
"dashboard/datastore-details.js"
),
"output_filename": "datastore.js",
},
},
}
########## SECRET CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#secret-key
# Note: This key should only be used for development and testing.
......@@ -279,26 +278,31 @@ FIXTURE_DIRS = (
########## TEMPLATE CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#template-context-processors
TEMPLATE_CONTEXT_PROCESSORS = (
'django.contrib.auth.context_processors.auth',
'django.core.context_processors.debug',
'django.core.context_processors.i18n',
'django.core.context_processors.media',
'django.core.context_processors.static',
'django.core.context_processors.tz',
'django.contrib.messages.context_processors.messages',
'django.core.context_processors.request',
'dashboard.context_processors.notifications',
'dashboard.context_processors.extract_settings',
'dashboard.context_processors.broadcast_messages',
)
# See: https://docs.djangoproject.com/en/dev/ref/settings/#template-dirs
TEMPLATE_DIRS = (
normpath(join(SITE_ROOT, '../../site-circle/templates')),
normpath(join(SITE_ROOT, 'templates')),
)
# See: https://docs.djangoproject.com/en/dev/ref/settings/#TEMPLATES
TEMPLATES = [{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS' : (
normpath(join(SITE_ROOT, '../../site-circle/templates')),
normpath(join(SITE_ROOT, 'templates')),
),
'APP_DIRS': True,
'OPTIONS': {
'context_processors': (
'django.contrib.auth.context_processors.auth',
'django.template.context_processors.debug',
'django.template.context_processors.i18n',
'django.template.context_processors.media',
'django.template.context_processors.static',
'django.template.context_processors.tz',
'django.contrib.messages.context_processors.messages',
'django.template.context_processors.request',
'dashboard.context_processors.notifications',
'dashboard.context_processors.extract_settings',
'dashboard.context_processors.broadcast_messages',
),
},
}]
########## END TEMPLATE CONFIGURATION
......@@ -336,6 +340,10 @@ DJANGO_APPS = (
# Useful template tags:
# 'django.contrib.humanize',
# Django autocomplete light
# it needs registering before django admin
'dal',
'dal_select2',
# Admin panel and documentation:
'django.contrib.admin',
# 'django.contrib.admindocs',
......@@ -348,7 +356,6 @@ THIRD_PARTY_APPS = (
'taggit',
'statici18n',
'django_sshkey',
'autocomplete_light',
'pipeline',
)
......
......@@ -27,7 +27,7 @@ from base import * # noqa
DEBUG = True
# See: https://docs.djangoproject.com/en/dev/ref/settings/#template-debug
TEMPLATE_DEBUG = DEBUG
TEMPLATES[0]['OPTIONS']['debug'] = DEBUG
########## END DEBUG CONFIGURATION
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTOCOL', 'https')
......@@ -110,8 +110,10 @@ if DEBUG:
from django.dispatch import Signal
Signal.send_robust = Signal.send
PIPELINE_COMPILERS = (
PIPELINE["COMPILERS"] = (
'dashboard.compilers.DummyLessCompiler',
)
ADMIN_ENABLED = True
ALLOWED_HOSTS = ['*']
......@@ -14,9 +14,10 @@
#
# You should have received a copy of the GNU General Public License along
# with CIRCLE. If not, see <http://www.gnu.org/licenses/>.
import os
from .base import * # noqa
from .base import * # flake8:noqa
# fix https://github.com/django-nose/django-nose/issues/197
......
......@@ -38,7 +38,11 @@ INSTALLED_APPS += (
'django_nose',
)
TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'
NOSE_ARGS = ['--with-doctest', '--exclude-dir=dashboard/tests/selenium']
NOSE_ARGS = [
'--with-doctest',
'--exclude-dir=dashboard/tests/selenium',
'--exclude=circle'
]
PASSWORD_HASHERS = ['django.contrib.auth.hashers.MD5PasswordHasher']
CACHES = {
......@@ -59,7 +63,7 @@ for i in LOCAL_APPS:
# don't print SQL queries
LOGGING['handlers']['null'] = {'level': "DEBUG",
'class': "django.utils.log.NullHandler"}
'class': "logging.NullHandler"}
LOGGING['loggers']['django.db.backends'] = {
'handlers': ['null'],
'propagate': False,
......
......@@ -15,13 +15,16 @@
# You should have received a copy of the GNU General Public License along
# with CIRCLE. If not, see <http://www.gnu.org/licenses/>.
from django.conf.urls import patterns, include, url
from django.conf.urls import include, url
from django.views.generic import TemplateView
from django.conf import settings
from django.contrib import admin
from django.core.urlresolvers import reverse
from django.shortcuts import redirect
from django.contrib.auth.views import (
password_reset_confirm, password_reset
)
from circle.settings.base import get_env_variable
......@@ -33,9 +36,7 @@ from firewall.views import add_blacklist_item
admin.autodiscover()
urlpatterns = patterns(
'',
urlpatterns = [
url(r'^$', lambda x: redirect(reverse("dashboard.index"))),
url(r'^network/', include('network.urls')),
url(r'^blacklist-add/', add_blacklist_item),
......@@ -45,12 +46,11 @@ urlpatterns = patterns(
# django/contrib/auth/urls.py (care when new version)
url((r'^accounts/reset/(?P<uidb64>[0-9A-Za-z_\-]+)/'
r'(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$'),
'django.contrib.auth.views.password_reset_confirm',
password_reset_confirm,
{'set_password_form': CircleSetPasswordForm},
name='accounts.password_reset_confirm'
),
url(r'^accounts/password/reset/$', ("django.contrib.auth.views."
"password_reset"),
url(r'^accounts/password/reset/$', password_reset,
{'password_reset_form': CirclePasswordResetForm},
name="accounts.password-reset",
),
......@@ -73,27 +73,24 @@ urlpatterns = patterns(
name="info.support"),
url(r'^info/resize-how-to/$', ResizeHelpView.as_view(),
name="info.resize"),
)
]
if 'rosetta' in settings.INSTALLED_APPS:
urlpatterns += patterns(
'',
urlpatterns += [
url(r'^rosetta/', include('rosetta.urls')),
)
]
if settings.ADMIN_ENABLED:
urlpatterns += patterns(
'',
urlpatterns += [
url(r'^admin/', include(admin.site.urls)),
)
]
if get_env_variable('DJANGO_SAML', 'FALSE') == 'TRUE':
urlpatterns += patterns(
'',
urlpatterns += [
(r'^saml2/', include('djangosaml2.urls')),
)
]
handler500 = 'common.views.handler500'
handler403 = 'common.views.handler403'
......@@ -45,7 +45,8 @@ def handler500(request):
logger.exception("unhandled exception")
ctx = get_context(request, exception)
try:
resp = render_to_response("500.html", ctx, RequestContext(request))
resp = render_to_response("500.html", ctx,
RequestContext(request).flatten())
except:
resp = render_to_response("500.html", ctx)
resp.status_code = 500
......
......@@ -31,7 +31,7 @@ from django.contrib.auth.models import User, Group
from django.core.validators import URLValidator
from django.core.exceptions import PermissionDenied, ValidationError
import autocomplete_light
from dal import autocomplete
from crispy_forms.helper import FormHelper
from crispy_forms.layout import (
Layout, Div, BaseInput, Field, HTML, Submit, TEMPLATE_PACK, Fieldset
......@@ -43,7 +43,6 @@ from crispy_forms.bootstrap import FormActions
from django import forms
from django.contrib.auth.forms import UserCreationForm as OrgUserCreationForm
from django.forms.widgets import TextInput, HiddenInput
from django.template import Context
from django.template.loader import render_to_string
from django.utils.html import escape, format_html
from django.utils.safestring import mark_safe
......@@ -67,6 +66,7 @@ from .validators import domain_validator
from dashboard.models import ConnectCommand, create_profile
LANGUAGES_WITH_CODE = ((l[0], string_concat(l[1], " (", l[0], ")"))
for l in LANGUAGES)
......@@ -1180,8 +1180,7 @@ class AnyTag(Div):
fields += render_field(field, form, form_style, context,
template_pack=template_pack)
return render_to_string(self.template, Context({'tag': self,
'fields': fields}))
return render_to_string(self.template, {'tag': self, 'fields': fields})
class WorkingBaseInput(BaseInput):
......@@ -1334,27 +1333,31 @@ class UserEditForm(forms.ModelForm):
class AclUserOrGroupAddForm(forms.Form):
name = forms.CharField(widget=autocomplete_light.TextWidget(
'AclUserGroupAutocomplete',
attrs={'class': 'form-control',
'placeholder': _("Name of group or user")}))
name = forms.CharField(
widget=autocomplete.ListSelect2(
url='autocomplete.acl.user-group',
attrs={'class': 'form-control',
'data-html': 'true',
'data-placeholder': _("Name of group or user")}))
class TransferOwnershipForm(forms.Form):
name = forms.CharField(
widget=autocomplete_light.TextWidget(
'AclUserAutocomplete',
widget=autocomplete.ListSelect2(
url='autocomplete.acl.user',
attrs={'class': 'form-control',
'placeholder': _("Name of user")}),
'data-html': 'true',
'data-placeholder': _("Name of user")}),
label=_("E-mail address or identifier of user"))
class AddGroupMemberForm(forms.Form):
new_member = forms.CharField(
widget=autocomplete_light.TextWidget(
'AclUserAutocomplete',
widget=autocomplete.ListSelect2(
url='autocomplete.acl.user',
attrs={'class': 'form-control',
'placeholder': _("Name of user")}),
'data-html': 'true',
'data-placeholder': _("Name of user")}),
label=_("E-mail address or identifier of user"))
......
......@@ -18,7 +18,6 @@
from __future__ import unicode_literals, absolute_import
import logging
from optparse import make_option
from django.contrib.auth.models import User
from django.core.management.base import BaseCommand
......@@ -32,19 +31,18 @@ logger = logging.getLogger(__name__)
class Command(BaseCommand):
option_list = BaseCommand.option_list + (
make_option('--force', action="store_true"),
make_option('--external-net'),
make_option('--management-net'),
make_option('--vm-net'),
make_option('--external-if'),
make_option('--management-if'),
make_option('--vm-if'),
make_option('--datastore-queue'),
make_option('--firewall-queue'),
make_option('--admin-user'),
make_option('--admin-pass'),
)
def add_arguments(self, parser):
parser.add_argument('--force', action="store_true")
parser.add_argument('--external-net')
parser.add_argument('--management-net')
parser.add_argument('--vm-net')
parser.add_argument('--external-if')
parser.add_argument('--management-if')
parser.add_argument('--vm-if')
parser.add_argument('--datastore-queue')
parser.add_argument('--firewall-queue')
parser.add_argument('--admin-user')
parser.add_argument('--admin-pass')
def create(self, model, field, **kwargs):
value = kwargs[field]
......@@ -59,14 +57,15 @@ class Command(BaseCommand):
# http://docs.saltstack.com/en/latest/ref/states/all/salt.states.cmd.html
def print_state(self):
print "\nchanged=%s" % ("yes" if self.changed else "no")
self.stdout.write("\nchanged=%s" % ("yes" if self.changed else "no"))
def handle(self, *args, **options):
self.changed = False
if (DataStore.objects.exists() and Vlan.objects.exists() and
not options['force']):
return self.print_state()
self.print_state()
return
admin = self.create(User, 'username', username=options['admin_user'],
is_superuser=True, is_staff=True)
......@@ -153,4 +152,4 @@ class Command(BaseCommand):
direction='out', action='accept',
foreign_network=vg_net, vlan=man)
return self.print_state()
self.print_state()
# -*- coding: utf-8 -*-
# Generated by Django 1.11.3 on 2017-07-07 19:09
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dashboard', '0005_profile_two_factor_secret'),
]
operations = [
migrations.AlterField(
model_name='connectcommand',
name='name',
field=models.CharField(help_text='Name of your custom command.', max_length=128, verbose_name='name'),
),
]
......@@ -151,7 +151,7 @@ class ConnectCommand(Model):
access_method = CharField(max_length=10, choices=ACCESS_METHODS,
verbose_name=_('access method'),
help_text=_('Type of the remote access method.'))
name = CharField(max_length="128", verbose_name=_('name'), blank=False,
name = CharField(max_length=128, verbose_name=_('name'), blank=False,
help_text=_("Name of your custom command."))
template = CharField(blank=True, null=True, max_length=256,
verbose_name=_('command template'),
......
......@@ -508,13 +508,6 @@ $.ajaxSetup({
}
});
/* for autocomplete */
$(function() {
yourlabs.TextWidget.prototype.getValue = function(choice) {
return choice.children().html();
};
});
var tagsToReplace = {
'&': '&amp;',
'<': '&lt;',
......
......@@ -1031,7 +1031,7 @@ textarea[name="new_members"] {
font-weight: bold;
}
.hilight .autocomplete-hl {
.select2-results__option--highlighted .autocomplete-hl {
color: orange;
}
......
......@@ -24,7 +24,7 @@
<td>
<select class="form-control" name="perm-u-{{i.user.id}}"{% if i.level not in acl.allowed_levels %} disabled{% endif %}>
{% for id, name in acl.levels %}
<option{%if id = i.level%} selected="selected"{%endif%}
<option{%if id == i.level%} selected="selected"{%endif%}
{% if id not in acl.allowed_levels %} disabled{% endif %}
value="{{id}}">{{name}}</option>
{% endfor %}
......@@ -46,7 +46,7 @@
<td>
<select class="form-control" name="perm-g-{{i.group.id}}{% if i.level not in acl.allowed_levels %} disabled{% endif %}">
{% for id, name in acl.levels %}
<option{%if id = i.level%} selected="selected"{%endif%}
<option{%if id == i.level%} selected="selected"{%endif%}
{% if id not in acl.allowed_levels %} disabled{% endif %}
value="{{id}}">{{name}}</option>
{% endfor %}
......
......@@ -137,8 +137,10 @@
{% if user.is_superuser %}
<hr />
<script type="text/javascript" src="/static/admin/js/jquery.min.js"></script>
<script type="text/javascript" src="/static/admin/js/jquery.init.js"></script>
<script type="text/javascript" src="/static/admin/js/vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="/static/admin/js/jquery.init.js"></script>
<script type="text/javascript" src="/static/autocomplete_light/jquery.init.js"></script>
<script type="text/javascript" src="/static/autocomplete_light/vendor/select2/dist/js/select2.js"></script>
{{ group_perm_form.media }}
<h3>{% trans "Group permissions" %}</h3>
......
......@@ -52,7 +52,7 @@
<td>
<select class="form-control" name="perm-u-{{i.user.id}}">
{% for id, name in acl.levels %}
<option{%if id = i.level%} selected="selected"{%endif%} value="{{id}}">{{name}}</option>
<option{%if id == i.level%} selected="selected"{%endif%} value="{{id}}">{{name}}</option>
{% endfor %}
</select>
</td>
......@@ -72,7 +72,7 @@
<td>
<select class="form-control" name="perm-g-{{i.group.id}}">
{% for id, name in acl.levels %}
<option{%if id = i.level%} selected="selected"{%endif%} value="{{id}}">{{name}}</option>
<option{%if id == i.level%} selected="selected"{%endif%} value="{{id}}">{{name}}</option>
{% endfor %}
</select>
</td>
......
......@@ -4,9 +4,9 @@
{% if table.page %}
<div class="table-container">
{% endif %}
{% endspaceless %}
{% block table %}
<table{% if table.attrs %} {{ table.attrs.as_html }}{% endif %}>
{% nospaceless %}
{% block table.thead %}
<thead>
<tr>
......@@ -42,10 +42,9 @@
{% block table.tfoot %}
<tfoot></tfoot>
{% endblock table.tfoot %}
{% endnospaceless %}
</table>
{% endblock table %}
{% spaceless %}
{% if table.page %}
</div>
{% endif %}
......
......@@ -21,7 +21,7 @@ import warnings
from factory import Factory, Sequence
from mock import patch, MagicMock
from django.contrib.auth.models import User
from django.contrib.auth.models import User, AnonymousUser
from django.core.exceptions import PermissionDenied
from django.core.signing import TimestampSigner, JSONSerializer, b64_encode
from django.http import HttpRequest, Http404, QueryDict
......@@ -629,13 +629,13 @@ def FakeRequestFactory(user=None, **kwargs):
'''
if user is None:
user = UserFactory()
auth = kwargs.pop('authenticated', True)
user.is_authenticated = lambda: auth
user = UserFactory() if auth else AnonymousUser()
user.is_superuser = kwargs.pop('superuser', False)
if kwargs.pop('has_perms_mock', False):
user.has_perms = MagicMock(return_value=True)
user.save()
if auth:
user.save()
request = HttpRequest()
request.user = user
......
......@@ -29,22 +29,22 @@ class TemplateSyntaxTestCase(unittest.TestCase):
def test_templates(self):
"""Test all templates for syntax errors."""
for loader in Engine.get_default().template_loaders:
print loader
print(loader)
self._test_dir(loader.get_template_sources(''))
def _test_dir(self, dir, path="/"):
for i in dir:
i = join(path, i)
i = join(path, str(i))
if isfile(i):
self._test_template(join(path, i))
elif isdir(i):
print "%s:" % i
print("%s:" % i)
self._test_dir(listdir(i), i)
def _test_template(self, path):
print path
print(path)
try:
Template(open(path).read()).render(Context({}))
except (NoReverseMatch, VariableDoesNotExist, KeyError, AttributeError,
ValueError, ) as e:
print e
print(e)
......@@ -1902,9 +1902,9 @@ class TwoFactorTest(LoginMixin, TestCase):
response = c.get("/two-factor-login/", follow=True)
self.assertItemsEqual(
response.redirect_chain,
[('http://testserver/', 302),
('http://testserver/dashboard/', 302),
('http://testserver/accounts/login/?next=/dashboard/', 302)]
[('/', 302),
('/dashboard/', 302),
('/accounts/login/?next=/dashboard/', 302)]
)
def test_straight_to_2fa_as_user(self):
......@@ -1913,6 +1913,6 @@ class TwoFactorTest(LoginMixin, TestCase):
response = c.get("/two-factor-login/", follow=True)
self.assertItemsEqual(
response.redirect_chain,
[('http://testserver/', 302),
('http://testserver/dashboard/', 302)]
[('/', 302),
('/dashboard/', 302)]
)
......@@ -16,9 +16,8 @@
# with CIRCLE. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
from django.conf.urls import patterns, url, include
from django.conf.urls import url
import autocomplete_light
from vm.models import Instance
from .views import (
AclUpdateView, FavouriteView, GroupAclUpdateView, GroupDelete,
......@@ -56,14 +55,13 @@ from .views import (
StorageDetail, DiskDetail,
MessageList, MessageDetail, MessageCreate, MessageDelete,
EnableTwoFactorView, DisableTwoFactorView,
AclUserGroupAutocomplete, AclUserAutocomplete,
)
from .views.vm import vm_ops, vm_mass_ops
from .views.node import node_ops
autocomplete_light.autodiscover()
urlpatterns = patterns(
'',
urlpatterns = [
url(r'^$', IndexView.as_view(), name="dashboard.index"),
url(r"^profile/list/$", UserList.as_view(),
name="dashboard.views.user-list"),
......@@ -217,8 +215,6 @@ urlpatterns = patterns(
ConnectCommandCreate.as_view(),
name="dashboard.views.connect-command-create"),
url(r'^autocomplete/', include('autocomplete_light.urls')),
url(r"^store/list/$", StoreList.as_view(),
name="dashboard.views.store-list"),
url(r"^store/download/$", store_download,
......@@ -253,22 +249,26 @@ urlpatterns = patterns(
name="dashboard.views.message-create"),
url(r'^message/delete/(?P<pk>\d+)/$', MessageDelete.as_view(),
name="dashboard.views.message-delete"),
)
urlpatterns += patterns(
'',
*(url(r'^vm/(?P<pk>\d+)/op/%s/$' % op, v.as_view(), name=v.get_urlname())
for op, v in vm_ops.iteritems())
)
url(r'^autocomplete/acl/user-group/$',
AclUserGroupAutocomplete.as_view(),
name='autocomplete.acl.user-group'),
url(r'^autocomplete/acl/user/$',
AclUserAutocomplete.as_view(),
name='autocomplete.acl.user'),
]
urlpatterns += patterns(
'',
*(url(r'^vm/mass_op/%s/$' % op, v.as_view(), name=v.get_urlname())
for op, v in vm_mass_ops.iteritems())
)
urlpatterns += [
url(r'^vm/(?P<pk>\d+)/op/%s/$' % op, v.as_view(), name=v.get_urlname())
for op, v in vm_ops.iteritems()
]
urlpatterns += patterns(
'',
*(url(r'^node/(?P<pk>\d+)/op/%s/$' % op, v.as_view(), name=v.get_urlname())
for op, v in node_ops.iteritems())
)
urlpatterns += [
url(r'^vm/mass_op/%s/$' % op, v.as_view(), name=v.get_urlname())
for op, v in vm_mass_ops.iteritems()
]
urlpatterns += [
url(r'^node/(?P<pk>\d+)/op/%s/$' % op, v.as_view(), name=v.get_urlname())
for op, v in node_ops.iteritems()
]
......@@ -15,3 +15,4 @@ from graph import *
from storage import *
from request import *
from message import *
from autocomplete import *
......@@ -15,13 +15,16 @@
# You should have received a copy of the GNU General Public License along
# with CIRCLE. If not, see <http://www.gnu.org/licenses/>.
import autocomplete_light
import json
from dal import autocomplete
from django.contrib.auth.models import User
from django.utils.html import escape
from django.utils.translation import ugettext as _
from django.db.models import Q
from django.http import HttpResponse
from .views import AclUpdateView
from .models import Profile
from ..views import AclUpdateView
from ..models import Profile
def highlight(field, q, none_wo_match=True):
......@@ -48,13 +51,21 @@ def highlight(field, q, none_wo_match=True):
return escape(field)
class AclUserGroupAutocomplete(autocomplete_light.AutocompleteGenericBase):
search_fields = (
('first_name', 'last_name', 'username', 'email', 'profile__org_id'),
('name', 'groupprofile__org_id'),
)
choice_html_format = (u'<span data-value="%s"><span style="display:none"'
u'>%s</span>%s</span>')
class AclUserAutocomplete(autocomplete.Select2ListView):
search_fields = ('first_name', 'last_name', 'username',
'email', 'profile__org_id')
def filter(self, qs, search_fields):
if self.q:
condition = Q()
for field in search_fields:
condition |= Q(**{field + '__icontains': unicode(self.q)})
return list(qs.filter(condition))
return []
def get_list(self):
users = AclUpdateView.get_allowed_users(self.request.user)
return self.filter(users, self.search_fields)
def choice_displayed_text(self, choice):
q = unicode(self.request.GET.get('q', ''))
......@@ -71,35 +82,17 @@ class AclUserGroupAutocomplete(autocomplete_light.AutocompleteGenericBase):
else:
return _('%s (group)') % name
def choice_html(self, choice):
return self.choice_html_format % (
self.choice_value(choice), self.choice_label(choice),
self.choice_displayed_text(choice))
def choices_for_request(self):
user = self.request.user
self.choices = (AclUpdateView.get_allowed_users(user),
AclUpdateView.get_allowed_groups(user))
return super(AclUserGroupAutocomplete, self).choices_for_request()
def autocomplete_html(self):
html = []
for choice in self.choices_for_request():
html.append(self.choice_html(choice))
if not html:
html = self.empty_html_format % _('no matches found').capitalize()
return self.autocomplete_html_format % ''.join(html)
def get(self, *args, **kwargs):
return HttpResponse(json.dumps({
'results': [dict(id=unicode(r), text=self.choice_displayed_text(r))
for r in self.get_list()]
}), content_type="application/json")
class AclUserAutocomplete(AclUserGroupAutocomplete):
def choices_for_request(self):
user = self.request.user
self.choices = (AclUpdateView.get_allowed_users(user), )
return super(AclUserGroupAutocomplete, self).choices_for_request()
class AclUserGroupAutocomplete(AclUserAutocomplete):
group_search_fields = ('name', 'groupprofile__org_id')
autocomplete_light.register(AclUserGroupAutocomplete)
autocomplete_light.register(AclUserAutocomplete)
def get_list(self):
groups = AclUpdateView.get_allowed_groups(self.request.user)
groups = self.filter(groups, self.group_search_fields)
return super(AclUserGroupAutocomplete, self).get_list() + groups
......@@ -171,6 +171,7 @@ class TemplateVms(object):
def get_minmax(self):
return (0, None)
register_graph(TemplateVms, 'instances', TemplateGraphView)
......@@ -197,6 +198,7 @@ class Ram(object):
def get_minmax(self):
return (0, 105)
register_graph(Ram, 'memory', VmGraphView)
register_graph(Ram, 'memory', NodeGraphView)
......@@ -212,6 +214,7 @@ class Cpu(object):
else:
return (0, self.obj.num_cores * 100 + 5)
register_graph(Cpu, 'cpu', VmGraphView)
register_graph(Cpu, 'cpu', NodeGraphView)
......@@ -236,6 +239,7 @@ class VmNetwork(object):
params))
return 'group(%s)' % ','.join(metrics) if metrics else None
register_graph(VmNetwork, 'network', VmGraphView)
......@@ -251,6 +255,7 @@ class NodeNetwork(object):
'10), ".*\.bytes_(sent|recv)-([a-zA-Z0-9]+).*", "\\2 \\1")' % (
self.obj.metric_prefix))
register_graph(NodeNetwork, 'network', NodeGraphView)
......@@ -262,6 +267,7 @@ class NodeVms(object):
def get_minmax(self):
return (0, None)
register_graph(NodeVms, 'vm', NodeGraphView)
......@@ -282,6 +288,7 @@ class NodeAllocated(object):
def get_minmax(self):
return (0, None)
register_graph(NodeAllocated, 'alloc', NodeGraphView)
......@@ -302,6 +309,7 @@ class NodeListAllocated(object):
def get_minmax(self):
return (0, None)
register_graph(NodeListAllocated, 'alloc', NodeListGraphView)
......@@ -315,4 +323,5 @@ class NodeListVms(object):
def get_minmax(self):
return (0, None)
register_graph(NodeListVms, 'vm', NodeListGraphView)
......@@ -18,7 +18,7 @@ from __future__ import unicode_literals, absolute_import
import logging
from django.core.cache import get_cache
from django.core.cache import cache
from django.core.urlresolvers import reverse
from django.conf import settings
from django.contrib.auth.models import Group, User
......@@ -103,7 +103,6 @@ class IndexView(LoginRequiredMixin, TemplateView):
# toplist
if settings.STORE_URL:
cache_key = "files-%d" % self.request.user.pk
cache = get_cache("default")
files = cache.get(cache_key)
if not files:
try:
......
......@@ -27,7 +27,6 @@ from django.db.models import Count
from django.forms.models import inlineformset_factory
from django.http import HttpResponse
from django.shortcuts import redirect
from django.template import RequestContext
from django.template.loader import render_to_string
from django.utils.translation import ugettext as _
from django.views.generic import DetailView, TemplateView, View
......@@ -330,8 +329,12 @@ class NodeActivityView(LoginRequiredMixin, SuperuserRequiredMixin, View):
response = {
'activities': render_to_string(
"dashboard/node-detail/_activity-timeline.html",
RequestContext(request, {'activities': activities,
'show_show_all': show_show_all}))
{
'activities': activities,
'show_show_all': show_show_all
},
request
)
}
return HttpResponse(
......
......@@ -24,12 +24,11 @@ from django.conf import settings
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.template.defaultfilters import urlencode
from django.core.cache import get_cache
from django.core.cache import cache
from django.core.exceptions import SuspiciousOperation
from django.core.urlresolvers import reverse
from django.http import HttpResponse
from django.shortcuts import redirect, render_to_response, render
from django.template import RequestContext
from django.utils.translation import ugettext as _
from django.views.decorators.http import require_GET, require_POST
from django.views.generic import TemplateView
......@@ -65,7 +64,7 @@ class StoreList(LoginRequiredMixin, TemplateView):
context = self.get_context_data(**kwargs)
return render_to_response(
"dashboard/store/_list-box.html",
RequestContext(self.request, context),
context, self.request
)
else:
return super(StoreList, self).get(*args, **kwargs)
......@@ -193,7 +192,6 @@ def store_new_directory(request):
@login_required
def store_refresh_toplist(request):
cache_key = "files-%d" % request.user.pk
cache = get_cache("default")
try:
store = Store(request.user)
toplist = store.toplist()
......
......@@ -231,7 +231,7 @@ class MyPreferencesView(UpdateView):
def get(self, request, form=None, *args, **kwargs):
# if this is not here, it won't work
self.object = self.get_object()
context = self.get_context_data(*args, **kwargs)
context = self.get_context_data(form=form, *args, **kwargs)
if form is not None:
# a little cheating, users can't post invalid
# language selection forms (without modifying the HTML)
......
......@@ -32,7 +32,6 @@ from django.http import (
HttpResponse, Http404, HttpResponseRedirect, JsonResponse
)
from django.shortcuts import redirect, get_object_or_404
from django.template import RequestContext
from django.template.loader import render_to_string
from django.utils.translation import (
ugettext as _, ugettext_noop, ungettext_lazy,
......@@ -1289,15 +1288,15 @@ def vm_activity(request, pk):
response['activities'] = render_to_string(
"dashboard/vm-detail/_activity-timeline.html",
RequestContext(request, context),
context, request
)
response['ops'] = render_to_string(
"dashboard/vm-detail/_operations.html",
RequestContext(request, context),
context, request
)
response['disk_ops'] = render_to_string(
"dashboard/vm-detail/_disk-operations.html",
RequestContext(request, context),
context, request
)
return HttpResponse(
......
......@@ -143,6 +143,7 @@ class SwitchPortAdmin(admin.ModelAdmin):
class EthernetDeviceAdmin(admin.ModelAdmin):
list_display = ('name', )
admin.site.register(Host, HostAdmin)
admin.site.register(Vlan, VlanAdmin)
admin.site.register(Rule, RuleAdmin)
......
......@@ -52,12 +52,19 @@ class MACAddressFormField(forms.Field):
class MACAddressField(models.Field):
description = _('MAC Address object')
__metaclass__ = models.SubfieldBase
def __init__(self, *args, **kwargs):
kwargs['max_length'] = 17
super(MACAddressField, self).__init__(*args, **kwargs)
def deconstruct(self):
name, path, args, kwargs = super(MACAddressField, self).deconstruct()
del kwargs['max_length']
return name, path, args, kwargs
def from_db_value(self, value, expression, connection, context):
return self.to_python(value)
def to_python(self, value):
if not value:
return None
......@@ -105,16 +112,25 @@ class IPAddressFormField(forms.Field):
class IPAddressField(models.Field):
description = _('IP Network object')
__metaclass__ = models.SubfieldBase
def __init__(self, version=4, serialize=True, *args, **kwargs):
kwargs['max_length'] = 100
self.version = version
super(IPAddressField, self).__init__(*args, **kwargs)
def deconstruct(self):
name, path, args, kwargs = super(IPAddressField, self).deconstruct()
del kwargs['max_length']
if self.version != 4:
kwargs['version'] = self.version
return name, path, args, kwargs
def get_internal_type(self):
return "CharField"
def from_db_value(self, value, expression, connection, context):
return self.to_python(value)
def to_python(self, value):
if not value:
return None
......@@ -163,13 +179,22 @@ class IPNetworkFormField(forms.Field):
class IPNetworkField(models.Field):
description = _('IP Network object')
__metaclass__ = models.SubfieldBase
def __init__(self, version=4, serialize=True, *args, **kwargs):
kwargs['max_length'] = 100
self.version = version
super(IPNetworkField, self).__init__(*args, **kwargs)
def deconstruct(self):
name, path, args, kwargs = super(IPNetworkField, self).deconstruct()
del kwargs['max_length']
if self.version != 4:
kwargs['version'] = self.version
return name, path, args, kwargs
def from_db_value(self, value, expression, connection, context):
return self.to_python(value)
def to_python(self, value):
if not value:
return None
......
......@@ -25,7 +25,7 @@ from .models import (Host, Rule, Vlan, Domain, Record, BlacklistItem,
SwitchPort)
from .iptables import IptRule, IptChain
import django.conf
from django.template import loader, Context
from django.template import loader
from django.utils import timezone
......@@ -152,9 +152,9 @@ class BuildFirewall:
template = loader.get_template('firewall/iptables.conf')
context['proto'] = 'ipv4'
ipv4 = unicode(template.render(Context(context)))
ipv4 = unicode(template.render(context))
context['proto'] = 'ipv6'
ipv6 = unicode(template.render(Context(context)))
ipv6 = unicode(template.render(context))
return (ipv4, ipv6)
......
# -*- coding: utf-8 -*-
# Generated by Django 1.11.3 on 2017-07-07 19:09
from __future__ import unicode_literals
from django.db import migrations
import firewall.fields
class Migration(migrations.Migration):
dependencies = [
('firewall', '0005_auto_20150520_2250'),
]
operations = [
migrations.AlterField(
model_name='host',
name='ipv6',
field=firewall.fields.IPAddressField(blank=True, help_text='The global IPv6 address of the host, for example 2001:db:88:200::10.', null=True, unique=True, verbose_name='IPv6 address', version=6),
),
migrations.AlterField(
model_name='vlan',
name='network6',
field=firewall.fields.IPNetworkField(blank=True, help_text='The IPv6 address and the prefix length of the gateway.', null=True, verbose_name='IPv6 address/prefix', version=6),
),
]
......@@ -80,7 +80,7 @@ class GetNewAddressTestCase(MockCeleryMixin, TestCase):
self.vlan = Vlan(vid=1, name='test', network4='10.0.0.1/29',
network6='2001:738:2001:4031::/80', domain=d,
owner=self.u1)
self.vlan.clean()
self.vlan.full_clean()
self.vlan.save()
self.vlan.host_set.all().delete()
for i in range(3, 6):
......
......@@ -15,7 +15,7 @@
# You should have received a copy of the GNU General Public License along
# with CIRCLE. If not, see <http://www.gnu.org/licenses/>.
from django.conf.urls import patterns, url
from django.conf.urls import url
from .views import (
IndexView,
HostList, HostDetail, HostCreate, HostDelete,
......@@ -33,8 +33,7 @@ from .views import (
VlanAclUpdateView
)
urlpatterns = patterns(
'',
urlpatterns = [
url('^$', IndexView.as_view(), name='network.index'),
# blacklist
url('^blacklist/$', BlacklistList.as_view(),
......@@ -135,4 +134,4 @@ urlpatterns = patterns(
remove_switch_port_device, name='network.remove_switch_port_device'),
url('^switchports/(?P<pk>\d+)/add/$', add_switch_port_device,
name='network.add_switch_port_device'),
)
]
......@@ -19,7 +19,6 @@ from django.forms import (
Textarea, ValidationError
)
from django.utils.translation import ugettext_lazy as _
from django.template import RequestContext
from django.template.loader import render_to_string
from sizefield.widgets import FileSizeWidget
......@@ -68,8 +67,7 @@ class InitialFromFileMixin(object):
super(InitialFromFileMixin, self).__init__(*args, **kwargs)
self.initial['message'] = render_to_string(
self.initial_template,
RequestContext(request, {}),
self.initial_template, {}, request
)
def clean_message(self):
......
......@@ -16,7 +16,7 @@
# with CIRCLE. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
from django.conf.urls import patterns, url
from django.conf.urls import url
from .views import (
RequestList, RequestDetail, RequestTypeList,
......@@ -26,8 +26,7 @@ from .views import (
LeaseTypeDelete, TemplateAccessTypeDelete, ResizeRequestView,
)
urlpatterns = patterns(
'',
urlpatterns = [
url(r'^list/$', RequestList.as_view(),
name="request.views.request-list"),
url(r'^(?P<pk>\d+)/$', RequestDetail.as_view(),
......@@ -62,4 +61,4 @@ urlpatterns = patterns(
name="request.views.request-resource"),
url(r'resize/(?P<vm_pk>\d+)/(?P<disk_pk>\d+)/$',
ResizeRequestView.as_view(), name="request.views.request-resize"),
)
]
# This import is responsible for running the operations' registration code.
from . import operations # noqa
# noqa
......@@ -177,9 +177,9 @@ class InterfaceTestCase(MockCeleryMixin, TestCase):
i = Instance(id=10, owner=owner, access_method='rdp')
d = Domain(owner=owner)
d.save()
v = Vlan(vid=55, network4='127.0.0.1/8',
v = Vlan(name='vlan', vid=55, network4='127.0.0.1/8',
network6='2001::1/32', domain=d)
v.clean()
v.full_clean()
v.save()
Interface.create(i, v, managed=True, owner=owner)
......
......@@ -4,18 +4,19 @@ arrow==0.7.0
billiard==3.3.0.20
bpython==0.14.1
celery==3.1.18
Django==1.8.15
django-appconf==1.0.1
django-autocomplete-light==2.1.1
django-braces==1.8.0
django-crispy-forms==1.6.0
django-model-utils==2.2
djangosaml2==0.13.0
django-sizefield==0.7
Django==1.11.3
django-appconf==1.0.2
django-autocomplete-light==3.2.9
django-braces==1.11.0
django-crispy-forms==1.6.1
django-model-utils==3.0.0
django-pipeline==1.6.13
django-sizefield==0.9.1
django-statici18n==1.4.0
django-tables2==1.10.0
django-taggit==0.22.1
djangosaml2==0.16.0
git+https://git.ik.bme.hu/circle/django-sshkey.git
django-statici18n==1.1.3
django-tables2==0.16.0
django-taggit==0.14.0
docutils==0.12
Jinja2==2.7.3
jsonfield==1.0.3
......@@ -39,6 +40,6 @@ six==1.9.0
slimit==0.8.1
sqlparse==0.1.15
pika==0.9.14
django-pipeline==1.4.7
Fabric==1.10.1
lxml==3.4.4
python-memcached==1.58
\ No newline at end of file
# Local development dependencies go here
-r base.txt
coverage==3.7.1
django-debug-toolbar==1.3.0
django-rosetta==0.7.6
django-debug-toolbar==1.8
django-rosetta==0.7.13
Sphinx==1.3.1
......@@ -3,9 +3,9 @@
coverage==3.7.1
factory-boy==2.4.1
mock==1.0.1
django-nose==1.4
nose==1.3.6
nose-exclude==0.2.0
django-nose==1.4.4
nose==1.3.7
nose-exclude==0.5.0
selenium==2.45.0
selenose==1.3
-e git+https://github.com/kmmbvnr/django-jenkins.git@019774dc2f668bc66b66f90f97eb8e14ae9566a4#egg=django_jenkins-dev
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment