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_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_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')

View File

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

View File

@@ -1,24 +1,14 @@
from __future__ import absolute_import, unicode_literals
from django.conf import settings
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
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 documents.models import Document, DocumentType
from documents.permissions import permission_document_view
from documents.test_models import (
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 documents.test_models import TEST_SMALL_DOCUMENT_PATH, TEST_DOCUMENT_TYPE
from permissions.classes import Permission
from permissions.models import Role
@@ -128,7 +118,6 @@ class PermissionTestCase(TestCase):
self.assertTrue(self.document_2 in result)
self.assertTrue(self.document_3 not in result)
def test_filtering_with_inherited_permissions_and_local_acl(self):
self.group.user_set.add(self.user)
self.role.permissions.add(permission_document_view.stored_permission)

View File

@@ -24,7 +24,6 @@ from .permissions import (
)
class CheckoutsApp(MayanAppConfig):
name = 'checkouts'
verbose_name = _('Checkouts')
@@ -34,18 +33,10 @@ class CheckoutsApp(MayanAppConfig):
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('checkout_info', lambda document: DocumentCheckout.objects.document_checkout_info(document))
Document.add_to_class('checkout_state', lambda document: DocumentCheckout.objects.document_checkout_state(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'}
},
})
Document.add_to_class('is_checked_out', lambda document: DocumentCheckout.objects.is_document_checked_out(document))
ModelPermission.register(
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_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'])

View File

@@ -4,7 +4,7 @@ from django.utils.translation import ugettext_lazy as _
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_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'))

View File

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

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
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):

View File

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

View File

@@ -6,6 +6,6 @@ from permissions import PermissionNamespace
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_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'):
tzname = request.session.get(settings.TIMEZONE_SESSION_KEY)
else:
tzname = HttpRequest.COOKIES.get(settings.TIMEZONE_COOKIE_NAME)
tzname = request.COOKIES.get(settings.TIMEZONE_COOKIE_NAME)
if tzname:
timezone.activate(pytz.timezone(tzname))

View File

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

View File

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

View File

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

View File

@@ -6,7 +6,6 @@ import tempfile
import types
from django.conf import settings
from django.contrib.auth.models import User
from django.utils.datastructures import MultiValueDict
from django.utils.http import urlquote as django_urlquote
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.forms.util import flatatt
from django.utils.datastructures import MultiValueDict, MergeDict
from django.utils.encoding import force_unicode, force_text
from django.utils.html import conditional_escape, format_html
from django.utils.safestring import mark_safe

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -3,7 +3,7 @@ from __future__ import unicode_literals
from django.core.files.base import File
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 metadata.models import MetadataType, DocumentTypeMetadataType

View File

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

View File

@@ -23,15 +23,12 @@ class DocumentVersionSignature(models.Model):
"""
Model that describes a document version signature properties
"""
document_version = models.ForeignKey(DocumentVersion, verbose_name=_('Document version'), editable=False)
signature_file = models.FileField(blank=True, null=True, upload_to=upload_to, storage=storage_backend, verbose_name=_('Signature file'))
document_version = models.ForeignKey(DocumentVersion, editable=False, verbose_name=_('Document version'))
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'))
objects = DocumentVersionSignatureManager()
def delete_detached_signature_file(self):
self.signature_file.storage.delete(self.signature_file.path)
def check_for_embedded_signature(self):
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.save()
def delete_detached_signature_file(self):
self.signature_file.storage.delete(self.signature_file.path)
class Meta:
verbose_name = _('Document version signature')
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.test import TestCase
from documents.models import Document, DocumentType
from documents.test_models import TEST_DOCUMENT_TYPE
from documents.models import DocumentType
from documents.test_models import TEST_DOCUMENT_PATH, TEST_DOCUMENT_TYPE
from django_gpg.literals import SIGNATURE_STATE_VALID
from django_gpg.runtime import gpg
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_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')

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -3,13 +3,9 @@
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.core.files import File
from django.core.urlresolvers import reverse
from django.test.client import Client
from django.test import TestCase
from rest_framework import status
@@ -18,11 +14,9 @@ from rest_framework.test import APIClient
from .models import Document, DocumentType
from .test_models import (
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
TEST_SMALL_DOCUMENT_FILENAME, TEST_DOCUMENT_PATH,
TEST_SMALL_DOCUMENT_PATH,
TEST_DOCUMENT_TYPE
)

