PEP8 cleanups and code style cleanups.

This commit is contained in:
Roberto Rosario
2015-07-10 17:19:36 -04:00
parent c3be4bef53
commit e891fe9525
80 changed files with 557 additions and 630 deletions

View File

@@ -17,6 +17,6 @@ def get_kwargs_factory(variable_name):
link_acl_delete = Link(permissions=[permission_acl_edit], tags='dangerous', text=_('Delete'), view='acls:acl_delete', args='resolved_object.pk') link_acl_delete = Link(permissions=[permission_acl_edit], tags='dangerous', text=_('Delete'), view='acls:acl_delete', args='resolved_object.pk')
link_acl_new = Link(permissions=[permission_acl_edit], text=_('New ACL'), view='acls:acl_new', kwargs=get_kwargs_factory('resolved_object'))
link_acl_list = Link(permissions=[permission_acl_view], text=_('ACLs'), view='acls:acl_list', kwargs=get_kwargs_factory('resolved_object')) link_acl_list = Link(permissions=[permission_acl_view], text=_('ACLs'), view='acls:acl_list', kwargs=get_kwargs_factory('resolved_object'))
link_acl_new = Link(permissions=[permission_acl_edit], text=_('New ACL'), view='acls:acl_new', kwargs=get_kwargs_factory('resolved_object'))
link_acl_permissions = Link(permissions=[permission_acl_edit], text=_('Permissions'), view='acls:acl_permissions', args='resolved_object.pk') link_acl_permissions = Link(permissions=[permission_acl_edit], text=_('Permissions'), view='acls:acl_permissions', args='resolved_object.pk')

View File

@@ -10,7 +10,6 @@ from django.utils.translation import ugettext_lazy as _
from permissions.models import Role, StoredPermission from permissions.models import Role, StoredPermission
from .classes import ModelPermission
from .managers import AccessControlListManager from .managers import AccessControlListManager
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)

View File

@@ -1,24 +1,14 @@
from __future__ import absolute_import, unicode_literals from __future__ import absolute_import, unicode_literals
from django.conf import settings
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.core.files import File from django.core.files import File
from django.core.urlresolvers import reverse
from django.test.client import Client
from django.test import TestCase from django.test import TestCase
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.test_models import ( from documents.test_models import TEST_SMALL_DOCUMENT_PATH, TEST_DOCUMENT_TYPE
TEST_ADMIN_PASSWORD, TEST_ADMIN_USERNAME, TEST_ADMIN_EMAIL,
TEST_SMALL_DOCUMENT_FILENAME, TEST_NON_ASCII_DOCUMENT_FILENAME,
TEST_NON_ASCII_COMPRESSED_DOCUMENT_FILENAME, TEST_DOCUMENT_PATH,
TEST_SIGNED_DOCUMENT_PATH, TEST_SMALL_DOCUMENT_PATH,
TEST_NON_ASCII_DOCUMENT_PATH, TEST_NON_ASCII_COMPRESSED_DOCUMENT_PATH,
TEST_DOCUMENT_DESCRIPTION, TEST_DOCUMENT_TYPE
)
from permissions.classes import Permission from permissions.classes import Permission
from permissions.models import Role from permissions.models import Role
@@ -128,7 +118,6 @@ class PermissionTestCase(TestCase):
self.assertTrue(self.document_2 in result) self.assertTrue(self.document_2 in result)
self.assertTrue(self.document_3 not in result) self.assertTrue(self.document_3 not in result)
def test_filtering_with_inherited_permissions_and_local_acl(self): def test_filtering_with_inherited_permissions_and_local_acl(self):
self.group.user_set.add(self.user) self.group.user_set.add(self.user)
self.role.permissions.add(permission_document_view.stored_permission) self.role.permissions.add(permission_document_view.stored_permission)

View File

@@ -24,7 +24,6 @@ from .permissions import (
) )
class CheckoutsApp(MayanAppConfig): class CheckoutsApp(MayanAppConfig):
name = 'checkouts' name = 'checkouts'
verbose_name = _('Checkouts') verbose_name = _('Checkouts')
@@ -34,18 +33,10 @@ class CheckoutsApp(MayanAppConfig):
APIEndPoint('checkouts') APIEndPoint('checkouts')
Document.add_to_class('is_checked_out', lambda document: DocumentCheckout.objects.is_document_checked_out(document))
Document.add_to_class('check_in', lambda document, user=None: DocumentCheckout.objects.check_in_document(document, user)) Document.add_to_class('check_in', lambda document, user=None: DocumentCheckout.objects.check_in_document(document, user))
Document.add_to_class('checkout_info', lambda document: DocumentCheckout.objects.document_checkout_info(document)) Document.add_to_class('checkout_info', lambda document: DocumentCheckout.objects.document_checkout_info(document))
Document.add_to_class('checkout_state', lambda document: DocumentCheckout.objects.document_checkout_state(document)) Document.add_to_class('checkout_state', lambda document: DocumentCheckout.objects.document_checkout_state(document))
Document.add_to_class('is_checked_out', lambda document: DocumentCheckout.objects.is_document_checked_out(document))
app.conf.CELERYBEAT_SCHEDULE.update({
'check_expired_check_outs': {
'task': 'checkouts.tasks.task_check_expired_check_outs',
'schedule': timedelta(seconds=CHECK_EXPIRED_CHECK_OUTS_INTERVAL),
'options': {'queue': 'checkouts'}
},
})
ModelPermission.register( ModelPermission.register(
model=Document, permissions=( model=Document, permissions=(
@@ -55,6 +46,14 @@ class CheckoutsApp(MayanAppConfig):
) )
) )
app.conf.CELERYBEAT_SCHEDULE.update({
'check_expired_check_outs': {
'task': 'checkouts.tasks.task_check_expired_check_outs',
'schedule': timedelta(seconds=CHECK_EXPIRED_CHECK_OUTS_INTERVAL),
'options': {'queue': 'checkouts'}
},
})
menu_facet.bind_links(links=[link_checkout_info], sources=[Document]) menu_facet.bind_links(links=[link_checkout_info], sources=[Document])
menu_main.bind_links(links=[link_checkout_list]) menu_main.bind_links(links=[link_checkout_list])
menu_sidebar.bind_links(links=[link_checkout_document, link_checkin_document], sources=['checkouts:checkout_info', 'checkouts:checkout_document', 'checkouts:checkin_document']) menu_sidebar.bind_links(links=[link_checkout_document, link_checkin_document], sources=['checkouts:checkout_info', 'checkouts:checkout_document', 'checkouts:checkin_document'])

View File

@@ -4,7 +4,7 @@ from django.utils.translation import ugettext_lazy as _
from events.classes import Event from events.classes import Event
event_document_check_out = Event(name='checkouts_document_check_out', label=_('Document checked out'))
event_document_check_in = Event(name='checkouts_document_check_in', label=_('Document checked in'))
event_document_auto_check_in = Event(name='checkouts_document_auto_check_in', label=_('Document automatically checked in')) event_document_auto_check_in = Event(name='checkouts_document_auto_check_in', label=_('Document automatically checked in'))
event_document_check_in = Event(name='checkouts_document_check_in', label=_('Document checked in'))
event_document_check_out = Event(name='checkouts_document_check_out', label=_('Document checked out'))
event_document_forceful_check_in = Event(name='checkouts_document_forceful_check_in', label=_('Document forcefully checked in')) event_document_forceful_check_in = Event(name='checkouts_document_forceful_check_in', label=_('Document forcefully checked in'))

View File

@@ -12,4 +12,3 @@ STATE_LABELS = {
STATE_CHECKED_OUT: _('Checked out'), STATE_CHECKED_OUT: _('Checked out'),
STATE_CHECKED_IN: _('Checked in/available'), STATE_CHECKED_IN: _('Checked in/available'),
} }

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import models, migrations from django.db import migrations
def move_from_content_type_user_to_foreign_key_field_user(apps, schema_editor): def move_from_content_type_user_to_foreign_key_field_user(apps, schema_editor):

View File

@@ -35,6 +35,9 @@ class DocumentCheckout(models.Model):
def __str__(self): def __str__(self):
return unicode(self.document) return unicode(self.document)
def get_absolute_url(self):
return reverse('checkout:checkout_info', args=[self.document.pk])
def clean(self): def clean(self):
if self.expiration_datetime < now(): if self.expiration_datetime < now():
raise ValidationError(_('Check out expiration date and time must be in the future.')) raise ValidationError(_('Check out expiration date and time must be in the future.'))
@@ -51,9 +54,6 @@ class DocumentCheckout(models.Model):
return result return result
def get_absolute_url(self):
return reverse('checkout:checkout_info', args=[self.document.pk])
class Meta: class Meta:
verbose_name = _('Document checkout') verbose_name = _('Document checkout')
verbose_name_plural = _('Document checkouts') verbose_name_plural = _('Document checkouts')

View File

@@ -6,6 +6,6 @@ from permissions import PermissionNamespace
namespace = PermissionNamespace('checkouts', _('Document checkout')) namespace = PermissionNamespace('checkouts', _('Document checkout'))
permission_document_checkout = namespace.add_permission(name='checkout_document', label=_('Check out documents'))
permission_document_checkin = namespace.add_permission(name='checkin_document', label=_('Check in documents')) permission_document_checkin = namespace.add_permission(name='checkin_document', label=_('Check in documents'))
permission_document_checkin_override = namespace.add_permission(name='checkin_document_override', label=_('Forcefully check in documents')) permission_document_checkin_override = namespace.add_permission(name='checkin_document_override', label=_('Forcefully check in documents'))
permission_document_checkout = namespace.add_permission(name='checkout_document', label=_('Check out documents'))

