Commit 04c13498 by Csók Tamás

Merge remote-tracking branch 'origin/master' into issue-218

parents fa9fb516 dc674ca8
...@@ -39,3 +39,4 @@ circle/static_collected ...@@ -39,3 +39,4 @@ circle/static_collected
# jsi18n files # jsi18n files
jsi18n jsi18n
scripts.rc
...@@ -161,7 +161,7 @@ STATICFILES_FINDERS = ( ...@@ -161,7 +161,7 @@ STATICFILES_FINDERS = (
) )
########## END STATIC FILE CONFIGURATION ########## END STATIC FILE CONFIGURATION
p = join(dirname(SITE_ROOT), 'site-circle/static') p = normpath(join(SITE_ROOT, '../../site-circle/static'))
if exists(p): if exists(p):
STATICFILES_DIRS = (p, ) STATICFILES_DIRS = (p, )
...@@ -211,8 +211,8 @@ TEMPLATE_LOADERS = ( ...@@ -211,8 +211,8 @@ TEMPLATE_LOADERS = (
# See: https://docs.djangoproject.com/en/dev/ref/settings/#template-dirs # See: https://docs.djangoproject.com/en/dev/ref/settings/#template-dirs
TEMPLATE_DIRS = ( TEMPLATE_DIRS = (
normpath(join(SITE_ROOT, '../../site-circle/templates')),
normpath(join(SITE_ROOT, 'templates')), normpath(join(SITE_ROOT, 'templates')),
join(dirname(SITE_ROOT), 'site-circle/templates'),
) )
########## END TEMPLATE CONFIGURATION ########## END TEMPLATE CONFIGURATION
...@@ -368,9 +368,9 @@ if get_env_variable('DJANGO_SAML', 'FALSE') == 'TRUE': ...@@ -368,9 +368,9 @@ if get_env_variable('DJANGO_SAML', 'FALSE') == 'TRUE':
from shutilwhich import which from shutilwhich import which
from saml2 import BINDING_HTTP_POST, BINDING_HTTP_REDIRECT from saml2 import BINDING_HTTP_POST, BINDING_HTTP_REDIRECT
# INSTALLED_APPS += ( # needed only for testing djangosaml2 INSTALLED_APPS += (
# 'djangosaml', 'djangosaml2',
# ) )
AUTHENTICATION_BACKENDS = ( AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend', 'django.contrib.auth.backends.ModelBackend',
'djangosaml2.backends.Saml2Backend', 'djangosaml2.backends.Saml2Backend',
...@@ -465,3 +465,6 @@ SESSION_COOKIE_NAME = "csessid%x" % (((getnode() // 139) ^ ...@@ -465,3 +465,6 @@ SESSION_COOKIE_NAME = "csessid%x" % (((getnode() // 139) ^
(getnode() % 983)) & 0xffff) (getnode() % 983)) & 0xffff)
MAX_NODE_RAM = get_env_variable("MAX_NODE_RAM", 1024) MAX_NODE_RAM = get_env_variable("MAX_NODE_RAM", 1024)
# Url to download the client: (e.g. http://circlecloud.org/client/download/)
CLIENT_DOWNLOAD_URL = get_env_variable('CLIENT_DOWNLOAD_URL', 'http://circlecloud.org/client/download/')
...@@ -20,22 +20,17 @@ ...@@ -20,22 +20,17 @@
from os import environ from os import environ
from sys import argv
from base import * # noqa from base import * # noqa
if 'runserver' in argv:
def get_env_setting(setting): SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTOCOL', 'https')
""" Get the environment setting or return exception """
try:
return environ[setting]
except KeyError:
error_msg = "Set the %s env variable" % setting
raise ImproperlyConfigured(error_msg)
########## HOST CONFIGURATION ########## HOST CONFIGURATION
# See: https://docs.djangoproject.com/en/1.5/releases/1.5/ # See: https://docs.djangoproject.com/en/1.5/releases/1.5/
# #allowed-hosts-required-in-production # #allowed-hosts-required-in-production
ALLOWED_HOSTS = get_env_setting('DJANGO_ALLOWED_HOSTS').split(',') ALLOWED_HOSTS = get_env_variable('DJANGO_ALLOWED_HOSTS').split(',')
########## END HOST CONFIGURATION ########## END HOST CONFIGURATION
########## EMAIL CONFIGURATION ########## EMAIL CONFIGURATION
...@@ -44,18 +39,18 @@ EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' ...@@ -44,18 +39,18 @@ EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
try: try:
# See: https://docs.djangoproject.com/en/dev/ref/settings/#email-host # See: https://docs.djangoproject.com/en/dev/ref/settings/#email-host
EMAIL_HOST = environ.get('EMAIL_HOST') EMAIL_HOST = get_env_variable('EMAIL_HOST')
except ImproperlyConfigured: except ImproperlyConfigured:
pass EMAIL_HOST = 'localhost'
else: else:
# https://docs.djangoproject.com/en/dev/ref/settings/#email-host-password # https://docs.djangoproject.com/en/dev/ref/settings/#email-host-password
EMAIL_HOST_PASSWORD = environ.get('EMAIL_HOST_PASSWORD', '') EMAIL_HOST_PASSWORD = get_env_variable('EMAIL_HOST_PASSWORD', '')
# See: https://docs.djangoproject.com/en/dev/ref/settings/#email-host-user # See: https://docs.djangoproject.com/en/dev/ref/settings/#email-host-user
EMAIL_HOST_USER = environ.get('EMAIL_HOST_USER', 'your_email@example.com') EMAIL_HOST_USER = get_env_variable('EMAIL_HOST_USER', 'your_email@example.com')
# See: https://docs.djangoproject.com/en/dev/ref/settings/#email-port # See: https://docs.djangoproject.com/en/dev/ref/settings/#email-port
EMAIL_PORT = environ.get('EMAIL_PORT', 587) EMAIL_PORT = get_env_variable('EMAIL_PORT', 587)
# See: https://docs.djangoproject.com/en/dev/ref/settings/#email-use-tls # See: https://docs.djangoproject.com/en/dev/ref/settings/#email-use-tls
EMAIL_USE_TLS = True EMAIL_USE_TLS = True
...@@ -64,7 +59,8 @@ else: ...@@ -64,7 +59,8 @@ else:
EMAIL_SUBJECT_PREFIX = '[%s] ' % SITE_NAME EMAIL_SUBJECT_PREFIX = '[%s] ' % SITE_NAME
# See: https://docs.djangoproject.com/en/dev/ref/settings/#server-email # See: https://docs.djangoproject.com/en/dev/ref/settings/#server-email
SERVER_EMAIL = EMAIL_HOST_USER DEFAULT_FROM_EMAIL = get_env_variable('DEFAULT_FROM_EMAIL')
SERVER_EMAIL = get_env_variable('SERVER_EMAIL', DEFAULT_FROM_EMAIL)
########## END EMAIL CONFIGURATION ########## END EMAIL CONFIGURATION
...@@ -83,5 +79,12 @@ CACHES = { ...@@ -83,5 +79,12 @@ CACHES = {
########## SECRET CONFIGURATION ########## SECRET CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#secret-key # See: https://docs.djangoproject.com/en/dev/ref/settings/#secret-key
SECRET_KEY = get_env_setting('SECRET_KEY') SECRET_KEY = get_env_variable('SECRET_KEY')
########## END SECRET CONFIGURATION ########## END SECRET CONFIGURATION
level = environ.get('LOGLEVEL', 'INFO')
LOGGING['handlers']['syslog']['level'] = level
for i in LOCAL_APPS:
LOGGING['loggers'][i] = {'handlers': ['syslog'], 'level': level}
LOGGING['loggers']['djangosaml2'] = {'handlers': ['syslog'], 'level': level}
LOGGING['loggers']['django'] = {'handlers': ['syslog'], 'level': level}
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
from collections import deque from collections import deque
from contextlib import contextmanager from contextlib import contextmanager
from functools import update_wrapper
from hashlib import sha224 from hashlib import sha224
from itertools import chain, imap from itertools import chain, imap
from logging import getLogger from logging import getLogger
...@@ -26,6 +27,7 @@ from warnings import warn ...@@ -26,6 +27,7 @@ from warnings import warn
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.cache import cache from django.core.cache import cache
from django.core.exceptions import PermissionDenied
from django.core.serializers.json import DjangoJSONEncoder from django.core.serializers.json import DjangoJSONEncoder
from django.db.models import ( from django.db.models import (
CharField, DateTimeField, ForeignKey, NullBooleanField CharField, DateTimeField, ForeignKey, NullBooleanField
...@@ -36,6 +38,7 @@ from django.utils.functional import Promise ...@@ -36,6 +38,7 @@ from django.utils.functional import Promise
from django.utils.translation import ugettext_lazy as _, ugettext_noop from django.utils.translation import ugettext_lazy as _, ugettext_noop
from jsonfield import JSONField from jsonfield import JSONField
from manager.mancelery import celery
from model_utils.models import TimeStampedModel from model_utils.models import TimeStampedModel
logger = getLogger(__name__) logger = getLogger(__name__)
...@@ -211,6 +214,46 @@ class ActivityModel(TimeStampedModel): ...@@ -211,6 +214,46 @@ class ActivityModel(TimeStampedModel):
self.result_data = None if value is None else value.to_dict() self.result_data = None if value is None else value.to_dict()
@classmethod
def construct_activity_code(cls, code_suffix, sub_suffix=None):
code = join_activity_code(cls.ACTIVITY_CODE_BASE, code_suffix)
if sub_suffix:
return join_activity_code(code, sub_suffix)
else:
return code
@celery.task()
def compute_cached(method, instance, memcached_seconds,
key, start, *args, **kwargs):
"""Compute and store actual value of cached method."""
if isinstance(method, basestring):
model, id = instance
instance = model.objects.get(id=id)
try:
method = getattr(model, method)
while hasattr(method, '_original') or hasattr(method, 'fget'):
try:
method = method._original
except AttributeError:
method = method.fget
except AttributeError:
logger.exception("Couldnt get original method of %s",
unicode(method))
raise
# call the actual method
result = method(instance, *args, **kwargs)
# save to memcache
cache.set(key, result, memcached_seconds)
elapsed = time() - start
cache.set("%s.cached" % key, 2, max(memcached_seconds * 0.5,
memcached_seconds * 0.75 - elapsed))
logger.debug('Value of <%s>.%s(%s)=<%s> saved to cache (%s elapsed).',
unicode(instance), method.__name__, unicode(args),
unicode(result), elapsed)
return result
def method_cache(memcached_seconds=60, instance_seconds=5): # noqa def method_cache(memcached_seconds=60, instance_seconds=5): # noqa
"""Cache return value of decorated method to memcached and memory. """Cache return value of decorated method to memcached and memory.
...@@ -233,9 +276,11 @@ def method_cache(memcached_seconds=60, instance_seconds=5): # noqa ...@@ -233,9 +276,11 @@ def method_cache(memcached_seconds=60, instance_seconds=5): # noqa
def inner_cache(method): def inner_cache(method):
method_name = method.__name__
def get_key(instance, *args, **kwargs): def get_key(instance, *args, **kwargs):
return sha224(unicode(method.__module__) + return sha224(unicode(method.__module__) +
unicode(method.__name__) + method_name +
unicode(instance.id) + unicode(instance.id) +
unicode(args) + unicode(args) +
unicode(kwargs)).hexdigest() unicode(kwargs)).hexdigest()
...@@ -254,21 +299,31 @@ def method_cache(memcached_seconds=60, instance_seconds=5): # noqa ...@@ -254,21 +299,31 @@ def method_cache(memcached_seconds=60, instance_seconds=5): # noqa
if vals['time'] + instance_seconds > now: if vals['time'] + instance_seconds > now:
# has valid on class cache, return that # has valid on class cache, return that
result = vals['value'] result = vals['value']
setattr(instance, key, {'time': now, 'value': result})
if result is None: if result is None:
result = cache.get(key) result = cache.get(key)
if invalidate or (result is None): if invalidate or (result is None):
# all caches failed, call the actual method logger.debug("all caches failed, compute now")
result = method(instance, *args, **kwargs) result = compute_cached(method, instance, memcached_seconds,
# save to memcache and class attr key, time(), *args, **kwargs)
cache.set(key, result, memcached_seconds)
setattr(instance, key, {'time': now, 'value': result}) setattr(instance, key, {'time': now, 'value': result})
logger.debug('Value of <%s>.%s(%s)=<%s> saved to cache.', elif not cache.get("%s.cached" % key):
unicode(instance), method.__name__, logger.debug("caches expiring, compute async")
unicode(args), unicode(result)) cache.set("%s.cached" % key, 1, memcached_seconds * 0.5)
try:
compute_cached.apply_async(
queue='localhost.man', kwargs=kwargs, args=[
method_name, (instance.__class__, instance.id),
memcached_seconds, key, time()] + list(args))
except:
logger.exception("Couldnt compute async %s", method_name)
return result return result
update_wrapper(x, method)
x._original = method
return x return x
return inner_cache return inner_cache
...@@ -367,6 +422,10 @@ class HumanReadableObject(object): ...@@ -367,6 +422,10 @@ class HumanReadableObject(object):
self._set_values(user_text_template, admin_text_template, params) self._set_values(user_text_template, admin_text_template, params)
def _set_values(self, user_text_template, admin_text_template, params): def _set_values(self, user_text_template, admin_text_template, params):
if isinstance(user_text_template, Promise):
user_text_template = user_text_template._proxy____args[0]
if isinstance(admin_text_template, Promise):
admin_text_template = admin_text_template._proxy____args[0]
self.user_text_template = user_text_template self.user_text_template = user_text_template
self.admin_text_template = admin_text_template self.admin_text_template = admin_text_template
self.params = params self.params = params
...@@ -405,6 +464,12 @@ class HumanReadableObject(object): ...@@ -405,6 +464,12 @@ class HumanReadableObject(object):
self.user_text_template, unicode(self.params)) self.user_text_template, unicode(self.params))
return self.user_text_template return self.user_text_template
def get_text(self, user):
if user and user.is_superuser:
return self.get_admin_text()
else:
return self.get_user_text()
def to_dict(self): def to_dict(self):
return {"user_text_template": self.user_text_template, return {"user_text_template": self.user_text_template,
"admin_text_template": self.admin_text_template, "admin_text_template": self.admin_text_template,
...@@ -431,17 +496,38 @@ class HumanReadableException(HumanReadableObject, Exception): ...@@ -431,17 +496,38 @@ class HumanReadableException(HumanReadableObject, Exception):
"Level should be the name of an attribute of django." "Level should be the name of an attribute of django."
"contrib.messages (and it should be callable with " "contrib.messages (and it should be callable with "
"(request, message)). Like 'error', 'warning'.") "(request, message)). Like 'error', 'warning'.")
else: elif not hasattr(self, "level"):
self.level = "error" self.level = "error"
def send_message(self, request, level=None): def send_message(self, request, level=None):
if request.user and request.user.is_superuser: msg = self.get_text(request.user)
msg = self.get_admin_text()
else:
msg = self.get_user_text()
getattr(messages, level or self.level)(request, msg) getattr(messages, level or self.level)(request, msg)
def fetch_human_exception(exception, user=None):
"""Fetch user readable message from exception.
>>> r = humanize_exception("foo", Exception())
>>> fetch_human_exception(r, User())
u'foo'
>>> fetch_human_exception(r).get_text(User())
u'foo'
>>> fetch_human_exception(Exception(), User())
u'Unknown error'
>>> fetch_human_exception(PermissionDenied(), User())
u'Permission Denied'
"""
if not isinstance(exception, HumanReadableException):
if isinstance(exception, PermissionDenied):
exception = create_readable(ugettext_noop("Permission Denied"))
else:
exception = create_readable(ugettext_noop("Unknown error"),
ugettext_noop("Unknown error: %(ex)s"),
ex=unicode(exception))
return exception.get_text(user) if user else exception
def humanize_exception(message, exception=None, level=None, **params): def humanize_exception(message, exception=None, level=None, **params):
"""Return new dynamic-class exception which is based on """Return new dynamic-class exception which is based on
HumanReadableException and the original class with the dict of exception. HumanReadableException and the original class with the dict of exception.
......
...@@ -18,10 +18,10 @@ ...@@ -18,10 +18,10 @@
from inspect import getargspec from inspect import getargspec
from logging import getLogger from logging import getLogger
from .models import activity_context, has_suffix
from django.core.exceptions import PermissionDenied, ImproperlyConfigured from django.core.exceptions import PermissionDenied, ImproperlyConfigured
from django.utils.translation import ugettext_noop
from .models import activity_context, has_suffix, humanize_exception
logger = getLogger(__name__) logger = getLogger(__name__)
...@@ -31,6 +31,7 @@ class Operation(object): ...@@ -31,6 +31,7 @@ class Operation(object):
""" """
async_queue = 'localhost.man' async_queue = 'localhost.man'
required_perms = None required_perms = None
superuser_required = False
do_not_call_in_templates = True do_not_call_in_templates = True
abortable = False abortable = False
has_percentage = False has_percentage = False
...@@ -143,13 +144,26 @@ class Operation(object): ...@@ -143,13 +144,26 @@ class Operation(object):
def check_precond(self): def check_precond(self):
pass pass
def check_auth(self, user): @classmethod
if self.required_perms is None: def check_perms(cls, user):
"""Check if user is permitted to run this operation on any instance
"""
if cls.required_perms is None:
raise ImproperlyConfigured( raise ImproperlyConfigured(
"Set required_perms to () if none needed.") "Set required_perms to () if none needed.")
if not user.has_perms(self.required_perms): if not user.has_perms(cls.required_perms):
raise PermissionDenied("%s doesn't have the required permissions." raise PermissionDenied("%s doesn't have the required permissions."
% user) % user)
if cls.superuser_required and not user.is_superuser:
raise humanize_exception(ugettext_noop(
"Superuser privileges are required."), PermissionDenied())
def check_auth(self, user):
"""Check if user is permitted to run this operation on this instance
"""
self.check_perms(user)
def create_activity(self, parent, user, kwargs): def create_activity(self, parent, user, kwargs):
raise NotImplementedError raise NotImplementedError
...@@ -185,14 +199,17 @@ class OperatedMixin(object): ...@@ -185,14 +199,17 @@ class OperatedMixin(object):
def __getattr__(self, name): def __getattr__(self, name):
# NOTE: __getattr__ is only called if the attribute doesn't already # NOTE: __getattr__ is only called if the attribute doesn't already
# exist in your __dict__ # exist in your __dict__
cls = self.__class__ return self.get_operation_class(name)(self)
@classmethod
def get_operation_class(cls, name):
ops = getattr(cls, operation_registry_name, {}) ops = getattr(cls, operation_registry_name, {})
op = ops.get(name) op = ops.get(name)
if op: if op:
return op(self) return op
else: else:
raise AttributeError("%r object has no attribute %r" % raise AttributeError("%r object has no attribute %r" %
(self.__class__.__name__, name)) (cls.__name__, name))
def get_available_operations(self, user): def get_available_operations(self, user):
"""Yield Operations that match permissions of user and preconditions. """Yield Operations that match permissions of user and preconditions.
...@@ -256,3 +273,4 @@ def register_operation(op_cls, op_id=None, target_cls=None): ...@@ -256,3 +273,4 @@ def register_operation(op_cls, op_id=None, target_cls=None):
setattr(target_cls, operation_registry_name, dict()) setattr(target_cls, operation_registry_name, dict())
getattr(target_cls, operation_registry_name)[op_id] = op_cls getattr(target_cls, operation_registry_name)[op_id] = op_cls
return op_cls
...@@ -25,9 +25,9 @@ def handler500(request): ...@@ -25,9 +25,9 @@ def handler500(request):
ctx['error'] = exception.get_admin_text() ctx['error'] = exception.get_admin_text()
except: except:
pass pass
try: try:
resp = render_to_response("500.html", ctx, RequestContext(request)) resp = render_to_response("500.html", ctx, RequestContext(request))
except: except:
resp = render_to_response("500.html", ctx) resp = render_to_response("500.html", ctx)
resp.status_code = 500 resp.status_code = 500
return resp return resp
...@@ -21,18 +21,22 @@ from django import contrib ...@@ -21,18 +21,22 @@ from django import contrib
from django.contrib.auth.admin import UserAdmin, GroupAdmin from django.contrib.auth.admin import UserAdmin, GroupAdmin
from django.contrib.auth.models import User, Group from django.contrib.auth.models import User, Group
from dashboard.models import Profile, GroupProfile from dashboard.models import Profile, GroupProfile, ConnectCommand
class ProfileInline(contrib.admin.TabularInline): class ProfileInline(contrib.admin.TabularInline):
model = Profile model = Profile
class CommandInline(contrib.admin.TabularInline):
model = ConnectCommand
class GroupProfileInline(contrib.admin.TabularInline): class GroupProfileInline(contrib.admin.TabularInline):
model = GroupProfile model = GroupProfile
UserAdmin.inlines = (ProfileInline, ) UserAdmin.inlines = (ProfileInline, CommandInline, )
GroupAdmin.inlines = (GroupProfileInline, ) GroupAdmin.inlines = (GroupProfileInline, )
contrib.admin.site.unregister(User) contrib.admin.site.unregister(User)
......
import autocomplete_light import autocomplete_light
from django.contrib.auth.models import User
from django.utils.html import escape
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from .views import AclUpdateView from .views import AclUpdateView
from .models import Profile
class AclUserAutocomplete(autocomplete_light.AutocompleteGenericBase): def highlight(field, q, none_wo_match=True):
"""
>>> highlight('<b>Akkount Krokodil', 'kro', False)
u'&lt;b&gt;Akkount <span class="autocomplete-hl">Kro</span>kodil'
"""
if not field:
return None
try:
match = field.lower().index(q.lower())
except ValueError:
match = None
if q and match is not None:
match_end = match + len(q)
return (escape(field[:match])
+ '<span class="autocomplete-hl">'
+ escape(field[match:match_end])
+ '</span>' + escape(field[match_end:]))
elif none_wo_match:
return None
else:
return escape(field)
class AclUserGroupAutocomplete(autocomplete_light.AutocompleteGenericBase):
search_fields = ( search_fields = (
('^first_name', 'last_name', 'username', '^email', 'profile__org_id'), ('first_name', 'last_name', 'username', 'email', 'profile__org_id'),
('^name', 'groupprofile__org_id'), ('name', 'groupprofile__org_id'),
) )
autocomplete_js_attributes = {'placeholder': _("Name of group or user")} choice_html_format = (u'<span data-value="%s"><span style="display:none"'
choice_html_format = u'<span data-value="%s"><span>%s</span> %s</span>' u'>%s</span>%s</span>')
def choice_html(self, choice): def choice_displayed_text(self, choice):
try: q = unicode(self.request.GET.get('q', ''))
name = choice.get_full_name() name = highlight(unicode(choice), q, False)
except AttributeError: if isinstance(choice, User):
name = _('group') extra_fields = [highlight(choice.get_full_name(), q, False),
if name: highlight(choice.email, q)]
name = u'(%s)' % name try:
extra_fields.append(highlight(choice.profile.org_id, q))
except Profile.DoesNotExist:
pass
return '%s (%s)' % (name, ', '.join(f for f in extra_fields
if f))
else:
return _('%s (group)') % name
def choice_html(self, choice):
return self.choice_html_format % ( return self.choice_html_format % (
self.choice_value(choice), self.choice_label(choice), name) self.choice_value(choice), self.choice_label(choice),
self.choice_displayed_text(choice))
def choices_for_request(self): def choices_for_request(self):
user = self.request.user user = self.request.user
self.choices = (AclUpdateView.get_allowed_users(user), self.choices = (AclUpdateView.get_allowed_users(user),
AclUpdateView.get_allowed_groups(user)) AclUpdateView.get_allowed_groups(user))
return super(AclUserAutocomplete, self).choices_for_request() 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)
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()
autocomplete_light.register(AclUserGroupAutocomplete)
autocomplete_light.register(AclUserAutocomplete) autocomplete_light.register(AclUserAutocomplete)
...@@ -1383,7 +1383,6 @@ ...@@ -1383,7 +1383,6 @@
"time_of_suspend": null, "time_of_suspend": null,
"ram_size": 200, "ram_size": 200,
"priority": 10, "priority": 10,
"active_since": null,
"template": null, "template": null,
"access_method": "nx", "access_method": "nx",
"lease": 1, "lease": 1,
...@@ -1413,7 +1412,6 @@ ...@@ -1413,7 +1412,6 @@
"time_of_suspend": null, "time_of_suspend": null,
"ram_size": 200, "ram_size": 200,
"priority": 10, "priority": 10,
"active_since": null,
"template": null, "template": null,
"access_method": "nx", "access_method": "nx",
"lease": 1, "lease": 1,
......