PEP8 cleanups.
This commit is contained in:
@@ -10,7 +10,9 @@ from .permissions import permission_acl_view, permission_acl_edit
|
|||||||
|
|
||||||
def get_kwargs_factory(variable_name):
|
def get_kwargs_factory(variable_name):
|
||||||
def get_kwargs(context):
|
def get_kwargs(context):
|
||||||
content_type = ContentType.objects.get_for_model(context[variable_name])
|
content_type = ContentType.objects.get_for_model(
|
||||||
|
context[variable_name]
|
||||||
|
)
|
||||||
return {
|
return {
|
||||||
'app_label': '"{}"'.format(content_type.app_label),
|
'app_label': '"{}"'.format(content_type.app_label),
|
||||||
'model': '"{}"'.format(content_type.model),
|
'model': '"{}"'.format(content_type.model),
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ from __future__ import unicode_literals
|
|||||||
|
|
||||||
from django.conf.urls import patterns, url
|
from django.conf.urls import patterns, url
|
||||||
|
|
||||||
from .views import ACLCreateView, ACLDeleteView, ACLListView, ACLPermissionsView
|
from .views import (
|
||||||
|
ACLCreateView, ACLDeleteView, ACLListView, ACLPermissionsView
|
||||||
|
)
|
||||||
|
|
||||||
urlpatterns = patterns(
|
urlpatterns = patterns(
|
||||||
'acls.views',
|
'acls.views',
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ from ..settings import setting_login_method
|
|||||||
TEST_ADMIN_EMAIL = 'admin@admin.com'
|
TEST_ADMIN_EMAIL = 'admin@admin.com'
|
||||||
TEST_ADMIN_PASSWORD = 'test_admin_password'
|
TEST_ADMIN_PASSWORD = 'test_admin_password'
|
||||||
TEST_ADMIN_USERNAME = 'test_admin'
|
TEST_ADMIN_USERNAME = 'test_admin'
|
||||||
|
TEST_EMAIL_AUTHENTICATION_BACKEND = 'authentication.auth.email_auth_backend.EmailAuthBackend'
|
||||||
|
|
||||||
|
|
||||||
class UserLoginTestCase(TestCase):
|
class UserLoginTestCase(TestCase):
|
||||||
@@ -43,7 +44,7 @@ class UserLoginTestCase(TestCase):
|
|||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
def test_email_login(self):
|
def test_email_login(self):
|
||||||
with self.settings(AUTHENTICATION_BACKENDS=('authentication.auth.email_auth_backend.EmailAuthBackend',)):
|
with self.settings(AUTHENTICATION_BACKENDS=(TEST_EMAIL_AUTHENTICATION_BACKEND,)):
|
||||||
setting_login_method.value = 'email'
|
setting_login_method.value = 'email'
|
||||||
|
|
||||||
logged_in = self.client.login(
|
logged_in = self.client.login(
|
||||||
@@ -78,7 +79,7 @@ class UserLoginTestCase(TestCase):
|
|||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
def test_email_login_via_views(self):
|
def test_email_login_via_views(self):
|
||||||
with self.settings(AUTHENTICATION_BACKENDS=('authentication.auth.email_auth_backend.EmailAuthBackend',)):
|
with self.settings(AUTHENTICATION_BACKENDS=(TEST_EMAIL_AUTHENTICATION_BACKEND,)):
|
||||||
setting_login_method.value = 'email'
|
setting_login_method.value = 'email'
|
||||||
response = self.client.get(reverse('documents:document_list'))
|
response = self.client.get(reverse('documents:document_list'))
|
||||||
self.assertRedirects(
|
self.assertRedirects(
|
||||||
|
|||||||
@@ -118,7 +118,9 @@ class APICheckedoutDocumentView(generics.RetrieveDestroyAPIView):
|
|||||||
filtered_documents = documents
|
filtered_documents = documents
|
||||||
|
|
||||||
return DocumentCheckout.objects.filter(
|
return DocumentCheckout.objects.filter(
|
||||||
document__pk__in=filtered_documents.values_list('pk', flat=True)
|
document__pk__in=filtered_documents.values_list(
|
||||||
|
'pk', flat=True
|
||||||
|
)
|
||||||
)
|
)
|
||||||
elif self.request.method == 'DELETE':
|
elif self.request.method == 'DELETE':
|
||||||
return DocumentCheckout.objects.all()
|
return DocumentCheckout.objects.all()
|
||||||
@@ -155,7 +157,10 @@ class APICheckedoutDocumentView(generics.RetrieveDestroyAPIView):
|
|||||||
)
|
)
|
||||||
except PermissionDenied:
|
except PermissionDenied:
|
||||||
AccessControlList.objects.check_access(
|
AccessControlList.objects.check_access(
|
||||||
permission_document_checkin_override, request.user, document
|
permission_document_checkin_override, request.user,
|
||||||
|
document
|
||||||
)
|
)
|
||||||
|
|
||||||
return super(APICheckedoutDocumentView, self).delete(request, *args, **kwargs)
|
return super(
|
||||||
|
APICheckedoutDocumentView, self
|
||||||
|
).delete(request, *args, **kwargs)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ def check_if_new_versions_allowed(sender, **kwargs):
|
|||||||
if not DocumentCheckout.objects.are_document_new_versions_allowed(kwargs['instance'].document):
|
if not DocumentCheckout.objects.are_document_new_versions_allowed(kwargs['instance'].document):
|
||||||
raise NewDocumentVersionNotAllowed(
|
raise NewDocumentVersionNotAllowed(
|
||||||
_(
|
_(
|
||||||
'New versions not allowed for the checkedout document: %s' % kwargs['instance'].document
|
'New versions not allowed for the checkedout document: %s'
|
||||||
|
% kwargs['instance'].document
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -15,13 +15,53 @@ class Migration(migrations.Migration):
|
|||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='DocumentCheckout',
|
name='DocumentCheckout',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
(
|
||||||
('checkout_datetime', models.DateTimeField(auto_now_add=True, verbose_name='Check out date and time')),
|
'id', models.AutoField(
|
||||||
('expiration_datetime', models.DateTimeField(help_text='Amount of time to hold the document checked out in minutes.', verbose_name='Check out expiration date and time')),
|
verbose_name='ID', serialize=False, auto_created=True,
|
||||||
('user_object_id', models.PositiveIntegerField(null=True, blank=True)),
|
primary_key=True
|
||||||
('block_new_version', models.BooleanField(default=True, help_text='Do not allow new version of this document to be uploaded.', verbose_name='Block new version upload')),
|
)
|
||||||
('document', models.ForeignKey(verbose_name='Document', to='documents.Document', unique=True)),
|
),
|
||||||
('user_content_type', models.ForeignKey(blank=True, to='contenttypes.ContentType', null=True)),
|
(
|
||||||
|
'checkout_datetime',
|
||||||
|
models.DateTimeField(
|
||||||
|
auto_now_add=True,
|
||||||
|
verbose_name='Check out date and time'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'expiration_datetime',
|
||||||
|
models.DateTimeField(
|
||||||
|
help_text='Amount of time to hold the document '
|
||||||
|
'checked out in minutes.',
|
||||||
|
verbose_name='Check out expiration date and time'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'user_object_id',
|
||||||
|
models.PositiveIntegerField(null=True, blank=True)
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'block_new_version',
|
||||||
|
models.BooleanField(
|
||||||
|
default=True,
|
||||||
|
help_text='Do not allow new version of this document '
|
||||||
|
'to be uploaded.',
|
||||||
|
verbose_name='Block new version upload'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'document',
|
||||||
|
models.ForeignKey(
|
||||||
|
verbose_name='Document', to='documents.Document',
|
||||||
|
unique=True
|
||||||
|
)
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'user_content_type',
|
||||||
|
models.ForeignKey(
|
||||||
|
blank=True, to='contenttypes.ContentType', null=True
|
||||||
|
)
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'Document checkout',
|
'verbose_name': 'Document checkout',
|
||||||
|
|||||||
@@ -16,7 +16,10 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='documentcheckout',
|
model_name='documentcheckout',
|
||||||
name='user',
|
name='user',
|
||||||
field=models.ForeignKey(verbose_name='User', blank=True, to=settings.AUTH_USER_MODEL, null=True),
|
field=models.ForeignKey(
|
||||||
|
verbose_name='User', blank=True, to=settings.AUTH_USER_MODEL,
|
||||||
|
null=True
|
||||||
|
),
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -23,5 +23,7 @@ class Migration(migrations.Migration):
|
|||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.RunPython(move_from_content_type_user_to_foreign_key_field_user),
|
migrations.RunPython(
|
||||||
|
move_from_content_type_user_to_foreign_key_field_user
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -23,7 +23,9 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='documentcheckout',
|
model_name='documentcheckout',
|
||||||
name='user',
|
name='user',
|
||||||
field=models.ForeignKey(verbose_name='User', to=settings.AUTH_USER_MODEL),
|
field=models.ForeignKey(
|
||||||
|
verbose_name='User', to=settings.AUTH_USER_MODEL
|
||||||
|
),
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ from common.literals import TIME_DELTA_UNIT_CHOICES
|
|||||||
|
|
||||||
class SplitTimeDeltaWidget(forms.widgets.MultiWidget):
|
class SplitTimeDeltaWidget(forms.widgets.MultiWidget):
|
||||||
"""
|
"""
|
||||||
A Widget that splits a timedelta input into three <input type="text"> boxes.
|
A Widget that splits a timedelta input into three <input type="text">
|
||||||
|
boxes.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, attrs=None):
|
def __init__(self, attrs=None):
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ class ModelAttribute(object):
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
except IndexError:
|
except IndexError:
|
||||||
# We were passed a model instance, try again using the model of the
|
# We were passed a model instance, try again using the model of
|
||||||
# instance
|
# the instance
|
||||||
|
|
||||||
# If we are already in the model class, exit with an error
|
# If we are already in the model class, exit with an error
|
||||||
if model.__class__ == models.base.ModelBase:
|
if model.__class__ == models.base.ModelBase:
|
||||||
@@ -30,16 +30,24 @@ class ModelAttribute(object):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def get_choices_for(cls, model, type_names=None):
|
def get_choices_for(cls, model, type_names=None):
|
||||||
return [
|
return [
|
||||||
(attribute.name, attribute) for attribute in cls.get_for(model, type_names)
|
(
|
||||||
|
attribute.name, attribute
|
||||||
|
) for attribute in cls.get_for(model, type_names)
|
||||||
]
|
]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def help_text_for(cls, model, type_names=None):
|
def help_text_for(cls, model, type_names=None):
|
||||||
result = []
|
result = []
|
||||||
for count, attribute in enumerate(cls.get_for(model, type_names), 1):
|
for count, attribute in enumerate(cls.get_for(model, type_names), 1):
|
||||||
result.append('{}) {}'.format(count, unicode(attribute.get_display(show_name=True))))
|
result.append(
|
||||||
|
'{}) {}'.format(
|
||||||
|
count, unicode(attribute.get_display(show_name=True))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
return ' '.join([ugettext('Available attributes: '), ', '.join(result)])
|
return ' '.join(
|
||||||
|
[ugettext('Available attributes: '), ', '.join(result)]
|
||||||
|
)
|
||||||
|
|
||||||
def get_display(self, show_name=False):
|
def get_display(self, show_name=False):
|
||||||
if self.description:
|
if self.description:
|
||||||
|
|||||||
@@ -101,7 +101,9 @@ class CompressedFile(object):
|
|||||||
filename for filename in zfobj.namelist() if not filename.endswith('/')
|
filename for filename in zfobj.namelist() if not filename.endswith('/')
|
||||||
]
|
]
|
||||||
return (
|
return (
|
||||||
SimpleUploadedFile(name=filename, content=zfobj.read(filename)) for filename in filenames
|
SimpleUploadedFile(
|
||||||
|
name=filename, content=zfobj.read(filename)
|
||||||
|
) for filename in filenames
|
||||||
)
|
)
|
||||||
except zipfile.BadZipfile:
|
except zipfile.BadZipfile:
|
||||||
raise NotACompressedFile
|
raise NotACompressedFile
|
||||||
|
|||||||
@@ -54,7 +54,9 @@ class DetailForm(forms.ModelForm):
|
|||||||
self.fields[field_name].help_text = ''
|
self.fields[field_name].help_text = ''
|
||||||
|
|
||||||
for field_name, field in self.fields.items():
|
for field_name, field in self.fields.items():
|
||||||
self.fields[field_name].widget.attrs.update({'readonly': 'readonly'})
|
self.fields[field_name].widget.attrs.update(
|
||||||
|
{'readonly': 'readonly'}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ChoiceForm(forms.Form):
|
class ChoiceForm(forms.Form):
|
||||||
|
|||||||
@@ -4,11 +4,9 @@ from django.conf import settings
|
|||||||
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.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.http import HttpResponseRedirect
|
||||||
from django.http import Http404, HttpResponseRedirect
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.views.generic import FormView, TemplateView
|
from django.views.generic import FormView, TemplateView
|
||||||
from django.views.generic.detail import SingleObjectMixin
|
|
||||||
from django.views.generic.edit import CreateView, DeleteView, UpdateView
|
from django.views.generic.edit import CreateView, DeleteView, UpdateView
|
||||||
from django.views.generic.list import ListView
|
from django.views.generic.list import ListView
|
||||||
|
|
||||||
@@ -110,7 +108,9 @@ class AssignRemoveView(ExtraContextMixin, ViewPermissionCheckMixin, ObjectPermis
|
|||||||
label = dict(flat_list)[selection]
|
label = dict(flat_list)[selection]
|
||||||
if self.decode_content_type:
|
if self.decode_content_type:
|
||||||
model, pk = selection.split(',')
|
model, pk = selection.split(',')
|
||||||
selection_obj = ContentType.objects.get(model=model).get_object_for_this_type(pk=pk)
|
selection_obj = ContentType.objects.get(
|
||||||
|
model=model
|
||||||
|
).get_object_for_this_type(pk=pk)
|
||||||
else:
|
else:
|
||||||
selection_obj = selection
|
selection_obj = selection
|
||||||
|
|
||||||
@@ -202,7 +202,9 @@ class MultiFormView(FormView):
|
|||||||
def get_forms(self, form_classes):
|
def get_forms(self, form_classes):
|
||||||
return dict(
|
return dict(
|
||||||
[
|
[
|
||||||
(key, self._create_form(key, klass)) for key, klass in form_classes.items()
|
(
|
||||||
|
key, self._create_form(key, klass)
|
||||||
|
) for key, klass in form_classes.items()
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -270,7 +272,9 @@ class SingleObjectCreateView(ViewPermissionCheckMixin, ExtraContextMixin, Redire
|
|||||||
try:
|
try:
|
||||||
messages.success(
|
messages.success(
|
||||||
self.request,
|
self.request,
|
||||||
_('%s created successfully.') % self.extra_context['object_name'].capitalize()
|
_(
|
||||||
|
'%s created successfully.'
|
||||||
|
) % self.extra_context['object_name'].capitalize()
|
||||||
)
|
)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
messages.success(
|
messages.success(
|
||||||
@@ -294,7 +298,8 @@ class SingleObjectDeleteView(ViewPermissionCheckMixin, ObjectPermissionCheckMixi
|
|||||||
except Exception as exception:
|
except Exception as exception:
|
||||||
try:
|
try:
|
||||||
messages.error(
|
messages.error(
|
||||||
self.request, _('Error deleting %s.') % self.extra_context['object_name']
|
self.request,
|
||||||
|
_('Error deleting %s.') % self.extra_context['object_name']
|
||||||
)
|
)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
messages.error(
|
messages.error(
|
||||||
@@ -305,7 +310,10 @@ class SingleObjectDeleteView(ViewPermissionCheckMixin, ObjectPermissionCheckMixi
|
|||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
messages.success(
|
messages.success(
|
||||||
self.request, _('%s deleted successfully.') % self.extra_context['object_name'].capitalize()
|
self.request,
|
||||||
|
_(
|
||||||
|
'%s deleted successfully.'
|
||||||
|
) % self.extra_context['object_name'].capitalize()
|
||||||
)
|
)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
messages.success(
|
messages.success(
|
||||||
@@ -325,7 +333,10 @@ class SingleObjectEditView(ViewPermissionCheckMixin, ObjectPermissionCheckMixin,
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
messages.error(
|
messages.error(
|
||||||
self.request, _('Error saving %s details.') % self.extra_context['object_name']
|
self.request,
|
||||||
|
_(
|
||||||
|
'Error saving %s details.'
|
||||||
|
) % self.extra_context['object_name']
|
||||||
)
|
)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
messages.error(
|
messages.error(
|
||||||
@@ -339,7 +350,10 @@ class SingleObjectEditView(ViewPermissionCheckMixin, ObjectPermissionCheckMixin,
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
messages.success(
|
messages.success(
|
||||||
self.request, _('%s details saved successfully.') % self.extra_context['object_name'].capitalize()
|
self.request,
|
||||||
|
_(
|
||||||
|
'%s details saved successfully.'
|
||||||
|
) % self.extra_context['object_name'].capitalize()
|
||||||
)
|
)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
messages.success(
|
messages.success(
|
||||||
@@ -354,4 +368,3 @@ class SingleObjectListView(PaginationMixin, ViewPermissionCheckMixin, ObjectList
|
|||||||
|
|
||||||
def get_paginate_by(self, queryset):
|
def get_paginate_by(self, queryset):
|
||||||
return setting_paginate_by.value
|
return setting_paginate_by.value
|
||||||
|
|
||||||
|
|||||||
@@ -8,5 +8,7 @@ class AjaxRedirect(object):
|
|||||||
def process_response(self, request, response):
|
def process_response(self, request, response):
|
||||||
if request.is_ajax():
|
if request.is_ajax():
|
||||||
if type(response) == HttpResponseRedirect:
|
if type(response) == HttpResponseRedirect:
|
||||||
response.status_code = getattr(settings, 'AJAX_REDIRECT_CODE', 302)
|
response.status_code = getattr(
|
||||||
|
settings, 'AJAX_REDIRECT_CODE', 302
|
||||||
|
)
|
||||||
return response
|
return response
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -49,7 +49,8 @@ class ObjectListPermissionFilterMixin(object):
|
|||||||
self.request.user, (self.object_permission,)
|
self.request.user, (self.object_permission,)
|
||||||
)
|
)
|
||||||
except PermissionDenied:
|
except PermissionDenied:
|
||||||
# No global permission, filter ther queryset per object + permission
|
# No global permission, filter ther queryset per object +
|
||||||
|
# permission
|
||||||
return AccessControlList.objects.filter_by_access(
|
return AccessControlList.objects.filter_by_access(
|
||||||
self.object_permission, self.request.user, queryset
|
self.object_permission, self.request.user, queryset
|
||||||
)
|
)
|
||||||
@@ -79,7 +80,9 @@ class ObjectPermissionCheckMixin(object):
|
|||||||
self.get_permission_object()
|
self.get_permission_object()
|
||||||
)
|
)
|
||||||
|
|
||||||
return super(ObjectPermissionCheckMixin, self).dispatch(request, *args, **kwargs)
|
return super(
|
||||||
|
ObjectPermissionCheckMixin, self
|
||||||
|
).dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class RedirectionMixin(object):
|
class RedirectionMixin(object):
|
||||||
@@ -111,7 +114,9 @@ class RedirectionMixin(object):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
return super(RedirectionMixin, self).dispatch(request, *args, **kwargs)
|
return super(
|
||||||
|
RedirectionMixin, self
|
||||||
|
).dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(RedirectionMixin, self).get_context_data(**kwargs)
|
context = super(RedirectionMixin, self).get_context_data(**kwargs)
|
||||||
@@ -137,4 +142,6 @@ class ViewPermissionCheckMixin(object):
|
|||||||
self.request.user, (self.view_permission,)
|
self.request.user, (self.view_permission,)
|
||||||
)
|
)
|
||||||
|
|
||||||
return super(ViewPermissionCheckMixin, self).dispatch(request, *args, **kwargs)
|
return super(
|
||||||
|
ViewPermissionCheckMixin, self
|
||||||
|
).dispatch(request, *args, **kwargs)
|
||||||
|
|||||||
@@ -9,7 +9,11 @@ from smart_settings import Namespace
|
|||||||
namespace = Namespace(name='common', label=_('Common'))
|
namespace = Namespace(name='common', label=_('Common'))
|
||||||
setting_temporary_directory = namespace.add_setting(
|
setting_temporary_directory = namespace.add_setting(
|
||||||
global_name='COMMON_TEMPORARY_DIRECTORY', default=tempfile.gettempdir(),
|
global_name='COMMON_TEMPORARY_DIRECTORY', default=tempfile.gettempdir(),
|
||||||
help_text=_('Temporary directory used site wide to store thumbnails, previews and temporary files. If none is specified, one will be created using tempfile.mkdtemp()'),
|
help_text=_(
|
||||||
|
'Temporary directory used site wide to store thumbnails, previews '
|
||||||
|
'and temporary files. If none is specified, one will be created '
|
||||||
|
'using tempfile.mkdtemp()'
|
||||||
|
),
|
||||||
is_path=True
|
is_path=True
|
||||||
)
|
)
|
||||||
setting_shared_storage = namespace.add_setting(
|
setting_shared_storage = namespace.add_setting(
|
||||||
@@ -20,5 +24,7 @@ setting_shared_storage = namespace.add_setting(
|
|||||||
setting_paginate_by = namespace.add_setting(
|
setting_paginate_by = namespace.add_setting(
|
||||||
global_name='COMMON_PAGINATE_BY',
|
global_name='COMMON_PAGINATE_BY',
|
||||||
default=40,
|
default=40,
|
||||||
help_text=_('An integer specifying how many objects should be displayed per page.')
|
help_text=_(
|
||||||
|
'An integer specifying how many objects should be displayed per page.'
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -100,7 +100,9 @@ def return_attrib(obj, attrib, arguments=None):
|
|||||||
try:
|
try:
|
||||||
if isinstance(attrib, types.FunctionType):
|
if isinstance(attrib, types.FunctionType):
|
||||||
return attrib(obj)
|
return attrib(obj)
|
||||||
elif isinstance(obj, types.DictType) or isinstance(obj, types.DictionaryType):
|
elif isinstance(
|
||||||
|
obj, types.DictType
|
||||||
|
) or isinstance(obj, types.DictionaryType):
|
||||||
return obj[attrib]
|
return obj[attrib]
|
||||||
else:
|
else:
|
||||||
result = reduce(getattr, attrib.split('.'), obj)
|
result = reduce(getattr, attrib.split('.'), obj)
|
||||||
@@ -140,12 +142,13 @@ def urlquote(link=None, get=None):
|
|||||||
|
|
||||||
assert link or get
|
assert link or get
|
||||||
if isinstance(link, dict):
|
if isinstance(link, dict):
|
||||||
# urlqoute({'key': 'value', 'key2': 'value2'}) --> key=value&key2=value2
|
# urlqoute({'key': 'value', 'key2': 'value2'}) -->
|
||||||
|
# key=value&key2=value2
|
||||||
assert not get, get
|
assert not get, get
|
||||||
get = link
|
get = link
|
||||||
link = ''
|
link = ''
|
||||||
assert isinstance(get, dict), 'wrong type "%s", dict required' % type(get)
|
assert isinstance(get, dict), 'wrong type "%s", dict required' % type(get)
|
||||||
# assert not (link.startswith('http://') or link.startswith('https://')), \
|
# assert not (link.startswith('http://') or link.startswith('https://')),
|
||||||
# 'This method should only quote the url path.
|
# 'This method should only quote the url path.
|
||||||
# It should not start with http(s):// (%s)' % (
|
# It should not start with http(s):// (%s)' % (
|
||||||
# link)
|
# link)
|
||||||
|
|||||||
@@ -12,9 +12,6 @@ from django.utils.http import urlencode
|
|||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.views.generic import TemplateView
|
from django.views.generic import TemplateView
|
||||||
|
|
||||||
from documents.search import document_search
|
|
||||||
|
|
||||||
from .classes import MissingItem
|
|
||||||
from .forms import (
|
from .forms import (
|
||||||
LicenseForm, LocaleProfileForm, LocaleProfileForm_view,
|
LicenseForm, LocaleProfileForm, LocaleProfileForm_view,
|
||||||
UserForm, UserForm_view
|
UserForm, UserForm_view
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from itertools import chain
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
@@ -107,50 +106,6 @@ class PlainWidget(forms.widgets.Widget):
|
|||||||
return mark_safe('%s' % value)
|
return mark_safe('%s' % value)
|
||||||
|
|
||||||
|
|
||||||
class ScrollableCheckboxSelectMultiple(forms.widgets.CheckboxSelectMultiple):
|
|
||||||
"""
|
|
||||||
Class for a form widget composed of a selection of checkboxes wrapped
|
|
||||||
in a div tag with automatic overflow to add scrollbars when the list
|
|
||||||
exceds the height of the div
|
|
||||||
"""
|
|
||||||
def render(self, name, value, attrs=None, choices=()):
|
|
||||||
if value is None:
|
|
||||||
value = []
|
|
||||||
has_id = attrs and 'id' in attrs
|
|
||||||
final_attrs = self.build_attrs(attrs, name=name)
|
|
||||||
# TODO: Move this styling to a CSS class
|
|
||||||
output = [
|
|
||||||
'<ul class="undecorated_list" style="margin-left: 5px; margin-top: 3px; margin-bottom: 3px;">'
|
|
||||||
]
|
|
||||||
# Normalize to strings
|
|
||||||
str_values = set([force_unicode(v) for v in value])
|
|
||||||
for i, (option_value, option_label) in enumerate(chain(self.choices, choices)):
|
|
||||||
# If an ID attribute was given, add a numeric index as a suffix,
|
|
||||||
# so that the checkboxes don't all have the same ID attribute.
|
|
||||||
if has_id:
|
|
||||||
final_attrs = dict(final_attrs, id='%s_%s' % (attrs['id'], i))
|
|
||||||
label_for = ' for="%s"' % final_attrs['id']
|
|
||||||
else:
|
|
||||||
label_for = ''
|
|
||||||
|
|
||||||
cb = forms.widgets.CheckboxInput(
|
|
||||||
final_attrs, check_test=lambda value: value in str_values
|
|
||||||
)
|
|
||||||
option_value = force_unicode(option_value)
|
|
||||||
rendered_cb = cb.render(name, option_value)
|
|
||||||
option_label = conditional_escape(force_unicode(option_label))
|
|
||||||
output.append(
|
|
||||||
'<li><label%s>%s %s</label></li>' % (
|
|
||||||
label_for, rendered_cb, option_label
|
|
||||||
)
|
|
||||||
)
|
|
||||||
output.append('</ul>')
|
|
||||||
|
|
||||||
return mark_safe(
|
|
||||||
'<div class="text_area_div">%s</div>' % '\n'.join(output)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class TextAreaDiv(forms.widgets.Widget):
|
class TextAreaDiv(forms.widgets.Widget):
|
||||||
"""
|
"""
|
||||||
Class to define a form widget that simulates the behavior of a
|
Class to define a form widget that simulates the behavior of a
|
||||||
|
|||||||
@@ -32,7 +32,9 @@ class DjangoGPGTestCase(TestCase):
|
|||||||
|
|
||||||
# Test querying the keyservers
|
# Test querying the keyservers
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
TEST_KEY_ID in [key_stub.key_id for key_stub in self.gpg.query(TEST_UIDS)]
|
TEST_KEY_ID in [
|
||||||
|
key_stub.key_id for key_stub in self.gpg.query(TEST_UIDS)
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
# Receive a public key from the keyserver
|
# Receive a public key from the keyserver
|
||||||
@@ -40,5 +42,7 @@ class DjangoGPGTestCase(TestCase):
|
|||||||
|
|
||||||
# Check that the received key is indeed in the keyring
|
# Check that the received key is indeed in the keyring
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
TEST_KEY_ID[-16:] in [key_stub.key_id for key_stub in Key.get_all(self.gpg)]
|
TEST_KEY_ID[-16:] in [
|
||||||
|
key_stub.key_id for key_stub in Key.get_all(self.gpg)
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
from __future__ import absolute_import, unicode_literals
|
from __future__ import absolute_import, unicode_literals
|
||||||
|
|
||||||
from datetime import datetime
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|||||||
@@ -51,10 +51,16 @@ def comment_delete(request, comment_id=None, comment_id_list=None):
|
|||||||
)
|
)
|
||||||
|
|
||||||
previous = request.POST.get(
|
previous = request.POST.get(
|
||||||
'previous', request.GET.get('previous', request.META.get('HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL)))
|
'previous', request.GET.get(
|
||||||
|
'previous', request.META.get(
|
||||||
|
'HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL)
|
||||||
|
)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
next = request.POST.get(
|
next = request.POST.get(
|
||||||
'next', request.GET.get('next', post_action_redirect if post_action_redirect else request.META.get('HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL)))
|
'next', request.GET.get(
|
||||||
|
'next', post_action_redirect if post_action_redirect else request.META.get('HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL))
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
@@ -110,7 +116,11 @@ def comment_add(request, document_id):
|
|||||||
|
|
||||||
post_action_redirect = None
|
post_action_redirect = None
|
||||||
|
|
||||||
next = request.POST.get('next', request.GET.get('next', post_action_redirect if post_action_redirect else request.META.get('HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL))))
|
next = request.POST.get(
|
||||||
|
'next', request.GET.get(
|
||||||
|
'next', post_action_redirect if post_action_redirect else request.META.get('HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
form = CommentForm(request.POST)
|
form = CommentForm(request.POST)
|
||||||
@@ -144,7 +154,8 @@ class DocumentCommentListView(SingleObjectListView):
|
|||||||
)
|
)
|
||||||
except PermissionDenied:
|
except PermissionDenied:
|
||||||
AccessControlList.objects.check_access(
|
AccessControlList.objects.check_access(
|
||||||
permission_comment_view, self.request.user, self.get_document()
|
permission_comment_view, self.request.user,
|
||||||
|
self.get_document()
|
||||||
)
|
)
|
||||||
|
|
||||||
return self.get_document().comments.all()
|
return self.get_document().comments.all()
|
||||||
|
|||||||
@@ -61,7 +61,8 @@ class DocumentIndexingApp(MayanAppConfig):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
SourceColumn(
|
SourceColumn(
|
||||||
source=IndexInstance, label=_('Document types'), attribute='get_document_types_names'
|
source=IndexInstance, label=_('Document types'),
|
||||||
|
attribute='get_document_types_names'
|
||||||
)
|
)
|
||||||
|
|
||||||
SourceColumn(
|
SourceColumn(
|
||||||
@@ -74,7 +75,9 @@ class DocumentIndexingApp(MayanAppConfig):
|
|||||||
)
|
)
|
||||||
SourceColumn(
|
SourceColumn(
|
||||||
source=IndexTemplateNode, label=_('Has document links?'),
|
source=IndexTemplateNode, label=_('Has document links?'),
|
||||||
func=lambda context: two_state_template(context['object'].link_documents)
|
func=lambda context: two_state_template(
|
||||||
|
context['object'].link_documents
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
SourceColumn(
|
SourceColumn(
|
||||||
|
|||||||
@@ -20,7 +20,8 @@ class IndexInstanceNodeManager(models.Manager):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def delete_empty_index_nodes_recursive(instance_node):
|
def delete_empty_index_nodes_recursive(instance_node):
|
||||||
"""
|
"""
|
||||||
Calls itself recursively deleting empty index instance nodes up to root
|
Calls itself recursively deleting empty index instance nodes up to
|
||||||
|
root
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if instance_node.get_children().count() == 0:
|
if instance_node.get_children().count() == 0:
|
||||||
|
|||||||
@@ -15,11 +15,38 @@ class Migration(migrations.Migration):
|
|||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Index',
|
name='Index',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
(
|
||||||
('name', models.CharField(help_text='Internal name used to reference this index.', unique=True, max_length=64, verbose_name='Name')),
|
'id', models.AutoField(
|
||||||
('title', models.CharField(help_text='The name that will be visible to users.', unique=True, max_length=128, verbose_name='Title')),
|
verbose_name='ID', serialize=False, auto_created=True,
|
||||||
('enabled', models.BooleanField(default=True, help_text='Causes this index to be visible and updated when document data changes.', verbose_name='Enabled')),
|
primary_key=True
|
||||||
('document_types', models.ManyToManyField(to='documents.DocumentType', verbose_name='Document types')),
|
)
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'name', models.CharField(
|
||||||
|
help_text='Internal name used to reference this index.',
|
||||||
|
unique=True, max_length=64, verbose_name='Name'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'title', models.CharField(
|
||||||
|
help_text='The name that will be visible to users.',
|
||||||
|
unique=True, max_length=128, verbose_name='Title'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'enabled', models.BooleanField(
|
||||||
|
default=True,
|
||||||
|
help_text='Causes this index to be visible and updated when document data changes.',
|
||||||
|
verbose_name='Enabled'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'document_types',
|
||||||
|
models.ManyToManyField(
|
||||||
|
to='documents.DocumentType',
|
||||||
|
verbose_name='Document types'
|
||||||
|
)
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'Index',
|
'verbose_name': 'Index',
|
||||||
@@ -30,13 +57,43 @@ class Migration(migrations.Migration):
|
|||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='IndexInstanceNode',
|
name='IndexInstanceNode',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
(
|
||||||
('value', models.CharField(max_length=128, verbose_name='Value', blank=True)),
|
'id', models.AutoField(
|
||||||
('lft', models.PositiveIntegerField(editable=False, db_index=True)),
|
verbose_name='ID', serialize=False, auto_created=True,
|
||||||
('rght', models.PositiveIntegerField(editable=False, db_index=True)),
|
primary_key=True
|
||||||
('tree_id', models.PositiveIntegerField(editable=False, db_index=True)),
|
)
|
||||||
('level', models.PositiveIntegerField(editable=False, db_index=True)),
|
),
|
||||||
('documents', models.ManyToManyField(related_name='node_instances', verbose_name='Documents', to='documents.Document')),
|
(
|
||||||
|
'value', models.CharField(
|
||||||
|
max_length=128, verbose_name='Value', blank=True
|
||||||
|
)
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'lft', models.PositiveIntegerField(
|
||||||
|
editable=False, db_index=True
|
||||||
|
)
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'rght', models.PositiveIntegerField(
|
||||||
|
editable=False, db_index=True
|
||||||
|
)
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'tree_id', models.PositiveIntegerField(
|
||||||
|
editable=False, db_index=True
|
||||||
|
)
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'level', models.PositiveIntegerField(
|
||||||
|
editable=False, db_index=True
|
||||||
|
)
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'documents', models.ManyToManyField(
|
||||||
|
related_name='node_instances',
|
||||||
|
verbose_name='Documents', to='documents.Document'
|
||||||
|
)
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'Index node instance',
|
'verbose_name': 'Index node instance',
|
||||||
@@ -47,16 +104,64 @@ class Migration(migrations.Migration):
|
|||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='IndexTemplateNode',
|
name='IndexTemplateNode',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
(
|
||||||
('expression', models.CharField(help_text='Enter a python string expression to be evaluated.', max_length=128, verbose_name='Indexing expression')),
|
'id', models.AutoField(
|
||||||
('enabled', models.BooleanField(default=True, help_text='Causes this node to be visible and updated when document data changes.', verbose_name='Enabled')),
|
verbose_name='ID', serialize=False, auto_created=True,
|
||||||
('link_documents', models.BooleanField(default=False, help_text='Check this option to have this node act as a container for documents and not as a parent for further nodes.', verbose_name='Link documents')),
|
primary_key=True
|
||||||
('lft', models.PositiveIntegerField(editable=False, db_index=True)),
|
)
|
||||||
('rght', models.PositiveIntegerField(editable=False, db_index=True)),
|
),
|
||||||
('tree_id', models.PositiveIntegerField(editable=False, db_index=True)),
|
(
|
||||||
('level', models.PositiveIntegerField(editable=False, db_index=True)),
|
'expression', models.CharField(
|
||||||
('index', models.ForeignKey(related_name='node_templates', verbose_name='Index', to='document_indexing.Index')),
|
help_text='Enter a python string expression to be evaluated.',
|
||||||
('parent', mptt.fields.TreeForeignKey(blank=True, to='document_indexing.IndexTemplateNode', null=True)),
|
max_length=128, verbose_name='Indexing expression'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'enabled', models.BooleanField(
|
||||||
|
default=True,
|
||||||
|
help_text='Causes this node to be visible and updated when document data changes.',
|
||||||
|
verbose_name='Enabled'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'link_documents', models.BooleanField(
|
||||||
|
default=False,
|
||||||
|
help_text='Check this option to have this node act as a container for documents and not as a parent for further nodes.',
|
||||||
|
verbose_name='Link documents'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'lft', models.PositiveIntegerField(
|
||||||
|
editable=False, db_index=True
|
||||||
|
)
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'rght', models.PositiveIntegerField(
|
||||||
|
editable=False, db_index=True
|
||||||
|
)
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'tree_id', models.PositiveIntegerField(
|
||||||
|
editable=False, db_index=True
|
||||||
|
)
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'level', models.PositiveIntegerField(
|
||||||
|
editable=False, db_index=True
|
||||||
|
)
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'index', models.ForeignKey(
|
||||||
|
related_name='node_templates', verbose_name='Index',
|
||||||
|
to='document_indexing.Index'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'parent', mptt.fields.TreeForeignKey(
|
||||||
|
blank=True, to='document_indexing.IndexTemplateNode',
|
||||||
|
null=True
|
||||||
|
)
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'Index node template',
|
'verbose_name': 'Index node template',
|
||||||
@@ -67,13 +172,20 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='indexinstancenode',
|
model_name='indexinstancenode',
|
||||||
name='index_template_node',
|
name='index_template_node',
|
||||||
field=models.ForeignKey(related_name='node_instance', verbose_name='Index template node', to='document_indexing.IndexTemplateNode'),
|
field=models.ForeignKey(
|
||||||
|
related_name='node_instance',
|
||||||
|
verbose_name='Index template node',
|
||||||
|
to='document_indexing.IndexTemplateNode'
|
||||||
|
),
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='indexinstancenode',
|
model_name='indexinstancenode',
|
||||||
name='parent',
|
name='parent',
|
||||||
field=mptt.fields.TreeForeignKey(blank=True, to='document_indexing.IndexInstanceNode', null=True),
|
field=mptt.fields.TreeForeignKey(
|
||||||
|
blank=True, to='document_indexing.IndexInstanceNode',
|
||||||
|
null=True
|
||||||
|
),
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -14,7 +14,9 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='index',
|
model_name='index',
|
||||||
name='label',
|
name='label',
|
||||||
field=models.CharField(unique=True, max_length=128, verbose_name='Label'),
|
field=models.CharField(
|
||||||
|
unique=True, max_length=128, verbose_name='Label'
|
||||||
|
),
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -14,7 +14,11 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='index',
|
model_name='index',
|
||||||
name='slug',
|
name='slug',
|
||||||
field=models.SlugField(null=True, max_length=128, blank=True, help_text='This values will be used by other apps to reference this index.', unique=True, verbose_name='Slug'),
|
field=models.SlugField(
|
||||||
|
null=True, max_length=128, blank=True,
|
||||||
|
help_text='This values will be used by other apps to reference this index.',
|
||||||
|
unique=True, verbose_name='Slug'
|
||||||
|
),
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -14,7 +14,11 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='index',
|
model_name='index',
|
||||||
name='slug',
|
name='slug',
|
||||||
field=models.SlugField(default='', max_length=128, help_text='This values will be used by other apps to reference this index.', unique=True, verbose_name='Slug'),
|
field=models.SlugField(
|
||||||
|
default='', max_length=128,
|
||||||
|
help_text='This values will be used by other apps to reference this index.',
|
||||||
|
unique=True, verbose_name='Slug'
|
||||||
|
),
|
||||||
preserve_default=False,
|
preserve_default=False,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -14,7 +14,10 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='indexinstancenode',
|
model_name='indexinstancenode',
|
||||||
name='value',
|
name='value',
|
||||||
field=models.CharField(db_index=True, max_length=128, verbose_name='Value', blank=True),
|
field=models.CharField(
|
||||||
|
db_index=True, max_length=128, verbose_name='Value',
|
||||||
|
blank=True
|
||||||
|
),
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -14,7 +14,10 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='indextemplatenode',
|
model_name='indextemplatenode',
|
||||||
name='expression',
|
name='expression',
|
||||||
field=models.CharField(help_text="Enter a template to render. Use Django's default templating language (https://docs.djangoproject.com/en/1.7/ref/templates/builtins/)", max_length=128, verbose_name='Indexing expression'),
|
field=models.CharField(
|
||||||
|
help_text="Enter a template to render. Use Django's default templating language (https://docs.djangoproject.com/en/1.7/ref/templates/builtins/)",
|
||||||
|
max_length=128, verbose_name='Indexing expression'
|
||||||
|
),
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -71,7 +71,9 @@ class Index(models.Model):
|
|||||||
|
|
||||||
def get_document_types_names(self):
|
def get_document_types_names(self):
|
||||||
return ', '.join(
|
return ', '.join(
|
||||||
[unicode(document_type) for document_type in self.document_types.all()] or ['None']
|
[
|
||||||
|
unicode(document_type) for document_type in self.document_types.all()
|
||||||
|
] or ['None']
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ urlpatterns = patterns(
|
|||||||
),
|
),
|
||||||
url(
|
url(
|
||||||
r'^setup/index/(?P<pk>\d+)/document_types/$',
|
r'^setup/index/(?P<pk>\d+)/document_types/$',
|
||||||
SetupIndexDocumentTypesView.as_view(), name='index_setup_document_types'
|
SetupIndexDocumentTypesView.as_view(),
|
||||||
|
name='index_setup_document_types'
|
||||||
),
|
),
|
||||||
url(
|
url(
|
||||||
r'^setup/template/node/(?P<parent_pk>\d+)/create/child/$',
|
r'^setup/template/node/(?P<parent_pk>\d+)/create/child/$',
|
||||||
@@ -84,8 +85,8 @@ api_urls = patterns(
|
|||||||
name='index-detail'
|
name='index-detail'
|
||||||
),
|
),
|
||||||
url(
|
url(
|
||||||
r'^index/(?P<pk>[0-9]+)/template/$', APIIndexTemplateListView.as_view(),
|
r'^index/(?P<pk>[0-9]+)/template/$',
|
||||||
name='index-template-detail'
|
APIIndexTemplateListView.as_view(), name='index-template-detail'
|
||||||
),
|
),
|
||||||
url(r'^indexes/$', APIIndexListView.as_view(), name='index-list'),
|
url(r'^indexes/$', APIIndexListView.as_view(), name='index-list'),
|
||||||
url(
|
url(
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ from common.views import (
|
|||||||
AssignRemoveView, SingleObjectCreateView, SingleObjectDeleteView,
|
AssignRemoveView, SingleObjectCreateView, SingleObjectDeleteView,
|
||||||
SingleObjectEditView, SingleObjectListView
|
SingleObjectEditView, SingleObjectListView
|
||||||
)
|
)
|
||||||
from common.widgets import two_state_template
|
|
||||||
from documents.models import Document, DocumentType
|
from documents.models import Document, DocumentType
|
||||||
from documents.permissions import permission_document_view
|
from documents.permissions import permission_document_view
|
||||||
from documents.views import DocumentListView
|
from documents.views import DocumentListView
|
||||||
@@ -33,7 +32,7 @@ from .permissions import (
|
|||||||
permission_document_indexing_setup, permission_document_indexing_view
|
permission_document_indexing_setup, permission_document_indexing_view
|
||||||
)
|
)
|
||||||
from .tasks import task_do_rebuild_all_indexes
|
from .tasks import task_do_rebuild_all_indexes
|
||||||
from .widgets import index_instance_item_link, get_breadcrumbs, node_level
|
from .widgets import get_breadcrumbs
|
||||||
|
|
||||||
|
|
||||||
# Setup views
|
# Setup views
|
||||||
|
|||||||
@@ -21,7 +21,9 @@ def get_instance_link(index_instance_node, text=None, simple=False):
|
|||||||
|
|
||||||
return template % {
|
return template % {
|
||||||
'url': index_instance_node.get_absolute_url(),
|
'url': index_instance_node.get_absolute_url(),
|
||||||
'value': text if text else (index_instance_node if index_instance_node.parent else index_instance_node.index_template_node.index)
|
'value': text if text else (
|
||||||
|
index_instance_node if index_instance_node.parent else index_instance_node.index_template_node.index
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -50,7 +52,9 @@ def get_breadcrumbs(index_instance_node, simple=False, single_link=False, includ
|
|||||||
# Return the entire breadcrumb path as a single HTML anchor
|
# Return the entire breadcrumb path as a single HTML anchor
|
||||||
output.insert(
|
output.insert(
|
||||||
0, get_instance_link(
|
0, get_instance_link(
|
||||||
index_instance_node=index_instance_node, text=(' / '.join(result))
|
index_instance_node=index_instance_node, text=(
|
||||||
|
' / '.join(result)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return mark_safe(' '.join(output))
|
return mark_safe(' '.join(output))
|
||||||
@@ -68,11 +72,13 @@ def index_instance_item_link(index_instance_item):
|
|||||||
else:
|
else:
|
||||||
icon_template = ''
|
icon_template = ''
|
||||||
|
|
||||||
return mark_safe('%(icon_template)s <a href="%(url)s">%(text)s</a>' % {
|
return mark_safe(
|
||||||
'url': index_instance_item.get_absolute_url(),
|
'%(icon_template)s <a href="%(url)s">%(text)s</a>' % {
|
||||||
'icon_template': icon_template,
|
'url': index_instance_item.get_absolute_url(),
|
||||||
'text': index_instance_item
|
'icon_template': icon_template,
|
||||||
})
|
'text': index_instance_item
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def node_level(node):
|
def node_level(node):
|
||||||
@@ -83,8 +89,9 @@ def node_level(node):
|
|||||||
return mark_safe(
|
return mark_safe(
|
||||||
''.join(
|
''.join(
|
||||||
[
|
[
|
||||||
' ' * (getattr(node, node._mptt_meta.level_attr) - 1),
|
' ' * (
|
||||||
'' if node.is_root_node() else '<i class="fa fa-level-up fa-rotate-90"></i> ',
|
getattr(node, node._mptt_meta.level_attr) - 1
|
||||||
|
), '' if node.is_root_node() else '<i class="fa fa-level-up fa-rotate-90"></i> ',
|
||||||
ugettext('Root') if node.is_root_node() else unicode(node)
|
ugettext('Root') if node.is_root_node() else unicode(node)
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -103,15 +103,6 @@ class PrintForm(forms.Form):
|
|||||||
page_range = forms.CharField(label=_('Page range'), required=False)
|
page_range = forms.CharField(label=_('Page range'), required=False)
|
||||||
|
|
||||||
|
|
||||||
class DocumentTypeFilenameForm(forms.ModelForm):
|
|
||||||
"""
|
|
||||||
Model class form to edit a document type filename
|
|
||||||
"""
|
|
||||||
class Meta:
|
|
||||||
fields = ('filename', 'enabled')
|
|
||||||
model = DocumentTypeFilename
|
|
||||||
|
|
||||||
|
|
||||||
class DocumentTypeFilenameForm_create(forms.ModelForm):
|
class DocumentTypeFilenameForm_create(forms.ModelForm):
|
||||||
"""
|
"""
|
||||||
Model class form to create a new document type filename
|
Model class form to create a new document type filename
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
from .literals import *
|
from .literals import * # NOQA
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.core.files import File
|
from django.core.files import File
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
|
|||||||
@@ -21,8 +21,7 @@ from common.generics import (
|
|||||||
SingleObjectEditView, SingleObjectListView
|
SingleObjectEditView, SingleObjectListView
|
||||||
)
|
)
|
||||||
from common.mixins import MultipleInstanceActionMixin
|
from common.mixins import MultipleInstanceActionMixin
|
||||||
from common.utils import encapsulate, pretty_size
|
from common.utils import pretty_size
|
||||||
from common.widgets import two_state_template
|
|
||||||
from converter.literals import (
|
from converter.literals import (
|
||||||
DEFAULT_PAGE_NUMBER, DEFAULT_ROTATION, DEFAULT_ZOOM_LEVEL
|
DEFAULT_PAGE_NUMBER, DEFAULT_ROTATION, DEFAULT_ZOOM_LEVEL
|
||||||
)
|
)
|
||||||
@@ -36,8 +35,8 @@ from .events import (
|
|||||||
)
|
)
|
||||||
from .forms import (
|
from .forms import (
|
||||||
DocumentDownloadForm, DocumentForm, DocumentPageForm, DocumentPreviewForm,
|
DocumentDownloadForm, DocumentForm, DocumentPageForm, DocumentPreviewForm,
|
||||||
DocumentPropertiesForm, DocumentTypeFilenameForm,
|
DocumentPropertiesForm, DocumentTypeSelectForm,
|
||||||
DocumentTypeFilenameForm_create, DocumentTypeSelectForm, PrintForm
|
DocumentTypeFilenameForm_create, PrintForm
|
||||||
)
|
)
|
||||||
from .literals import DOCUMENT_IMAGE_TASK_TIMEOUT
|
from .literals import DOCUMENT_IMAGE_TASK_TIMEOUT
|
||||||
from .models import (
|
from .models import (
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from rest_api.filters import MayanObjectPermissionsFilter
|
|||||||
from .classes import SearchModel
|
from .classes import SearchModel
|
||||||
from .filters import RecentSearchUserFilter
|
from .filters import RecentSearchUserFilter
|
||||||
from .models import RecentSearch
|
from .models import RecentSearch
|
||||||
from .serializers import RecentSearchSerializer, SearchSerializer
|
from .serializers import RecentSearchSerializer
|
||||||
|
|
||||||
|
|
||||||
class APIRecentSearchListView(generics.ListAPIView):
|
class APIRecentSearchListView(generics.ListAPIView):
|
||||||
|
|||||||
@@ -15,7 +15,3 @@ class RecentSearchSerializer(serializers.HyperlinkedModelSerializer):
|
|||||||
fields = ('datetime_created', 'hits', 'query', 'url', 'user')
|
fields = ('datetime_created', 'hits', 'query', 'url', 'user')
|
||||||
model = RecentSearch
|
model = RecentSearch
|
||||||
read_only_fields = ('datetime_created', 'hits', 'query', 'user')
|
read_only_fields = ('datetime_created', 'hits', 'query', 'user')
|
||||||
|
|
||||||
|
|
||||||
class SearchSerializer(serializers.Serializer):
|
|
||||||
results = serializers.CharField()
|
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ import urlparse
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.shortcuts import render_to_response
|
|
||||||
from django.template import RequestContext
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from common.generics import SimpleView, SingleObjectListView
|
from common.generics import SimpleView, SingleObjectListView
|
||||||
|
|||||||
@@ -20,7 +20,8 @@ class EventsApp(MayanAppConfig):
|
|||||||
|
|
||||||
SourceColumn(source=Action, label=_('Timestamp'), attribute='timestamp')
|
SourceColumn(source=Action, label=_('Timestamp'), attribute='timestamp')
|
||||||
SourceColumn(source=Action, label=_('Actor'), attribute='actor')
|
SourceColumn(source=Action, label=_('Actor'), attribute='actor')
|
||||||
SourceColumn(source=Action, label=_('Verb'),
|
SourceColumn(
|
||||||
|
source=Action, label=_('Verb'),
|
||||||
func=lambda context: event_type_link(context['object'])
|
func=lambda context: event_type_link(context['object'])
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
from __future__ import absolute_import, unicode_literals
|
from __future__ import absolute_import, unicode_literals
|
||||||
|
|
||||||
from django.shortcuts import render_to_response
|
|
||||||
from django.template import RequestContext
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from common.generics import SingleObjectListView
|
from common.generics import SingleObjectListView
|
||||||
from permissions import Permission
|
|
||||||
|
|
||||||
from .classes import PropertyNamespace
|
from .classes import PropertyNamespace
|
||||||
from .permissions import permission_installation_details
|
from .permissions import permission_installation_details
|
||||||
@@ -37,4 +34,3 @@ class NamespaceDetailView(SingleObjectListView):
|
|||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return self.get_namespace().get_properties()
|
return self.get_namespace().get_properties()
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ from common.generics import (
|
|||||||
AssignRemoveView, SingleObjectCreateView, SingleObjectEditView,
|
AssignRemoveView, SingleObjectCreateView, SingleObjectEditView,
|
||||||
SingleObjectListView
|
SingleObjectListView
|
||||||
)
|
)
|
||||||
from common.widgets import two_state_template
|
|
||||||
from documents.models import Document, DocumentType
|
from documents.models import Document, DocumentType
|
||||||
from documents.permissions import permission_document_view
|
from documents.permissions import permission_document_view
|
||||||
from documents.views import DocumentListView
|
from documents.views import DocumentListView
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ from fuse import FUSE, FuseOSError, Operations
|
|||||||
from django.core import management
|
from django.core import management
|
||||||
from django.core.cache import caches
|
from django.core.cache import caches
|
||||||
from django.core.exceptions import MultipleObjectsReturned
|
from django.core.exceptions import MultipleObjectsReturned
|
||||||
from django.db.models import Count, Max
|
from django.db.models import Count
|
||||||
|
|
||||||
from document_indexing.models import Index, IndexInstanceNode
|
from document_indexing.models import Index, IndexInstanceNode
|
||||||
from documents.models import Document
|
from documents.models import Document
|
||||||
|
|||||||
@@ -32,8 +32,14 @@ class UserManagementApp(MayanAppConfig):
|
|||||||
|
|
||||||
APIEndPoint(app=self, version_string='1')
|
APIEndPoint(app=self, version_string='1')
|
||||||
|
|
||||||
MetadataLookup(description=_('All the groups.'), name='group', value=Group.objects.all())
|
MetadataLookup(
|
||||||
MetadataLookup(description=_('All the users.'), name='users', value=get_user_model().objects.all())
|
description=_('All the groups.'), name='group',
|
||||||
|
value=Group.objects.all()
|
||||||
|
)
|
||||||
|
MetadataLookup(
|
||||||
|
description=_('All the users.'), name='users',
|
||||||
|
value=get_user_model().objects.all()
|
||||||
|
)
|
||||||
|
|
||||||
SourceColumn(
|
SourceColumn(
|
||||||
source=Group, label=_('Members'), attribute='user_set.count'
|
source=Group, label=_('Members'), attribute='user_set.count'
|
||||||
@@ -47,11 +53,15 @@ class UserManagementApp(MayanAppConfig):
|
|||||||
)
|
)
|
||||||
SourceColumn(
|
SourceColumn(
|
||||||
source=User, label=_('Active'),
|
source=User, label=_('Active'),
|
||||||
func=lambda context: two_state_template(context['object'].is_active)
|
func=lambda context: two_state_template(
|
||||||
|
context['object'].is_active
|
||||||
|
)
|
||||||
)
|
)
|
||||||
SourceColumn(
|
SourceColumn(
|
||||||
source=User, label=_('Has usable password?'),
|
source=User, label=_('Has usable password?'),
|
||||||
func=lambda context: two_state_template(context['object'].has_usable_password())
|
func=lambda context: two_state_template(
|
||||||
|
context['object'].has_usable_password()
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
menu_multi_item.bind_links(
|
menu_multi_item.bind_links(
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ from common.views import (
|
|||||||
AssignRemoveView, SingleObjectCreateView, SingleObjectEditView,
|
AssignRemoveView, SingleObjectCreateView, SingleObjectEditView,
|
||||||
SingleObjectListView
|
SingleObjectListView
|
||||||
)
|
)
|
||||||
from common.widgets import two_state_template
|
|
||||||
from permissions import Permission
|
from permissions import Permission
|
||||||
|
|
||||||
from .forms import PasswordForm, UserForm
|
from .forms import PasswordForm, UserForm
|
||||||
@@ -47,7 +46,10 @@ def user_edit(request, user_id):
|
|||||||
if user.is_superuser or user.is_staff:
|
if user.is_superuser or user.is_staff:
|
||||||
messages.error(
|
messages.error(
|
||||||
request,
|
request,
|
||||||
_('Super user and staff user editing is not allowed, use the admin interface for these cases.')
|
_(
|
||||||
|
'Super user and staff user editing is not allowed, use the '
|
||||||
|
'admin interface for these cases.'
|
||||||
|
)
|
||||||
)
|
)
|
||||||
return HttpResponseRedirect(
|
return HttpResponseRedirect(
|
||||||
request.META.get(
|
request.META.get(
|
||||||
@@ -106,7 +108,9 @@ def user_delete(request, user_id=None, user_id_list=None):
|
|||||||
post_action_redirect = reverse('user_management:user_list')
|
post_action_redirect = reverse('user_management:user_list')
|
||||||
elif user_id_list:
|
elif user_id_list:
|
||||||
users = [
|
users = [
|
||||||
get_object_or_404(User, pk=user_id) for user_id in user_id_list.split(',')
|
get_object_or_404(
|
||||||
|
User, pk=user_id
|
||||||
|
) for user_id in user_id_list.split(',')
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
messages.error(request, _('Must provide at least one user.'))
|
messages.error(request, _('Must provide at least one user.'))
|
||||||
@@ -123,14 +127,24 @@ def user_delete(request, user_id=None, user_id_list=None):
|
|||||||
for user in users:
|
for user in users:
|
||||||
try:
|
try:
|
||||||
if user.is_superuser or user.is_staff:
|
if user.is_superuser or user.is_staff:
|
||||||
messages.error(request, _('Super user and staff user deleting is not allowed, use the admin interface for these cases.'))
|
messages.error(
|
||||||
|
request,
|
||||||
|
_(
|
||||||
|
'Super user and staff user deleting is not '
|
||||||
|
'allowed, use the admin interface for these cases.'
|
||||||
|
)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
user.delete()
|
user.delete()
|
||||||
messages.success(request, _('User "%s" deleted successfully.') % user)
|
messages.success(
|
||||||
|
request, _('User "%s" deleted successfully.') % user
|
||||||
|
)
|
||||||
except Exception as exception:
|
except Exception as exception:
|
||||||
messages.error(request, _('Error deleting user "%(user)s": %(error)s') % {
|
messages.error(
|
||||||
'user': user, 'error': exception
|
request, _('Error deleting user "%(user)s": %(error)s') % {
|
||||||
})
|
'user': user, 'error': exception
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
return HttpResponseRedirect(next)
|
return HttpResponseRedirect(next)
|
||||||
|
|
||||||
@@ -145,8 +159,10 @@ def user_delete(request, user_id=None, user_id_list=None):
|
|||||||
elif len(users) > 1:
|
elif len(users) > 1:
|
||||||
context['title'] = _('Delete the users: %s?') % ', '.join([unicode(d) for d in users])
|
context['title'] = _('Delete the users: %s?') % ', '.join([unicode(d) for d in users])
|
||||||
|
|
||||||
return render_to_response('appearance/generic_confirm.html', context,
|
return render_to_response(
|
||||||
context_instance=RequestContext(request))
|
'appearance/generic_confirm.html', context,
|
||||||
|
context_instance=RequestContext(request)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def user_multiple_delete(request):
|
def user_multiple_delete(request):
|
||||||
@@ -166,7 +182,11 @@ def user_set_password(request, user_id=None, user_id_list=None):
|
|||||||
users = [get_object_or_404(User, pk=user_id) for user_id in user_id_list.split(',')]
|
users = [get_object_or_404(User, pk=user_id) for user_id in user_id_list.split(',')]
|
||||||
else:
|
else:
|
||||||
messages.error(request, _('Must provide at least one user.'))
|
messages.error(request, _('Must provide at least one user.'))
|
||||||
return HttpResponseRedirect(request.META.get('HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL)))
|
return HttpResponseRedirect(
|
||||||
|
request.META.get(
|
||||||
|
'HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
next = request.POST.get('next', request.GET.get('next', post_action_redirect if post_action_redirect else request.META.get('HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL))))
|
next = request.POST.get('next', request.GET.get('next', post_action_redirect if post_action_redirect else request.META.get('HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL))))
|
||||||
|
|
||||||
@@ -181,15 +201,30 @@ def user_set_password(request, user_id=None, user_id_list=None):
|
|||||||
for user in users:
|
for user in users:
|
||||||
try:
|
try:
|
||||||
if user.is_superuser or user.is_staff:
|
if user.is_superuser or user.is_staff:
|
||||||
messages.error(request, _('Super user and staff user password reseting is not allowed, use the admin interface for these cases.'))
|
messages.error(
|
||||||
|
request,
|
||||||
|
_(
|
||||||
|
'Super user and staff user password '
|
||||||
|
'reseting is not allowed, use the admin '
|
||||||
|
'interface for these cases.'
|
||||||
|
)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
user.set_password(password_1)
|
user.set_password(password_1)
|
||||||
user.save()
|
user.save()
|
||||||
messages.success(request, _('Successfull password reset for user: %s.') % user)
|
messages.success(
|
||||||
|
request, _(
|
||||||
|
'Successfull password reset for user: %s.'
|
||||||
|
) % user
|
||||||
|
)
|
||||||
except Exception as exception:
|
except Exception as exception:
|
||||||
messages.error(request, _('Error reseting password for user "%(user)s": %(error)s') % {
|
messages.error(
|
||||||
'user': user, 'error': exception
|
request, _(
|
||||||
})
|
'Error reseting password for user "%(user)s": %(error)s'
|
||||||
|
) % {
|
||||||
|
'user': user, 'error': exception
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
return HttpResponseRedirect(next)
|
return HttpResponseRedirect(next)
|
||||||
else:
|
else:
|
||||||
@@ -243,10 +278,14 @@ class UserGroupsView(AssignRemoveView):
|
|||||||
return get_object_or_404(User, pk=self.kwargs['pk'])
|
return get_object_or_404(User, pk=self.kwargs['pk'])
|
||||||
|
|
||||||
def left_list(self):
|
def left_list(self):
|
||||||
return AssignRemoveView.generate_choices(get_user_non_groups(self.get_object()))
|
return AssignRemoveView.generate_choices(
|
||||||
|
get_user_non_groups(self.get_object())
|
||||||
|
)
|
||||||
|
|
||||||
def right_list(self):
|
def right_list(self):
|
||||||
return AssignRemoveView.generate_choices(get_user_groups(self.get_object()))
|
return AssignRemoveView.generate_choices(
|
||||||
|
get_user_groups(self.get_object())
|
||||||
|
)
|
||||||
|
|
||||||
def remove(self, item):
|
def remove(self, item):
|
||||||
item.user_set.remove(self.get_object())
|
item.user_set.remove(self.get_object())
|
||||||
@@ -297,7 +336,9 @@ def group_delete(request, group_id=None, group_id_list=None):
|
|||||||
groups = [get_object_or_404(Group, pk=group_id)]
|
groups = [get_object_or_404(Group, pk=group_id)]
|
||||||
post_action_redirect = reverse('user_management:group_list')
|
post_action_redirect = reverse('user_management:group_list')
|
||||||
elif group_id_list:
|
elif group_id_list:
|
||||||
groups = [get_object_or_404(Group, pk=group_id) for group_id in group_id_list.split(',')]
|
groups = [
|
||||||
|
get_object_or_404(Group, pk=group_id) for group_id in group_id_list.split(',')
|
||||||
|
]
|
||||||
else:
|
else:
|
||||||
messages.error(request, _('Must provide at least one group.'))
|
messages.error(request, _('Must provide at least one group.'))
|
||||||
return HttpResponseRedirect(request.META.get('HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL)))
|
return HttpResponseRedirect(request.META.get('HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL)))
|
||||||
@@ -359,10 +400,16 @@ class GroupMembersView(AssignRemoveView):
|
|||||||
return get_object_or_404(Group, pk=self.kwargs['pk'])
|
return get_object_or_404(Group, pk=self.kwargs['pk'])
|
||||||
|
|
||||||
def left_list(self):
|
def left_list(self):
|
||||||
return AssignRemoveView.generate_choices(User.objects.exclude(groups=self.get_object()).exclude(is_staff=True).exclude(is_superuser=True))
|
return AssignRemoveView.generate_choices(
|
||||||
|
User.objects.exclude(
|
||||||
|
groups=self.get_object()
|
||||||
|
).exclude(is_staff=True).exclude(is_superuser=True)
|
||||||
|
)
|
||||||
|
|
||||||
def right_list(self):
|
def right_list(self):
|
||||||
return AssignRemoveView.generate_choices(self.get_object().user_set.all())
|
return AssignRemoveView.generate_choices(
|
||||||
|
self.get_object().user_set.all()
|
||||||
|
)
|
||||||
|
|
||||||
def remove(self, item):
|
def remove(self, item):
|
||||||
self.get_object().user_set.remove(item)
|
self.get_object().user_set.remove(item)
|
||||||
|
|||||||
Reference in New Issue
Block a user