View File

@@ -0,0 +1,382 @@
from __future__ import absolute_import, unicode_literals
from django.conf import settings
from django.contrib import messages
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ImproperlyConfigured
from django.http import Http404, HttpResponseRedirect
from django.utils.translation import ugettext_lazy as _
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.list import ListView
from .forms import ChoiceForm
from .mixins import (
ExtraContextMixin, ObjectListPermissionFilterMixin,
ObjectPermissionCheckMixin, RedirectionMixin, ViewPermissionCheckMixin
)
__all__ = (
'AssignRemoveView', 'ConfirmView', 'MultiFormView', 'ParentChildListView',
'SingleObjectCreateView', 'SingleObjectDeleteView',
'SingleObjectEditView', 'SingleObjectListView', 'SimpleView',
)
class AssignRemoveView(ExtraContextMixin, ViewPermissionCheckMixin, ObjectPermissionCheckMixin, TemplateView):
decode_content_type = False
extra_context = None
grouped = False
left_list_title = None
right_list_title = None
template_name = 'appearance/generic_form.html'
LEFT_LIST_NAME = 'left_list'
RIGHT_LIST_NAME = 'right_list'
@staticmethod
def generate_choices(choices):
results = []
for choice in choices:
ct = ContentType.objects.get_for_model(choice)
if isinstance(choice, User):
label = choice.get_full_name() if choice.get_full_name() else choice
else:
label = unicode(choice)
results.append(('%s,%s' % (ct.model, choice.pk), '%s' % (label)))
# Sort results by the label not the key value
return sorted(results, key=lambda x: x[1])
def left_list(self):
# Subclass must override
raise NotImplementedError
def right_list(self):
# Subclass must override
raise NotImplementedError
def add(self, item):
# Subclass must override
raise NotImplementedError
def remove(self, item):
# Subclass must override
raise NotImplementedError
def get_disabled_choices(self):
return ()
def get_help_text(self):
return self.help_text
def get(self, request, *args, **kwargs):
self.unselected_list = ChoiceForm(prefix=self.LEFT_LIST_NAME, choices=self.left_list())
self.selected_list = ChoiceForm(prefix=self.RIGHT_LIST_NAME, choices=self.right_list(), disabled_choices=self.get_disabled_choices(), help_text=self.get_help_text())
return self.render_to_response(self.get_context_data())
def process_form(self, prefix, items_function, action_function):
if '%s-submit' % prefix in self.request.POST.keys():
form = ChoiceForm(
self.request.POST, prefix=prefix,
choices=items_function()
)
if form.is_valid():
for selection in form.cleaned_data['selection']:
if self.grouped:
flat_list = []
for group in items_function():
flat_list.extend(group[1])
else:
flat_list = items_function()
label = dict(flat_list)[selection]
if self.decode_content_type:
model, pk = selection.split(',')
selection_obj = ContentType.objects.get(model=model).get_object_for_this_type(pk=pk)
else:
selection_obj = selection
try:
action_function(selection_obj)
except:
if settings.DEBUG:
raise
else:
messages.error(self.request, _('Unable to transfer selection: %s.') % label)
def post(self, request, *args, **kwargs):
self.process_form(prefix=self.LEFT_LIST_NAME, items_function=self.left_list, action_function=self.add)
self.process_form(prefix=self.RIGHT_LIST_NAME, items_function=self.right_list, action_function=self.remove)
return self.get(request, *args, **kwargs)
def get_context_data(self, **kwargs):
data = super(AssignRemoveView, self).get_context_data(**kwargs)
data.update({
'subtemplates_list': [
{
'name': 'appearance/generic_form_subtemplate.html',
'column_class': 'col-xs-12 col-sm-6 col-md-6 col-lg-6',
'context': {
'form': self.unselected_list,
'title': self.left_list_title or ' ',
'submit_label': _('Add'),
'submit_icon': 'fa fa-plus',
'hide_labels': True,
}
},
{
'name': 'appearance/generic_form_subtemplate.html',
'column_class': 'col-xs-12 col-sm-6 col-md-6 col-lg-6',
'context': {
'form': self.selected_list,
'title': self.right_list_title or ' ',
'submit_label': _('Remove'),
'submit_icon': 'fa fa-minus',
'hide_labels': True,
}
},
],
})
return data
class ConfirmView(ObjectListPermissionFilterMixin, ViewPermissionCheckMixin, ExtraContextMixin, RedirectionMixin, TemplateView):
template_name = 'appearance/generic_confirm.html'
class MultiFormView(FormView):
prefixes = {}
prefix = None
def get_form_kwargs(self, form_name):
kwargs = {}
kwargs.update({'initial': self.get_initial(form_name)})
kwargs.update({'prefix': self.get_prefix(form_name)})
if self.request.method in ('POST', 'PUT'):
kwargs.update({
'data': self.request.POST,
'files': self.request.FILES,
})
return kwargs
def _create_form(self, form_name, klass):
form_kwargs = self.get_form_kwargs(form_name)
form_create_method = 'create_%s_form' % form_name
if hasattr(self, form_create_method):
form = getattr(self, form_create_method)(**form_kwargs)
else:
form = klass(**form_kwargs)
return form
def get_forms(self, form_classes):
return dict([(key, self._create_form(key, klass)) for key, klass in form_classes.items()])
def get_initial(self, form_name):
initial_method = 'get_%s_initial' % form_name
if hasattr(self, initial_method):
return getattr(self, initial_method)()
else:
return self.initial.copy()
def get_prefix(self, form_name):
return self.prefixes.get(form_name, self.prefix)
def get(self, request, *args, **kwargs):
form_classes = self.get_form_classes()
forms = self.get_forms(form_classes)
return self.render_to_response(self.get_context_data(forms=forms))
def forms_valid(self, forms):
for form_name, form in forms.items():
form_valid_method = '%s_form_valid' % form_name
if hasattr(self, form_valid_method):
return getattr(self, form_valid_method)(form)
self.all_forms_valid(forms)
return HttpResponseRedirect(self.get_success_url())
def forms_invalid(self, forms):
return self.render_to_response(self.get_context_data(forms=forms))
def post(self, request, *args, **kwargs):
form_classes = self.get_form_classes()
forms = self.get_forms(form_classes)
if all([form.is_valid() for form in forms.values()]):
return self.forms_valid(forms)
else:
return self.forms_invalid(forms)
class ParentChildListView(ViewPermissionCheckMixin, ObjectPermissionCheckMixin, ExtraContextMixin, ListView, SingleObjectMixin):
parent_model = None
parent_queryset = None
template_name = 'appearance/generic_list.html'
def get(self, request, *args, **kwargs):
# Parent
self.object = self.get_object()
# Children
self.object_list = self.get_queryset()
allow_empty = self.get_allow_empty()
if not allow_empty:
# When pagination is enabled and object_list is a queryset,
# it's better to do a cheap query than to load the unpaginated
# queryset in memory.
if (self.get_paginate_by(self.object_list) is not None
and hasattr(self.object_list, 'exists')):
is_empty = not self.object_list.exists()
else:
is_empty = len(self.object_list) == 0
if is_empty:
raise Http404(_("Empty list and '%(class_name)s.allow_empty' is False.")
% {'class_name': self.__class__.__name__})
context = self.get_context_data(object=self.object)
return self.render_to_response(context)
def get_object(self, queryset=None):
# Use a custom queryset if provided; this is required for subclasses
# like DateDetailView
if queryset is None:
queryset = self.get_parent_queryset()
# Next, try looking up by primary key.
pk = self.kwargs.get(self.pk_url_kwarg, None)
slug = self.kwargs.get(self.slug_url_kwarg, None)
if pk is not None:
queryset = queryset.filter(pk=pk)
# Next, try looking up by slug.
if slug is not None and (pk is None or self.query_pk_and_slug):
slug_field = self.get_slug_field()
queryset = queryset.filter(**{slug_field: slug})
# If none of those are defined, it's an error.
if pk is None and slug is None:
raise AttributeError("Generic detail view %s must be called with "
"either an object pk or a slug."
% self.__class__.__name__)
try:
# Get the single item from the filtered queryset
obj = queryset.get()
except queryset.model.DoesNotExist:
raise Http404(_("No %(verbose_name)s found matching the query") %
{'verbose_name': queryset.model._meta.verbose_name})
return obj
def get_parent_queryset(self):
"""
Return the `QuerySet` that will be used to look up the object.
Note that this method is called by the default implementation of
`get_object` and may not be called if `get_object` is overridden.
"""
if self.parent_queryset is None:
if self.parent_model:
return self.model._default_manager.all()
else:
raise ImproperlyConfigured(
"%(cls)s is missing a QuerySet. Define "
"%(cls)s.parent_model, %(cls)s.parent_queryset, or override "
"%(cls)s.get_parent_queryset()." % {
'cls': self.__class__.__name__
}
)
return self.parent_queryset.all()
def get_queryset(self):
raise NotImplementedError
class SimpleView(ViewPermissionCheckMixin, ExtraContextMixin, TemplateView):
pass
class SingleObjectCreateView(ViewPermissionCheckMixin, ExtraContextMixin, RedirectionMixin, CreateView):
template_name = 'appearance/generic_form.html'
def form_invalid(self, form):
result = super(SingleObjectCreateView, self).form_invalid(form)
try:
messages.error(self.request, _('Error creating new %s.') % self.extra_context['object_name'])
except KeyError:
messages.error(self.request, _('Error creating object.'))
return result
def form_valid(self, form):
result = super(SingleObjectCreateView, self).form_valid(form)
try:
messages.success(self.request, _('%s created successfully.') % self.extra_context['object_name'].capitalize())
except KeyError:
messages.success(self.request, _('New object created successfully.'))
return result
class SingleObjectDeleteView(ViewPermissionCheckMixin, ObjectPermissionCheckMixin, ExtraContextMixin, RedirectionMixin, DeleteView):
template_name = 'appearance/generic_confirm.html'
def get_context_data(self, **kwargs):
context = super(SingleObjectDeleteView, self).get_context_data(**kwargs)
context.update({'delete_view': True})
return context
def delete(self, request, *args, **kwargs):
try:
result = super(SingleObjectDeleteView, self).delete(request, *args, **kwargs)
except Exception as exception:
try:
messages.error(self.request, _('Error deleting %s.') % self.extra_context['object_name'])
except KeyError:
messages.error(self.request, _('Error deleting object.'))
raise exception
else:
try:
messages.success(self.request, _('%s deleted successfully.') % self.extra_context['object_name'].capitalize())
except KeyError:
messages.success(self.request, _('Object deleted successfully.'))
return result
# TODO: check/test if ViewPermissionCheckMixin, ObjectPermissionCheckMixin are
# in the right MRO
class SingleObjectEditView(ViewPermissionCheckMixin, ObjectPermissionCheckMixin, ExtraContextMixin, RedirectionMixin, UpdateView):
template_name = 'appearance/generic_form.html'
def form_invalid(self, form):
result = super(SingleObjectEditView, self).form_invalid(form)
try:
messages.error(self.request, _('Error saving %s details.') % self.extra_context['object_name'])
except KeyError:
messages.error(self.request, _('Error saving details.'))
return result
def form_valid(self, form):
result = super(SingleObjectEditView, self).form_valid(form)
try:
messages.success(self.request, _('%s details saved successfully.') % self.extra_context['object_name'].capitalize())
except KeyError:
messages.success(self.request, _('Details saved successfully.'))
return result
class SingleObjectListView(ViewPermissionCheckMixin, ObjectListPermissionFilterMixin, ExtraContextMixin, RedirectionMixin, ListView):
template_name = 'appearance/generic_list.html'