View File

@@ -1,20 +1,12 @@
# -*- coding: utf-8 -*-
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.core.files import File
from django.core.urlresolvers import reverse
from django.test.client import Client
from django.test import TestCase
from rest_framework import status
from rest_framework.test import APIClient
from .models import DeletedDocument, Document, DocumentType
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_COMPRESSED_DOCUMENT_FILENAME = 'I18N_title_áéíóúüñÑ.png.zip'
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_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)

View File

@@ -2,27 +2,16 @@
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.core.files import File
from django.core.urlresolvers import reverse
from django.test.client import Client
from django.test import TestCase
from rest_framework import status
from rest_framework.test import APIClient
from .models import DeletedDocument, Document, DocumentType
from .test_models import (
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
TEST_SMALL_DOCUMENT_PATH, TEST_DOCUMENT_TYPE
)
@@ -45,7 +34,7 @@ class DocumentsViewsFunctionalTestCase(TestCase):
self.assertTrue(logged_in)
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')
def tearDown(self):

View File

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

View File

@@ -2,15 +2,13 @@ from __future__ import unicode_literals
from django.contrib.auth.models import User
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 documents.models import Document, DocumentType
from documents.models import DocumentType
from documents.search import document_search
from documents.test_models import (
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 import TestCase
from documents.models import Document, DocumentType
from documents.models import DocumentType
from documents.search import document_search
from documents.test_models import (
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.core.exceptions import PermissionDenied
from django.db.models.loading import get_model
from django.http import Http404
from django.shortcuts import get_object_or_404, render_to_response
from django.template import RequestContext
from django.shortcuts import get_object_or_404
from django.utils.translation import ugettext_lazy as _
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,
menu_sidebar, menu_multi_item
)
from common.utils import encapsulate
from documents.models import Document
from navigation import CombinedSource, SourceColumn
from rest_api.classes import APIEndPoint

View File

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

View File

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

View File

@@ -11,9 +11,9 @@ from documents.models import Document
@python_2_unicode_compatible
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'))
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'))
def __str__(self):
@@ -23,7 +23,7 @@ class Folder(models.Model):
return reverse('folders:folder_view', args=[self.pk])
class Meta:
unique_together = ('label', 'user')
ordering = ('label',)
unique_together = ('label', 'user')
verbose_name = _('Folder')
verbose_name_plural = _('Folders')

View File

@@ -10,7 +10,7 @@ from django.test import TestCase
from authentication.test_views import (
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 .models import Folder
@@ -35,7 +35,6 @@ class FolderTestCase(TestCase):
folder.delete()
def test_addition_of_documents(self):
user = User.objects.all()[0]
folder = Folder.objects.create(label='test', user=self.user)
folder.documents.add(self.document)
@@ -44,7 +43,6 @@ class FolderTestCase(TestCase):
folder.delete()
def test_addition_and_deletion_of_documents(self):
user = User.objects.all()[0]
folder = Folder.objects.create(label='test', user=self.user)
folder.documents.add(self.document)

View File

@@ -4,7 +4,7 @@ import logging
from django.conf import settings
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.http import HttpResponseRedirect
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 permissions import Permission
from .forms import FolderForm, FolderListForm
from .forms import FolderListForm
from .models import Folder
from .permissions import (
permission_folder_add_document, permission_folder_create,

View File

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

View File

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

View File

@@ -15,7 +15,7 @@ from .literals import (
@python_2_unicode_compatible
class SmartLink(models.Model):
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'))
document_types = models.ManyToManyField(DocumentType, verbose_name=_('Document types'))
@@ -31,9 +31,6 @@ class SmartLink(models.Model):
else:
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):
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.'))
@@ -57,6 +54,9 @@ class SmartLink(models.Model):
else:
return Document.objects.none()
def resolve_for(self, document):
return ResolvedSmartLink(smart_link=self, queryset=self.get_linked_document_for(document))
class Meta:
verbose_name = _('Smart link')
verbose_name_plural = _('Smart links')
@@ -70,11 +70,11 @@ class ResolvedSmartLink(SmartLink):
@python_2_unicode_compatible
class SmartLinkCondition(models.Model):
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.'))
foreign_document_data = models.CharField(max_length=128, verbose_name=_('Foreign document attribute'), help_text=_('This represents the metadata of all other documents.'))
operator = models.CharField(max_length=16, choices=OPERATOR_CHOICES)
expression = models.TextField(verbose_name=_('Expression'), help_text=_('This expression will be evaluated against the current document.'))
negated = models.BooleanField(default=False, verbose_name=_('Negated'), help_text=_('Inverts the logic of the operator.'))
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(help_text=_('This represents the metadata of all other documents.'), max_length=128, verbose_name=_('Foreign document attribute'))
operator = models.CharField(choices=OPERATOR_CHOICES, max_length=16)
expression = models.TextField(help_text=_('This expression will be evaluated against the current document.'), verbose_name=_('Expression'))
negated = models.BooleanField(default=False, help_text=_('Inverts the logic of the operator.'), verbose_name=_('Negated'))
enabled = models.BooleanField(default=True, verbose_name=_('Enabled'))
def __str__(self):

View File

@@ -85,7 +85,7 @@ class ResolvedSmartLinkView(DocumentListView):
queryset = Document.objects.none()
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

View File

@@ -10,9 +10,9 @@ from .settings import DEFAULT_LOCK_TIMEOUT
@python_2_unicode_compatible
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'))
name = models.CharField(max_length=64, verbose_name=_('Name'), unique=True)
name = models.CharField(max_length=64, unique=True, verbose_name=_('Name'))
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_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(
model=Document, permissions=(
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__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_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_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 .models import MetadataType
from .settings import (
setting_available_functions, setting_available_models,
setting_available_validators
)
from .settings import setting_available_functions, setting_available_models
class MetadataForm(forms.Form):

View File

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

View File

@@ -20,16 +20,12 @@ class MetadataType(models.Model):
"""
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'))
default = models.CharField(max_length=128, blank=True, null=True,
verbose_name=_('Default'),
help_text=_('Enter a string to be evaluated.'))
default = models.CharField(blank=True, max_length=128, null=True, help_text=_('Enter a string to be evaluated.'), verbose_name=_('Default'))
# TODO: Add enable_lookup boolean to allow users to switch the lookup on and
# off without losing the lookup expression
lookup = models.TextField(blank=True, null=True,
verbose_name=_('Lookup'),
help_text=_('Enter a string to be evaluated that returns an iterable.'))
lookup = models.TextField(blank=True, null=True, help_text=_('Enter a string to be evaluated that returns an iterable.'), verbose_name=_('Lookup'))
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
# 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'))
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):
return unicode(self.metadata_type)

View File

@@ -1,7 +1,8 @@
# -*- coding: utf-8 -*-
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):
DocumentPage = apps.get_model('documents', 'DocumentPage')

View File

@@ -22,7 +22,7 @@ class DocumentTypeSettings(models.Model):
@python_2_unicode_compatible
class DocumentVersionOCRError(models.Model):
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'))
def __str__(self):

View File

@@ -3,7 +3,7 @@ from __future__ import unicode_literals
from django.core.files.base import File
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

View File

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

View File

@@ -1,7 +1,5 @@
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 common import (

View File

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

View File

@@ -1,16 +1,12 @@
from __future__ import unicode_literals
from django.conf import settings
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
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 .classes import Permission
from .models import Role, StoredPermission
from .models import Role
from .permissions import permission_role_view

View File

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

View File

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

View File

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

View File

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

View File

@@ -108,11 +108,11 @@ class StagingFolderSource(InteractiveSource):
is_interactive = True
source_type = SOURCE_CHOICE_STAGING
folder_path = models.CharField(max_length=255, verbose_name=_('Folder path'), help_text=_('Server side filesystem path.'))
preview_width = models.IntegerField(verbose_name=_('Preview width'), help_text=_('Width value to be passed to the converter backend.'))
preview_height = models.IntegerField(blank=True, null=True, verbose_name=_('Preview height'), help_text=_('Height value to be passed to the converter backend.'))
uncompress = models.CharField(max_length=1, choices=SOURCE_INTERACTIVE_UNCOMPRESS_CHOICES, verbose_name=_('Uncompress'), help_text=_('Whether to expand or not compressed archives.'))
delete_after_upload = models.BooleanField(default=True, verbose_name=_('Delete after upload'), help_text=_('Delete the file after is has been successfully uploaded.'))
folder_path = models.CharField(max_length=255, help_text=_('Server side filesystem path.'), verbose_name=_('Folder path'))
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, help_text=_('Height value to be passed to the converter backend.'), verbose_name=_('Preview height'))
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, help_text=_('Delete the file after is has been successfully uploaded.'), verbose_name=_('Delete after upload'))
def get_preview_size(self):
dimensions = []
@@ -155,7 +155,7 @@ class WebFormSource(InteractiveSource):
source_type = SOURCE_CHOICE_WEB_FORM
# 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
def get_upload_file_object(self, form_data):
@@ -175,9 +175,9 @@ class OutOfProcessSource(Source):
class IntervalBaseModel(OutOfProcessSource):
interval = models.PositiveIntegerField(default=DEFAULT_INTERVAL, verbose_name=_('Interval'), help_text=_('Interval in seconds between checks for new documents.'))
document_type = models.ForeignKey(DocumentType, verbose_name=_('Document type'), help_text=_('Assign a document type to documents uploaded from this source.'))
uncompress = models.CharField(max_length=1, choices=SOURCE_UNCOMPRESS_CHOICES, verbose_name=_('Uncompress'), help_text=_('Whether to expand or not, compressed archives.'))
interval = models.PositiveIntegerField(default=DEFAULT_INTERVAL, help_text=_('Interval in seconds between checks for new documents.'), verbose_name=_('Interval'))
document_type = models.ForeignKey(DocumentType, help_text=_('Assign a document type to documents uploaded from this source.'), verbose_name=_('Document type'))
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):
return 'check_interval_source-%i' % (pk or self.pk)
@@ -223,7 +223,7 @@ class IntervalBaseModel(OutOfProcessSource):
class EmailBaseModel(IntervalBaseModel):
host = models.CharField(max_length=128, verbose_name=_('Host'))
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'))
password = models.CharField(max_length=96, verbose_name=_('Password'))
@@ -302,7 +302,7 @@ class POP3Email(EmailBaseModel):
class IMAPEmail(EmailBaseModel):
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/
def check_source(self):
@@ -341,7 +341,7 @@ class IMAPEmail(EmailBaseModel):
class WatchFolderSource(IntervalBaseModel):
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):
# Force self.folder_path to unicode to avoid os.listdir returning

View File

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

View File

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

View File

@@ -1,8 +1,5 @@
from __future__ import unicode_literals
import shutil
import tempfile
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
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_DOCUMENT_PATH, TEST_SMALL_DOCUMENT_PATH,
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):
"""

View File

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

View File

@@ -1,7 +1,7 @@
from __future__ import unicode_literals
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 _

View File

@@ -6,11 +6,11 @@ from permissions import PermissionNamespace
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_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_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(
'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/add/$', 'user_add', name='user_add'),
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/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'^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(