diff --git a/actions/users b/actions/users
index e1a84c228..4cf7dcb87 100755
--- a/actions/users
+++ b/actions/users
@@ -86,6 +86,11 @@ def parse_arguments():
subparser.add_argument('groupname',
help='LDAP group to remove the user from')
+ help_get_admin_user = 'Get the list of all users in an LDAP group'
+ subparser = subparsers.add_parser('get-group-users', help=help_get_admin_user)
+ subparser.add_argument('groupname', help='name of the LDAP group to get the '
+ 'list of users')
+
subparsers.required = True
return parser.parse_args()
@@ -345,6 +350,16 @@ def subcommand_remove_user_from_group(arguments):
flush_cache()
+def subcommand_get_group_users(arguments):
+ """ Get the list of admin users """
+ process = _run(['ldapgid', arguments.groupname], stdout=subprocess.PIPE)
+ output = str(process.stdout).split()
+ users_info = output[1].split('=')[1].strip('\\n').split(',')
+ for user_info in users_info:
+ user_name = user_info.split('(')[1].split(')')[0]
+ print(user_name)
+
+
def flush_cache():
"""Flush nscd cache."""
_run(['nscd', '--invalidate=passwd'])
diff --git a/plinth/forms.py b/plinth/forms.py
index 319c3431d..0358080e9 100644
--- a/plinth/forms.py
+++ b/plinth/forms.py
@@ -19,10 +19,13 @@ Common forms for use by modules.
"""
import os
+from itertools import chain
from django import forms
from django.conf import settings
+from django.forms import CheckboxInput
from django.utils import translation
+from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import get_language_info
@@ -32,8 +35,8 @@ from plinth import utils
class ServiceForm(forms.Form):
"""Generic configuration form for a service."""
- is_enabled = forms.BooleanField(label=_('Enable application'),
- required=False)
+ is_enabled = forms.BooleanField(
+ label=_('Enable application'), required=False)
class DomainSelectionForm(forms.Form):
@@ -82,3 +85,38 @@ class LanguageSelectionForm(LanguageSelectionFormMixin, forms.Form):
"""Language selection form."""
language = LanguageSelectionFormMixin.language
+
+
+class CheckboxSelectMultipleWithDisabled(forms.widgets.CheckboxSelectMultiple):
+ """
+ Subclass of Django's checkbox select multiple widget that allows disabling checkbox-options.
+ To disable an option, pass a dict instead of a string for its label,
+ of the form: {'label': 'option label', 'disabled': True}
+
+ Derived from https://djangosnippets.org/snippets/2786/
+ """
+
+ def render(self, name, value, attrs=None, choices=(), renderer=None):
+ if value is None: value = []
+ final_attrs = self.build_attrs(attrs)
+ output = [u'
']
+ global_disabled = 'disabled' in final_attrs
+ str_values = set([v for v in value])
+ for i, (option_value, option_label) in enumerate(
+ chain(self.choices, choices)):
+ if not global_disabled and 'disabled' in final_attrs:
+ # If the entire group is disabled keep all options disabled
+ del final_attrs['disabled']
+ if isinstance(option_label, dict):
+ if dict.get(option_label, 'disabled'):
+ final_attrs = dict(final_attrs, disabled='disabled')
+ option_label = option_label['label']
+ final_attrs = dict(final_attrs, id='%s_%s' % (attrs['id'], i))
+ label_for = u' for="%s"' % final_attrs['id']
+ cb = CheckboxInput(final_attrs,
+ check_test=lambda value: value in str_values)
+ rendered_cb = cb.render(name, option_value)
+ output.append(u'' %
+ (label_for, rendered_cb, option_label))
+ output.append(u'
')
+ return mark_safe(u'\n'.join(output))
diff --git a/plinth/modules/users/__init__.py b/plinth/modules/users/__init__.py
index adf55e577..4edea4275 100644
--- a/plinth/modules/users/__init__.py
+++ b/plinth/modules/users/__init__.py
@@ -105,3 +105,15 @@ def remove_group(group):
def register_group(group):
groups[group[0]] = group[1]
+
+
+def get_last_admin_user():
+ """ Check if there is only one admin user
+ if yes return its name else return None
+ """
+ admin_users = actions.superuser_run('users',
+ ['get-group-users','admin']
+ ).strip().split('\n')
+ if len(admin_users) > 1:
+ return None
+ return admin_users[0]
diff --git a/plinth/modules/users/forms.py b/plinth/modules/users/forms.py
index 2b7188ca8..aff9d8c14 100644
--- a/plinth/modules/users/forms.py
+++ b/plinth/modules/users/forms.py
@@ -22,6 +22,7 @@ from django.contrib import auth, messages
from django.contrib.auth.forms import SetPasswordForm, UserCreationForm
from django.contrib.auth.models import Group, User
from django.core.exceptions import ValidationError
+
from django.utils.translation import ugettext as _
from django.utils.translation import ugettext_lazy
@@ -33,6 +34,8 @@ from plinth.modules.security import set_restricted_access
from plinth.translation import set_language
from plinth.utils import is_user_admin
+from . import get_last_admin_user
+
def get_group_choices():
"""Return localized group description and group name in one string."""
@@ -159,7 +162,7 @@ class UserUpdateForm(ValidNewUsernameCheckMixin,
fields = ('username', 'groups', 'ssh_keys', 'language', 'is_active')
model = User
widgets = {
- 'groups': forms.widgets.CheckboxSelectMultiple(),
+ 'groups': plinth.forms.CheckboxSelectMultipleWithDisabled(),
}
def __init__(self, request, username, *args, **kwargs):
@@ -171,6 +174,7 @@ class UserUpdateForm(ValidNewUsernameCheckMixin,
self.request = request
self.username = username
super(UserUpdateForm, self).__init__(*args, **kwargs)
+ last_admin_user = get_last_admin_user()
choices = []
@@ -179,7 +183,10 @@ class UserUpdateForm(ValidNewUsernameCheckMixin,
# applications not installed yet.
if c[1] in group_choices:
# Replace group names with descriptions
- choices.append((c[0], group_choices[c[1]]))
+ if c[1] == 'admin' and last_admin_user is not None:
+ choices.append((c[0], {'label': group_choices[c[1]], 'disabled': True}))
+ else:
+ choices.append((c[0], group_choices[c[1]]))
self.fields['groups'].label = _('Permissions')
self.fields['groups'].choices = choices
@@ -188,6 +195,9 @@ class UserUpdateForm(ValidNewUsernameCheckMixin,
self.fields['is_active'].widget = forms.HiddenInput()
self.fields['groups'].disabled = True
+ if last_admin_user and last_admin_user == self.username:
+ self.fields['is_active'].disabled = True
+
def save(self, commit=True):
"""Update LDAP user name and groups after saving user model."""
user = super(UserUpdateForm, self).save(commit=False)
diff --git a/plinth/modules/users/templates/users_list.html b/plinth/modules/users/templates/users_list.html
index de36f745a..94a264121 100644
--- a/plinth/modules/users/templates/users_list.html
+++ b/plinth/modules/users/templates/users_list.html
@@ -40,7 +40,7 @@
{% for user in object_list %}
- {% if object_list|length != 1 %}
+ {% if user.username != last_admin_user %}