View File

@@ -11,7 +11,7 @@ class TimezoneMiddleware(object):
if hasattr(request, 'session'): if hasattr(request, 'session'):
tzname = request.session.get(settings.TIMEZONE_SESSION_KEY) tzname = request.session.get(settings.TIMEZONE_SESSION_KEY)
else: else:
tzname = HttpRequest.COOKIES.get(settings.TIMEZONE_COOKIE_NAME) tzname = request.COOKIES.get(settings.TIMEZONE_COOKIE_NAME)
if tzname: if tzname:
timezone.activate(pytz.timezone(tzname)) timezone.activate(pytz.timezone(tzname))

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import models, migrations from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import models, migrations from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import models, migrations from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@@ -6,7 +6,6 @@ import tempfile
import types import types
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import User
from django.utils.datastructures import MultiValueDict from django.utils.datastructures import MultiValueDict
from django.utils.http import urlquote as django_urlquote from django.utils.http import urlquote as django_urlquote
from django.utils.http import urlencode as django_urlencode from django.utils.http import urlencode as django_urlencode

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,6 @@ import os
from django import forms from django import forms
from django.forms.util import flatatt from django.forms.util import flatatt
from django.utils.datastructures import MultiValueDict, MergeDict
from django.utils.encoding import force_unicode, force_text from django.utils.encoding import force_unicode, force_text
from django.utils.html import conditional_escape, format_html from django.utils.html import conditional_escape, format_html
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import models, migrations from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@@ -4,7 +4,6 @@ import logging
from django.contrib.contenttypes import generic from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ValidationError
from django.db import models from django.db import models
from django.utils.encoding import python_2_unicode_compatible from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _

View File

@@ -5,7 +5,7 @@ from django import forms
from common.classes import ModelAttribute from common.classes import ModelAttribute
from documents.models import Document from documents.models import Document
from .models import Index, IndexTemplateNode from .models import IndexTemplateNode
class IndexTemplateNodeForm(forms.ModelForm): class IndexTemplateNodeForm(forms.ModelForm):

View File

@@ -89,9 +89,9 @@ class IndexInstanceNodeManager(models.Manager):
self.delete_empty_index_nodes() self.delete_empty_index_nodes()
def rebuild_all_indexes(): def rebuild_all_indexes(self):
for instance_node in self.all(): for instance_node in self.all():
instance_node.delete() instance_node.delete()
for document in Document.objects.all(): for document in Document.objects.all():
index_document(document) self.index_document(document)

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import models, migrations from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import models, migrations from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@@ -3,7 +3,7 @@ from __future__ import unicode_literals
from django.core.files.base import File from django.core.files.base import File
from django.test import TestCase from django.test import TestCase
from documents.models import Document, DocumentType from documents.models import DocumentType
from documents.test_models import TEST_SMALL_DOCUMENT_PATH, TEST_DOCUMENT_TYPE from documents.test_models import TEST_SMALL_DOCUMENT_PATH, TEST_DOCUMENT_TYPE
from metadata.models import MetadataType, DocumentTypeMetadataType from metadata.models import MetadataType, DocumentTypeMetadataType

View File

@@ -3,7 +3,6 @@ from __future__ import unicode_literals
import io import io
import logging import logging
from django.core.files import File
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from acls import ModelPermission from acls import ModelPermission

View File

@@ -23,15 +23,12 @@ class DocumentVersionSignature(models.Model):
""" """
Model that describes a document version signature properties Model that describes a document version signature properties
""" """
document_version = models.ForeignKey(DocumentVersion, verbose_name=_('Document version'), editable=False) document_version = models.ForeignKey(DocumentVersion, editable=False, verbose_name=_('Document version'))
signature_file = models.FileField(blank=True, null=True, upload_to=upload_to, storage=storage_backend, verbose_name=_('Signature file')) signature_file = models.FileField(blank=True, null=True, storage=storage_backend, upload_to=upload_to, verbose_name=_('Signature file'))
has_embedded_signature = models.BooleanField(default=False, verbose_name=_('Has embedded signature')) has_embedded_signature = models.BooleanField(default=False, verbose_name=_('Has embedded signature'))
objects = DocumentVersionSignatureManager() objects = DocumentVersionSignatureManager()
def delete_detached_signature_file(self):
self.signature_file.storage.delete(self.signature_file.path)
def check_for_embedded_signature(self): def check_for_embedded_signature(self):
logger.debug('checking for embedded signature') logger.debug('checking for embedded signature')
@@ -39,6 +36,9 @@ class DocumentVersionSignature(models.Model):
self.has_embedded_signature = gpg.has_embedded_signature(file_object) self.has_embedded_signature = gpg.has_embedded_signature(file_object)
self.save() self.save()
def delete_detached_signature_file(self):
self.signature_file.storage.delete(self.signature_file.path)
class Meta: class Meta:
verbose_name = _('Document version signature') verbose_name = _('Document version signature')
verbose_name_plural = _('Document version signatures') verbose_name_plural = _('Document version signatures')

View File

@@ -6,14 +6,13 @@ from django.conf import settings
from django.core.files.base import File from django.core.files.base import File
from django.test import TestCase from django.test import TestCase
from documents.models import Document, DocumentType from documents.models import DocumentType
from documents.test_models import TEST_DOCUMENT_TYPE from documents.test_models import TEST_DOCUMENT_PATH, TEST_DOCUMENT_TYPE
from django_gpg.literals import SIGNATURE_STATE_VALID from django_gpg.literals import SIGNATURE_STATE_VALID
from django_gpg.runtime import gpg from django_gpg.runtime import gpg
from .models import DocumentVersionSignature from .models import DocumentVersionSignature
TEST_DOCUMENT_PATH = os.path.join(settings.BASE_DIR, 'contrib', 'sample_documents', 'mayan_11_1.pdf')
TEST_SIGNED_DOCUMENT_PATH = os.path.join(settings.BASE_DIR, 'contrib', 'sample_documents', 'mayan_11_1.pdf.gpg') TEST_SIGNED_DOCUMENT_PATH = os.path.join(settings.BASE_DIR, 'contrib', 'sample_documents', 'mayan_11_1.pdf.gpg')
TEST_SIGNATURE_FILE_PATH = os.path.join(settings.BASE_DIR, 'contrib', 'sample_documents', 'mayan_11_1.pdf.sig') TEST_SIGNATURE_FILE_PATH = os.path.join(settings.BASE_DIR, 'contrib', 'sample_documents', 'mayan_11_1.pdf.sig')
TEST_KEY_FILE = os.path.join(settings.BASE_DIR, 'contrib', 'sample_documents', 'key0x5F3F7F75D210724D.asc') TEST_KEY_FILE = os.path.join(settings.BASE_DIR, 'contrib', 'sample_documents', 'key0x5F3F7F75D210724D.asc')

View File

