diff --git a/orchestra/apps/users/__init__.py b/orchestra/apps/users/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/orchestra/apps/users/admin.py b/orchestra/apps/users/admin.py deleted file mode 100644 index 6451d0af..00000000 --- a/orchestra/apps/users/admin.py +++ /dev/null @@ -1,110 +0,0 @@ -from django.conf.urls import patterns, url -from django.core.urlresolvers import reverse -from django.contrib import admin -from django.contrib.admin.util import unquote -from django.contrib.auth import admin as auth -from django.utils.translation import ugettext, ugettext_lazy as _ - -from orchestra.admin import ExtendedModelAdmin -from orchestra.admin.utils import wrap_admin_view -from orchestra.apps.accounts.admin import AccountAdminMixin - -from .forms import UserCreationForm, UserChangeForm -from .models import User -from .roles.filters import role_list_filter_factory - - -class UserAdmin(AccountAdminMixin, auth.UserAdmin, ExtendedModelAdmin): - list_display = ('username', 'display_is_main') - list_filter = ('is_staff', 'is_superuser', 'is_active') - fieldsets = ( - (None, { - 'fields': ('account', 'username', 'password') - }), - (_("Personal info"), { - 'fields': ('first_name', 'last_name', 'email') - }), - (_("Permissions"), { - 'fields': ('is_active', 'is_staff', 'is_superuser', 'display_is_main') - }), - (_("Important dates"), { - 'fields': ('last_login', 'date_joined') - }), - ) - add_fieldsets = ( - (None, { - 'classes': ('wide',), - 'fields': ('username', 'password1', 'password2', 'account'), - }), - ) - search_fields = ['username', 'account__user__username'] - readonly_fields = ('display_is_main', 'account_link') - change_readonly_fields = ('username',) - filter_horizontal = () - add_form = UserCreationForm - form = UserChangeForm - roles = [] - ordering = ('-id',) - change_form_template = 'admin/users/user/change_form.html' - - def display_is_main(self, instance): - return instance.is_main - display_is_main.short_description = _("is main") - display_is_main.boolean = True - - def get_urls(self): - """ Returns the additional urls for the change view links """ - urls = super(UserAdmin, self).get_urls() - opts = self.model._meta - new_urls = patterns("") - for role in self.roles: - new_urls += patterns("", - url('^(\d+)/%s/$' % role.url_name, - wrap_admin_view(self, role().change_view), - name='%s_%s_%s_change' % (opts.app_label, opts.model_name, role.name)), - url('^(\d+)/%s/delete/$' % role.url_name, - wrap_admin_view(self, role().delete_view), - name='%s_%s_%s_delete' % (opts.app_label, opts.model_name, role.name)) - ) - return new_urls + urls - - def get_fieldsets(self, request, obj=None): - fieldsets = super(UserAdmin, self).get_fieldsets(request, obj=obj) - if obj and obj.account: - fieldsets[0][1]['fields'] = ('account_link',) + fieldsets[0][1]['fields'][1:] - return fieldsets - - def get_list_display(self, request): - roles = [] - for role in self.roles: - def has_role(user, role_class=role): - role = role_class(user=user) - if role.exists: - return 'True' - url = reverse('admin:users_user_%s_change' % role.name, args=(user.pk,)) - false = 'False' - return '%s' % (url, false) - has_role.short_description = _("Has %s") % role.name - has_role.admin_order_field = role.name - has_role.allow_tags = True - roles.append(has_role) - return list(self.list_display) + roles + ['account_link'] - - def get_list_filter(self, request): - roles = [ role_list_filter_factory(role) for role in self.roles ] - return list(self.list_filter) + roles - - def change_view(self, request, object_id, **kwargs): - user = self.get_object(User, unquote(object_id)) - extra_context = kwargs.get('extra_context', {}) - extra_context['roles'] = [ role(user=user) for role in self.roles ] - kwargs['extra_context'] = extra_context - return super(UserAdmin, self).change_view(request, object_id, **kwargs) - - def get_queryset(self, request): - """ Select related for performance """ - related = ['account__user'] + [ role.name for role in self.roles ] - return super(UserAdmin, self).get_queryset(request).select_related(*related) - - -admin.site.register(User, UserAdmin) diff --git a/orchestra/apps/users/api.py b/orchestra/apps/users/api.py deleted file mode 100644 index dda373e5..00000000 --- a/orchestra/apps/users/api.py +++ /dev/null @@ -1,20 +0,0 @@ -from django.contrib.auth import get_user_model -from rest_framework import viewsets - -from orchestra.api import router, SetPasswordApiMixin -from orchestra.apps.accounts.api import AccountApiMixin - -from .serializers import UserSerializer - - -class UserViewSet(AccountApiMixin, SetPasswordApiMixin, viewsets.ModelViewSet): - model = get_user_model() - serializer_class = UserSerializer - - def get_queryset(self): - """ select related roles """ - qs = super(UserViewSet, self).get_queryset() - return qs.select_related(*self.inserted) - - -router.register(r'users', UserViewSet) diff --git a/orchestra/apps/users/backends.py b/orchestra/apps/users/backends.py deleted file mode 100644 index 1af71f40..00000000 --- a/orchestra/apps/users/backends.py +++ /dev/null @@ -1,123 +0,0 @@ -import textwrap - -from django.utils import timezone -from django.utils.translation import ugettext_lazy as _ - -from orchestra.apps.orchestration import ServiceController -from orchestra.apps.resources import ServiceMonitor - -from . import settings - - -class SystemUserBackend(ServiceController): - verbose_name = _("System User") - model = 'users.User' - ignore_fields = ['last_login'] - - def save(self, user): - context = self.get_context(user) - if user.is_main: - self.append(textwrap.dedent(""" - if [[ $( id %(username)s ) ]]; then - usermod --password '%(password)s' %(username)s - else - useradd %(username)s --password '%(password)s' \\ - --shell /bin/false - fi - mkdir -p %(home)s - chown %(username)s.%(username)s %(home)s""" % context - )) - else: - self.delete(user) - - def delete(self, user): - context = self.get_context(user) - self.append("{ sleep 2 && killall -u %(username)s -s KILL; } &" % context) - self.append("killall -u %(username)s" % context) - self.append("userdel %(username)s" % context) - - def get_context(self, user): - context = { - 'username': user.username, - 'password': user.password if user.is_active else '*%s' % user.password, - } - context['home'] = settings.USERS_SYSTEMUSER_HOME % context - return context - - -class SystemUserDisk(ServiceMonitor): - model = 'users.User' - resource = ServiceMonitor.DISK - verbose_name = _('System user disk') - - def monitor(self, user): - context = self.get_context(user) - self.append("du -s %(home)s | xargs echo %(object_id)s" % context) - - def get_context(self, user): - context = SystemUserBackend().get_context(user) - context['object_id'] = user.pk - return context - - -class FTPTraffic(ServiceMonitor): - model = 'users.User' - resource = ServiceMonitor.TRAFFIC - verbose_name = _('FTP traffic') - - def prepare(self): - current_date = timezone.localtime(self.current_date) - current_date = current_date.strftime("%Y%m%d%H%M%S") - self.append(textwrap.dedent(""" - function monitor () { - OBJECT_ID=$1 - INI_DATE=$2 - USERNAME="$3" - LOG_FILE="$4" - grep "UPLOAD\|DOWNLOAD" "${LOG_FILE}" \\ - | grep " \\[${USERNAME}\\] " \\ - | awk -v ini="${INI_DATE}" ' - BEGIN { - end = "%s" - sum = 0 - months["Jan"] = "01" - months["Feb"] = "02" - months["Mar"] = "03" - months["Apr"] = "04" - months["May"] = "05" - months["Jun"] = "06" - months["Jul"] = "07" - months["Aug"] = "08" - months["Sep"] = "09" - months["Oct"] = "10" - months["Nov"] = "11" - months["Dec"] = "12" - } { - # log: Fri Jul 11 13:23:17 2014 - split($4, t, ":") - # line_date = year month day hour minute second - line_date = $5 months[$2] $3 t[1] t[2] t[3] - if ( line_date > ini && line_date < end) - split($0, l, "\\", ") - split(l[3], b, " ") - sum += b[1] - } END { - print sum - } - ' | xargs echo ${OBJECT_ID} - }""" % current_date)) - - def monitor(self, user): - context = self.get_context(user) - self.append( - 'monitor %(object_id)i %(last_date)s "%(username)s" "%(log_file)s"' % context) - - def get_context(self, user): - last_date = timezone.localtime(self.get_last_date(user.pk)) - return { - 'log_file': settings.USERS_FTP_LOG_PATH, - 'last_date': last_date.strftime("%Y%m%d%H%M%S"), - 'object_id': user.pk, - 'username': user.username, - } - diff --git a/orchestra/apps/users/forms.py b/orchestra/apps/users/forms.py deleted file mode 100644 index 42c52ac5..00000000 --- a/orchestra/apps/users/forms.py +++ /dev/null @@ -1,49 +0,0 @@ -from django import forms -from django.contrib import auth -from django.utils.translation import ugettext, ugettext_lazy as _ - -from orchestra.core.validators import validate_password - -from .models import User - - -class UserCreationForm(auth.forms.UserCreationForm): - class Meta(auth.forms.UserCreationForm.Meta): - model = User - - def __init__(self, *args, **kwargs): - super(UserCreationForm, self).__init__(*args, **kwargs) - self.fields['password1'].validators.append(validate_password) - - def clean_username(self): - # Since User.username is unique, this check is redundant, - # but it sets a nicer error message than the ORM. See #13147. - username = self.cleaned_data["username"] - try: - User._default_manager.get(username=username) - except User.DoesNotExist: - return username - raise forms.ValidationError(self.error_messages['duplicate_username']) - - -class UserChangeForm(forms.ModelForm): - password = auth.forms.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 this form.")) - - class Meta: - model = User - fields = '__all__' - - def __init__(self, *args, **kwargs): - super(UserChangeForm, self).__init__(*args, **kwargs) - f = self.fields.get('user_permissions', None) - if f is not None: - f.queryset = f.queryset.select_related('content_type') - - 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"] diff --git a/orchestra/apps/users/models.py b/orchestra/apps/users/models.py deleted file mode 100644 index b91b72aa..00000000 --- a/orchestra/apps/users/models.py +++ /dev/null @@ -1,92 +0,0 @@ -from django.contrib.auth import models as auth -from django.core import validators -from django.core.mail import send_mail -from django.db import models -from django.utils import timezone -from django.utils.translation import ugettext_lazy as _ - -from orchestra.core import services - - -class User(auth.AbstractBaseUser): - username = models.CharField(_("username"), max_length=64, unique=True, - help_text=_("Required. 30 characters or fewer. Letters, digits and " - "./-/_ only."), - validators=[validators.RegexValidator(r'^[\w.-]+$', - _("Enter a valid username."), 'invalid')]) - account = models.ForeignKey('accounts.Account', verbose_name=_("Account"), - related_name='users') - first_name = models.CharField(_("first name"), max_length=30, blank=True) - last_name = models.CharField(_("last name"), max_length=30, blank=True) - email = models.EmailField(_('email address'), blank=True) - is_superuser = models.BooleanField(_("superuser status"), default=False, - help_text=_("Designates that this user has all permissions without " - "explicitly assigning them.")) - is_staff = models.BooleanField(_("staff status"), default=False, - help_text=_("Designates whether the user can log into this admin " - "site.")) - is_admin = models.BooleanField(_("admin status"), default=False, - help_text=_("Designates whether the user can administrate its account.")) - is_active = models.BooleanField(_("active"), default=True, - help_text=_("Designates whether this user should be treated as " - "active. Unselect this instead of deleting accounts.")) - date_joined = models.DateTimeField(_("date joined"), default=timezone.now) - - objects = auth.UserManager() - - USERNAME_FIELD = 'username' - REQUIRED_FIELDS = ['email'] - - @property - def is_main(self): - return self.account.user == self - - def get_full_name(self): - full_name = '%s %s' % (self.first_name, self.last_name) - return full_name.strip() or self.username - - def get_short_name(self): - """ Returns the short name for the user """ - return self.first_name - - def email_user(self, subject, message, from_email=None, **kwargs): - """ Sends an email to this User """ - send_mail(subject, message, from_email, [self.email], **kwargs) - - def has_perm(self, perm, obj=None): - """ - Returns True if the user has the specified permission. This method - queries all available auth backends, but returns immediately if any - backend returns True. Thus, a user who has permission from a single - auth backend is assumed to have permission in general. If an object is - provided, permissions for this specific object are checked. - """ - # Active superusers have all permissions. - if self.is_active and self.is_superuser: - return True - # Otherwise we need to check the backends. - return auth._user_has_perm(self, perm, obj) - - def has_perms(self, perm_list, obj=None): - """ - Returns True if the user has each of the specified permissions. If - object is passed, it checks if the user has all required perms for this - object. - """ - for perm in perm_list: - if not self.has_perm(perm, obj): - return False - return True - - def has_module_perms(self, app_label): - """ - Returns True if the user has any permissions in the given app label. - Uses pretty much the same logic as has_perm, above. - """ - # Active superusers have all permissions. - if self.is_active and self.is_superuser: - return True - return auth._user_has_module_perms(self, app_label) - - -services.register(User, menu=False) diff --git a/orchestra/apps/users/roles/__init__.py b/orchestra/apps/users/roles/__init__.py deleted file mode 100644 index 62b9ee6f..00000000 --- a/orchestra/apps/users/roles/__init__.py +++ /dev/null @@ -1,27 +0,0 @@ -from ..models import User - - -class Register(object): - def __init__(self): - self._registry = {} - - def __contains__(self, key): - return key in self._registry - - def register(self, name, model): - if name in self._registry: - raise KeyError("%s already registered" % name) - def has_role(user, model=model): - try: - getattr(user, name) - except model.DoesNotExist: - return False - return True - setattr(User, 'has_%s' % name, has_role) - self._registry[name] = model - - def get(self): - return self._registry - - -roles = Register() diff --git a/orchestra/apps/users/roles/admin.py b/orchestra/apps/users/roles/admin.py deleted file mode 100644 index 0432a682..00000000 --- a/orchestra/apps/users/roles/admin.py +++ /dev/null @@ -1,145 +0,0 @@ -from django.contrib import messages -from django.contrib.admin.util import unquote, get_deleted_objects -from django.contrib.admin.templatetags.admin_urls import add_preserved_filters -from django.db import router -from django.http import Http404, HttpResponseRedirect -from django.template.response import TemplateResponse -from django.shortcuts import redirect -from django.utils.encoding import force_text -from django.utils.html import escape -from django.utils.translation import ugettext, ugettext_lazy as _ - -from orchestra.admin.utils import get_modeladmin, change_url - -from .forms import role_form_factory -from ..models import User - - -class RoleAdmin(object): - model = None - name = '' - url_name = '' - form = None - - def __init__(self, user=None): - self.user = user - - @property - def exists(self): - try: - return getattr(self.user, self.name) - except self.model.DoesNotExist: - return False - - def get_user(self, request, object_id): - try: - user = User.objects.get(pk=unquote(object_id)) - except User.DoesNotExist: - opts = self.model._meta - raise Http404( - _('%(name)s object with primary key %(key)r does not exist.') % - {'name': force_text(opts.verbose_name), 'key': escape(object_id)} - ) - return user - - def change_view(self, request, object_id): - modeladmin = get_modeladmin(User) - user = self.get_user(request, object_id) - self.user = user - obj = None - exists = self.exists - if exists: - obj = getattr(user, self.name) - form_class = self.form if self.form else role_form_factory(self) - form = form_class(instance=obj) - opts = User._meta - app_label = opts.app_label - title = _("Add %s for user %s" % (self.name, user)) - action = _("Create") - # User has submitted the form - if request.method == 'POST': - form = form_class(request.POST, instance=obj) - form.user = user - if form.is_valid(): - obj = form.save() - context = { - 'name': obj._meta.verbose_name, - 'obj': obj, - 'action': _("saved" if exists else "created") - } - modeladmin.log_change(request, request.user, "%s saved" % self.name.capitalize()) - msg = _('The role %(name)s for user "%(obj)s" was %(action)s successfully.') % context - modeladmin.message_user(request, msg, messages.SUCCESS) - if not "_continue" in request.POST: - return redirect(change_url(user)) - exists = True - - if exists: - title = _("Change %s %s settings" % (user, self.name)) - action = _("Save") - form = form_class(instance=obj) - - context = { - 'title': title, - 'opts': opts, - 'app_label': app_label, - 'form': form, - 'action': action, - 'role': self, - 'roles': [ role(user=user) for role in modeladmin.roles ], - 'media': modeladmin.media - } - - template = 'admin/users/user/role.html' - app = modeladmin.admin_site.name - return TemplateResponse(request, template, context, current_app=app) - - def delete_view(self, request, object_id): - "The 'delete' admin view for this model." - opts = self.model._meta - app_label = opts.app_label - modeladmin = get_modeladmin(User) - user = self.get_user(request, object_id) - obj = getattr(user, self.name) - - using = router.db_for_write(self.model) - - # Populate deleted_objects, a data structure of all related objects that - # will also be deleted. - (deleted_objects, perms_needed, protected) = get_deleted_objects( - [obj], opts, request.user, modeladmin.admin_site, using) - - if request.POST: # The user has already confirmed the deletion. - if perms_needed: - raise PermissionDenied - obj_display = force_text(obj) - modeladmin.log_deletion(request, obj, obj_display) - modeladmin.delete_model(request, obj) - post_url = change_url(user) - preserved_filters = modeladmin.get_preserved_filters(request) - post_url = add_preserved_filters( - {'preserved_filters': preserved_filters, 'opts': opts}, post_url - ) - return HttpResponseRedirect(post_url) - - object_name = force_text(opts.verbose_name) - - if perms_needed or protected: - title = _("Cannot delete %(name)s") % {"name": object_name} - else: - title = _("Are you sure?") - - context = { - "title": title, - "object_name": object_name, - "object": obj, - "deleted_objects": deleted_objects, - "perms_lacking": perms_needed, - "protected": protected, - "opts": opts, - "app_label": app_label, - 'preserved_filters': modeladmin.get_preserved_filters(request), - 'role': self, - } - return TemplateResponse(request, 'admin/users/user/delete_role.html', - context, current_app=modeladmin.admin_site.name) diff --git a/orchestra/apps/users/roles/filters.py b/orchestra/apps/users/roles/filters.py deleted file mode 100644 index 7bac9a3b..00000000 --- a/orchestra/apps/users/roles/filters.py +++ /dev/null @@ -1,23 +0,0 @@ -from django.contrib.admin import SimpleListFilter -from django.utils.translation import ugettext_lazy as _ - - -def role_list_filter_factory(role): - class RoleListFilter(SimpleListFilter): - """ Filter Nodes by group according to request.user """ - title = _("has %s" % role.name) - parameter_name = role.url_name - - def lookups(self, request, model_admin): - return ( - ('True', _("Yes")), - ('False', _("No")), - ) - - def queryset(self, request, queryset): - if self.value() == 'True': - return queryset.filter(**{ '%s__isnull' % role.name: False }) - if self.value() == 'False': - return queryset.filter(**{ '%s__isnull' % role.name: True }) - - return RoleListFilter diff --git a/orchestra/apps/users/roles/forms.py b/orchestra/apps/users/roles/forms.py deleted file mode 100644 index decc6610..00000000 --- a/orchestra/apps/users/roles/forms.py +++ /dev/null @@ -1,17 +0,0 @@ -from django import forms - - -class RoleAdminBaseForm(forms.ModelForm): - class Meta: - exclude = ('user', ) - - def save(self, *args, **kwargs): - self.instance.user = self.user - return super(RoleAdminBaseForm, self).save(*args, **kwargs) - - -def role_form_factory(role): - class RoleAdminForm(RoleAdminBaseForm): - class Meta(RoleAdminBaseForm.Meta): - model = role.model - return RoleAdminForm diff --git a/orchestra/apps/users/roles/jabber/__init__.py b/orchestra/apps/users/roles/jabber/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/orchestra/apps/users/roles/jabber/admin.py b/orchestra/apps/users/roles/jabber/admin.py deleted file mode 100644 index ba126c0f..00000000 --- a/orchestra/apps/users/roles/jabber/admin.py +++ /dev/null @@ -1,15 +0,0 @@ -from django.contrib.auth import get_user_model - -from orchestra.admin.utils import insertattr -from orchestra.apps.users.roles.admin import RoleAdmin - -from .models import Jabber - - -class JabberRoleAdmin(RoleAdmin): - model = Jabber - name = 'jabber' - url_name = 'jabber' - - -insertattr(get_user_model(), 'roles', JabberRoleAdmin) diff --git a/orchestra/apps/users/roles/jabber/models.py b/orchestra/apps/users/roles/jabber/models.py deleted file mode 100644 index 32850579..00000000 --- a/orchestra/apps/users/roles/jabber/models.py +++ /dev/null @@ -1,15 +0,0 @@ -from django.db import models -from django.utils.translation import ugettext_lazy as _ - -from .. import roles - - -class Jabber(models.Model): - user = models.OneToOneField('users.User', verbose_name=_("user"), - related_name='jabber') - - def __unicode__(self): - return str(self.user) - - -roles.register('jabber', Jabber) diff --git a/orchestra/apps/users/roles/mail/__init__.py b/orchestra/apps/users/roles/mail/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/orchestra/apps/users/roles/mail/admin.py b/orchestra/apps/users/roles/mail/admin.py deleted file mode 100644 index 58d3fa56..00000000 --- a/orchestra/apps/users/roles/mail/admin.py +++ /dev/null @@ -1,124 +0,0 @@ -from django import forms -from django.contrib import admin -from django.contrib.auth import get_user_model -from django.core.urlresolvers import reverse -from django.utils.translation import ugettext_lazy as _ - -from orchestra.admin import ExtendedModelAdmin -from orchestra.admin.utils import insertattr, admin_link -from orchestra.apps.accounts.admin import SelectAccountAdminMixin -from orchestra.apps.users.roles.admin import RoleAdmin - -from .forms import MailRoleAdminForm -from .models import Mailbox, Address, Autoresponse - - -class AutoresponseInline(admin.StackedInline): - model = Autoresponse - verbose_name_plural = _("autoresponse") - - def formfield_for_dbfield(self, db_field, **kwargs): - if db_field.name == 'subject': - kwargs['widget'] = forms.TextInput(attrs={'size':'118'}) - return super(AutoresponseInline, self).formfield_for_dbfield(db_field, **kwargs) - - -#class AddressAdmin(SelectAccountAdminMixin, ExtendedModelAdmin): -# list_display = ('email', 'domain_link', 'mailboxes', 'forwards', 'account_link') -# fields = ('account_link', ('name', 'domain'), 'destination') -# inlines = [AutoresponseInline] -# search_fields = ('name', 'domain__name',) -# readonly_fields = ('account_link', 'domain_link', 'email_link') -# filter_by_account_fields = ['domain'] -# -# domain_link = link('domain', order='domain__name') -# -# def email_link(self, address): -# link = self.domain_link(address) -# return "%s@%s" % (address.name, link) -# email_link.short_description = _("Email") -# email_link.allow_tags = True -# -# def mailboxes(self, address): -# boxes = [] -# for mailbox in address.get_mailboxes(): -# user = mailbox.user -# url = reverse('admin:users_user_mailbox_change', args=(user.pk,)) -# boxes.append('%s' % (url, user.username)) -# return '
'.join(boxes) -# mailboxes.allow_tags = True -# -# def forwards(self, address): -# values = [ dest for dest in address.destination.split() if '@' in dest ] -# return '
'.join(values) -# forwards.allow_tags = True -# -# def formfield_for_dbfield(self, db_field, **kwargs): -# if db_field.name == 'destination': -# kwargs['widget'] = forms.TextInput(attrs={'size':'118'}) -# return super(AddressAdmin, self).formfield_for_dbfield(db_field, **kwargs) -# -# def queryset(self, request): -# """ Select related for performance """ -# qs = super(AddressAdmin, self).queryset(request) -# return qs.select_related('domain') - - -class AddressAdmin(SelectAccountAdminMixin, ExtendedModelAdmin): - list_display = ( - 'email', 'domain_link', 'display_mailboxes', 'display_forward', 'account_link' - ) - fields = ('account_link', ('name', 'domain'), 'mailboxes', 'forward') - inlines = [AutoresponseInline] - search_fields = ('name', 'domain__name',) - readonly_fields = ('account_link', 'domain_link', 'email_link') - filter_by_account_fields = ['domain'] - filter_horizontal = ['mailboxes'] - - domain_link = admin_link('domain', order='domain__name') - - def email_link(self, address): - link = self.domain_link(address) - return "%s@%s" % (address.name, link) - email_link.short_description = _("Email") - email_link.allow_tags = True - - def display_mailboxes(self, address): - boxes = [] - for mailbox in address.mailboxes.all(): - user = mailbox.user - url = reverse('admin:users_user_mailbox_change', args=(user.pk,)) - boxes.append('%s' % (url, user.username)) - return '
'.join(boxes) - display_mailboxes.short_description = _("Mailboxes") - display_mailboxes.allow_tags = True - - def display_forward(self, address): - values = [ dest for dest in address.forward.split() ] - return '
'.join(values) - display_forward.short_description = _("Forward") - display_forward.allow_tags = True - - def formfield_for_dbfield(self, db_field, **kwargs): - if db_field.name == 'forward': - kwargs['widget'] = forms.TextInput(attrs={'size':'118'}) - if db_field.name == 'mailboxes': - mailboxes = db_field.rel.to.objects.select_related('user') - kwargs['queryset'] = mailboxes.filter(user__account=self.account) - return super(AddressAdmin, self).formfield_for_dbfield(db_field, **kwargs) - - def get_queryset(self, request): - """ Select related for performance """ - qs = super(AddressAdmin, self).get_queryset(request) - return qs.select_related('domain') - - -class MailRoleAdmin(RoleAdmin): - model = Mailbox - name = 'mailbox' - url_name = 'mailbox' - form = MailRoleAdminForm - - -admin.site.register(Address, AddressAdmin) -insertattr(get_user_model(), 'roles', MailRoleAdmin) diff --git a/orchestra/apps/users/roles/mail/api.py b/orchestra/apps/users/roles/mail/api.py deleted file mode 100644 index 410d8a1c..00000000 --- a/orchestra/apps/users/roles/mail/api.py +++ /dev/null @@ -1,27 +0,0 @@ -from rest_framework import viewsets - -from orchestra.api import router -from orchestra.apps.accounts.api import AccountApiMixin - -from .models import Address, Mailbox -from .serializers import AddressSerializer, MailboxSerializer - - -class AddressViewSet(AccountApiMixin, viewsets.ModelViewSet): - model = Address - serializer_class = AddressSerializer - - - -class MailboxViewSet(viewsets.ModelViewSet): - model = Mailbox - serializer_class = MailboxSerializer - - def get_queryset(self): - qs = super(MailboxViewSet, self).get_queryset() - qs = qs.select_related('user') - return qs.filter(user__account=self.request.user.account_id) - - -router.register(r'mailboxes', MailboxViewSet) -router.register(r'addresses', AddressViewSet) diff --git a/orchestra/apps/users/roles/mail/backends.py b/orchestra/apps/users/roles/mail/backends.py deleted file mode 100644 index b29d03ae..00000000 --- a/orchestra/apps/users/roles/mail/backends.py +++ /dev/null @@ -1,160 +0,0 @@ -import os - -from django.utils import timezone -from django.utils.translation import ugettext_lazy as _ - -from orchestra.apps.orchestration import ServiceController -from orchestra.apps.resources import ServiceMonitor - -from . import settings -from .models import Address - - -class MailSystemUserBackend(ServiceController): - verbose_name = _("Mail system user") - model = 'mail.Mailbox' - # TODO related_models = ('resources__content_type') ?? - - DEFAULT_GROUP = 'postfix' - - def create_user(self, context): - self.append( - "if [[ $( id %(username)s ) ]]; then \n" - " usermod -p '%(password)s' %(username)s \n" - "else \n" - " useradd %(username)s --password '%(password)s' \\\n" - " --shell /dev/null \n" - "fi" % context - ) - self.append("mkdir -p %(home)s" % context) - self.append("chown %(username)s.%(group)s %(home)s" % context) - - def generate_filter(self, mailbox, context): - now = timezone.now().strftime("%B %d, %Y, %H:%M") - context['filtering'] = ( - "# Sieve Filter\n" - "# Generated by Orchestra %s\n\n" % now - ) - if mailbox.use_custom_filtering: - context['filtering'] += mailbox.custom_filtering - else: - context['filtering'] += settings.EMAILS_DEFAUL_FILTERING - context['filter_path'] = os.path.join(context['home'], '.orchestra.sieve') - self.append("echo '%(filtering)s' > %(filter_path)s" % context) - - def save(self, mailbox): - context = self.get_context(mailbox) - self.create_user(context) - self.generate_filter(mailbox, context) - - def delete(self, mailbox): - context = self.get_context(mailbox) - self.append("{ sleep 2 && killall -u %(username)s -s KILL; } &" % context) - self.append("killall -u %(username)s" % context) - self.append("userdel %(username)s" % context) - self.append("rm -fr %(home)s" % context) - - def get_context(self, mailbox): - user = mailbox.user - context = { - 'username': user.username, - 'password': user.password if user.is_active else '*%s' % user.password, - 'group': self.DEFAULT_GROUP - } - context['home'] = settings.EMAILS_HOME % context - return context - - -class PostfixAddressBackend(ServiceController): - verbose_name = _("Postfix address") - model = 'mail.Address' - - def include_virtdomain(self, context): - self.append( - '[[ $(grep "^\s*%(domain)s\s*$" %(virtdomains)s) ]]' - ' || { echo "%(domain)s" >> %(virtdomains)s; UPDATED=1; }' % context - ) - - def exclude_virtdomain(self, context): - domain = context['domain'] - if not Address.objects.filter(domain=domain).exists(): - self.append('sed -i "s/^%(domain)s//" %(virtdomains)s' % context) - - def update_virtusertable(self, context): - self.append( - 'LINE="%(email)s\t%(destination)s"\n' - 'if [[ ! $(grep "^%(email)s\s" %(virtusertable)s) ]]; then\n' - ' echo "$LINE" >> %(virtusertable)s\n' - ' UPDATED=1\n' - 'else\n' - ' if [[ ! $(grep "^${LINE}$" %(virtusertable)s) ]]; then\n' - ' sed -i "s/^%(email)s\s.*$/${LINE}/" %(virtusertable)s\n' - ' UPDATED=1\n' - ' fi\n' - 'fi' % context - ) - - def exclude_virtusertable(self, context): - self.append( - 'if [[ $(grep "^%(email)s\s") ]]; then\n' - ' sed -i "s/^%(email)s\s.*$//" %(virtusertable)s\n' - ' UPDATED=1\n' - 'fi' - ) - - def save(self, address): - context = self.get_context(address) - self.include_virtdomain(context) - self.update_virtusertable(context) - - def delete(self, address): - context = self.get_context(address) - self.exclude_virtdomain(context) - self.exclude_virtusertable(context) - - def commit(self): - context = self.get_context_files() - self.append('[[ $UPDATED == 1 ]] && { ' - 'postmap %(virtdomains)s;' - 'postmap %(virtusertable)s;' - '}' % context) - - def get_context_files(self): - return { - 'virtdomains': settings.EMAILS_VIRTDOMAINS_PATH, - 'virtusertable': settings.EMAILS_VIRTUSERTABLE_PATH, - } - - def get_context(self, address): - context = self.get_context_files() - context.update({ - 'domain': address.domain, - 'email': address.email, - 'destination': address.destination, - }) - return context - - -class AutoresponseBackend(ServiceController): - verbose_name = _("Mail autoresponse") - model = 'mail.Autoresponse' - - -class MaildirDisk(ServiceMonitor): - model = 'email.Mailbox' - resource = ServiceMonitor.DISK - verbose_name = _("Maildir disk usage") - - def monitor(self, mailbox): - context = self.get_context(mailbox) - self.append( - "SIZE=$(sed -n '2p' %(maildir_path)s | cut -d' ' -f1)\n" - "echo %(object_id)s ${SIZE:-0}" % context - ) - - def get_context(self, mailbox): - context = MailSystemUserBackend().get_context(mailbox) - context['home'] = settings.EMAILS_HOME % context - context['maildir_path'] = os.path.join(context['home'], 'Maildir/maildirsize') - context['object_id'] = mailbox.pk - return context diff --git a/orchestra/apps/users/roles/mail/forms.py b/orchestra/apps/users/roles/mail/forms.py deleted file mode 100644 index 7066e5d0..00000000 --- a/orchestra/apps/users/roles/mail/forms.py +++ /dev/null @@ -1,53 +0,0 @@ -from django import forms -from django.core.urlresolvers import reverse -from django.utils.safestring import mark_safe -from django.utils.translation import ugettext_lazy as _ - -from orchestra.forms.widgets import ReadOnlyWidget - -from .models import Mailbox -from ..forms import RoleAdminBaseForm - - -class MailRoleAdminForm(RoleAdminBaseForm): - class Meta(RoleAdminBaseForm.Meta): - model = Mailbox - - def __init__(self, *args, **kwargs): - super(MailRoleAdminForm, self).__init__(*args, **kwargs) - instance = kwargs.get('instance') - if instance: - widget = ReadOnlyWidget(self.addresses(instance)) - self.fields['addresses'] = forms.CharField(widget=widget, - label=_("Addresses")) - -# def addresses(self, mailbox): -# account = mailbox.user.account -# addresses = account.addresses.filter(destination__contains=mailbox.user.username) -# add_url = reverse('admin:mail_address_add') -# add_url += '?account=%d&destination=%s' % (account.pk, mailbox.user.username) -# img = 'Add Another' -# onclick = 'onclick="return showAddAnotherPopup(this);"' -# add_link = '%s Add address' % (add_url, onclick, img) -# value = '%s