@@ -91,6 +91,9 @@ class WorkflowInstance(models.Model):
workflow = models.ForeignKey(Workflow, related_name='instances', verbose_name=_('Workflow')) workflow = models.ForeignKey(Workflow, related_name='instances', verbose_name=_('Workflow'))
document = models.ForeignKey(Document, related_name='workflows', verbose_name=_('Document')) document = models.ForeignKey(Document, related_name='workflows', verbose_name=_('Document'))
def __str__(self):
return unicode(self.workflow)
def get_absolute_url(self): def get_absolute_url(self):
return reverse('document_states:workflow_instance_detail', args=[str(self.pk)]) return reverse('document_states:workflow_instance_detail', args=[str(self.pk)])
@@ -108,24 +111,21 @@ class WorkflowInstance(models.Model):
except AttributeError: except AttributeError:
return self.workflow.get_initial_state() return self.workflow.get_initial_state()
def get_last_transition(self):
try:
return self.get_last_log_entry().transition
except AttributeError:
return None
def get_last_log_entry(self): def get_last_log_entry(self):
try: try:
return self.log_entries.order_by('datetime').last() return self.log_entries.order_by('datetime').last()
except AttributeError: except AttributeError:
return None return None
def get_last_transition(self):
try:
return self.get_last_log_entry().transition
except AttributeError:
return None
def get_transition_choices(self): def get_transition_choices(self):
return self.get_current_state().origin_transitions.all() return self.get_current_state().origin_transitions.all()
def __str__(self):
return unicode(self.workflow)
class Meta: class Meta:
unique_together = ('document', 'workflow') unique_together = ('document', 'workflow')
verbose_name = _('Workflow instance') verbose_name = _('Workflow instance')

View File

@@ -77,7 +77,7 @@ class WorkflowDocumentListView(DocumentListView):
'hide_links': True, 'hide_links': True,
'object': self.workflow, 'object': self.workflow,
'title': _('Documents with the workflow: %s') % self.workflow 'title': _('Documents with the workflow: %s') % self.workflow
} }
class WorkflowInstanceDetailView(SingleObjectListView): class WorkflowInstanceDetailView(SingleObjectListView):

View File

@@ -7,10 +7,8 @@ from django.shortcuts import get_object_or_404
from rest_framework import generics, status from rest_framework import generics, status
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.settings import api_settings
from acls.models import AccessControlList from acls.models import AccessControlList
from common.models import SharedUploadedFile
from converter.exceptions import UnkownConvertError, UnknownFileFormat from converter.exceptions import UnkownConvertError, UnknownFileFormat
from converter.literals import ( from converter.literals import (
DEFAULT_PAGE_NUMBER, DEFAULT_ROTATION, DEFAULT_ZOOM_LEVEL DEFAULT_PAGE_NUMBER, DEFAULT_ROTATION, DEFAULT_ZOOM_LEVEL

View File

@@ -2,8 +2,8 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations
import documents.models
from django.conf import settings from django.conf import settings
import storage.backends.filebasedstorage import storage.backends.filebasedstorage

View File

@@ -1,8 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import models, migrations from django.db import migrations
import storage.backends.filebasedstorage
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import models, migrations from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import models, migrations from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import models, migrations from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import models, migrations from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import models, migrations from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@@ -102,7 +102,7 @@ class Document(models.Model):
""" """
uuid = models.CharField(default=UUID_FUNCTION, editable=False, max_length=48) uuid = models.CharField(default=UUID_FUNCTION, editable=False, max_length=48)
document_type = models.ForeignKey(DocumentType, related_name='documents', verbose_name=_('Document type')) document_type = models.ForeignKey(DocumentType, related_name='documents', verbose_name=_('Document type'))
label = models.CharField(db_index=True, default=_('Uninitialized document'), max_length=255, help_text=_('The name of the document'), verbose_name=_('Label')) label = models.CharField(db_index=True, default=_('Uninitialized document'), max_length=255, help_text=_('The name of the document'), verbose_name=_('Label'))
description = models.TextField(blank=True, verbose_name=_('Description')) description = models.TextField(blank=True, verbose_name=_('Description'))
date_added = models.DateTimeField(auto_now_add=True, verbose_name=_('Added')) date_added = models.DateTimeField(auto_now_add=True, verbose_name=_('Added'))

View File

@@ -4,7 +4,6 @@ from datetime import timedelta
import logging import logging
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.files import File
from django.utils.timezone import now from django.utils.timezone import now
from mayan.celery import app from mayan.celery import app

View File

@@ -3,13 +3,9 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from json import loads from json import loads
import os
from django.conf import settings
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.files import File
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.test.client import Client
from django.test import TestCase from django.test import TestCase
from rest_framework import status from rest_framework import status
@@ -18,11 +14,9 @@ from rest_framework.test import APIClient
from .models import Document, DocumentType from .models import Document, DocumentType
from .test_models import ( from .test_models import (
TEST_ADMIN_PASSWORD, TEST_ADMIN_USERNAME, TEST_ADMIN_EMAIL, TEST_ADMIN_PASSWORD, TEST_ADMIN_USERNAME, TEST_ADMIN_EMAIL,
TEST_SMALL_DOCUMENT_FILENAME, TEST_NON_ASCII_DOCUMENT_FILENAME, TEST_SMALL_DOCUMENT_FILENAME, TEST_DOCUMENT_PATH,
TEST_NON_ASCII_COMPRESSED_DOCUMENT_FILENAME, TEST_DOCUMENT_PATH, TEST_SMALL_DOCUMENT_PATH,
TEST_SIGNED_DOCUMENT_PATH, TEST_SMALL_DOCUMENT_PATH, TEST_DOCUMENT_TYPE
TEST_NON_ASCII_DOCUMENT_PATH, TEST_NON_ASCII_COMPRESSED_DOCUMENT_PATH,
TEST_DOCUMENT_DESCRIPTION, TEST_DOCUMENT_TYPE
) )

View File

@@ -1,20 +1,12 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
from json import loads
import os import os
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import User
from django.core.files import File from django.core.files import File
from django.core.urlresolvers import reverse
from django.test.client import Client
from django.test import TestCase from django.test import TestCase
from rest_framework import status
from rest_framework.test import APIClient
from .models import DeletedDocument, Document, DocumentType from .models import DeletedDocument, Document, DocumentType
TEST_ADMIN_PASSWORD = 'test_admin_password' TEST_ADMIN_PASSWORD = 'test_admin_password'
@@ -24,7 +16,6 @@ TEST_SMALL_DOCUMENT_FILENAME = 'title_page.png'
TEST_NON_ASCII_DOCUMENT_FILENAME = 'I18N_title_áéíóúüñÑ.png' TEST_NON_ASCII_DOCUMENT_FILENAME = 'I18N_title_áéíóúüñÑ.png'
TEST_NON_ASCII_COMPRESSED_DOCUMENT_FILENAME = 'I18N_title_áéíóúüñÑ.png.zip' TEST_NON_ASCII_COMPRESSED_DOCUMENT_FILENAME = 'I18N_title_áéíóúüñÑ.png.zip'
TEST_DOCUMENT_PATH = os.path.join(settings.BASE_DIR, 'contrib', 'sample_documents', 'mayan_11_1.pdf') TEST_DOCUMENT_PATH = os.path.join(settings.BASE_DIR, 'contrib', 'sample_documents', 'mayan_11_1.pdf')
TEST_SIGNED_DOCUMENT_PATH = os.path.join(settings.BASE_DIR, 'contrib', 'sample_documents', 'mayan_11_1.pdf.gpg')
TEST_SMALL_DOCUMENT_PATH = os.path.join(settings.BASE_DIR, 'contrib', 'sample_documents', TEST_SMALL_DOCUMENT_FILENAME) TEST_SMALL_DOCUMENT_PATH = os.path.join(settings.BASE_DIR, 'contrib', 'sample_documents', TEST_SMALL_DOCUMENT_FILENAME)
TEST_NON_ASCII_DOCUMENT_PATH = os.path.join(settings.BASE_DIR, 'contrib', 'sample_documents', TEST_NON_ASCII_DOCUMENT_FILENAME) TEST_NON_ASCII_DOCUMENT_PATH = os.path.join(settings.BASE_DIR, 'contrib', 'sample_documents', TEST_NON_ASCII_DOCUMENT_FILENAME)
TEST_NON_ASCII_COMPRESSED_DOCUMENT_PATH = os.path.join(settings.BASE_DIR, 'contrib', 'sample_documents', TEST_NON_ASCII_COMPRESSED_DOCUMENT_FILENAME) TEST_NON_ASCII_COMPRESSED_DOCUMENT_PATH = os.path.join(settings.BASE_DIR, 'contrib', 'sample_documents', TEST_NON_ASCII_COMPRESSED_DOCUMENT_FILENAME)

View File

@@ -2,27 +2,16 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from json import loads
import os
from django.conf import settings
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.files import File from django.core.files import File
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.test.client import Client from django.test.client import Client
from django.test import TestCase from django.test import TestCase
from rest_framework import status
from rest_framework.test import APIClient
from .models import DeletedDocument, Document, DocumentType from .models import DeletedDocument, Document, DocumentType
from .test_models import ( from .test_models import (
TEST_ADMIN_PASSWORD, TEST_ADMIN_USERNAME, TEST_ADMIN_EMAIL, TEST_ADMIN_PASSWORD, TEST_ADMIN_USERNAME, TEST_ADMIN_EMAIL,
TEST_SMALL_DOCUMENT_FILENAME, TEST_NON_ASCII_DOCUMENT_FILENAME, TEST_SMALL_DOCUMENT_PATH, TEST_DOCUMENT_TYPE
TEST_NON_ASCII_COMPRESSED_DOCUMENT_FILENAME, TEST_DOCUMENT_PATH,
TEST_SIGNED_DOCUMENT_PATH, TEST_SMALL_DOCUMENT_PATH,
TEST_NON_ASCII_DOCUMENT_PATH, TEST_NON_ASCII_COMPRESSED_DOCUMENT_PATH,
TEST_DOCUMENT_DESCRIPTION, TEST_DOCUMENT_TYPE
) )
@@ -45,7 +34,7 @@ class DocumentsViewsFunctionalTestCase(TestCase):
self.assertTrue(logged_in) self.assertTrue(logged_in)
self.assertTrue(self.admin_user.is_authenticated()) self.assertTrue(self.admin_user.is_authenticated())
with open(TEST_DOCUMENT_PATH) as file_object: with open(TEST_SMALL_DOCUMENT_PATH) as file_object:
self.document = self.document_type.new_document(file_object=File(file_object), label='mayan_11_1.pdf') self.document = self.document_type.new_document(file_object=File(file_object), label='mayan_11_1.pdf')
def tearDown(self): def tearDown(self):

View File

@@ -23,9 +23,9 @@ class RecentSearch(models.Model):
# Should be fixed by DRF v2.4.4 # Should be fixed by DRF v2.4.4
# TODO: Fix after upgrade to DRF v2.4.4 # TODO: Fix after upgrade to DRF v2.4.4
query = models.TextField(verbose_name=_('Query'), editable=False) query = models.TextField(editable=False, verbose_name=_('Query'))
datetime_created = models.DateTimeField(verbose_name=_('Datetime created'), auto_now=True, db_index=True) datetime_created = models.DateTimeField(auto_now=True, db_index=True, verbose_name=_('Datetime created'))
hits = models.IntegerField(verbose_name=_('Hits'), editable=False) hits = models.IntegerField(editable=False, verbose_name=_('Hits'))
objects = RecentSearchManager() objects = RecentSearchManager()

View File

@@ -2,15 +2,13 @@ from __future__ import unicode_literals
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.files.base import File from django.core.files.base import File
from django.core.urlresolvers import reverse
from django.test.client import Client
from django.test import TestCase from django.test import TestCase
from documents.models import Document, DocumentType from documents.models import DocumentType
from documents.search import document_search from documents.search import document_search
from documents.test_models import ( from documents.test_models import (
TEST_ADMIN_PASSWORD, TEST_ADMIN_USERNAME, TEST_ADMIN_EMAIL, TEST_ADMIN_PASSWORD, TEST_ADMIN_USERNAME, TEST_ADMIN_EMAIL,
TEST_DOCUMENT_PATH, TEST_DOCUMENT_TYPE, TEST_SMALL_DOCUMENT_PATH TEST_DOCUMENT_TYPE, TEST_SMALL_DOCUMENT_PATH
) )

View File

@@ -6,11 +6,11 @@ from django.core.urlresolvers import reverse
from django.test.client import Client from django.test.client import Client
from django.test import TestCase from django.test import TestCase
from documents.models import Document, DocumentType from documents.models import DocumentType
from documents.search import document_search from documents.search import document_search
from documents.test_models import ( from documents.test_models import (
TEST_ADMIN_PASSWORD, TEST_ADMIN_USERNAME, TEST_ADMIN_EMAIL, TEST_ADMIN_PASSWORD, TEST_ADMIN_USERNAME, TEST_ADMIN_EMAIL,
TEST_DOCUMENT_PATH, TEST_DOCUMENT_TYPE, TEST_SMALL_DOCUMENT_PATH TEST_DOCUMENT_TYPE, TEST_SMALL_DOCUMENT_PATH
) )

View File

@@ -2,10 +2,8 @@ from __future__ import absolute_import, unicode_literals
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.db.models.loading import get_model
from django.http import Http404 from django.http import Http404
from django.shortcuts import get_object_or_404, render_to_response from django.shortcuts import get_object_or_404
from django.template import RequestContext
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from actstream.models import Action, any_stream from actstream.models import Action, any_stream

View File

@@ -9,7 +9,6 @@ from common import (
MayanAppConfig, menu_facet, menu_main, menu_object, menu_secondary, MayanAppConfig, menu_facet, menu_main, menu_object, menu_secondary,
menu_sidebar, menu_multi_item menu_sidebar, menu_multi_item
) )
from common.utils import encapsulate
from documents.models import Document from documents.models import Document
from navigation import CombinedSource, SourceColumn from navigation import CombinedSource, SourceColumn
from rest_api.classes import APIEndPoint from rest_api.classes import APIEndPoint

View File

@@ -15,12 +15,6 @@ from .permissions import permission_folder_view
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class FolderForm(forms.ModelForm):
class Meta:
model = Folder
fields = ('label',)
class FolderListForm(forms.Form): class FolderListForm(forms.Form):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None) user = kwargs.pop('user', None)

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import models, migrations from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@@ -11,9 +11,9 @@ from documents.models import Document
@python_2_unicode_compatible @python_2_unicode_compatible
class Folder(models.Model): class Folder(models.Model):
label = models.CharField(max_length=128, verbose_name=_('Label'), db_index=True) label = models.CharField(db_index=True, max_length=128, verbose_name=_('Label'))
user = models.ForeignKey(User, verbose_name=_('User')) user = models.ForeignKey(User, verbose_name=_('User'))
datetime_created = models.DateTimeField(verbose_name=_('Datetime created'), auto_now_add=True) datetime_created = models.DateTimeField(auto_now_add=True, verbose_name=_('Datetime created'))
documents = models.ManyToManyField(Document, related_name='folders', verbose_name=_('Documents')) documents = models.ManyToManyField(Document, related_name='folders', verbose_name=_('Documents'))
def __str__(self): def __str__(self):
@@ -23,7 +23,7 @@ class Folder(models.Model):
return reverse('folders:folder_view', args=[self.pk]) return reverse('folders:folder_view', args=[self.pk])
class Meta: class Meta:
unique_together = ('label', 'user')
ordering = ('label',) ordering = ('label',)
unique_together = ('label', 'user')
verbose_name = _('Folder') verbose_name = _('Folder')
verbose_name_plural = _('Folders') verbose_name_plural = _('Folders')

View File

@@ -10,7 +10,7 @@ from django.test import TestCase
from authentication.test_views import ( from authentication.test_views import (
TEST_ADMIN_EMAIL, TEST_ADMIN_PASSWORD, TEST_ADMIN_USERNAME TEST_ADMIN_EMAIL, TEST_ADMIN_PASSWORD, TEST_ADMIN_USERNAME
) )
from documents.models import Document, DocumentType from documents.models import DocumentType
from documents.test_models import TEST_DOCUMENT_TYPE from documents.test_models import TEST_DOCUMENT_TYPE
from .models import Folder from .models import Folder
@@ -35,7 +35,6 @@ class FolderTestCase(TestCase):
folder.delete() folder.delete()
def test_addition_of_documents(self): def test_addition_of_documents(self):
user = User.objects.all()[0]
folder = Folder.objects.create(label='test', user=self.user) folder = Folder.objects.create(label='test', user=self.user)
folder.documents.add(self.document) folder.documents.add(self.document)
@@ -44,7 +43,6 @@ class FolderTestCase(TestCase):
folder.delete() folder.delete()
def test_addition_and_deletion_of_documents(self): def test_addition_and_deletion_of_documents(self):
user = User.objects.all()[0]
folder = Folder.objects.create(label='test', user=self.user) folder = Folder.objects.create(label='test', user=self.user)
folder.documents.add(self.document) folder.documents.add(self.document)

View File