' % add_link -# for pk, name, domain in addresses.values_list('pk', 'name', 'domain__name'): -# url = reverse('admin:mail_address_change', args=(pk,)) -# name = '%s@%s' % (name, domain) -# value += '
  • %s
  • ' % (url, name) -# value = '' % value -# return mark_safe('
    %s
    ' % value) - - def addresses(self, mailbox): - account = mailbox.user.account - add_url = reverse('admin:mail_address_add') - add_url += '?account=%d&mailboxes=%s' % (account.pk, mailbox.pk) - img = 'Add Another' - onclick = 'onclick="return showAddAnotherPopup(this);"' - add_link = '%s Add address' % (add_url, onclick, img) - value = '%s

    ' % add_link - for pk, name, domain in mailbox.addresses.values_list('pk', 'name', 'domain__name'): - url = reverse('admin:mail_address_change', args=(pk,)) - name = '%s@%s' % (name, domain) - value += '
  • %s
  • ' % (url, name) - value = '' % value - return mark_safe('
    %s
    ' % value) diff --git a/orchestra/apps/users/roles/mail/models.py b/orchestra/apps/users/roles/mail/models.py deleted file mode 100644 index 35d28355..00000000 --- a/orchestra/apps/users/roles/mail/models.py +++ /dev/null @@ -1,110 +0,0 @@ -from django.db import models -from django.utils.translation import ugettext_lazy as _ - -from orchestra.core import services - -from .. import roles - -from . import validators, settings - - -class Mailbox(models.Model): - user = models.OneToOneField('users.User', verbose_name=_("User"), - related_name='mailbox') - use_custom_filtering = models.BooleanField(_("Use custom filtering"), - default=False) - custom_filtering = models.TextField(_("filtering"), blank=True, - validators=[validators.validate_sieve], - help_text=_("Arbitrary email filtering in sieve language.")) - - class Meta: - verbose_name_plural = _("mailboxes") - - def __unicode__(self): - return self.user.username - -# def get_addresses(self): -# regex = r'(^|\s)+%s(\s|$)+' % self.user.username -# return Address.objects.filter(destination__regex=regex) -# -# def delete(self, *args, **kwargs): -# """ Update related addresses """ -# regex = re.compile(r'(^|\s)+(\s*%s)(\s|$)+' % self.user.username) -# super(Mailbox, self).delete(*args, **kwargs) -# for address in self.get_addresses(): -# address.destination = regex.sub(r'\3', address.destination).strip() -# if not address.destination: -# address.delete() -# else: -# address.save() - - -#class Address(models.Model): -# name = models.CharField(_("name"), max_length=64, -# validators=[validators.validate_emailname]) -# domain = models.ForeignKey(settings.EMAILS_DOMAIN_MODEL, -# verbose_name=_("domain"), -# related_name='addresses') -# destination = models.CharField(_("destination"), max_length=256, -# validators=[validators.validate_destination], -# help_text=_("Space separated mailbox names or email addresses")) -# account = models.ForeignKey('accounts.Account', verbose_name=_("Account"), -# related_name='addresses') -# -# class Meta: -# verbose_name_plural = _("addresses") -# unique_together = ('name', 'domain') -# -# def __unicode__(self): -# return self.email -# -# @property -# def email(self): -# return "%s@%s" % (self.name, self.domain) -# -# def get_mailboxes(self): -# for dest in self.destination.split(): -# if '@' not in dest: -# yield Mailbox.objects.select_related('user').get(user__username=dest) - - -class Address(models.Model): - name = models.CharField(_("name"), max_length=64, - validators=[validators.validate_emailname]) - domain = models.ForeignKey(settings.EMAILS_DOMAIN_MODEL, - verbose_name=_("domain"), - related_name='addresses') - mailboxes = models.ManyToManyField('mail.Mailbox', - verbose_name=_("mailboxes"), - related_name='addresses', blank=True) - forward = models.CharField(_("forward"), max_length=256, blank=True, - validators=[validators.validate_forward]) - account = models.ForeignKey('accounts.Account', verbose_name=_("Account"), - related_name='addresses') - - class Meta: - verbose_name_plural = _("addresses") - unique_together = ('name', 'domain') - - def __unicode__(self): - return self.email - - @property - def email(self): - return "%s@%s" % (self.name, self.domain) - - -class Autoresponse(models.Model): - address = models.OneToOneField(Address, verbose_name=_("address"), - related_name='autoresponse') - # TODO initial_date - subject = models.CharField(_("subject"), max_length=256) - message = models.TextField(_("message")) - enabled = models.BooleanField(_("enabled"), default=False) - - def __unicode__(self): - return self.address - - -services.register(Address) -roles.register('mailbox', Mailbox) diff --git a/orchestra/apps/users/roles/mail/serializers.py b/orchestra/apps/users/roles/mail/serializers.py deleted file mode 100644 index 24bf1a70..00000000 --- a/orchestra/apps/users/roles/mail/serializers.py +++ /dev/null @@ -1,43 +0,0 @@ -from rest_framework import serializers - -from orchestra.api import router -from orchestra.apps.accounts.serializers import AccountSerializerMixin - -from .models import Address, Mailbox - - -#class AddressSerializer(serializers.HyperlinkedModelSerializer): -# class Meta: -# model = Address -# fields = ('url', 'name', 'domain', 'destination') - - -class NestedMailboxSerializer(serializers.HyperlinkedModelSerializer): - class Meta: - model = Mailbox - fields = ('url', 'use_custom_filtering', 'custom_filtering') - - -class MailboxSerializer(serializers.HyperlinkedModelSerializer): - class Meta: - model = Mailbox - fields = ('url', 'user', 'use_custom_filtering', 'custom_filtering') - - -class AddressSerializer(AccountSerializerMixin, serializers.HyperlinkedModelSerializer): - class Meta: - model = Address - fields = ('url', 'name', 'domain', 'mailboxes', 'forward') - - def get_fields(self, *args, **kwargs): - fields = super(AddressSerializer, self).get_fields(*args, **kwargs) - account = self.context['view'].request.user.account_id - mailboxes = fields['mailboxes'].queryset.select_related('user') - fields['mailboxes'].queryset = mailboxes.filter(user__account=account) - # TODO do it on permissions or in self.filter_by_account_field ? - domain = fields['domain'].queryset - fields['domain'].queryset = domain .filter(account=account) - return fields - - -router.insert('users', 'mailbox', NestedMailboxSerializer, required=False) diff --git a/orchestra/apps/users/roles/mail/settings.py b/orchestra/apps/users/roles/mail/settings.py deleted file mode 100644 index fcca1e32..00000000 --- a/orchestra/apps/users/roles/mail/settings.py +++ /dev/null @@ -1,29 +0,0 @@ -from django.conf import settings - - -EMAILS_DOMAIN_MODEL = getattr(settings, 'EMAILS_DOMAIN_MODEL', 'domains.Domain') - -EMAILS_HOME = getattr(settings, 'EMAILS_HOME', '/home/%(username)s/') - -EMAILS_SIEVETEST_PATH = getattr(settings, 'EMAILS_SIEVETEST_PATH', '/dev/shm') - -EMAILS_SIEVETEST_BIN_PATH = getattr(settings, 'EMAILS_SIEVETEST_BIN_PATH', - '%(orchestra_root)s/bin/sieve-test') - - -EMAILS_VIRTUSERTABLE_PATH = getattr(settings, 'EMAILS_VIRTUSERTABLE_PATH', - '/etc/postfix/virtusertable') - - -EMAILS_VIRTDOMAINS_PATH = getattr(settings, 'EMAILS_VIRTDOMAINS_PATH', - '/etc/postfix/virtdomains') - - -EMAILS_DEFAUL_FILTERING = getattr(settings, 'EMAILS_DEFAULT_FILTERING', - 'require ["fileinto","regex","envelope","vacation","reject","relational","comparator-i;ascii-numeric"];\n' - '\n' - 'if header :value "ge" :comparator "i;ascii-numeric" "X-Spam-Score" "5" {\n' - ' fileinto "Junk";\n' - ' discard;\n' - '}' -) diff --git a/orchestra/apps/users/roles/mail/validators.py b/orchestra/apps/users/roles/mail/validators.py deleted file mode 100644 index eab400fa..00000000 --- a/orchestra/apps/users/roles/mail/validators.py +++ /dev/null @@ -1,62 +0,0 @@ -import hashlib -import os -import re - -from django.core.validators import ValidationError, EmailValidator -from django.utils.translation import ugettext_lazy as _ - -from orchestra.utils import paths -from orchestra.utils.system import run - -from . import settings - - -def validate_emailname(value): - msg = _("'%s' is not a correct email name" % value) - if '@' in value: - raise ValidationError(msg) - value += '@localhost' - try: - EmailValidator(value) - except ValidationError: - raise ValidationError(msg) - - -#def validate_destination(value): -# """ space separated mailboxes or emails """ -# for destination in value.split(): -# msg = _("'%s' is not an existent mailbox" % destination) -# if '@' in destination: -# if not destination[-1].isalpha(): -# raise ValidationError(msg) -# EmailValidator(destination) -# else: -# from .models import Mailbox -# if not Mailbox.objects.filter(user__username=destination).exists(): -# raise ValidationError(msg) -# validate_emailname(destination) - - -def validate_forward(value): - """ space separated mailboxes or emails """ - for destination in value.split(): - EmailValidator(destination) - - -def validate_sieve(value): - sieve_name = '%s.sieve' % hashlib.md5(value).hexdigest() - path = os.path.join(settings.EMAILS_SIEVETEST_PATH, sieve_name) - with open(path, 'wb') as f: - f.write(value) - context = { - 'orchestra_root': paths.get_orchestra_root() - } - sievetest = settings.EMAILS_SIEVETEST_BIN_PATH % context - test = run(' '.join([sievetest, path, '/dev/null']), display=False) - if test.return_code: - errors = [] - for line in test.stderr.splitlines(): - error = re.match(r'^.*(line\s+[0-9]+:.*)', line) - if error: - errors += error.groups() - raise ValidationError(' '.join(errors)) diff --git a/orchestra/apps/users/roles/owncloud/__init__.py b/orchestra/apps/users/roles/owncloud/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/orchestra/apps/users/roles/posix/__init__.py b/orchestra/apps/users/roles/posix/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/orchestra/apps/users/roles/posix/admin.py b/orchestra/apps/users/roles/posix/admin.py deleted file mode 100644 index 0ef5af77..00000000 --- a/orchestra/apps/users/roles/posix/admin.py +++ /dev/null @@ -1,15 +0,0 @@ -from django.contrib.auth import get_user_model - -from orchestra.admin.utils import insertattr -from orchestra.apps.users.roles.admin import RoleAdmin - -from .models import POSIX - - -class POSIXRoleAdmin(RoleAdmin): - model = POSIX - name = 'posix' - url_name = 'posix' - - -insertattr(get_user_model(), 'roles', POSIXRoleAdmin) diff --git a/orchestra/apps/users/roles/posix/models.py b/orchestra/apps/users/roles/posix/models.py deleted file mode 100644 index 3639afc9..00000000 --- a/orchestra/apps/users/roles/posix/models.py +++ /dev/null @@ -1,22 +0,0 @@ -from django.db import models -from django.utils.translation import ugettext_lazy as _ - -from .. import roles - -from . import settings - - -class POSIX(models.Model): - user = models.OneToOneField('users.User', verbose_name=_("user"), - related_name='posix') - home = models.CharField(_("home"), max_length=256, blank=True, - help_text=_("Home directory relative to account's ~primary_user")) - shell = models.CharField(_("shell"), max_length=32, - choices=settings.POSIX_SHELLS, default=settings.POSIX_DEFAULT_SHELL) - - def __unicode__(self): - return str(self.user) - -# TODO groups - -roles.register('posix', POSIX) diff --git a/orchestra/apps/users/roles/posix/serializers.py b/orchestra/apps/users/roles/posix/serializers.py deleted file mode 100644 index 3dc341c5..00000000 --- a/orchestra/apps/users/roles/posix/serializers.py +++ /dev/null @@ -1,14 +0,0 @@ -from rest_framework import serializers - -from orchestra.api import router - -from .models import POSIX - - -class POSIXSerializer(serializers.ModelSerializer): - class Meta: - model = POSIX - fields = ('home', 'shell') - - -router.insert('users', 'posix', POSIXSerializer, required=False) diff --git a/orchestra/apps/users/roles/posix/settings.py b/orchestra/apps/users/roles/posix/settings.py deleted file mode 100644 index 36860863..00000000 --- a/orchestra/apps/users/roles/posix/settings.py +++ /dev/null @@ -1,11 +0,0 @@ -from django.conf import settings -from django.utils.translation import ugettext, ugettext_lazy as _ - - -POSIX_SHELLS = getattr(settings, 'POSIX_SHELLS', ( - ('/bin/false', _("FTP/sFTP only")), - ('/bin/rsync', _("rsync shell")), - ('/bin/bash', "Bash"), -)) - -POSIX_DEFAULT_SHELL = getattr(settings, 'POSIX_DEFAULT_SHELL', '/bin/false') diff --git a/orchestra/apps/users/serializers.py b/orchestra/apps/users/serializers.py deleted file mode 100644 index 321e8b02..00000000 --- a/orchestra/apps/users/serializers.py +++ /dev/null @@ -1,35 +0,0 @@ -from django.contrib.auth import get_user_model -from django.forms import widgets -from django.utils.translation import ugettext, ugettext_lazy as _ -from rest_framework import serializers - -from orchestra.apps.accounts.serializers import AccountSerializerMixin -from orchestra.core.validators import validate_password - - -class UserSerializer(AccountSerializerMixin, serializers.HyperlinkedModelSerializer): - password = serializers.CharField(max_length=128, label=_('Password'), - validators=[validate_password], write_only=True, required=False, - widget=widgets.PasswordInput) - - class Meta: - model = get_user_model() - fields = ( - 'url', 'username', 'password', 'first_name', 'last_name', 'email', - 'is_admin', 'is_active', - ) - - def validate_password(self, attrs, source): - """ POST only password """ - if self.object.pk: - if 'password' in attrs: - raise serializers.ValidationError(_("Can not set password")) - elif 'password' not in attrs: - raise serializers.ValidationError(_("Password required")) - return attrs - - def save_object(self, obj, **kwargs): - # FIXME this method will be called when saving nested serializers :( - if not obj.pk: - obj.set_password(obj.password) - super(UserSerializer, self).save_object(obj, **kwargs) diff --git a/orchestra/apps/users/settings.py b/orchestra/apps/users/settings.py deleted file mode 100644 index 012099a4..00000000 --- a/orchestra/apps/users/settings.py +++ /dev/null @@ -1,6 +0,0 @@ -from django.conf import settings - - -USERS_SYSTEMUSER_HOME = getattr(settings, 'USERES_SYSTEMUSER_HOME', '/home/%(username)s') - -USERS_FTP_LOG_PATH = getattr(settings, 'USERS_FTP_LOG_PATH', '/var/log/vsftpd.log') diff --git a/orchestra/apps/users/templates/admin/users/user/change_form.html b/orchestra/apps/users/templates/admin/users/user/change_form.html deleted file mode 100644 index 82814f98..00000000 --- a/orchestra/apps/users/templates/admin/users/user/change_form.html +++ /dev/null @@ -1,15 +0,0 @@ -{% extends "admin/change_form.html" %} -{% load i18n admin_urls %} - -{% block object-tools-items %} -
  • {% trans "User" %}
  • -{% for item in roles %} -
  • {% if item.exists %}{{ item.name.capitalize }}{% else %}Add {{ item.name }}{% endif %}
  • -{% endfor %} -
  • - {% url opts|admin_urlname:'history' original.pk|admin_urlquote as history_url %} - {% trans "History" %} -
  • -{% if has_absolute_url %}
  • {% trans "View on site" %}
  • {% endif%} -{% endblock %} - diff --git a/orchestra/apps/users/templates/admin/users/user/delete_role.html b/orchestra/apps/users/templates/admin/users/user/delete_role.html deleted file mode 100644 index ae94df22..00000000 --- a/orchestra/apps/users/templates/admin/users/user/delete_role.html +++ /dev/null @@ -1,15 +0,0 @@ -{% extends "admin/delete_confirmation.html" %} -{% load i18n admin_urls %} - - -{% block breadcrumbs %} - -{% endblock %} - diff --git a/orchestra/apps/users/templates/admin/users/user/role.html b/orchestra/apps/users/templates/admin/users/user/role.html deleted file mode 100644 index 75927310..00000000 --- a/orchestra/apps/users/templates/admin/users/user/role.html +++ /dev/null @@ -1,70 +0,0 @@ -{% extends "admin/base_site.html" %} -{% load i18n admin_urls admin_static admin_modify utils %} - - -{% block extrastyle %} -{{ block.super }} - -{{ media }} -{% endblock %} - -{% block coltype %}colM{% endblock %} -{% block bodyclass %}{{ block.super }} app-{{ opts.app_label }} model-{{ opts.model_name }} change-form{% endblock %} - - -{% block breadcrumbs %} - -{% endblock %} - - - -{% block content %}
    -{% block object-tools %} - -{% endblock %} - -
    {% csrf_token %} -
    - {% for field in form %} -
    - - {% if not line.fields|length_is:'1' and not field.is_readonly %}{{ field.errors }}{% endif %} - {% if field|is_checkbox %} - {{ field }} - {% else %} - {{ field.label_tag }} {{ field }} - {% endif %} - {% if field.help_text %} -

    {{ field.help_text|safe }}

    - {% endif %} -
    -
    - {% endfor %} - - -
    - - {% if role.exists %}{% endif %} - -
    - - -{% endblock %}