@@ -4,7 +4,7 @@ import logging
from django.conf import settings from django.conf import settings
from django.contrib import messages from django.contrib import messages
from django.core.exceptions import PermissionDenied, ValidationError from django.core.exceptions import PermissionDenied
from django.core.urlresolvers import reverse, reverse_lazy from django.core.urlresolvers import reverse, reverse_lazy
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, render_to_response from django.shortcuts import get_object_or_404, render_to_response
@@ -21,7 +21,7 @@ from documents.models import Document
from documents.views import DocumentListView from documents.views import DocumentListView
from permissions import Permission from permissions import Permission
from .forms import FolderForm, FolderListForm from .forms import FolderListForm
from .models import Folder from .models import Folder
from .permissions import ( from .permissions import (
permission_folder_add_document, permission_folder_create, permission_folder_add_document, permission_folder_create,

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import models, migrations from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import models, migrations from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@@ -15,7 +15,7 @@ from .literals import (
@python_2_unicode_compatible @python_2_unicode_compatible
class SmartLink(models.Model): class SmartLink(models.Model):
label = models.CharField(max_length=96, verbose_name=_('Label')) label = models.CharField(max_length=96, verbose_name=_('Label'))
dynamic_label = models.CharField(blank=True, max_length=96, verbose_name=_('Dynamic label'), help_text=_('This expression will be evaluated against the current selected document.')) dynamic_label = models.CharField(blank=True, max_length=96, help_text=_('This expression will be evaluated against the current selected document.'), verbose_name=_('Dynamic label'))
enabled = models.BooleanField(default=True, verbose_name=_('Enabled')) enabled = models.BooleanField(default=True, verbose_name=_('Enabled'))
document_types = models.ManyToManyField(DocumentType, verbose_name=_('Document types')) document_types = models.ManyToManyField(DocumentType, verbose_name=_('Document types'))
@@ -31,9 +31,6 @@ class SmartLink(models.Model):
else: else:
return self.label return self.label
def resolve_for(self, document):
return ResolvedSmartLink(smart_link=self, queryset=self.get_linked_document_for(document))
def get_linked_document_for(self, document): def get_linked_document_for(self, document):
if document.document_type.pk not in self.document_types.values_list('pk', flat=True): if document.document_type.pk not in self.document_types.values_list('pk', flat=True):
raise Exception(_('This smart link is not allowed for the selected document\'s type.')) raise Exception(_('This smart link is not allowed for the selected document\'s type.'))
@@ -57,6 +54,9 @@ class SmartLink(models.Model):
else: else:
return Document.objects.none() return Document.objects.none()
def resolve_for(self, document):
return ResolvedSmartLink(smart_link=self, queryset=self.get_linked_document_for(document))
class Meta: class Meta:
verbose_name = _('Smart link') verbose_name = _('Smart link')
verbose_name_plural = _('Smart links') verbose_name_plural = _('Smart links')
@@ -70,11 +70,11 @@ class ResolvedSmartLink(SmartLink):
@python_2_unicode_compatible @python_2_unicode_compatible
class SmartLinkCondition(models.Model): class SmartLinkCondition(models.Model):
smart_link = models.ForeignKey(SmartLink, related_name='conditions', verbose_name=_('Smart link')) smart_link = models.ForeignKey(SmartLink, related_name='conditions', verbose_name=_('Smart link'))
inclusion = models.CharField(default=INCLUSION_AND, max_length=16, choices=INCLUSION_CHOICES, help_text=_('The inclusion is ignored for the first item.')) inclusion = models.CharField(choices=INCLUSION_CHOICES, default=INCLUSION_AND, help_text=_('The inclusion is ignored for the first item.'), max_length=16)
foreign_document_data = models.CharField(max_length=128, verbose_name=_('Foreign document attribute'), help_text=_('This represents the metadata of all other documents.')) foreign_document_data = models.CharField(help_text=_('This represents the metadata of all other documents.'), max_length=128, verbose_name=_('Foreign document attribute'))
operator = models.CharField(max_length=16, choices=OPERATOR_CHOICES) operator = models.CharField(choices=OPERATOR_CHOICES, max_length=16)
expression = models.TextField(verbose_name=_('Expression'), help_text=_('This expression will be evaluated against the current document.')) expression = models.TextField(help_text=_('This expression will be evaluated against the current document.'), verbose_name=_('Expression'))
negated = models.BooleanField(default=False, verbose_name=_('Negated'), help_text=_('Inverts the logic of the operator.')) negated = models.BooleanField(default=False, help_text=_('Inverts the logic of the operator.'), verbose_name=_('Negated'))
enabled = models.BooleanField(default=True, verbose_name=_('Enabled')) enabled = models.BooleanField(default=True, verbose_name=_('Enabled'))
def __str__(self): def __str__(self):

View File

@@ -85,7 +85,7 @@ class ResolvedSmartLinkView(DocumentListView):
queryset = Document.objects.none() queryset = Document.objects.none()
if self.request.user.is_staff or self.request.user.is_superuser: if self.request.user.is_staff or self.request.user.is_superuser:
messages.error(request, _('Smart link query error: %s' % exception)) messages.error(self.request, _('Smart link query error: %s' % exception))
return queryset return queryset

View File

@@ -10,9 +10,9 @@ from .settings import DEFAULT_LOCK_TIMEOUT
@python_2_unicode_compatible @python_2_unicode_compatible
class Lock(models.Model): class Lock(models.Model):
creation_datetime = models.DateTimeField(verbose_name=_('Creation datetime'), auto_now_add=True) creation_datetime = models.DateTimeField(auto_now_add=True, verbose_name=_('Creation datetime'))
timeout = models.IntegerField(default=DEFAULT_LOCK_TIMEOUT, verbose_name=_('Timeout')) timeout = models.IntegerField(default=DEFAULT_LOCK_TIMEOUT, verbose_name=_('Timeout'))
name = models.CharField(max_length=64, verbose_name=_('Name'), unique=True) name = models.CharField(max_length=64, unique=True, verbose_name=_('Name'))
objects = LockManager() objects = LockManager()

View File

@@ -58,8 +58,6 @@ class MetadataApp(MayanAppConfig):
ModelAttribute(Document, 'metadata__value', label=_('Metadata type value'), type_name='query') ModelAttribute(Document, 'metadata__value', label=_('Metadata type value'), type_name='query')
ModelAttribute(Document, 'metadata_value_of', label=_('Value of a metadata'), description=_('Return the value of a specific document metadata'), type_name=['property', 'indexing']) ModelAttribute(Document, 'metadata_value_of', label=_('Value of a metadata'), description=_('Return the value of a specific document metadata'), type_name=['property', 'indexing'])
SourceColumn(source=Document, label=_('Metadata'), attribute=encapsulate(lambda document: get_metadata_string(document)))
ModelPermission.register( ModelPermission.register(
model=Document, permissions=( model=Document, permissions=(
permission_metadata_document_add, permission_metadata_document_edit, permission_metadata_document_add, permission_metadata_document_edit,
@@ -67,6 +65,8 @@ class MetadataApp(MayanAppConfig):
) )
) )
SourceColumn(source=Document, label=_('Metadata'), attribute=encapsulate(lambda document: get_metadata_string(document)))
document_search.add_model_field(field='metadata__metadata_type__name', label=_('Metadata type')) document_search.add_model_field(field='metadata__metadata_type__name', label=_('Metadata type'))
document_search.add_model_field(field='metadata__value', label=_('Metadata value')) document_search.add_model_field(field='metadata__value', label=_('Metadata value'))
@@ -79,6 +79,6 @@ class MetadataApp(MayanAppConfig):
menu_sidebar.bind_links(links=[link_metadata_add, link_metadata_edit, link_metadata_remove], sources=['metadata:metadata_add', 'metadata:metadata_edit', 'metadata:metadata_remove', 'metadata:metadata_view']) menu_sidebar.bind_links(links=[link_metadata_add, link_metadata_edit, link_metadata_remove], sources=['metadata:metadata_add', 'metadata:metadata_edit', 'metadata:metadata_remove', 'metadata:metadata_view'])
menu_tools.bind_links(links=[link_documents_missing_required_metadata]) menu_tools.bind_links(links=[link_documents_missing_required_metadata])
post_save.connect(post_document_type_metadata_type_add, dispatch_uid='post_document_type_metadata_type_add', sender=DocumentTypeMetadataType)
post_delete.connect(post_document_type_metadata_type_delete, dispatch_uid='post_document_type_metadata_type_delete', sender=DocumentTypeMetadataType) post_delete.connect(post_document_type_metadata_type_delete, dispatch_uid='post_document_type_metadata_type_delete', sender=DocumentTypeMetadataType)
post_document_type_change.connect(post_post_document_type_change_metadata, dispatch_uid='post_post_document_type_change_metadata', sender=Document) post_document_type_change.connect(post_post_document_type_change_metadata, dispatch_uid='post_post_document_type_change_metadata', sender=Document)
post_save.connect(post_document_type_metadata_type_add, dispatch_uid='post_document_type_metadata_type_add', sender=DocumentTypeMetadataType)

View File

@@ -7,10 +7,7 @@ from django.utils.module_loading import import_string
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from .models import MetadataType from .models import MetadataType
from .settings import ( from .settings import setting_available_functions, setting_available_models
setting_available_functions, setting_available_models,
setting_available_validators
)
class MetadataForm(forms.Form): class MetadataForm(forms.Form):

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import models, migrations from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@@ -20,16 +20,12 @@ class MetadataType(models.Model):
""" """
Define a type of metadata Define a type of metadata
""" """
name = models.CharField(unique=True, max_length=48, verbose_name=_('Name'), help_text=_('Do not use python reserved words, or spaces.')) name = models.CharField(max_length=48, help_text=_('Do not use python reserved words, or spaces.'), unique=True, verbose_name=_('Name'))
label = models.CharField(max_length=48, verbose_name=_('Label')) label = models.CharField(max_length=48, verbose_name=_('Label'))
default = models.CharField(max_length=128, blank=True, null=True, default = models.CharField(blank=True, max_length=128, null=True, help_text=_('Enter a string to be evaluated.'), verbose_name=_('Default'))
verbose_name=_('Default'),
help_text=_('Enter a string to be evaluated.'))
# TODO: Add enable_lookup boolean to allow users to switch the lookup on and # TODO: Add enable_lookup boolean to allow users to switch the lookup on and
# off without losing the lookup expression # off without losing the lookup expression
lookup = models.TextField(blank=True, null=True, lookup = models.TextField(blank=True, null=True, help_text=_('Enter a string to be evaluated that returns an iterable.'), verbose_name=_('Lookup'))
verbose_name=_('Lookup'),
help_text=_('Enter a string to be evaluated that returns an iterable.'))
validation = models.CharField(blank=True, choices=validation_choices(), max_length=64, verbose_name=_('Validation function name')) validation = models.CharField(blank=True, choices=validation_choices(), max_length=64, verbose_name=_('Validation function name'))
# TODO: Find a different way to let users know what models and functions are # TODO: Find a different way to let users know what models and functions are
# available now that we removed these from the help_text # available now that we removed these from the help_text
@@ -55,7 +51,7 @@ class DocumentMetadata(models.Model):
""" """
document = models.ForeignKey(Document, related_name='metadata', verbose_name=_('Document')) document = models.ForeignKey(Document, related_name='metadata', verbose_name=_('Document'))
metadata_type = models.ForeignKey(MetadataType, verbose_name=_('Type')) metadata_type = models.ForeignKey(MetadataType, verbose_name=_('Type'))
value = models.CharField(max_length=255, blank=True, null=True, verbose_name=_('Value'), db_index=True) value = models.CharField(blank=True, db_index=True, max_length=255, null=True, verbose_name=_('Value'))
def __str__(self): def __str__(self):
return unicode(self.metadata_type) return unicode(self.metadata_type)

View File

@@ -1,7 +1,8 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import models, migrations from django.db import migrations
def move_content_from_documents_to_ocr_app(apps, schema_editor): def move_content_from_documents_to_ocr_app(apps, schema_editor):
DocumentPage = apps.get_model('documents', 'DocumentPage') DocumentPage = apps.get_model('documents', 'DocumentPage')

View File

@@ -22,7 +22,7 @@ class DocumentTypeSettings(models.Model):
@python_2_unicode_compatible @python_2_unicode_compatible
class DocumentVersionOCRError(models.Model): class DocumentVersionOCRError(models.Model):
document_version = models.ForeignKey(DocumentVersion, verbose_name=_('Document version')) document_version = models.ForeignKey(DocumentVersion, verbose_name=_('Document version'))
datetime_submitted = models.DateTimeField(verbose_name=_('Date time submitted'), auto_now=True, db_index=True) datetime_submitted = models.DateTimeField(auto_now=True, db_index=True, verbose_name=_('Date time submitted'))
result = models.TextField(blank=True, null=True, verbose_name=_('Result')) result = models.TextField(blank=True, null=True, verbose_name=_('Result'))
def __str__(self): def __str__(self):

View File

@@ -3,7 +3,7 @@ from __future__ import unicode_literals
from django.core.files.base import File from django.core.files.base import File
from django.test import TransactionTestCase from django.test import TransactionTestCase
from documents.models import Document, DocumentType from documents.models import DocumentType
from documents.test_models import TEST_SMALL_DOCUMENT_PATH, TEST_DOCUMENT_TYPE from documents.test_models import TEST_SMALL_DOCUMENT_PATH, TEST_DOCUMENT_TYPE

View File

@@ -15,7 +15,7 @@ from documents.models import Document, DocumentType, DocumentVersion
from permissions import Permission from permissions import Permission
from .forms import DocumentContentForm from .forms import DocumentContentForm
from .models import DocumentTypeSettings, DocumentVersionOCRError from .models import DocumentVersionOCRError
from .permissions import ( from .permissions import (
permission_ocr_content_view, permission_ocr_document, permission_ocr_content_view, permission_ocr_document,
permission_ocr_document_delete, permission_document_type_ocr_setup permission_ocr_document_delete, permission_document_type_ocr_setup

View File

@@ -1,7 +1,5 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from common import ( from common import (

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import models, migrations from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@@ -1,16 +1,12 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django.conf import settings
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.core.files import File
from django.core.urlresolvers import reverse
from django.test.client import Client
from django.test import TestCase from django.test import TestCase
from .classes import Permission from .classes import Permission
from .models import Role, StoredPermission from .models import Role
from .permissions import permission_role_view from .permissions import permission_role_view

View File

@@ -2,7 +2,6 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations
import sources.models
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import models, migrations from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import models, migrations from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import models, migrations from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):

View File

@@ -108,11 +108,11 @@ class StagingFolderSource(InteractiveSource):
is_interactive = True is_interactive = True
source_type = SOURCE_CHOICE_STAGING source_type = SOURCE_CHOICE_STAGING
folder_path = models.CharField(max_length=255, verbose_name=_('Folder path'), help_text=_('Server side filesystem path.')) folder_path = models.CharField(max_length=255, help_text=_('Server side filesystem path.'), verbose_name=_('Folder path'))
preview_width = models.IntegerField(verbose_name=_('Preview width'), help_text=_('Width value to be passed to the converter backend.')) preview_width = models.IntegerField(help_text=_('Width value to be passed to the converter backend.'), verbose_name=_('Preview width'))
preview_height = models.IntegerField(blank=True, null=True, verbose_name=_('Preview height'), help_text=_('Height value to be passed to the converter backend.')) preview_height = models.IntegerField(blank=True, null=True, help_text=_('Height value to be passed to the converter backend.'), verbose_name=_('Preview height'))
uncompress = models.CharField(max_length=1, choices=SOURCE_INTERACTIVE_UNCOMPRESS_CHOICES, verbose_name=_('Uncompress'), help_text=_('Whether to expand or not compressed archives.')) uncompress = models.CharField(choices=SOURCE_INTERACTIVE_UNCOMPRESS_CHOICES, max_length=1, help_text=_('Whether to expand or not compressed archives.'), verbose_name=_('Uncompress'))
delete_after_upload = models.BooleanField(default=True, verbose_name=_('Delete after upload'), help_text=_('Delete the file after is has been successfully uploaded.')) delete_after_upload = models.BooleanField(default=True, help_text=_('Delete the file after is has been successfully uploaded.'), verbose_name=_('Delete after upload'))
def get_preview_size(self): def get_preview_size(self):
dimensions = [] dimensions = []
@@ -155,7 +155,7 @@ class WebFormSource(InteractiveSource):
source_type = SOURCE_CHOICE_WEB_FORM source_type = SOURCE_CHOICE_WEB_FORM
# TODO: unify uncompress as an InteractiveSource field # TODO: unify uncompress as an InteractiveSource field
uncompress = models.CharField(max_length=1, choices=SOURCE_INTERACTIVE_UNCOMPRESS_CHOICES, verbose_name=_('Uncompress'), help_text=_('Whether to expand or not compressed archives.')) uncompress = models.CharField(choices=SOURCE_INTERACTIVE_UNCOMPRESS_CHOICES, help_text=_('Whether to expand or not compressed archives.'), max_length=1, verbose_name=_('Uncompress'))
# Default path # Default path
def get_upload_file_object(self, form_data): def get_upload_file_object(self, form_data):
@@ -175,9 +175,9 @@ class OutOfProcessSource(Source):
class IntervalBaseModel(OutOfProcessSource): class IntervalBaseModel(OutOfProcessSource):
interval = models.PositiveIntegerField(default=DEFAULT_INTERVAL, verbose_name=_('Interval'), help_text=_('Interval in seconds between checks for new documents.')) interval = models.PositiveIntegerField(default=DEFAULT_INTERVAL, help_text=_('Interval in seconds between checks for new documents.'), verbose_name=_('Interval'))
document_type = models.ForeignKey(DocumentType, verbose_name=_('Document type'), help_text=_('Assign a document type to documents uploaded from this source.')) document_type = models.ForeignKey(DocumentType, help_text=_('Assign a document type to documents uploaded from this source.'), verbose_name=_('Document type'))
uncompress = models.CharField(max_length=1, choices=SOURCE_UNCOMPRESS_CHOICES, verbose_name=_('Uncompress'), help_text=_('Whether to expand or not, compressed archives.')) uncompress = models.CharField(choices=SOURCE_UNCOMPRESS_CHOICES, help_text=_('Whether to expand or not, compressed archives.'), max_length=1, verbose_name=_('Uncompress'))
def _get_periodic_task_name(self, pk=None): def _get_periodic_task_name(self, pk=None):
return 'check_interval_source-%i' % (pk or self.pk) return 'check_interval_source-%i' % (pk or self.pk)
@@ -223,7 +223,7 @@ class IntervalBaseModel(OutOfProcessSource):
class EmailBaseModel(IntervalBaseModel): class EmailBaseModel(IntervalBaseModel):
host = models.CharField(max_length=128, verbose_name=_('Host')) host = models.CharField(max_length=128, verbose_name=_('Host'))
ssl = models.BooleanField(default=True, verbose_name=_('SSL')) ssl = models.BooleanField(default=True, verbose_name=_('SSL'))
port = models.PositiveIntegerField(blank=True, null=True, verbose_name=_('Port'), help_text=_('Typical choices are 110 for POP3, 995 for POP3 over SSL, 143 for IMAP, 993 for IMAP over SSL.')) port = models.PositiveIntegerField(blank=True, null=True, help_text=_('Typical choices are 110 for POP3, 995 for POP3 over SSL, 143 for IMAP, 993 for IMAP over SSL.'), verbose_name=_('Port'))
username = models.CharField(max_length=96, verbose_name=_('Username')) username = models.CharField(max_length=96, verbose_name=_('Username'))
password = models.CharField(max_length=96, verbose_name=_('Password')) password = models.CharField(max_length=96, verbose_name=_('Password'))
@@ -302,7 +302,7 @@ class POP3Email(EmailBaseModel):
class IMAPEmail(EmailBaseModel): class IMAPEmail(EmailBaseModel):
source_type = SOURCE_CHOICE_EMAIL_IMAP source_type = SOURCE_CHOICE_EMAIL_IMAP
mailbox = models.CharField(max_length=64, default=DEFAULT_IMAP_MAILBOX, verbose_name=_('Mailbox'), help_text=_('Mail from which to check for messages with attached documents.')) mailbox = models.CharField(default=DEFAULT_IMAP_MAILBOX, help_text=_('Mail from which to check for messages with attached documents.'), max_length=64, verbose_name=_('Mailbox'))
# http://www.doughellmann.com/PyMOTW/imaplib/ # http://www.doughellmann.com/PyMOTW/imaplib/
def check_source(self): def check_source(self):
@@ -341,7 +341,7 @@ class IMAPEmail(EmailBaseModel):
class WatchFolderSource(IntervalBaseModel): class WatchFolderSource(IntervalBaseModel):
source_type = SOURCE_CHOICE_WATCH source_type = SOURCE_CHOICE_WATCH
folder_path = models.CharField(max_length=255, verbose_name=_('Folder path'), help_text=_('Server side filesystem path.')) folder_path = models.CharField(help_text=_('Server side filesystem path.'), max_length=255, verbose_name=_('Folder path'))
def check_source(self): def check_source(self):
# Force self.folder_path to unicode to avoid os.listdir returning # Force self.folder_path to unicode to avoid os.listdir returning

View File

@@ -1,7 +1,6 @@
import logging import logging
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.files import File
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from mayan.celery import app from mayan.celery import app

View File

@@ -4,23 +4,18 @@ import shutil
import tempfile import tempfile
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
from django.test.client import Client from django.test.client import Client
from django.test import TestCase from django.test import TestCase
from documents.models import Document, DocumentType from documents.models import Document, DocumentType
from sources.literals import SOURCE_CHOICE_WEB_FORM
from sources.models import WebFormSource
from documents.test_models import ( from documents.test_models import (
TEST_ADMIN_PASSWORD, TEST_ADMIN_USERNAME, TEST_ADMIN_EMAIL, TEST_ADMIN_PASSWORD, TEST_ADMIN_USERNAME, TEST_ADMIN_EMAIL,
TEST_DOCUMENT_PATH, TEST_SMALL_DOCUMENT_PATH, TEST_DOCUMENT_TYPE, TEST_NON_ASCII_DOCUMENT_FILENAME,
TEST_DOCUMENT_DESCRIPTION, TEST_DOCUMENT_TYPE, TEST_NON_ASCII_DOCUMENT_PATH, TEST_NON_ASCII_COMPRESSED_DOCUMENT_PATH
TEST_NON_ASCII_DOCUMENT_FILENAME, TEST_NON_ASCII_DOCUMENT_PATH,
TEST_NON_ASCII_COMPRESSED_DOCUMENT_PATH
) )
from .literals import SOURCE_UNCOMPRESS_CHOICE_N, SOURCE_UNCOMPRESS_CHOICE_Y from .literals import SOURCE_UNCOMPRESS_CHOICE_Y
from .models import WatchFolderSource from .models import WatchFolderSource

View File

@@ -1,8 +1,5 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import shutil
import tempfile
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.test.client import Client from django.test.client import Client
@@ -16,13 +13,8 @@ from documents.test_models import (
TEST_ADMIN_PASSWORD, TEST_ADMIN_USERNAME, TEST_ADMIN_EMAIL, TEST_ADMIN_PASSWORD, TEST_ADMIN_USERNAME, TEST_ADMIN_EMAIL,
TEST_DOCUMENT_PATH, TEST_SMALL_DOCUMENT_PATH, TEST_DOCUMENT_PATH, TEST_SMALL_DOCUMENT_PATH,
TEST_DOCUMENT_DESCRIPTION, TEST_DOCUMENT_TYPE, TEST_DOCUMENT_DESCRIPTION, TEST_DOCUMENT_TYPE,
TEST_NON_ASCII_DOCUMENT_FILENAME, TEST_NON_ASCII_DOCUMENT_PATH,
TEST_NON_ASCII_COMPRESSED_DOCUMENT_PATH
) )
from .literals import SOURCE_UNCOMPRESS_CHOICE_N, SOURCE_UNCOMPRESS_CHOICE_Y
from .models import WatchFolderSource
class UploadDocumentTestCase(TestCase): class UploadDocumentTestCase(TestCase):
""" """

View File

@@ -11,8 +11,8 @@ from .literals import COLOR_CHOICES, COLOR_CODES
@python_2_unicode_compatible @python_2_unicode_compatible
class Tag(models.Model): class Tag(models.Model):
label = models.CharField(max_length=128, verbose_name=_('Label'), unique=True, db_index=True) label = models.CharField(db_index=True, max_length=128, unique=True, verbose_name=_('Label'))
color = models.CharField(max_length=3, choices=COLOR_CHOICES, verbose_name=_('Color')) color = models.CharField(choices=COLOR_CHOICES, max_length=3, verbose_name=_('Color'))
documents = models.ManyToManyField(Document, related_name='tags', verbose_name=_('Documents')) documents = models.ManyToManyField(Document, related_name='tags', verbose_name=_('Documents'))
class Meta: class Meta:

View File

@@ -1,7 +1,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django import forms from django import forms
from django.contrib.auth.models import User, Group from django.contrib.auth.models import User
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _

View File

@@ -6,11 +6,11 @@ from permissions import PermissionNamespace
namespace = PermissionNamespace('user_management', _('User management')) namespace = PermissionNamespace('user_management', _('User management'))
permission_user_create = namespace.add_permission(name='user_create', label=_('Create new users'))
permission_user_edit = namespace.add_permission(name='user_edit', label=_('Edit existing users'))
permission_user_view = namespace.add_permission(name='user_view', label=_('View existing users'))
permission_user_delete = namespace.add_permission(name='user_delete', label=_('Delete existing users'))
permission_group_create = namespace.add_permission(name='group_create', label=_('Create new groups')) permission_group_create = namespace.add_permission(name='group_create', label=_('Create new groups'))
permission_group_delete = namespace.add_permission(name='group_delete', label=_('Delete existing groups'))
permission_group_edit = namespace.add_permission(name='group_edit', label=_('Edit existing groups')) permission_group_edit = namespace.add_permission(name='group_edit', label=_('Edit existing groups'))
permission_group_view = namespace.add_permission(name='group_view', label=_('View existing groups')) permission_group_view = namespace.add_permission(name='group_view', label=_('View existing groups'))
permission_group_delete = namespace.add_permission(name='group_delete', label=_('Delete existing groups')) permission_user_create = namespace.add_permission(name='user_create', label=_('Create new users'))
permission_user_delete = namespace.add_permission(name='user_delete', label=_('Delete existing users'))
permission_user_edit = namespace.add_permission(name='user_edit', label=_('Edit existing users'))
permission_user_view = namespace.add_permission(name='user_view', label=_('View existing users'))

View File

@@ -13,6 +13,13 @@ from .views import (
urlpatterns = patterns( urlpatterns = patterns(
'user_management.views', 'user_management.views',
url(r'^group/list/$', GroupListView.as_view(), name='group_list'),
url(r'^group/add/$', GroupCreateView.as_view(), name='group_add'),
url(r'^group/(?P<pk>\d+)/edit/$', GroupEditView.as_view(), name='group_edit'),
url(r'^group/(?P<group_id>\d+)/delete/$', 'group_delete', name='group_delete'),
url(r'^group/multiple/delete/$', 'group_multiple_delete', name='group_multiple_delete'),
url(r'^group/(?P<pk>\d+)/members/$', GroupMembersView.as_view(), name='group_members'),
url(r'^user/list/$', UserListView.as_view(), name='user_list'), url(r'^user/list/$', UserListView.as_view(), name='user_list'),
url(r'^user/add/$', 'user_add', name='user_add'), url(r'^user/add/$', 'user_add', name='user_add'),
url(r'^user/(?P<user_id>\d+)/edit/$', 'user_edit', name='user_edit'), url(r'^user/(?P<user_id>\d+)/edit/$', 'user_edit', name='user_edit'),
@@ -21,13 +28,6 @@ urlpatterns = patterns(
url(r'^user/(?P<user_id>\d+)/set_password/$', 'user_set_password', name='user_set_password'), url(r'^user/(?P<user_id>\d+)/set_password/$', 'user_set_password', name='user_set_password'),
url(r'^user/multiple/set_password/$', 'user_multiple_set_password', name='user_multiple_set_password'), url(r'^user/multiple/set_password/$', 'user_multiple_set_password', name='user_multiple_set_password'),
url(r'^user/(?P<pk>\d+)/groups/$', UserGroupsView.as_view(), name='user_groups'), url(r'^user/(?P<pk>\d+)/groups/$', UserGroupsView.as_view(), name='user_groups'),
url(r'^group/list/$', GroupListView.as_view(), name='group_list'),
url(r'^group/add/$', GroupCreateView.as_view(), name='group_add'),
url(r'^group/(?P<pk>\d+)/edit/$', GroupEditView.as_view(), name='group_edit'),
url(r'^group/(?P<group_id>\d+)/delete/$', 'group_delete', name='group_delete'),
url(r'^group/multiple/delete/$', 'group_multiple_delete', name='group_multiple_delete'),
url(r'^group/(?P<pk>\d+)/members/$', GroupMembersView.as_view(), name='group_members'),
) )
api_urls = patterns( api_urls = patterns(