http://www.github.com/rosarior/mayan/
diff --git a/apps/main/tests.py b/apps/main/tests.py
deleted file mode 100644
index 2247054b35..0000000000
--- a/apps/main/tests.py
+++ /dev/null
@@ -1,23 +0,0 @@
-"""
-This file demonstrates two different styles of tests (one doctest and one
-unittest). These will both pass when you run "manage.py test".
-
-Replace these with more appropriate tests for your application.
-"""
-
-from django.test import TestCase
-
-class SimpleTest(TestCase):
- def test_basic_addition(self):
- """
- Tests that 1 + 1 always equals 2.
- """
- self.failUnlessEqual(1 + 1, 2)
-
-__test__ = {"doctest": """
-Another way to test that 1 + 1 is equal to 2.
-
->>> 1 + 1 == 2
-True
-"""}
-
diff --git a/apps/main/views.py b/apps/main/views.py
index f4ff678e46..12aabda9e5 100644
--- a/apps/main/views.py
+++ b/apps/main/views.py
@@ -1,3 +1,5 @@
+from __future__ import absolute_import
+
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.utils.translation import ugettext_lazy as _
@@ -7,10 +9,10 @@ from django.core.urlresolvers import reverse
from documents.statistics import get_statistics as documents_statistics
from ocr.statistics import get_statistics as ocr_statistics
-from permissions.api import check_permissions
+from permissions.models import Permission
-from main.api import diagnostics, tools
-from main.conf.settings import DISABLE_HOME_VIEW
+from .api import diagnostics, tools
+from .conf.settings import DISABLE_HOME_VIEW
def home(request):
@@ -31,7 +33,7 @@ def maintenance_menu(request):
for link in values['links']:
try:
permissions = link.get('permissions', [])
- check_permissions(request.user, permissions)
+ Permission.objects.check_permissions(request.user, permissions)
user_tools[namespace]['links'].append(link)
except PermissionDenied:
pass
@@ -44,15 +46,18 @@ def maintenance_menu(request):
def statistics(request):
- blocks = []
- blocks.append(documents_statistics())
- blocks.append(ocr_statistics())
+ if request.user.is_superuser or request.user.is_staff:
+ blocks = []
+ blocks.append(documents_statistics())
+ blocks.append(ocr_statistics())
- return render_to_response('statistics.html', {
- 'blocks': blocks,
- 'title': _(u'Statistics')
- },
- context_instance=RequestContext(request))
+ return render_to_response('statistics.html', {
+ 'blocks': blocks,
+ 'title': _(u'Statistics')
+ },
+ context_instance=RequestContext(request))
+ else:
+ raise PermissionDenied
def diagnostics_view(request):
diff --git a/apps/metadata/__init__.py b/apps/metadata/__init__.py
index b61556e268..9f7ea6bb6e 100644
--- a/apps/metadata/__init__.py
+++ b/apps/metadata/__init__.py
@@ -1,76 +1,52 @@
+from __future__ import absolute_import
+
from django.utils.translation import ugettext_lazy as _
-from navigation.api import register_links, register_multi_item_links, \
- register_sidebar_template
-from permissions.api import register_permission, set_namespace_title
+from navigation.api import (register_links, register_multi_item_links,
+ register_sidebar_template)
from documents.models import Document, DocumentType
-from documents.literals import PERMISSION_DOCUMENT_TYPE_EDIT
+from documents.permissions import PERMISSION_DOCUMENT_TYPE_EDIT
from project_setup.api import register_setup
+from acls.api import class_permissions
-from metadata.models import MetadataType, MetadataSet
-
-PERMISSION_METADATA_DOCUMENT_EDIT = {'namespace': 'metadata', 'name': u'metadata_document_edit', 'label': _(u'Edit a document\'s metadata')}
-PERMISSION_METADATA_DOCUMENT_ADD = {'namespace': 'metadata', 'name': u'metadata_document_add', 'label': _(u'Add metadata to a document')}
-PERMISSION_METADATA_DOCUMENT_REMOVE = {'namespace': 'metadata', 'name': u'metadata_document_remove', 'label': _(u'Remove metadata from a document')}
-PERMISSION_METADATA_DOCUMENT_VIEW = {'namespace': 'metadata', 'name': u'metadata_document_view', 'label': _(u'View metadata from a document')}
-
-PERMISSION_METADATA_TYPE_EDIT = {'namespace': 'metadata_setup', 'name': u'metadata_type_edit', 'label': _(u'Edit metadata types')}
-PERMISSION_METADATA_TYPE_CREATE = {'namespace': 'metadata_setup', 'name': u'metadata_type_create', 'label': _(u'Create new metadata types')}
-PERMISSION_METADATA_TYPE_DELETE = {'namespace': 'metadata_setup', 'name': u'metadata_type_delete', 'label': _(u'Delete metadata types')}
-PERMISSION_METADATA_TYPE_VIEW = {'namespace': 'metadata_setup', 'name': u'metadata_type_view', 'label': _(u'View metadata types')}
-
-PERMISSION_METADATA_SET_EDIT = {'namespace': 'metadata_setup', 'name': u'metadata_set_edit', 'label': _(u'Edit metadata sets')}
-PERMISSION_METADATA_SET_CREATE = {'namespace': 'metadata_setup', 'name': u'metadata_set_create', 'label': _(u'Create new metadata sets')}
-PERMISSION_METADATA_SET_DELETE = {'namespace': 'metadata_setup', 'name': u'metadata_set_delete', 'label': _(u'Delete metadata sets')}
-PERMISSION_METADATA_SET_VIEW = {'namespace': 'metadata_setup', 'name': u'metadata_set_view', 'label': _(u'View metadata sets')}
-
-set_namespace_title('metadata', _(u'Metadata'))
-register_permission(PERMISSION_METADATA_DOCUMENT_EDIT)
-register_permission(PERMISSION_METADATA_DOCUMENT_ADD)
-register_permission(PERMISSION_METADATA_DOCUMENT_REMOVE)
-register_permission(PERMISSION_METADATA_DOCUMENT_VIEW)
-
-set_namespace_title('metadata_setup', _(u'Metadata setup'))
-register_permission(PERMISSION_METADATA_TYPE_EDIT)
-register_permission(PERMISSION_METADATA_TYPE_CREATE)
-register_permission(PERMISSION_METADATA_TYPE_DELETE)
-register_permission(PERMISSION_METADATA_TYPE_VIEW)
-
-register_permission(PERMISSION_METADATA_SET_EDIT)
-register_permission(PERMISSION_METADATA_SET_CREATE)
-register_permission(PERMISSION_METADATA_SET_DELETE)
-register_permission(PERMISSION_METADATA_SET_VIEW)
+from .models import MetadataType, MetadataSet
+from .permissions import (PERMISSION_METADATA_DOCUMENT_EDIT,
+ PERMISSION_METADATA_DOCUMENT_ADD, PERMISSION_METADATA_DOCUMENT_REMOVE,
+ PERMISSION_METADATA_DOCUMENT_VIEW, PERMISSION_METADATA_TYPE_EDIT,
+ PERMISSION_METADATA_TYPE_CREATE, PERMISSION_METADATA_TYPE_DELETE,
+ PERMISSION_METADATA_TYPE_VIEW, PERMISSION_METADATA_SET_EDIT,
+ PERMISSION_METADATA_SET_CREATE, PERMISSION_METADATA_SET_DELETE,
+ PERMISSION_METADATA_SET_VIEW)
metadata_edit = {'text': _(u'edit metadata'), 'view': 'metadata_edit', 'args': 'object.pk', 'famfam': 'xhtml_go', 'permissions': [PERMISSION_METADATA_DOCUMENT_EDIT]}
-metadata_view = {'text': _(u'metadata'), 'view': 'metadata_view', 'args': 'object.pk', 'famfam': 'xhtml_go', 'permissions': [PERMISSION_METADATA_DOCUMENT_EDIT], 'children_view_regex': ['metadata']}
+metadata_view = {'text': _(u'metadata'), 'view': 'metadata_view', 'args': 'object.pk', 'famfam': 'xhtml_go', 'permissions': [PERMISSION_METADATA_DOCUMENT_VIEW], 'children_view_regex': ['metadata']}
metadata_multiple_edit = {'text': _(u'edit metadata'), 'view': 'metadata_multiple_edit', 'famfam': 'xhtml_go', 'permissions': [PERMISSION_METADATA_DOCUMENT_EDIT]}
metadata_add = {'text': _(u'add metadata'), 'view': 'metadata_add', 'args': 'object.pk', 'famfam': 'xhtml_add', 'permissions': [PERMISSION_METADATA_DOCUMENT_ADD]}
metadata_multiple_add = {'text': _(u'add metadata'), 'view': 'metadata_multiple_add', 'famfam': 'xhtml_add', 'permissions': [PERMISSION_METADATA_DOCUMENT_ADD]}
metadata_remove = {'text': _(u'remove metadata'), 'view': 'metadata_remove', 'args': 'object.pk', 'famfam': 'xhtml_delete', 'permissions': [PERMISSION_METADATA_DOCUMENT_REMOVE]}
metadata_multiple_remove = {'text': _(u'remove metadata'), 'view': 'metadata_multiple_remove', 'famfam': 'xhtml_delete', 'permissions': [PERMISSION_METADATA_DOCUMENT_REMOVE]}
-setup_metadata_type_list = {'text': _(u'metadata types'), 'view': 'setup_metadata_type_list', 'famfam': 'xhtml_go', 'icon': 'xhtml.png', 'permissions': [PERMISSION_METADATA_TYPE_VIEW], 'children_view_regex': ['setup_metadata_type']}
+setup_metadata_type_list = {'text': _(u'metadata types'), 'view': 'setup_metadata_type_list', 'famfam': 'xhtml_go', 'icon': 'xhtml.png', 'permissions': [PERMISSION_METADATA_TYPE_VIEW], 'children_view_regex': [r'setup_metadata_type']}
setup_metadata_type_edit = {'text': _(u'edit'), 'view': 'setup_metadata_type_edit', 'args': 'object.pk', 'famfam': 'xhtml', 'permissions': [PERMISSION_METADATA_TYPE_EDIT]}
setup_metadata_type_delete = {'text': _(u'delete'), 'view': 'setup_metadata_type_delete', 'args': 'object.pk', 'famfam': 'xhtml_delete', 'permissions': [PERMISSION_METADATA_TYPE_DELETE]}
setup_metadata_type_create = {'text': _(u'create new'), 'view': 'setup_metadata_type_create', 'famfam': 'xhtml_add', 'permissions': [PERMISSION_METADATA_TYPE_CREATE]}
-setup_metadata_set_list = {'text': _(u'metadata sets'), 'view': 'setup_metadata_set_list', 'famfam': 'table', 'icon': 'table.png', 'permissions': [PERMISSION_METADATA_SET_VIEW], 'children_view_regex': ['setup_metadata_set']}
+setup_metadata_set_list = {'text': _(u'metadata sets'), 'view': 'setup_metadata_set_list', 'famfam': 'table', 'icon': 'table.png', 'permissions': [PERMISSION_METADATA_SET_VIEW], 'children_view_regex': [r'setup_metadata_set']}
setup_metadata_set_edit = {'text': _(u'edit'), 'view': 'setup_metadata_set_edit', 'args': 'object.pk', 'famfam': 'table_edit', 'permissions': [PERMISSION_METADATA_SET_EDIT]}
setup_metadata_set_delete = {'text': _(u'delete'), 'view': 'setup_metadata_set_delete', 'args': 'object.pk', 'famfam': 'table_delete', 'permissions': [PERMISSION_METADATA_SET_DELETE]}
setup_metadata_set_create = {'text': _(u'create new'), 'view': 'setup_metadata_set_create', 'famfam': 'table_add', 'permissions': [PERMISSION_METADATA_SET_CREATE]}
setup_document_type_metadata = {'text': _(u'default metadata'), 'view': 'setup_document_type_metadata', 'args': 'document_type.pk', 'famfam': 'xhtml', 'permissions': [PERMISSION_DOCUMENT_TYPE_EDIT]}
-#register_links(Document, [metadata_add, metadata_edit, metadata_remove])
register_links(['metadata_add', 'metadata_edit', 'metadata_remove', 'metadata_view'], [metadata_add, metadata_edit, metadata_remove], menu_name='sidebar')
-register_links(Document, [metadata_view], menu_name='form_header') #, metadata_edit, metadata_remove])
+register_links(Document, [metadata_view], menu_name='form_header')
register_multi_item_links(['document_find_duplicates', 'folder_view', 'index_instance_list', 'document_type_document_list', 'search', 'results', 'document_group_view', 'document_list', 'document_list_recent'], [metadata_multiple_add, metadata_multiple_edit, metadata_multiple_remove])
register_links(MetadataType, [setup_metadata_type_edit, setup_metadata_type_delete])
-register_links(['setup_metadata_type_delete', 'setup_metadata_type_edit', 'setup_metadata_type_list', 'setup_metadata_type_create'], [setup_metadata_type_list, setup_metadata_type_create], menu_name='sidebar')
+register_links([MetadataType, 'setup_metadata_type_list', 'setup_metadata_type_create'], [setup_metadata_type_list, setup_metadata_type_create], menu_name='secondary_menu')
register_links(MetadataSet, [setup_metadata_set_edit, setup_metadata_set_delete])
-register_links(['setup_metadata_set_delete', 'setup_metadata_set_edit', 'setup_metadata_set_list', 'setup_metadata_set_create'], [setup_metadata_set_list, setup_metadata_set_create], menu_name='sidebar')
+register_links([MetadataSet, 'setup_metadata_set_list', 'setup_metadata_set_create'], [setup_metadata_set_list, setup_metadata_set_create], menu_name='secondary_menu')
register_links(DocumentType, [setup_document_type_metadata])
@@ -83,3 +59,9 @@ register_sidebar_template(['setup_metadata_set_list'], 'metadata_set_help.html')
register_setup(setup_metadata_type_list)
register_setup(setup_metadata_set_list)
+class_permissions(Document, [
+ PERMISSION_METADATA_DOCUMENT_EDIT,
+ PERMISSION_METADATA_DOCUMENT_ADD,
+ PERMISSION_METADATA_DOCUMENT_REMOVE,
+ PERMISSION_METADATA_DOCUMENT_VIEW,
+])
diff --git a/apps/metadata/admin.py b/apps/metadata/admin.py
index ac32bdc131..058d5d0544 100644
--- a/apps/metadata/admin.py
+++ b/apps/metadata/admin.py
@@ -1,7 +1,9 @@
+from __future__ import absolute_import
+
from django.contrib import admin
-from metadata.models import MetadataType, MetadataSet, MetadataSetItem, \
- DocumentMetadata, DocumentTypeDefaults
+from .models import (MetadataType, MetadataSet, MetadataSetItem,
+ DocumentMetadata, DocumentTypeDefaults)
class MetadataTypeAdmin(admin.ModelAdmin):
diff --git a/apps/metadata/api.py b/apps/metadata/api.py
index 3208ef7e23..77a86056bb 100644
--- a/apps/metadata/api.py
+++ b/apps/metadata/api.py
@@ -1,14 +1,17 @@
"""Metadata handling commonalities"""
+from __future__ import absolute_import
from urllib import unquote_plus
from django.shortcuts import get_object_or_404
-from metadata.models import DocumentMetadata, MetadataType
+from .models import DocumentMetadata, MetadataType
def decode_metadata_from_url(url_dict):
- """Parse a URL query string to a list of metadata"""
+ """
+ Parse a URL query string to a list of metadata
+ """
metadata_dict = {
'id': {},
'value': {}
@@ -78,7 +81,9 @@ def save_metadata(metadata_dict, document, create=False):
def metadata_repr(metadata_list):
- """Return a printable representation of a metadata list"""
+ """
+ Return a printable representation of a metadata list
+ """
return u', '.join(metadata_repr_as_list(metadata_list))
@@ -102,3 +107,15 @@ def get_metadata_string(document):
Return a formated representation of a document's metadata values
"""
return u', '.join([u'%s - %s' % (metadata.metadata_type, metadata.value) for metadata in DocumentMetadata.objects.filter(document=document).select_related('metadata_type')])
+
+
+def convert_dict_to_dict_list(dictionary):
+ result = []
+ for key, value in dictionary.items():
+ try:
+ metadata_type = MetadataType.objects.get(name=key)
+ except MetadataType.DoesNotExist:
+ raise ValueError('Unknown metadata type name')
+ result.append({'id': metadata_type.pk, 'value': value})
+
+ return result
diff --git a/apps/metadata/classes.py b/apps/metadata/classes.py
index b8476a744f..5bb9db0709 100644
--- a/apps/metadata/classes.py
+++ b/apps/metadata/classes.py
@@ -1,7 +1,9 @@
from django.utils.translation import ugettext_lazy as _
+from acls.classes import EncapsulatedObject
-class MetadataObject(object):
+
+class MetadataClass(object):
def __init__(self, dictionary):
self.dictionary = dictionary
@@ -10,3 +12,7 @@ class MetadataObject(object):
return self.dictionary.get(name)
else:
raise AttributeError(_(u'\'metadata\' object has no attribute \'%s\'') % name)
+
+
+class MetadataObjectWrapper(EncapsulatedObject):
+ source_object_name = u'metadata_object'
diff --git a/apps/metadata/forms.py b/apps/metadata/forms.py
index ce921ee47c..c2e281242c 100644
--- a/apps/metadata/forms.py
+++ b/apps/metadata/forms.py
@@ -1,13 +1,13 @@
+from __future__ import absolute_import
+
from django import forms
from django.utils.translation import ugettext_lazy as _
from django.forms.formsets import formset_factory
from common.widgets import ScrollableCheckboxSelectMultiple
-from metadata.conf.settings import AVAILABLE_MODELS
-from metadata.conf.settings import AVAILABLE_FUNCTIONS
-from metadata.models import MetadataSet, MetadataType, \
- DocumentTypeDefaults
+from .conf.settings import AVAILABLE_MODELS, AVAILABLE_FUNCTIONS
+from .models import MetadataSet, MetadataType, DocumentTypeDefaults
class MetadataForm(forms.Form):
diff --git a/apps/metadata/locale/en/LC_MESSAGES/django.po b/apps/metadata/locale/en/LC_MESSAGES/django.po
index 6f75f44ea8..6d79066c9f 100644
--- a/apps/metadata/locale/en/LC_MESSAGES/django.po
+++ b/apps/metadata/locale/en/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-11-22 11:26-0400\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -17,103 +17,47 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: __init__.py:12
-msgid "Edit a document's metadata"
-msgstr ""
-
-#: __init__.py:13
-msgid "Add metadata to a document"
-msgstr ""
-
-#: __init__.py:14
-msgid "Remove metadata from a document"
-msgstr ""
-
-#: __init__.py:15
-msgid "View metadata from a document"
-msgstr ""
-
-#: __init__.py:17
-msgid "Edit metadata types"
-msgstr ""
-
-#: __init__.py:18
-msgid "Create new metadata types"
-msgstr ""
-
-#: __init__.py:19
-msgid "Delete metadata types"
-msgstr ""
-
-#: __init__.py:20
-msgid "View metadata types"
-msgstr ""
-
-#: __init__.py:22
-msgid "Edit metadata sets"
-msgstr ""
-
-#: __init__.py:23
-msgid "Create new metadata sets"
-msgstr ""
-
-#: __init__.py:24
-msgid "Delete metadata sets"
-msgstr ""
-
-#: __init__.py:25
-msgid "View metadata sets"
-msgstr ""
-
-#: __init__.py:27 forms.py:94
-msgid "Metadata"
-msgstr ""
-
-#: __init__.py:33
-msgid "Metadata setup"
-msgstr ""
-
-#: __init__.py:44 __init__.py:46
+#: __init__.py:21 __init__.py:23
msgid "edit metadata"
msgstr ""
-#: __init__.py:45
+#: __init__.py:22
msgid "metadata"
msgstr ""
-#: __init__.py:47 __init__.py:48
+#: __init__.py:24 __init__.py:25
msgid "add metadata"
msgstr ""
-#: __init__.py:49 __init__.py:50
+#: __init__.py:26 __init__.py:27
msgid "remove metadata"
msgstr ""
-#: __init__.py:52 models.py:33 views.py:294
+#: __init__.py:29 models.py:34 views.py:316
msgid "metadata types"
msgstr ""
-#: __init__.py:53 __init__.py:58
+#: __init__.py:30 __init__.py:35
msgid "edit"
msgstr ""
-#: __init__.py:54 __init__.py:59
+#: __init__.py:31 __init__.py:36
msgid "delete"
msgstr ""
-#: __init__.py:55 __init__.py:60
+#: __init__.py:32 __init__.py:37
msgid "create new"
msgstr ""
-#: __init__.py:57 views.py:394
+#: __init__.py:34 views.py:416
msgid "metadata sets"
msgstr ""
-#: __init__.py:62 models.py:92
+#: __init__.py:39 models.py:93
msgid "default metadata"
msgstr ""
-#: classes.py:12
+#: classes.py:14
#, python-format
msgid "'metadata' object has no attribute '%s'"
msgstr ""
@@ -146,276 +90,336 @@ msgstr ""
msgid "Remove"
msgstr ""
-#: forms.py:86
+#: forms.py:86 views.py:541 views.py:559
msgid "Metadata sets"
msgstr ""
-#: models.py:9
-#, python-format
-msgid " Available models: %s"
+#: forms.py:94 permissions.py:7
+msgid "Metadata"
msgstr ""
#: models.py:10
#, python-format
+msgid " Available models: %s"
+msgstr ""
+
+#: models.py:11
+#, python-format
msgid " Available functions: %s"
msgstr ""
-#: models.py:17
+#: models.py:18
msgid "name"
msgstr ""
-#: models.py:17
+#: models.py:18
msgid "Do not use python reserved words, or spaces."
msgstr ""
-#: models.py:18 models.py:40
+#: models.py:19 models.py:41
msgid "title"
msgstr ""
-#: models.py:20
+#: models.py:21
msgid "default"
msgstr ""
-#: models.py:21
+#: models.py:22
#, python-format
msgid "Enter a string to be evaluated.%s"
msgstr ""
-#: models.py:23
+#: models.py:24
msgid "lookup"
msgstr ""
-#: models.py:24
+#: models.py:25
#, python-format
msgid ""
"Enter a string to be evaluated. Example: [user.get_full_name() for user in "
"User.objects.all()].%s"
msgstr ""
-#: models.py:32 models.py:57 views.py:331 views.py:376
+#: models.py:33 models.py:58 views.py:353 views.py:398
msgid "metadata type"
msgstr ""
-#: models.py:47 models.py:48 models.py:56 views.py:446 views.py:491
+#: models.py:48 models.py:49 models.py:57 views.py:468 views.py:514
msgid "metadata set"
msgstr ""
-#: models.py:64
+#: models.py:65
msgid "metadata set item"
msgstr ""
-#: models.py:65
+#: models.py:66
msgid "metadata set items"
msgstr ""
-#: models.py:73
+#: models.py:74
msgid "document"
msgstr ""
-#: models.py:74
+#: models.py:75
msgid "type"
msgstr ""
-#: models.py:75 views.py:283
+#: models.py:76 views.py:304
msgid "value"
msgstr ""
-#: models.py:81 models.py:82
+#: models.py:82 models.py:83
msgid "document metadata"
msgstr ""
-#: models.py:90 views.py:559
+#: models.py:91 views.py:599
msgid "document type"
msgstr ""
-#: models.py:91
+#: models.py:92
msgid "default metadata sets"
msgstr ""
-#: models.py:98
+#: models.py:99
msgid "document type defaults"
msgstr ""
-#: models.py:99
+#: models.py:100
msgid "document types defaults"
msgstr ""
-#: views.py:38 views.py:193
+#: permissions.py:8
+msgid "Edit a document's metadata"
+msgstr ""
+
+#: permissions.py:9
+msgid "Add metadata to a document"
+msgstr ""
+
+#: permissions.py:10
+msgid "Remove metadata from a document"
+msgstr ""
+
+#: permissions.py:11
+msgid "View metadata from a document"
+msgstr ""
+
+#: permissions.py:13
+msgid "Metadata setup"
+msgstr ""
+
+#: permissions.py:14
+msgid "Edit metadata types"
+msgstr ""
+
+#: permissions.py:15
+msgid "Create new metadata types"
+msgstr ""
+
+#: permissions.py:16
+msgid "Delete metadata types"
+msgstr ""
+
+#: permissions.py:17
+msgid "View metadata types"
+msgstr ""
+
+#: permissions.py:19
+msgid "Edit metadata sets"
+msgstr ""
+
+#: permissions.py:20
+msgid "Create new metadata sets"
+msgstr ""
+
+#: permissions.py:21
+msgid "Delete metadata sets"
+msgstr ""
+
+#: permissions.py:22
+msgid "View metadata sets"
+msgstr ""
+
+#: views.py:41 views.py:204
msgid "The selected document doesn't have any metadata."
msgstr ""
-#: views.py:43 views.py:131 views.py:199
+#: views.py:52 views.py:144 views.py:216
msgid "Must provide at least one document."
msgstr ""
-#: views.py:78 views.py:234
+#: views.py:87 views.py:251
#, python-format
msgid "Error deleting document indexes; %s"
msgstr ""
-#: views.py:90
+#: views.py:99
#, python-format
msgid "Error editing metadata for document %(document)s; %(error)s."
msgstr ""
-#: views.py:93
+#: views.py:102
#, python-format
msgid "Metadata for document %s edited successfully."
msgstr ""
-#: views.py:98 views.py:251
+#: views.py:107 views.py:268
#, python-format
msgid "Error updating document indexes; %s"
msgstr ""
-#: views.py:100 views.py:253
+#: views.py:109 views.py:270
msgid "Document indexes updated successfully."
msgstr ""
-#: views.py:111
+#: views.py:120
#, python-format
msgid "Edit metadata for document: %s"
msgstr ""
-#: views.py:113
+#: views.py:122
#, python-format
msgid "Edit metadata for documents: %s"
msgstr ""
-#: views.py:148
+#: views.py:161
#, python-format
msgid ""
"Metadata type: %(metadata_type)s successfully added to document %(document)s."
msgstr ""
-#: views.py:151
+#: views.py:164
#, python-format
msgid ""
"Metadata type: %(metadata_type)s already present in document %(document)s."
msgstr ""
-#: views.py:175
+#: views.py:188
#, python-format
msgid "Add metadata type to document: %s"
msgstr ""
-#: views.py:177
+#: views.py:190
#, python-format
msgid "Add metadata type to documents: %s"
msgstr ""
-#: views.py:242
+#: views.py:259
#, python-format
msgid ""
"Successfully remove metadata type: %(metadata_type)s from document: "
"%(document)s."
msgstr ""
-#: views.py:245
+#: views.py:262
#, python-format
msgid ""
"Error removing metadata type: %(metadata_type)s from document: %(document)s."
msgstr ""
-#: views.py:264
+#: views.py:281
#, python-format
msgid "Remove metadata types from document: %s"
msgstr ""
-#: views.py:266
+#: views.py:283
#, python-format
msgid "Remove metadata types from documents: %s"
msgstr ""
-#: views.py:281
+#: views.py:302
#, python-format
msgid "metadata for: %s"
msgstr ""
-#: views.py:298
+#: views.py:320
msgid "internal name"
msgstr ""
-#: views.py:319
+#: views.py:341
msgid "Metadata type edited successfully"
msgstr ""
-#: views.py:322
+#: views.py:344
#, python-format
msgid "Error editing metadata type; %s"
msgstr ""
-#: views.py:328
+#: views.py:350
#, python-format
msgid "edit metadata type: %s"
msgstr ""
-#: views.py:343
+#: views.py:365
msgid "Metadata type created successfully"
msgstr ""
-#: views.py:349
+#: views.py:371
msgid "create metadata type"
msgstr ""
-#: views.py:368
+#: views.py:390
#, python-format
msgid "Metadata type: %s deleted successfully."
msgstr ""
-#: views.py:370
+#: views.py:392
#, python-format
msgid "Metadata type: %(metadata_type)s delete error: %(error)s"
msgstr ""
-#: views.py:381
+#: views.py:403
#, python-format
msgid "Are you sure you wish to delete the metadata type: %s?"
msgstr ""
-#: views.py:398
+#: views.py:420
msgid "members"
msgstr ""
-#: views.py:442
+#: views.py:464
#, python-format
msgid "non members of metadata set: %s"
msgstr ""
-#: views.py:443
+#: views.py:465
#, python-format
msgid "members of metadata set: %s"
msgstr ""
-#: views.py:458
+#: views.py:480
msgid "Metadata set created successfully"
msgstr ""
-#: views.py:464
+#: views.py:486
msgid "create metadata set"
msgstr ""
-#: views.py:483
+#: views.py:505
#, python-format
msgid "Metadata set: %s deleted successfully."
msgstr ""
-#: views.py:485
+#: views.py:508
#, python-format
msgid "Metadata set: %(metadata_set)s delete error: %(error)s"
msgstr ""
-#: views.py:496
+#: views.py:519
#, python-format
msgid "Are you sure you wish to delete the metadata set: %s?"
msgstr ""
-#: views.py:554
+#: views.py:538 views.py:556
+msgid "Metadata types"
+msgstr ""
+
+#: views.py:594
#, python-format
msgid "non members of document type: %s"
msgstr ""
-#: views.py:555
+#: views.py:595
#, python-format
msgid "members of document type: %s"
msgstr ""
diff --git a/apps/metadata/locale/es/LC_MESSAGES/django.mo b/apps/metadata/locale/es/LC_MESSAGES/django.mo
index be0c179aa5..1448638f9e 100644
Binary files a/apps/metadata/locale/es/LC_MESSAGES/django.mo and b/apps/metadata/locale/es/LC_MESSAGES/django.mo differ
diff --git a/apps/metadata/locale/es/LC_MESSAGES/django.po b/apps/metadata/locale/es/LC_MESSAGES/django.po
index 03f08e5442..6134319ba7 100644
--- a/apps/metadata/locale/es/LC_MESSAGES/django.po
+++ b/apps/metadata/locale/es/LC_MESSAGES/django.po
@@ -1,120 +1,64 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
-#
+#
# Translators:
+# Roberto Rosario , 2012.
msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-11-22 11:26-0400\n"
-"PO-Revision-Date: 2011-09-30 05:09+0000\n"
-"Last-Translator: rosarior \n"
-"Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/"
-"mayan-edms/team/es/)\n"
-"Language: es\n"
+"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
+"PO-Revision-Date: 2012-02-12 19:27+0000\n"
+"Last-Translator: Roberto Rosario \n"
+"Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/mayan-edms/team/es/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
+"Language: es\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
-#: __init__.py:12
-msgid "Edit a document's metadata"
-msgstr "Editar metadatos de documento"
-
-#: __init__.py:13
-msgid "Add metadata to a document"
-msgstr "Añadir metadatos a documento"
-
-#: __init__.py:14
-msgid "Remove metadata from a document"
-msgstr "Eliminar metadatos de un documento"
-
-#: __init__.py:15
-msgid "View metadata from a document"
-msgstr "Ver los metadatos de un documento"
-
-#: __init__.py:17
-msgid "Edit metadata types"
-msgstr "Editar tipos de metadatos"
-
-#: __init__.py:18
-msgid "Create new metadata types"
-msgstr "Crear nuevos tipos de metadatos"
-
-#: __init__.py:19
-msgid "Delete metadata types"
-msgstr "Eliminar tipos de metadatos"
-
-#: __init__.py:20
-msgid "View metadata types"
-msgstr "Ver los tipos de metadatos"
-
-#: __init__.py:22
-msgid "Edit metadata sets"
-msgstr "Editar conjuntos de metadatos"
-
-#: __init__.py:23
-msgid "Create new metadata sets"
-msgstr "Crear nuevos conjuntos de metadatos"
-
-#: __init__.py:24
-msgid "Delete metadata sets"
-msgstr "Eliminar conjuntos de metadatos"
-
-#: __init__.py:25
-msgid "View metadata sets"
-msgstr "Ver los conjuntos de metadatos"
-
-#: __init__.py:27 forms.py:94
-msgid "Metadata"
-msgstr "Metadatos"
-
-#: __init__.py:33
-msgid "Metadata setup"
-msgstr "Configuración de metadatos"
-
-#: __init__.py:44 __init__.py:46
+#: __init__.py:21 __init__.py:23
msgid "edit metadata"
msgstr "editar metadatos"
-#: __init__.py:45
+#: __init__.py:22
msgid "metadata"
msgstr "metadatos"
-#: __init__.py:47 __init__.py:48
+#: __init__.py:24 __init__.py:25
msgid "add metadata"
msgstr "añadir metadatos"
-#: __init__.py:49 __init__.py:50
+#: __init__.py:26 __init__.py:27
msgid "remove metadata"
msgstr "eliminar los metadatos"
-#: __init__.py:52 models.py:33 views.py:294
+#: __init__.py:29 models.py:34 views.py:316
msgid "metadata types"
msgstr "tipos de metadatos"
-#: __init__.py:53 __init__.py:58
+#: __init__.py:30 __init__.py:35
msgid "edit"
msgstr "editar"
-#: __init__.py:54 __init__.py:59
+#: __init__.py:31 __init__.py:36
msgid "delete"
msgstr "borrar"
-#: __init__.py:55 __init__.py:60
+#: __init__.py:32 __init__.py:37
msgid "create new"
msgstr "crear nuevo"
-#: __init__.py:57 views.py:394
+#: __init__.py:34 views.py:416
msgid "metadata sets"
msgstr "conjuntos de metadatos"
-#: __init__.py:62 models.py:92
+#: __init__.py:39 models.py:93
msgid "default metadata"
msgstr "metadatos predeterminados"
-#: classes.py:12
+#: classes.py:14
#, python-format
msgid "'metadata' object has no attribute '%s'"
msgstr "objeto 'metadata' no tiene attributo '%s'"
@@ -147,153 +91,210 @@ msgstr "Tipo de metadato"
msgid "Remove"
msgstr "Eliminar"
-#: forms.py:86
+#: forms.py:86 views.py:541 views.py:559
msgid "Metadata sets"
msgstr "Conjunto de metadatos"
-#: models.py:9
+#: forms.py:94 permissions.py:7
+msgid "Metadata"
+msgstr "Metadatos"
+
+#: models.py:10
#, python-format
msgid " Available models: %s"
msgstr "Modelos disponibles: %s"
-#: models.py:10
+#: models.py:11
#, python-format
msgid " Available functions: %s"
msgstr "Funciones disponibles: %s"
-#: models.py:17
+#: models.py:18
msgid "name"
msgstr "nombre"
-#: models.py:17
+#: models.py:18
msgid "Do not use python reserved words, or spaces."
msgstr "No utilice palabras reservadas de Python, o espacios."
-#: models.py:18 models.py:40
+#: models.py:19 models.py:41
msgid "title"
msgstr "título"
-#: models.py:20
+#: models.py:21
msgid "default"
msgstr "por defecto"
-#: models.py:21
+#: models.py:22
#, python-format
msgid "Enter a string to be evaluated.%s"
msgstr "Introduzca una cadena para ser evaluada. %s"
-#: models.py:23
+#: models.py:24
msgid "lookup"
msgstr "búsqueda"
-#: models.py:24
+#: models.py:25
#, python-format
msgid ""
"Enter a string to be evaluated. Example: [user.get_full_name() for user in "
"User.objects.all()].%s"
msgstr ""
-"Introduzca una cadena para ser evaluada. Ejemplo: [user.get_full_name() for "
-"user in User.objects.all ()].%s"
+"Introduzca una cadena para ser evaluada. Ejemplo: [user.get_full_name() for"
+" user in User.objects.all ()].%s"
-#: models.py:32 models.py:57 views.py:331 views.py:376
+#: models.py:33 models.py:58 views.py:353 views.py:398
msgid "metadata type"
msgstr "tipos de metadatos"
-#: models.py:47 models.py:48 models.py:56 views.py:446 views.py:491
+#: models.py:48 models.py:49 models.py:57 views.py:468 views.py:514
msgid "metadata set"
msgstr "conjunto de metadatos"
-#: models.py:64
+#: models.py:65
msgid "metadata set item"
msgstr "artículo de conjunto de metadatos"
-#: models.py:65
+#: models.py:66
msgid "metadata set items"
msgstr "artículos de conjuntos de metadatos"
-#: models.py:73
+#: models.py:74
msgid "document"
msgstr "documento"
-#: models.py:74
+#: models.py:75
msgid "type"
msgstr "tipo"
-#: models.py:75 views.py:283
+#: models.py:76 views.py:304
msgid "value"
msgstr "valor"
-#: models.py:81 models.py:82
+#: models.py:82 models.py:83
msgid "document metadata"
msgstr "metadatos de documento"
-#: models.py:90 views.py:559
+#: models.py:91 views.py:599
msgid "document type"
msgstr "tipo de documento"
-#: models.py:91
+#: models.py:92
msgid "default metadata sets"
msgstr "conjuntos de metadatos predeterminados "
-#: models.py:98
+#: models.py:99
msgid "document type defaults"
msgstr "predeterminados de tipo de documento"
-#: models.py:99
+#: models.py:100
msgid "document types defaults"
msgstr "predeterminados de tipos de documentos"
-#: views.py:38 views.py:193
+#: permissions.py:8
+msgid "Edit a document's metadata"
+msgstr "Editar metadatos de documento"
+
+#: permissions.py:9
+msgid "Add metadata to a document"
+msgstr "Añadir metadatos a documento"
+
+#: permissions.py:10
+msgid "Remove metadata from a document"
+msgstr "Eliminar metadatos de un documento"
+
+#: permissions.py:11
+msgid "View metadata from a document"
+msgstr "Ver los metadatos de un documento"
+
+#: permissions.py:13
+msgid "Metadata setup"
+msgstr "Configuración de metadatos"
+
+#: permissions.py:14
+msgid "Edit metadata types"
+msgstr "Editar tipos de metadatos"
+
+#: permissions.py:15
+msgid "Create new metadata types"
+msgstr "Crear nuevos tipos de metadatos"
+
+#: permissions.py:16
+msgid "Delete metadata types"
+msgstr "Eliminar tipos de metadatos"
+
+#: permissions.py:17
+msgid "View metadata types"
+msgstr "Ver los tipos de metadatos"
+
+#: permissions.py:19
+msgid "Edit metadata sets"
+msgstr "Editar conjuntos de metadatos"
+
+#: permissions.py:20
+msgid "Create new metadata sets"
+msgstr "Crear nuevos conjuntos de metadatos"
+
+#: permissions.py:21
+msgid "Delete metadata sets"
+msgstr "Eliminar conjuntos de metadatos"
+
+#: permissions.py:22
+msgid "View metadata sets"
+msgstr "Ver los conjuntos de metadatos"
+
+#: views.py:41 views.py:204
msgid "The selected document doesn't have any metadata."
msgstr "El documento seleccionado no tiene ningún tipo de metadatos."
-#: views.py:43 views.py:131 views.py:199
+#: views.py:52 views.py:144 views.py:216
msgid "Must provide at least one document."
msgstr "Debe proveer al menos un documento."
-#: views.py:78 views.py:234
+#: views.py:87 views.py:251
#, python-format
msgid "Error deleting document indexes; %s"
msgstr "Error eliminando indicies de documento; %s"
-#: views.py:90
+#: views.py:99
#, python-format
msgid "Error editing metadata for document %(document)s; %(error)s."
msgstr "Error editando metadatos para documento %(document)s; %(error)s."
-#: views.py:93
+#: views.py:102
#, python-format
msgid "Metadata for document %s edited successfully."
msgstr "Metadatos para documento %s editados exitosamente."
-#: views.py:98 views.py:251
+#: views.py:107 views.py:268
#, python-format
msgid "Error updating document indexes; %s"
msgstr "Error editando indices de documento; %s"
-#: views.py:100 views.py:253
+#: views.py:109 views.py:270
msgid "Document indexes updated successfully."
msgstr "Indices documento actualizados exitosamente."
-#: views.py:111
+#: views.py:120
#, python-format
msgid "Edit metadata for document: %s"
msgstr "Editar metadatos para documento: %s"
-#: views.py:113
+#: views.py:122
#, python-format
msgid "Edit metadata for documents: %s"
msgstr "Editar metadatos para documentos: %s"
-#: views.py:148
+#: views.py:161
#, python-format
msgid ""
-"Metadata type: %(metadata_type)s successfully added to document %(document)s."
+"Metadata type: %(metadata_type)s successfully added to document "
+"%(document)s."
msgstr ""
"Typo de metadatos: %(metadata_type)s agregado exitosamente al documento "
"%(document)s."
-#: views.py:151
+#: views.py:164
#, python-format
msgid ""
"Metadata type: %(metadata_type)s already present in document %(document)s."
@@ -301,17 +302,17 @@ msgstr ""
"Typo de metadatos: %(metadata_type)s ya esta presente en el documento "
"%(document)s."
-#: views.py:175
+#: views.py:188
#, python-format
msgid "Add metadata type to document: %s"
msgstr "Agregar tipo de metadato al documento: %s"
-#: views.py:177
+#: views.py:190
#, python-format
msgid "Add metadata type to documents: %s"
msgstr "Agregar tipo de metadato a los documentos: %s"
-#: views.py:242
+#: views.py:259
#, python-format
msgid ""
"Successfully remove metadata type: %(metadata_type)s from document: "
@@ -320,7 +321,7 @@ msgstr ""
"Se elimino exitosamente el tipo de metadatos: %(metadata_type)s del "
"documento: %(document)s."
-#: views.py:245
+#: views.py:262
#, python-format
msgid ""
"Error removing metadata type: %(metadata_type)s from document: %(document)s."
@@ -328,106 +329,110 @@ msgstr ""
"Se elimino exitosamente el tipo de metadatos: %(metadata_type)s de los "
"documentos: %(document)s."
-#: views.py:264
+#: views.py:281
#, python-format
msgid "Remove metadata types from document: %s"
msgstr "Eliminar tipos de metadatos del documento: %s"
-#: views.py:266
+#: views.py:283
#, python-format
msgid "Remove metadata types from documents: %s"
msgstr "Eliminar tipos de metadatos de los documentos: %s"
-#: views.py:281
+#: views.py:302
#, python-format
msgid "metadata for: %s"
msgstr "metadatos para: %s"
-#: views.py:298
+#: views.py:320
msgid "internal name"
msgstr "nombre interno"
-#: views.py:319
+#: views.py:341
msgid "Metadata type edited successfully"
msgstr "Tipo de metadatos editado exitosamente."
-#: views.py:322
+#: views.py:344
#, python-format
msgid "Error editing metadata type; %s"
msgstr "Error editando tipo de metadatos; %s"
-#: views.py:328
+#: views.py:350
#, python-format
msgid "edit metadata type: %s"
msgstr "editar tipo de metadatos: %s"
-#: views.py:343
+#: views.py:365
msgid "Metadata type created successfully"
msgstr "Tipo de metadatos creado exitosamente"
-#: views.py:349
+#: views.py:371
msgid "create metadata type"
msgstr "crear tipo de metadatos"
-#: views.py:368
+#: views.py:390
#, python-format
msgid "Metadata type: %s deleted successfully."
msgstr "Tipos de metadatos: %s eliminado exitosamente."
-#: views.py:370
+#: views.py:392
#, python-format
msgid "Metadata type: %(metadata_type)s delete error: %(error)s"
msgstr "Error: %(error)s, eliminando tipos de metadatos: %(metadata_type)s"
-#: views.py:381
+#: views.py:403
#, python-format
msgid "Are you sure you wish to delete the metadata type: %s?"
msgstr "¿Está seguro que desea eliminar el tipo de metadatos: %s?"
-#: views.py:398
+#: views.py:420
msgid "members"
msgstr "miembros"
-#: views.py:442
+#: views.py:464
#, python-format
msgid "non members of metadata set: %s"
msgstr "no miembros del conjunto de metadatos: %s"
-#: views.py:443
+#: views.py:465
#, python-format
msgid "members of metadata set: %s"
msgstr "miembros del conjunto de metadatos: %s"
-#: views.py:458
+#: views.py:480
msgid "Metadata set created successfully"
msgstr "Conjunto de metadatos creados exitosamente"
-#: views.py:464
+#: views.py:486
msgid "create metadata set"
msgstr "crear conjunto de metadatos"
-#: views.py:483
+#: views.py:505
#, python-format
msgid "Metadata set: %s deleted successfully."
msgstr "Conjunto de metadatos: %s eliminado exitosamente."
-#: views.py:485
+#: views.py:508
#, python-format
msgid "Metadata set: %(metadata_set)s delete error: %(error)s"
msgstr ""
"Error: %(error)s, eliminando el conjunto de metadatos: %(metadata_set)s"
-#: views.py:496
+#: views.py:519
#, python-format
msgid "Are you sure you wish to delete the metadata set: %s?"
msgstr "¿Está seguro que desea eliminar el conjunto de metadatos: %s?"
-#: views.py:554
+#: views.py:538 views.py:556
+msgid "Metadata types"
+msgstr "Tipos de metadatos"
+
+#: views.py:594
#, python-format
msgid "non members of document type: %s"
msgstr "no miembros del tipo de documento: %s"
-#: views.py:555
+#: views.py:595
#, python-format
msgid "members of document type: %s"
msgstr "miembros del tipo de documento: %s"
@@ -453,15 +458,15 @@ msgstr "¿Cuáles son los tipos de metadatos?"
#: templates/metadata_type_help.html:4
msgid ""
-"A metadata type defines the characteristics of a value of some kind that can "
-"be attached to a document. Examples of metadata types are: a client name, a "
-"date, or a project to which several documents belong. A metadata type's "
+"A metadata type defines the characteristics of a value of some kind that can"
+" be attached to a document. Examples of metadata types are: a client name, "
+"a date, or a project to which several documents belong. A metadata type's "
"name is the internal identifier with which it can be referenced to by other "
-"modules such as the indexing module, the title is the value that is shown to "
-"the users, the default value is the value an instance of this metadata type "
-"will have initially, and the lookup value turns an instance of a metadata of "
-"this type into a choice list which options are the result of the lookup's "
-"code execution."
+"modules such as the indexing module, the title is the value that is shown to"
+" the users, the default value is the value an instance of this metadata type"
+" will have initially, and the lookup value turns an instance of a metadata "
+"of this type into a choice list which options are the result of the lookup's"
+" code execution."
msgstr ""
"Un tipo de metadatos define las características de un valor de algún tipo "
"que se puede conectar a un documento. Ejemplos de tipos de metadatos son: "
@@ -471,5 +476,7 @@ msgstr ""
"indexación, el título es el valor que se muestra a los usuarios, el valor "
"por defecto es el valor que una instancia de este tipo de metadatos tendrá "
"inicialmente, y el valor de búsqueda vuelve a una instancia de metadatos de "
-"este tipo en una lista de opciones donde las opciones son el resultado de la "
-"ejecución del valor de búsqueda."
+"este tipo en una lista de opciones donde las opciones son el resultado de la"
+" ejecución del valor de búsqueda."
+
+
diff --git a/apps/metadata/locale/it/LC_MESSAGES/django.mo b/apps/metadata/locale/it/LC_MESSAGES/django.mo
new file mode 100644
index 0000000000..0303c94f85
Binary files /dev/null and b/apps/metadata/locale/it/LC_MESSAGES/django.mo differ
diff --git a/apps/metadata/locale/it/LC_MESSAGES/django.po b/apps/metadata/locale/it/LC_MESSAGES/django.po
new file mode 100644
index 0000000000..a37122bdee
--- /dev/null
+++ b/apps/metadata/locale/it/LC_MESSAGES/django.po
@@ -0,0 +1,481 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# , 2011.
+msgid ""
+msgstr ""
+"Project-Id-Version: Mayan EDMS\n"
+"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
+"PO-Revision-Date: 2012-02-12 19:24+0000\n"
+"Last-Translator: Roberto Rosario \n"
+"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/it/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: it\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+
+#: __init__.py:21 __init__.py:23
+msgid "edit metadata"
+msgstr "modifica metadati"
+
+#: __init__.py:22
+msgid "metadata"
+msgstr "metadati"
+
+#: __init__.py:24 __init__.py:25
+msgid "add metadata"
+msgstr "aggiungi metadata"
+
+#: __init__.py:26 __init__.py:27
+msgid "remove metadata"
+msgstr "revoca metadata"
+
+#: __init__.py:29 models.py:34 views.py:316
+msgid "metadata types"
+msgstr "tipo di metadata"
+
+#: __init__.py:30 __init__.py:35
+msgid "edit"
+msgstr "modifica"
+
+#: __init__.py:31 __init__.py:36
+msgid "delete"
+msgstr "cancella"
+
+#: __init__.py:32 __init__.py:37
+msgid "create new"
+msgstr "crea nuovo"
+
+#: __init__.py:34 views.py:416
+msgid "metadata sets"
+msgstr "set di metadati"
+
+#: __init__.py:39 models.py:93
+msgid "default metadata"
+msgstr "metadati di default"
+
+#: classes.py:14
+#, python-format
+msgid "'metadata' object has no attribute '%s'"
+msgstr "'metadata' non ha gli attributi '%s'"
+
+#: forms.py:28
+msgid "required"
+msgstr "richiesto"
+
+#: forms.py:54
+msgid "id"
+msgstr "id"
+
+#: forms.py:55
+msgid "Name"
+msgstr "Nome"
+
+#: forms.py:57
+msgid "Value"
+msgstr "Valore"
+
+#: forms.py:58
+msgid "Update"
+msgstr "Aggiurnato"
+
+#: forms.py:64
+msgid "Metadata type"
+msgstr "Tipo di metadato"
+
+#: forms.py:68
+msgid "Remove"
+msgstr "Revoca"
+
+#: forms.py:86 views.py:541 views.py:559
+msgid "Metadata sets"
+msgstr "Set di metadati"
+
+#: forms.py:94 permissions.py:7
+msgid "Metadata"
+msgstr "Metadati"
+
+#: models.py:10
+#, python-format
+msgid " Available models: %s"
+msgstr " Modelli disponibili: %s"
+
+#: models.py:11
+#, python-format
+msgid " Available functions: %s"
+msgstr " Funzioni disponibili: %s"
+
+#: models.py:18
+msgid "name"
+msgstr "nome"
+
+#: models.py:18
+msgid "Do not use python reserved words, or spaces."
+msgstr "Non usare parole riservate python, o spazi."
+
+#: models.py:19 models.py:41
+msgid "title"
+msgstr "titolo"
+
+#: models.py:21
+msgid "default"
+msgstr "default"
+
+#: models.py:22
+#, python-format
+msgid "Enter a string to be evaluated.%s"
+msgstr "Inserisci una stringa per la valutazione.%s"
+
+#: models.py:24
+msgid "lookup"
+msgstr "lookup"
+
+#: models.py:25
+#, python-format
+msgid ""
+"Enter a string to be evaluated. Example: [user.get_full_name() for user in "
+"User.objects.all()].%s"
+msgstr ""
+"Inserisci una stringa per la valutazione. Esempio: [user.get_full_name() "
+"per l'utente User.objects.all()].%s"
+
+#: models.py:33 models.py:58 views.py:353 views.py:398
+msgid "metadata type"
+msgstr "tipo di metadata"
+
+#: models.py:48 models.py:49 models.py:57 views.py:468 views.py:514
+msgid "metadata set"
+msgstr "set di metadata"
+
+#: models.py:65
+msgid "metadata set item"
+msgstr "set di elemento per il metadata"
+
+#: models.py:66
+msgid "metadata set items"
+msgstr "set di elementi per il metadata"
+
+#: models.py:74
+msgid "document"
+msgstr "documento"
+
+#: models.py:75
+msgid "type"
+msgstr "tipo"
+
+#: models.py:76 views.py:304
+msgid "value"
+msgstr "valore"
+
+#: models.py:82 models.py:83
+msgid "document metadata"
+msgstr "metadata per il doccumento"
+
+#: models.py:91 views.py:599
+msgid "document type"
+msgstr "tipo documento"
+
+#: models.py:92
+msgid "default metadata sets"
+msgstr "set di default di metadata"
+
+#: models.py:99
+msgid "document type defaults"
+msgstr "tipo documento predefinito"
+
+#: models.py:100
+msgid "document types defaults"
+msgstr "tipi di documento predefiniti"
+
+#: permissions.py:8
+msgid "Edit a document's metadata"
+msgstr "Modifica i metadata dei documenti"
+
+#: permissions.py:9
+msgid "Add metadata to a document"
+msgstr "Aggiungi il metadato al documento"
+
+#: permissions.py:10
+msgid "Remove metadata from a document"
+msgstr "Revoca il metadato al documento"
+
+#: permissions.py:11
+msgid "View metadata from a document"
+msgstr "Visualizza il metadato per il documento"
+
+#: permissions.py:13
+msgid "Metadata setup"
+msgstr "Setup metadati"
+
+#: permissions.py:14
+msgid "Edit metadata types"
+msgstr "Modifica il tipo di metadato"
+
+#: permissions.py:15
+msgid "Create new metadata types"
+msgstr "Crea il nuovo tipo di metadato"
+
+#: permissions.py:16
+msgid "Delete metadata types"
+msgstr "Cancella il tipo di metadato"
+
+#: permissions.py:17
+msgid "View metadata types"
+msgstr "Visualizza il tipo di metadato"
+
+#: permissions.py:19
+msgid "Edit metadata sets"
+msgstr "Modifica il set di metadati"
+
+#: permissions.py:20
+msgid "Create new metadata sets"
+msgstr "Crea un nuovo set di metadati"
+
+#: permissions.py:21
+msgid "Delete metadata sets"
+msgstr "Cancella il set dei metadati"
+
+#: permissions.py:22
+msgid "View metadata sets"
+msgstr "Visualizza il set dei metadati"
+
+#: views.py:41 views.py:204
+msgid "The selected document doesn't have any metadata."
+msgstr "Il documento selezionato non ha metadati."
+
+#: views.py:52 views.py:144 views.py:216
+msgid "Must provide at least one document."
+msgstr "Devi fornire almeno un documento."
+
+#: views.py:87 views.py:251
+#, python-format
+msgid "Error deleting document indexes; %s"
+msgstr "Errore nella cancellazione degli indici di documento;%s"
+
+#: views.py:99
+#, python-format
+msgid "Error editing metadata for document %(document)s; %(error)s."
+msgstr ""
+"Errore nella modifica dei metadata per il documento %(document)s; %(error)s."
+
+#: views.py:102
+#, python-format
+msgid "Metadata for document %s edited successfully."
+msgstr "Metadata per il documento %s modificato con successo."
+
+#: views.py:107 views.py:268
+#, python-format
+msgid "Error updating document indexes; %s"
+msgstr "Errore nella'ggiornamento degli indici del documento; %s"
+
+#: views.py:109 views.py:270
+msgid "Document indexes updated successfully."
+msgstr "Indici documento aggiornati con successo."
+
+#: views.py:120
+#, python-format
+msgid "Edit metadata for document: %s"
+msgstr "Modifica metadata per il documento: %s"
+
+#: views.py:122
+#, python-format
+msgid "Edit metadata for documents: %s"
+msgstr "Modifica metadata per i documenti: %s"
+
+#: views.py:161
+#, python-format
+msgid ""
+"Metadata type: %(metadata_type)s successfully added to document "
+"%(document)s."
+msgstr ""
+"Tipo metadata: %(metadata_type)s aggiunto con successo al documento "
+"%(document)s."
+
+#: views.py:164
+#, python-format
+msgid ""
+"Metadata type: %(metadata_type)s already present in document %(document)s."
+msgstr ""
+"Tipo Metadata: %(metadata_type)s già presente per il documento %(document)s."
+
+#: views.py:188
+#, python-format
+msgid "Add metadata type to document: %s"
+msgstr "Aggiungi tipo metadata al document: %s"
+
+#: views.py:190
+#, python-format
+msgid "Add metadata type to documents: %s"
+msgstr "Aggiungi tipo metadata ai documents: %s"
+
+#: views.py:259
+#, python-format
+msgid ""
+"Successfully remove metadata type: %(metadata_type)s from document: "
+"%(document)s."
+msgstr ""
+"Rimuovere con successo tipo di metadati: %(metadata_type)s per il "
+"documento: %(document)s."
+
+#: views.py:262
+#, python-format
+msgid ""
+"Error removing metadata type: %(metadata_type)s from document: %(document)s."
+msgstr ""
+"Errore durante la rimozione dei metadati di tipo: %(metadata_type)s per il "
+"documento: %(document)s."
+
+#: views.py:281
+#, python-format
+msgid "Remove metadata types from document: %s"
+msgstr "Rimuovi il tipo metadata per il documento: %s"
+
+#: views.py:283
+#, python-format
+msgid "Remove metadata types from documents: %s"
+msgstr "Rimuovi il tipo metadata per il documenti: %s"
+
+#: views.py:302
+#, python-format
+msgid "metadata for: %s"
+msgstr "metadata per:%s"
+
+#: views.py:320
+msgid "internal name"
+msgstr "nome interno"
+
+#: views.py:341
+msgid "Metadata type edited successfully"
+msgstr "Tipo di metadata modificato con successo"
+
+#: views.py:344
+#, python-format
+msgid "Error editing metadata type; %s"
+msgstr "Errore nella modifica del tipo di metadata ; %s"
+
+#: views.py:350
+#, python-format
+msgid "edit metadata type: %s"
+msgstr "modifica tipo di metadata: %s"
+
+#: views.py:365
+msgid "Metadata type created successfully"
+msgstr "Tipo metadata creato con successo"
+
+#: views.py:371
+msgid "create metadata type"
+msgstr "create tipo di metadata"
+
+#: views.py:390
+#, python-format
+msgid "Metadata type: %s deleted successfully."
+msgstr "Tipo metadata:%s cancellato con successo."
+
+#: views.py:392
+#, python-format
+msgid "Metadata type: %(metadata_type)s delete error: %(error)s"
+msgstr "Tipo metadata: %(metadata_type)s erroce di cancellazione: %(error)s"
+
+#: views.py:403
+#, python-format
+msgid "Are you sure you wish to delete the metadata type: %s?"
+msgstr "Sei sicuro di voler cancellare il tipo di metadata: %s?"
+
+#: views.py:420
+msgid "members"
+msgstr "membri"
+
+#: views.py:464
+#, python-format
+msgid "non members of metadata set: %s"
+msgstr "non membri del set di metadata:%s"
+
+#: views.py:465
+#, python-format
+msgid "members of metadata set: %s"
+msgstr "membri del set di metadata:%s"
+
+#: views.py:480
+msgid "Metadata set created successfully"
+msgstr "Set di metadata creata con successo"
+
+#: views.py:486
+msgid "create metadata set"
+msgstr "creazione del set di metadata"
+
+#: views.py:505
+#, python-format
+msgid "Metadata set: %s deleted successfully."
+msgstr "Set di metadata: %s cancellata con successo."
+
+#: views.py:508
+#, python-format
+msgid "Metadata set: %(metadata_set)s delete error: %(error)s"
+msgstr "Set di metadata: %(metadata_set)s errore di cancellazione: %(error)s"
+
+#: views.py:519
+#, python-format
+msgid "Are you sure you wish to delete the metadata set: %s?"
+msgstr "Sei sicuro di voler eliminare il set di metadati: %s?"
+
+#: views.py:538 views.py:556
+msgid "Metadata types"
+msgstr ""
+
+#: views.py:594
+#, python-format
+msgid "non members of document type: %s"
+msgstr "non membri del tipo di documento: %s"
+
+#: views.py:595
+#, python-format
+msgid "members of document type: %s"
+msgstr "membri del tipo di documento: %s"
+
+#: templates/metadata_set_help.html:3
+msgid "What are metadata sets?"
+msgstr "Cosa sono i set di metadati ?"
+
+#: templates/metadata_set_help.html:4
+msgid ""
+"A metadata set is a group of one or more metadata types. Metadata sets are "
+"useful when creating new documents; selecing a metadata set automatically "
+"attaches it's member metadata types to said document."
+msgstr ""
+"Un insieme di metadati è un gruppo di uno o più tipi di metadati. Set di "
+"metadati sono utili durante la creazione di nuovi documenti e, selezionando "
+"un set di metadati allega automaticamente è membro tipi di metadati per "
+"documentare detto."
+
+#: templates/metadata_type_help.html:3
+msgid "What are metadata types?"
+msgstr "Cosa sono i tipi di metadati?"
+
+#: templates/metadata_type_help.html:4
+msgid ""
+"A metadata type defines the characteristics of a value of some kind that can"
+" be attached to a document. Examples of metadata types are: a client name, "
+"a date, or a project to which several documents belong. A metadata type's "
+"name is the internal identifier with which it can be referenced to by other "
+"modules such as the indexing module, the title is the value that is shown to"
+" the users, the default value is the value an instance of this metadata type"
+" will have initially, and the lookup value turns an instance of a metadata "
+"of this type into a choice list which options are the result of the lookup's"
+" code execution."
+msgstr ""
+"Un tipo di metadati definisce le caratteristiche di un valore di qualche "
+"tipo che può essere collegato a un documento. Esempi di tipi di metadati: il"
+" nome del client, una data o un progetto a cui appartengono diversi "
+"documenti. Il nome di un tipo di metadati è l'identificatore interno con il "
+"quale possono essere pubblicati da altri moduli come il modulo di "
+"indicizzazione, il titolo è il valore che viene mostrato agli utenti, il "
+"valore predefinito è il valore di un'istanza di questo tipo di metadati avrà"
+" inizialmente, e il valore di ricerca si trasforma un'istanza di metadati di"
+" questo tipo in un elenco di opzioni di scelta che sono il risultato della "
+"esecuzione di codice la ricerca di."
+
+
diff --git a/apps/metadata/locale/pl/LC_MESSAGES/django.mo b/apps/metadata/locale/pl/LC_MESSAGES/django.mo
new file mode 100644
index 0000000000..2a866ba861
Binary files /dev/null and b/apps/metadata/locale/pl/LC_MESSAGES/django.mo differ
diff --git a/apps/metadata/locale/pl/LC_MESSAGES/django.po b/apps/metadata/locale/pl/LC_MESSAGES/django.po
new file mode 100644
index 0000000000..25e7b5a7be
--- /dev/null
+++ b/apps/metadata/locale/pl/LC_MESSAGES/django.po
@@ -0,0 +1,455 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# , 2012.
+msgid ""
+msgstr ""
+"Project-Id-Version: Mayan EDMS\n"
+"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
+"PO-Revision-Date: 2012-02-20 17:15+0000\n"
+"Last-Translator: mic \n"
+"Language-Team: Polish (http://www.transifex.net/projects/p/mayan-edms/language/pl/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: pl\n"
+"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
+
+#: __init__.py:21 __init__.py:23
+msgid "edit metadata"
+msgstr ""
+
+#: __init__.py:22
+msgid "metadata"
+msgstr ""
+
+#: __init__.py:24 __init__.py:25
+msgid "add metadata"
+msgstr ""
+
+#: __init__.py:26 __init__.py:27
+msgid "remove metadata"
+msgstr ""
+
+#: __init__.py:29 models.py:34 views.py:316
+msgid "metadata types"
+msgstr ""
+
+#: __init__.py:30 __init__.py:35
+msgid "edit"
+msgstr ""
+
+#: __init__.py:31 __init__.py:36
+msgid "delete"
+msgstr ""
+
+#: __init__.py:32 __init__.py:37
+msgid "create new"
+msgstr ""
+
+#: __init__.py:34 views.py:416
+msgid "metadata sets"
+msgstr ""
+
+#: __init__.py:39 models.py:93
+msgid "default metadata"
+msgstr ""
+
+#: classes.py:14
+#, python-format
+msgid "'metadata' object has no attribute '%s'"
+msgstr ""
+
+#: forms.py:28
+msgid "required"
+msgstr "wymagany"
+
+#: forms.py:54
+msgid "id"
+msgstr ""
+
+#: forms.py:55
+msgid "Name"
+msgstr "Nazwa"
+
+#: forms.py:57
+msgid "Value"
+msgstr "Wartość"
+
+#: forms.py:58
+msgid "Update"
+msgstr ""
+
+#: forms.py:64
+msgid "Metadata type"
+msgstr ""
+
+#: forms.py:68
+msgid "Remove"
+msgstr "Usuń"
+
+#: forms.py:86 views.py:541 views.py:559
+msgid "Metadata sets"
+msgstr ""
+
+#: forms.py:94 permissions.py:7
+msgid "Metadata"
+msgstr ""
+
+#: models.py:10
+#, python-format
+msgid " Available models: %s"
+msgstr ""
+
+#: models.py:11
+#, python-format
+msgid " Available functions: %s"
+msgstr ""
+
+#: models.py:18
+msgid "name"
+msgstr "nazwa"
+
+#: models.py:18
+msgid "Do not use python reserved words, or spaces."
+msgstr ""
+
+#: models.py:19 models.py:41
+msgid "title"
+msgstr "tytuł"
+
+#: models.py:21
+msgid "default"
+msgstr "domyślne"
+
+#: models.py:22
+#, python-format
+msgid "Enter a string to be evaluated.%s"
+msgstr ""
+
+#: models.py:24
+msgid "lookup"
+msgstr ""
+
+#: models.py:25
+#, python-format
+msgid ""
+"Enter a string to be evaluated. Example: [user.get_full_name() for user in "
+"User.objects.all()].%s"
+msgstr ""
+
+#: models.py:33 models.py:58 views.py:353 views.py:398
+msgid "metadata type"
+msgstr ""
+
+#: models.py:48 models.py:49 models.py:57 views.py:468 views.py:514
+msgid "metadata set"
+msgstr ""
+
+#: models.py:65
+msgid "metadata set item"
+msgstr ""
+
+#: models.py:66
+msgid "metadata set items"
+msgstr ""
+
+#: models.py:74
+msgid "document"
+msgstr "dokument"
+
+#: models.py:75
+msgid "type"
+msgstr "typ"
+
+#: models.py:76 views.py:304
+msgid "value"
+msgstr "wartość"
+
+#: models.py:82 models.py:83
+msgid "document metadata"
+msgstr ""
+
+#: models.py:91 views.py:599
+msgid "document type"
+msgstr ""
+
+#: models.py:92
+msgid "default metadata sets"
+msgstr ""
+
+#: models.py:99
+msgid "document type defaults"
+msgstr ""
+
+#: models.py:100
+msgid "document types defaults"
+msgstr ""
+
+#: permissions.py:8
+msgid "Edit a document's metadata"
+msgstr ""
+
+#: permissions.py:9
+msgid "Add metadata to a document"
+msgstr ""
+
+#: permissions.py:10
+msgid "Remove metadata from a document"
+msgstr ""
+
+#: permissions.py:11
+msgid "View metadata from a document"
+msgstr ""
+
+#: permissions.py:13
+msgid "Metadata setup"
+msgstr ""
+
+#: permissions.py:14
+msgid "Edit metadata types"
+msgstr ""
+
+#: permissions.py:15
+msgid "Create new metadata types"
+msgstr ""
+
+#: permissions.py:16
+msgid "Delete metadata types"
+msgstr ""
+
+#: permissions.py:17
+msgid "View metadata types"
+msgstr ""
+
+#: permissions.py:19
+msgid "Edit metadata sets"
+msgstr ""
+
+#: permissions.py:20
+msgid "Create new metadata sets"
+msgstr ""
+
+#: permissions.py:21
+msgid "Delete metadata sets"
+msgstr ""
+
+#: permissions.py:22
+msgid "View metadata sets"
+msgstr ""
+
+#: views.py:41 views.py:204
+msgid "The selected document doesn't have any metadata."
+msgstr ""
+
+#: views.py:52 views.py:144 views.py:216
+msgid "Must provide at least one document."
+msgstr ""
+
+#: views.py:87 views.py:251
+#, python-format
+msgid "Error deleting document indexes; %s"
+msgstr ""
+
+#: views.py:99
+#, python-format
+msgid "Error editing metadata for document %(document)s; %(error)s."
+msgstr ""
+
+#: views.py:102
+#, python-format
+msgid "Metadata for document %s edited successfully."
+msgstr ""
+
+#: views.py:107 views.py:268
+#, python-format
+msgid "Error updating document indexes; %s"
+msgstr ""
+
+#: views.py:109 views.py:270
+msgid "Document indexes updated successfully."
+msgstr ""
+
+#: views.py:120
+#, python-format
+msgid "Edit metadata for document: %s"
+msgstr ""
+
+#: views.py:122
+#, python-format
+msgid "Edit metadata for documents: %s"
+msgstr ""
+
+#: views.py:161
+#, python-format
+msgid ""
+"Metadata type: %(metadata_type)s successfully added to document "
+"%(document)s."
+msgstr ""
+
+#: views.py:164
+#, python-format
+msgid ""
+"Metadata type: %(metadata_type)s already present in document %(document)s."
+msgstr ""
+
+#: views.py:188
+#, python-format
+msgid "Add metadata type to document: %s"
+msgstr ""
+
+#: views.py:190
+#, python-format
+msgid "Add metadata type to documents: %s"
+msgstr ""
+
+#: views.py:259
+#, python-format
+msgid ""
+"Successfully remove metadata type: %(metadata_type)s from document: "
+"%(document)s."
+msgstr ""
+
+#: views.py:262
+#, python-format
+msgid ""
+"Error removing metadata type: %(metadata_type)s from document: %(document)s."
+msgstr ""
+
+#: views.py:281
+#, python-format
+msgid "Remove metadata types from document: %s"
+msgstr ""
+
+#: views.py:283
+#, python-format
+msgid "Remove metadata types from documents: %s"
+msgstr ""
+
+#: views.py:302
+#, python-format
+msgid "metadata for: %s"
+msgstr ""
+
+#: views.py:320
+msgid "internal name"
+msgstr ""
+
+#: views.py:341
+msgid "Metadata type edited successfully"
+msgstr ""
+
+#: views.py:344
+#, python-format
+msgid "Error editing metadata type; %s"
+msgstr ""
+
+#: views.py:350
+#, python-format
+msgid "edit metadata type: %s"
+msgstr ""
+
+#: views.py:365
+msgid "Metadata type created successfully"
+msgstr ""
+
+#: views.py:371
+msgid "create metadata type"
+msgstr ""
+
+#: views.py:390
+#, python-format
+msgid "Metadata type: %s deleted successfully."
+msgstr ""
+
+#: views.py:392
+#, python-format
+msgid "Metadata type: %(metadata_type)s delete error: %(error)s"
+msgstr ""
+
+#: views.py:403
+#, python-format
+msgid "Are you sure you wish to delete the metadata type: %s?"
+msgstr ""
+
+#: views.py:420
+msgid "members"
+msgstr ""
+
+#: views.py:464
+#, python-format
+msgid "non members of metadata set: %s"
+msgstr ""
+
+#: views.py:465
+#, python-format
+msgid "members of metadata set: %s"
+msgstr ""
+
+#: views.py:480
+msgid "Metadata set created successfully"
+msgstr ""
+
+#: views.py:486
+msgid "create metadata set"
+msgstr ""
+
+#: views.py:505
+#, python-format
+msgid "Metadata set: %s deleted successfully."
+msgstr ""
+
+#: views.py:508
+#, python-format
+msgid "Metadata set: %(metadata_set)s delete error: %(error)s"
+msgstr ""
+
+#: views.py:519
+#, python-format
+msgid "Are you sure you wish to delete the metadata set: %s?"
+msgstr ""
+
+#: views.py:538 views.py:556
+msgid "Metadata types"
+msgstr ""
+
+#: views.py:594
+#, python-format
+msgid "non members of document type: %s"
+msgstr ""
+
+#: views.py:595
+#, python-format
+msgid "members of document type: %s"
+msgstr ""
+
+#: templates/metadata_set_help.html:3
+msgid "What are metadata sets?"
+msgstr ""
+
+#: templates/metadata_set_help.html:4
+msgid ""
+"A metadata set is a group of one or more metadata types. Metadata sets are "
+"useful when creating new documents; selecing a metadata set automatically "
+"attaches it's member metadata types to said document."
+msgstr ""
+
+#: templates/metadata_type_help.html:3
+msgid "What are metadata types?"
+msgstr ""
+
+#: templates/metadata_type_help.html:4
+msgid ""
+"A metadata type defines the characteristics of a value of some kind that can"
+" be attached to a document. Examples of metadata types are: a client name, "
+"a date, or a project to which several documents belong. A metadata type's "
+"name is the internal identifier with which it can be referenced to by other "
+"modules such as the indexing module, the title is the value that is shown to"
+" the users, the default value is the value an instance of this metadata type"
+" will have initially, and the lookup value turns an instance of a metadata "
+"of this type into a choice list which options are the result of the lookup's"
+" code execution."
+msgstr ""
diff --git a/apps/metadata/locale/pt/LC_MESSAGES/django.mo b/apps/metadata/locale/pt/LC_MESSAGES/django.mo
index ad93c5f075..e2f2d544c3 100644
Binary files a/apps/metadata/locale/pt/LC_MESSAGES/django.mo and b/apps/metadata/locale/pt/LC_MESSAGES/django.mo differ
diff --git a/apps/metadata/locale/pt/LC_MESSAGES/django.po b/apps/metadata/locale/pt/LC_MESSAGES/django.po
index 4d7805cb79..bbf8bee6ad 100644
--- a/apps/metadata/locale/pt/LC_MESSAGES/django.po
+++ b/apps/metadata/locale/pt/LC_MESSAGES/django.po
@@ -1,122 +1,65 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
-#
+#
# Translators:
# , 2011.
# Renata Oliveira , 2011.
msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-11-22 11:26-0400\n"
-"PO-Revision-Date: 2011-11-04 00:42+0000\n"
-"Last-Translator: emersonsoares \n"
-"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/"
-"team/pt/)\n"
-"Language: pt\n"
+"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
+"PO-Revision-Date: 2012-02-12 19:24+0000\n"
+"Last-Translator: Roberto Rosario \n"
+"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/team/pt/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
+"Language: pt\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
-#: __init__.py:12
-msgid "Edit a document's metadata"
-msgstr "Editar metadados de um documento"
-
-#: __init__.py:13
-msgid "Add metadata to a document"
-msgstr "Adicionar metadados a um documento"
-
-#: __init__.py:14
-msgid "Remove metadata from a document"
-msgstr "Remover metadados de um documento"
-
-#: __init__.py:15
-msgid "View metadata from a document"
-msgstr "Ver os metadados de um documento"
-
-#: __init__.py:17
-msgid "Edit metadata types"
-msgstr "Editar tipos de metadados"
-
-#: __init__.py:18
-msgid "Create new metadata types"
-msgstr "Criar novos tipos de metadados"
-
-#: __init__.py:19
-msgid "Delete metadata types"
-msgstr "Excluir tipos de metadados"
-
-#: __init__.py:20
-msgid "View metadata types"
-msgstr "Ver tipos de metadados"
-
-#: __init__.py:22
-msgid "Edit metadata sets"
-msgstr "Editar conjuntos de metadados"
-
-#: __init__.py:23
-msgid "Create new metadata sets"
-msgstr "Criar novos conjuntos de metadados"
-
-#: __init__.py:24
-msgid "Delete metadata sets"
-msgstr "Excluir conjuntos de metadados"
-
-#: __init__.py:25
-msgid "View metadata sets"
-msgstr "Ver conjuntos de metadados"
-
-#: __init__.py:27 forms.py:94
-msgid "Metadata"
-msgstr "Metadados"
-
-#: __init__.py:33
-msgid "Metadata setup"
-msgstr "Configuração de metadados"
-
-#: __init__.py:44 __init__.py:46
+#: __init__.py:21 __init__.py:23
msgid "edit metadata"
msgstr "editar metadados"
-#: __init__.py:45
+#: __init__.py:22
msgid "metadata"
msgstr "metadados"
-#: __init__.py:47 __init__.py:48
+#: __init__.py:24 __init__.py:25
msgid "add metadata"
msgstr "adicionar metadados"
-#: __init__.py:49 __init__.py:50
+#: __init__.py:26 __init__.py:27
msgid "remove metadata"
msgstr "remover metadados"
-#: __init__.py:52 models.py:33 views.py:294
+#: __init__.py:29 models.py:34 views.py:316
msgid "metadata types"
msgstr "tipos de metadados"
-#: __init__.py:53 __init__.py:58
+#: __init__.py:30 __init__.py:35
msgid "edit"
msgstr "editar"
-#: __init__.py:54 __init__.py:59
+#: __init__.py:31 __init__.py:36
msgid "delete"
msgstr "excluir"
-#: __init__.py:55 __init__.py:60
+#: __init__.py:32 __init__.py:37
msgid "create new"
msgstr "criar novo"
-#: __init__.py:57 views.py:394
+#: __init__.py:34 views.py:416
msgid "metadata sets"
msgstr "conjuntos de metadados"
-#: __init__.py:62 models.py:92
+#: __init__.py:39 models.py:93
msgid "default metadata"
msgstr "metadados padrão"
-#: classes.py:12
+#: classes.py:14
#, python-format
msgid "'metadata' object has no attribute '%s'"
msgstr "Objeto 'metadados' tem nenhum atributo '%s'"
@@ -149,46 +92,50 @@ msgstr "Tipo de metadados"
msgid "Remove"
msgstr "Remover"
-#: forms.py:86
+#: forms.py:86 views.py:541 views.py:559
msgid "Metadata sets"
msgstr "Conjuntos de metadados"
-#: models.py:9
+#: forms.py:94 permissions.py:7
+msgid "Metadata"
+msgstr "Metadados"
+
+#: models.py:10
#, python-format
msgid " Available models: %s"
msgstr "Modelos disponíveis: %s"
-#: models.py:10
+#: models.py:11
#, python-format
msgid " Available functions: %s"
msgstr "Funções disponíveis: %s"
-#: models.py:17
+#: models.py:18
msgid "name"
msgstr "nome"
-#: models.py:17
+#: models.py:18
msgid "Do not use python reserved words, or spaces."
msgstr "Não use palavras reservadas python, ou espaços."
-#: models.py:18 models.py:40
+#: models.py:19 models.py:41
msgid "title"
msgstr "título"
-#: models.py:20
+#: models.py:21
msgid "default"
msgstr "padrão"
-#: models.py:21
+#: models.py:22
#, python-format
msgid "Enter a string to be evaluated.%s"
msgstr "Digite uma expressão a ser avaliada. %s"
-#: models.py:23
+#: models.py:24
msgid "lookup"
msgstr "pesquisa"
-#: models.py:24
+#: models.py:25
#, python-format
msgid ""
"Enter a string to be evaluated. Example: [user.get_full_name() for user in "
@@ -197,122 +144,176 @@ msgstr ""
"Digite uma expressão a ser avaliada. Exemplo: [user.get_full_name()para o "
"usuário em User.objects.all()]. %s"
-#: models.py:32 models.py:57 views.py:331 views.py:376
+#: models.py:33 models.py:58 views.py:353 views.py:398
msgid "metadata type"
msgstr "tipo de metadados"
-#: models.py:47 models.py:48 models.py:56 views.py:446 views.py:491
+#: models.py:48 models.py:49 models.py:57 views.py:468 views.py:514
msgid "metadata set"
msgstr "conjunto de metadados"
-#: models.py:64
+#: models.py:65
msgid "metadata set item"
msgstr "conjunto de item de metadados"
-#: models.py:65
+#: models.py:66
msgid "metadata set items"
msgstr "conjunto de itens de metadados"
-#: models.py:73
+#: models.py:74
msgid "document"
msgstr "documento"
-#: models.py:74
+#: models.py:75
msgid "type"
msgstr "tipo"
-#: models.py:75 views.py:283
+#: models.py:76 views.py:304
msgid "value"
msgstr "valor"
-#: models.py:81 models.py:82
+#: models.py:82 models.py:83
msgid "document metadata"
msgstr "metadados do documento"
-#: models.py:90 views.py:559
+#: models.py:91 views.py:599
msgid "document type"
msgstr "tipo de documento"
-#: models.py:91
+#: models.py:92
msgid "default metadata sets"
msgstr "padrão de metadados definidos"
-#: models.py:98
+#: models.py:99
msgid "document type defaults"
msgstr "padrões de tipo de documento"
-#: models.py:99
+#: models.py:100
msgid "document types defaults"
msgstr "padrões de tipos de documentos"
-#: views.py:38 views.py:193
+#: permissions.py:8
+msgid "Edit a document's metadata"
+msgstr "Editar metadados de um documento"
+
+#: permissions.py:9
+msgid "Add metadata to a document"
+msgstr "Adicionar metadados a um documento"
+
+#: permissions.py:10
+msgid "Remove metadata from a document"
+msgstr "Remover metadados de um documento"
+
+#: permissions.py:11
+msgid "View metadata from a document"
+msgstr "Ver os metadados de um documento"
+
+#: permissions.py:13
+msgid "Metadata setup"
+msgstr "Configuração de metadados"
+
+#: permissions.py:14
+msgid "Edit metadata types"
+msgstr "Editar tipos de metadados"
+
+#: permissions.py:15
+msgid "Create new metadata types"
+msgstr "Criar novos tipos de metadados"
+
+#: permissions.py:16
+msgid "Delete metadata types"
+msgstr "Excluir tipos de metadados"
+
+#: permissions.py:17
+msgid "View metadata types"
+msgstr "Ver tipos de metadados"
+
+#: permissions.py:19
+msgid "Edit metadata sets"
+msgstr "Editar conjuntos de metadados"
+
+#: permissions.py:20
+msgid "Create new metadata sets"
+msgstr "Criar novos conjuntos de metadados"
+
+#: permissions.py:21
+msgid "Delete metadata sets"
+msgstr "Excluir conjuntos de metadados"
+
+#: permissions.py:22
+msgid "View metadata sets"
+msgstr "Ver conjuntos de metadados"
+
+#: views.py:41 views.py:204
msgid "The selected document doesn't have any metadata."
msgstr "O documento selecionado não tem qualquer metadado."
-#: views.py:43 views.py:131 views.py:199
+#: views.py:52 views.py:144 views.py:216
msgid "Must provide at least one document."
msgstr "Deve fornecer pelo menos um documento."
-#: views.py:78 views.py:234
+#: views.py:87 views.py:251
#, python-format
msgid "Error deleting document indexes; %s"
msgstr "Erro ao excluir índices de documento; %s"
-#: views.py:90
+#: views.py:99
#, python-format
msgid "Error editing metadata for document %(document)s; %(error)s."
msgstr "Erro de edição de metadados para documento %(document)s; %(error)s."
-#: views.py:93
+#: views.py:102
#, python-format
msgid "Metadata for document %s edited successfully."
msgstr "Metadados para o documento %s alterados com sucesso."
-#: views.py:98 views.py:251
+#: views.py:107 views.py:268
#, python-format
msgid "Error updating document indexes; %s"
msgstr "Erro ao atualizar índices de documento; %s"
-#: views.py:100 views.py:253
+#: views.py:109 views.py:270
msgid "Document indexes updated successfully."
msgstr "Índices de documento atualizados com sucesso. "
-#: views.py:111
+#: views.py:120
#, python-format
msgid "Edit metadata for document: %s"
msgstr "Editar os metadados do documento: %s"
-#: views.py:113
+#: views.py:122
#, python-format
msgid "Edit metadata for documents: %s"
msgstr "Editar os metadados do documentos: %s"
-#: views.py:148
+#: views.py:161
#, python-format
msgid ""
-"Metadata type: %(metadata_type)s successfully added to document %(document)s."
+"Metadata type: %(metadata_type)s successfully added to document "
+"%(document)s."
msgstr ""
"Tipo de metadados: %(metadata_type)s adicionado com sucesso para documento "
"%(document)s."
-#: views.py:151
+#: views.py:164
#, python-format
msgid ""
"Metadata type: %(metadata_type)s already present in document %(document)s."
msgstr ""
-"Tipo de metadados: %(metadata_type)s já presente no documento %(document)s ."
+"Tipo de metadados: %(metadata_type)s já presente no documento %(document)s "
+"."
-#: views.py:175
+#: views.py:188
#, python-format
msgid "Add metadata type to document: %s"
msgstr "Adicionar tipo de metadados ao documento: %s"
-#: views.py:177
+#: views.py:190
#, python-format
msgid "Add metadata type to documents: %s"
msgstr "Adicionar tipo de metadados aos documentos: %s"
-#: views.py:242
+#: views.py:259
#, python-format
msgid ""
"Successfully remove metadata type: %(metadata_type)s from document: "
@@ -321,7 +322,7 @@ msgstr ""
"Tipos de metadados removidos com êxito: %(metadata_type)s do documento: "
"%(document)s."
-#: views.py:245
+#: views.py:262
#, python-format
msgid ""
"Error removing metadata type: %(metadata_type)s from document: %(document)s."
@@ -329,105 +330,109 @@ msgstr ""
"Erro ao remover tipo de metadados: %(metadata_type)s do documento: "
"%(document)s."
-#: views.py:264
+#: views.py:281
#, python-format
msgid "Remove metadata types from document: %s"
msgstr "Remover tipos de metadados do documento: %s"
-#: views.py:266
+#: views.py:283
#, python-format
msgid "Remove metadata types from documents: %s"
msgstr "Remover tipos de metadados dos documentos: %s"
-#: views.py:281
+#: views.py:302
#, python-format
msgid "metadata for: %s"
msgstr "metadados para: %s"
-#: views.py:298
+#: views.py:320
msgid "internal name"
msgstr "nome interno"
-#: views.py:319
+#: views.py:341
msgid "Metadata type edited successfully"
msgstr "Tipo de metadados editados com sucesso"
-#: views.py:322
+#: views.py:344
#, python-format
msgid "Error editing metadata type; %s"
msgstr "Erro de edição de tipo de metadados; %s"
-#: views.py:328
+#: views.py:350
#, python-format
msgid "edit metadata type: %s"
msgstr "editar tipo de metadados: %s"
-#: views.py:343
+#: views.py:365
msgid "Metadata type created successfully"
msgstr "Tipo de metadados criado com sucesso"
-#: views.py:349
+#: views.py:371
msgid "create metadata type"
msgstr "criar um tipo de metadados"
-#: views.py:368
+#: views.py:390
#, python-format
msgid "Metadata type: %s deleted successfully."
msgstr "Tipo de metadados: %s removido com sucesso."
-#: views.py:370
+#: views.py:392
#, python-format
msgid "Metadata type: %(metadata_type)s delete error: %(error)s"
msgstr "Tipo de metadados: %(metadata_type)s erro ao deletar: %(error)s"
-#: views.py:381
+#: views.py:403
#, python-format
msgid "Are you sure you wish to delete the metadata type: %s?"
msgstr "Tem certeza de que deseja excluir o tipo de metadados: %s?"
-#: views.py:398
+#: views.py:420
msgid "members"
msgstr "membros"
-#: views.py:442
+#: views.py:464
#, python-format
msgid "non members of metadata set: %s"
msgstr "não-membros do conjunto de metadados: %s"
-#: views.py:443
+#: views.py:465
#, python-format
msgid "members of metadata set: %s"
msgstr "membros do conjunto de metadados: %s"
-#: views.py:458
+#: views.py:480
msgid "Metadata set created successfully"
msgstr "Conjunto de metadados criado com sucesso"
-#: views.py:464
+#: views.py:486
msgid "create metadata set"
msgstr "criar um conjunto de metadados"
-#: views.py:483
+#: views.py:505
#, python-format
msgid "Metadata set: %s deleted successfully."
msgstr "Conjunto de metadados: %s removido com sucesso."
-#: views.py:485
+#: views.py:508
#, python-format
msgid "Metadata set: %(metadata_set)s delete error: %(error)s"
msgstr "Conjunto de metadados: %(metadata_set)s erro ao deletar: %(error)s "
-#: views.py:496
+#: views.py:519
#, python-format
msgid "Are you sure you wish to delete the metadata set: %s?"
msgstr "Tem certeza de que deseja excluir o conjunto de metadados: %s?"
-#: views.py:554
+#: views.py:538 views.py:556
+msgid "Metadata types"
+msgstr ""
+
+#: views.py:594
#, python-format
msgid "non members of document type: %s"
msgstr "não membros do tipo de documento: %s"
-#: views.py:555
+#: views.py:595
#, python-format
msgid "members of document type: %s"
msgstr "membros do tipo de documento: %s"
@@ -453,22 +458,24 @@ msgstr "Quais são os tipos de metadados?"
#: templates/metadata_type_help.html:4
msgid ""
-"A metadata type defines the characteristics of a value of some kind that can "
-"be attached to a document. Examples of metadata types are: a client name, a "
-"date, or a project to which several documents belong. A metadata type's "
+"A metadata type defines the characteristics of a value of some kind that can"
+" be attached to a document. Examples of metadata types are: a client name, "
+"a date, or a project to which several documents belong. A metadata type's "
"name is the internal identifier with which it can be referenced to by other "
-"modules such as the indexing module, the title is the value that is shown to "
-"the users, the default value is the value an instance of this metadata type "
-"will have initially, and the lookup value turns an instance of a metadata of "
-"this type into a choice list which options are the result of the lookup's "
-"code execution."
+"modules such as the indexing module, the title is the value that is shown to"
+" the users, the default value is the value an instance of this metadata type"
+" will have initially, and the lookup value turns an instance of a metadata "
+"of this type into a choice list which options are the result of the lookup's"
+" code execution."
msgstr ""
-"Um tipo de metadados define as características de um valor de algum tipo que "
-"pode ser anexado a um documento. Exemplos de tipos de metadados são: um nome "
-"de cliente, uma data ou um projeto ao qual pertencem vários documentos. O "
-"nome de um tipo de metadados é o identificador interno com o qual ele pode "
-"ser referenciado pelos outros módulos, como o módulo de indexação, o título "
-"é o valor que é mostrado para os usuários, o valor padrão é o valor de uma "
-"instância desse tipo de metadados terá inicialmente, o valor de pesquisa e "
-"vira um exemplo de um metadados deste tipo em uma lista de escolha de quais "
-"opções são o resultado da execução a pesquisa de código."
+"Um tipo de metadados define as características de um valor de algum tipo que"
+" pode ser anexado a um documento. Exemplos de tipos de metadados são: um "
+"nome de cliente, uma data ou um projeto ao qual pertencem vários documentos."
+" O nome de um tipo de metadados é o identificador interno com o qual ele "
+"pode ser referenciado pelos outros módulos, como o módulo de indexação, o "
+"título é o valor que é mostrado para os usuários, o valor padrão é o valor "
+"de uma instância desse tipo de metadados terá inicialmente, o valor de "
+"pesquisa e vira um exemplo de um metadados deste tipo em uma lista de "
+"escolha de quais opções são o resultado da execução a pesquisa de código."
+
+
diff --git a/apps/metadata/locale/ru/LC_MESSAGES/django.mo b/apps/metadata/locale/ru/LC_MESSAGES/django.mo
index d58dc848fd..c0c8184351 100644
Binary files a/apps/metadata/locale/ru/LC_MESSAGES/django.mo and b/apps/metadata/locale/ru/LC_MESSAGES/django.mo differ
diff --git a/apps/metadata/locale/ru/LC_MESSAGES/django.po b/apps/metadata/locale/ru/LC_MESSAGES/django.po
index bb28056cda..851c2f577b 100644
--- a/apps/metadata/locale/ru/LC_MESSAGES/django.po
+++ b/apps/metadata/locale/ru/LC_MESSAGES/django.po
@@ -1,122 +1,64 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
-#
+#
# Translators:
-# Sergey Glita , 2011.
+# Sergey Glita , 2011, 2012.
msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-11-22 11:26-0400\n"
-"PO-Revision-Date: 2011-11-04 10:20+0000\n"
-"Last-Translator: gsv70 \n"
-"Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/team/"
-"ru/)\n"
-"Language: ru\n"
+"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
+"PO-Revision-Date: 2012-02-27 04:25+0000\n"
+"Last-Translator: Sergey Glita \n"
+"Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/language/ru/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
-"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
+"Language: ru\n"
+"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
-#: __init__.py:12
-msgid "Edit a document's metadata"
-msgstr "Редактирование метаданные документа"
-
-#: __init__.py:13
-msgid "Add metadata to a document"
-msgstr "Добавить метаданные в документ"
-
-#: __init__.py:14
-msgid "Remove metadata from a document"
-msgstr "Удаление метаданных из документа"
-
-#: __init__.py:15
-msgid "View metadata from a document"
-msgstr "Просмотр метаданных из документа"
-
-#: __init__.py:17
-msgid "Edit metadata types"
-msgstr "Редактировать типы метаданных"
-
-#: __init__.py:18
-msgid "Create new metadata types"
-msgstr "Создание новых типов метаданных"
-
-#: __init__.py:19
-msgid "Delete metadata types"
-msgstr "Удаление типов метаданных"
-
-#: __init__.py:20
-msgid "View metadata types"
-msgstr "Просмотр типов метаданных"
-
-#: __init__.py:22
-msgid "Edit metadata sets"
-msgstr "Редактирование наборов метаданных"
-
-#: __init__.py:23
-msgid "Create new metadata sets"
-msgstr "Создание новых наборов метаданных"
-
-#: __init__.py:24
-msgid "Delete metadata sets"
-msgstr "Удаление наборов метаданных"
-
-#: __init__.py:25
-msgid "View metadata sets"
-msgstr "Просмотр наборов метаданных"
-
-#: __init__.py:27 forms.py:94
-msgid "Metadata"
-msgstr "Метаданные"
-
-#: __init__.py:33
-msgid "Metadata setup"
-msgstr "Настройки метаданных "
-
-#: __init__.py:44 __init__.py:46
+#: __init__.py:21 __init__.py:23
msgid "edit metadata"
msgstr "редактировать метаданные"
-#: __init__.py:45
+#: __init__.py:22
msgid "metadata"
msgstr "метаданные"
-#: __init__.py:47 __init__.py:48
+#: __init__.py:24 __init__.py:25
msgid "add metadata"
msgstr "добавить метаданные"
-#: __init__.py:49 __init__.py:50
+#: __init__.py:26 __init__.py:27
msgid "remove metadata"
msgstr "удалить метаданные"
-#: __init__.py:52 models.py:33 views.py:294
+#: __init__.py:29 models.py:34 views.py:316
msgid "metadata types"
msgstr "типы метаданных"
-#: __init__.py:53 __init__.py:58
+#: __init__.py:30 __init__.py:35
msgid "edit"
msgstr "редактировать"
-#: __init__.py:54 __init__.py:59
+#: __init__.py:31 __init__.py:36
msgid "delete"
msgstr "удалить"
-#: __init__.py:55 __init__.py:60
+#: __init__.py:32 __init__.py:37
msgid "create new"
msgstr "создание новых"
-#: __init__.py:57 views.py:394
+#: __init__.py:34 views.py:416
msgid "metadata sets"
msgstr "наборы метаданных"
-#: __init__.py:62 models.py:92
+#: __init__.py:39 models.py:93
msgid "default metadata"
msgstr "метаданные по умолчанию"
-#: classes.py:12
+#: classes.py:14
#, python-format
msgid "'metadata' object has no attribute '%s'"
msgstr "объект метаданных не имеет аттрибута '%s'"
@@ -149,284 +91,337 @@ msgstr "Тип метаданных"
msgid "Remove"
msgstr "Удалить"
-#: forms.py:86
+#: forms.py:86 views.py:541 views.py:559
msgid "Metadata sets"
msgstr "Наборы метаданных"
-#: models.py:9
+#: forms.py:94 permissions.py:7
+msgid "Metadata"
+msgstr "Метаданные"
+
+#: models.py:10
#, python-format
msgid " Available models: %s"
msgstr "Доступные модели: %s"
-#: models.py:10
+#: models.py:11
#, python-format
msgid " Available functions: %s"
msgstr "Доступные функции:%s."
-#: models.py:17
+#: models.py:18
msgid "name"
msgstr "имя"
-#: models.py:17
+#: models.py:18
msgid "Do not use python reserved words, or spaces."
msgstr "Не используйте зарезервированные слова python, или пробелы."
-#: models.py:18 models.py:40
+#: models.py:19 models.py:41
msgid "title"
msgstr "название"
-#: models.py:20
+#: models.py:21
msgid "default"
msgstr "умолчание"
-#: models.py:21
+#: models.py:22
#, python-format
msgid "Enter a string to be evaluated.%s"
msgstr "Введите строку для вычисления %s"
-#: models.py:23
+#: models.py:24
msgid "lookup"
msgstr "поиск"
-#: models.py:24
+#: models.py:25
#, python-format
msgid ""
"Enter a string to be evaluated. Example: [user.get_full_name() for user in "
"User.objects.all()].%s"
-msgstr ""
-"Введите строку для вычисления. Пример: [user.get_full_name() for user in "
-"User.objects.all()].%s"
+msgstr "Введите строку для вычисления. Пример: [user.get_full_name() for user in User.objects.all()].%s"
-#: models.py:32 models.py:57 views.py:331 views.py:376
+#: models.py:33 models.py:58 views.py:353 views.py:398
msgid "metadata type"
msgstr "тип метаданных"
-#: models.py:47 models.py:48 models.py:56 views.py:446 views.py:491
+#: models.py:48 models.py:49 models.py:57 views.py:468 views.py:514
msgid "metadata set"
msgstr "набор метаданных"
-#: models.py:64
+#: models.py:65
msgid "metadata set item"
msgstr "элемент набора метаданных"
-#: models.py:65
+#: models.py:66
msgid "metadata set items"
msgstr "элементы набора метаданных"
-#: models.py:73
+#: models.py:74
msgid "document"
msgstr "документ"
-#: models.py:74
+#: models.py:75
msgid "type"
msgstr "тип"
-#: models.py:75 views.py:283
+#: models.py:76 views.py:304
msgid "value"
msgstr "значение"
-#: models.py:81 models.py:82
+#: models.py:82 models.py:83
msgid "document metadata"
msgstr "метаданные документа"
-#: models.py:90 views.py:559
+#: models.py:91 views.py:599
msgid "document type"
msgstr "тип документа"
-#: models.py:91
+#: models.py:92
msgid "default metadata sets"
msgstr "набор метаданных по умолчанию"
-#: models.py:98
+#: models.py:99
msgid "document type defaults"
msgstr "умолчания для типа документа"
-#: models.py:99
+#: models.py:100
msgid "document types defaults"
msgstr "тип документа по умолчанию "
-#: views.py:38 views.py:193
+#: permissions.py:8
+msgid "Edit a document's metadata"
+msgstr "Редактирование метаданные документа"
+
+#: permissions.py:9
+msgid "Add metadata to a document"
+msgstr "Добавить метаданные в документ"
+
+#: permissions.py:10
+msgid "Remove metadata from a document"
+msgstr "Удаление метаданных из документа"
+
+#: permissions.py:11
+msgid "View metadata from a document"
+msgstr "Просмотр метаданных из документа"
+
+#: permissions.py:13
+msgid "Metadata setup"
+msgstr "Настройки метаданных "
+
+#: permissions.py:14
+msgid "Edit metadata types"
+msgstr "Редактировать типы метаданных"
+
+#: permissions.py:15
+msgid "Create new metadata types"
+msgstr "Создание новых типов метаданных"
+
+#: permissions.py:16
+msgid "Delete metadata types"
+msgstr "Удаление типов метаданных"
+
+#: permissions.py:17
+msgid "View metadata types"
+msgstr "Просмотр типов метаданных"
+
+#: permissions.py:19
+msgid "Edit metadata sets"
+msgstr "Редактирование наборов метаданных"
+
+#: permissions.py:20
+msgid "Create new metadata sets"
+msgstr "Создание новых наборов метаданных"
+
+#: permissions.py:21
+msgid "Delete metadata sets"
+msgstr "Удаление наборов метаданных"
+
+#: permissions.py:22
+msgid "View metadata sets"
+msgstr "Просмотр наборов метаданных"
+
+#: views.py:41 views.py:204
msgid "The selected document doesn't have any metadata."
msgstr "Выбранный документ не имеет метаданных."
-#: views.py:43 views.py:131 views.py:199
+#: views.py:52 views.py:144 views.py:216
msgid "Must provide at least one document."
msgstr "Необходимо предоставить хотя бы один документ."
-#: views.py:78 views.py:234
+#: views.py:87 views.py:251
#, python-format
msgid "Error deleting document indexes; %s"
msgstr "Ошибка при удалении индексов документа; %s"
-#: views.py:90
+#: views.py:99
#, python-format
msgid "Error editing metadata for document %(document)s; %(error)s."
-msgstr ""
-"Ошибка редактирования метаданных для документа %(document)s; %(error)s."
+msgstr "Ошибка редактирования метаданных для документа %(document)s; %(error)s."
-#: views.py:93
+#: views.py:102
#, python-format
msgid "Metadata for document %s edited successfully."
msgstr "Метаданные для документов %s изменены."
-#: views.py:98 views.py:251
+#: views.py:107 views.py:268
#, python-format
msgid "Error updating document indexes; %s"
msgstr "Ошибка при обновлении индексов документа; %s"
-#: views.py:100 views.py:253
+#: views.py:109 views.py:270
msgid "Document indexes updated successfully."
msgstr "Индексы документа успешно обновлены."
-#: views.py:111
+#: views.py:120
#, python-format
msgid "Edit metadata for document: %s"
msgstr "Редактировать метаданные документа:%s."
-#: views.py:113
+#: views.py:122
#, python-format
msgid "Edit metadata for documents: %s"
msgstr "Редактирование метаданных для документов: %s"
-#: views.py:148
+#: views.py:161
#, python-format
msgid ""
-"Metadata type: %(metadata_type)s successfully added to document %(document)s."
-msgstr ""
-"Тип метаданных: %(metadata_type)s успешно добавлены к документу %(document)s."
+"Metadata type: %(metadata_type)s successfully added to document "
+"%(document)s."
+msgstr "Тип метаданных: %(metadata_type)s успешно добавлены к документу %(document)s."
-#: views.py:151
+#: views.py:164
#, python-format
msgid ""
"Metadata type: %(metadata_type)s already present in document %(document)s."
msgstr "Тип метаданных: %(metadata_type)s уже есть в документе %(document)s."
-#: views.py:175
+#: views.py:188
#, python-format
msgid "Add metadata type to document: %s"
msgstr "Добавить метаданные типа к документу: %s."
-#: views.py:177
+#: views.py:190
#, python-format
msgid "Add metadata type to documents: %s"
msgstr "Добавляйте метаданные типа документов: %s"
-#: views.py:242
+#: views.py:259
#, python-format
msgid ""
"Successfully remove metadata type: %(metadata_type)s from document: "
"%(document)s."
-msgstr ""
-"Метаданные типа: %(metadata_type)s успешно удалены из документа: "
-"%(document)s."
+msgstr "Метаданные типа: %(metadata_type)s успешно удалены из документа: %(document)s."
-#: views.py:245
+#: views.py:262
#, python-format
msgid ""
"Error removing metadata type: %(metadata_type)s from document: %(document)s."
-msgstr ""
-"Ошибка удаления метаданных, наберите:%(metadata_type)s из документа: "
-"%(document)s ."
+msgstr "Ошибка удаления метаданных, наберите:%(metadata_type)s из документа: %(document)s ."
-#: views.py:264
+#: views.py:281
#, python-format
msgid "Remove metadata types from document: %s"
msgstr "Удалить типы метаданных из документа: %s"
-#: views.py:266
+#: views.py:283
#, python-format
msgid "Remove metadata types from documents: %s"
msgstr "Удалить типы метаданных из документа: %s"
-#: views.py:281
+#: views.py:302
#, python-format
msgid "metadata for: %s"
msgstr "метаданных для: %s"
-#: views.py:298
+#: views.py:320
msgid "internal name"
msgstr "внутреннее имя"
-#: views.py:319
+#: views.py:341
msgid "Metadata type edited successfully"
msgstr "Тип метаданных отредактирован."
-#: views.py:322
+#: views.py:344
#, python-format
msgid "Error editing metadata type; %s"
msgstr "Ошибка редактирования типа метаданных; %s"
-#: views.py:328
+#: views.py:350
#, python-format
msgid "edit metadata type: %s"
msgstr "редактировать метаданные типа: %s"
-#: views.py:343
+#: views.py:365
msgid "Metadata type created successfully"
msgstr "Тип метаданных успешно создан"
-#: views.py:349
+#: views.py:371
msgid "create metadata type"
msgstr "создать тип метаданных"
-#: views.py:368
+#: views.py:390
#, python-format
msgid "Metadata type: %s deleted successfully."
msgstr "Тип метаданных: %s успешно удален."
-#: views.py:370
+#: views.py:392
#, python-format
msgid "Metadata type: %(metadata_type)s delete error: %(error)s"
msgstr "Метаданные типа: %(metadata_type)s ошибка удаления: %(error)s"
-#: views.py:381
+#: views.py:403
#, python-format
msgid "Are you sure you wish to delete the metadata type: %s?"
msgstr "Вы действительно хотите удалить метаданные:%s?"
-#: views.py:398
+#: views.py:420
msgid "members"
msgstr "элементы"
-#: views.py:442
+#: views.py:464
#, python-format
msgid "non members of metadata set: %s"
msgstr "не входят в набор метаданных: %s"
-#: views.py:443
+#: views.py:465
#, python-format
msgid "members of metadata set: %s"
msgstr "входят в набор метаданных: %s"
-#: views.py:458
+#: views.py:480
msgid "Metadata set created successfully"
msgstr "Набор метаданных создан"
-#: views.py:464
+#: views.py:486
msgid "create metadata set"
msgstr "создать набор метаданных"
-#: views.py:483
+#: views.py:505
#, python-format
msgid "Metadata set: %s deleted successfully."
msgstr "Набор метаданных: %s удалён."
-#: views.py:485
+#: views.py:508
#, python-format
msgid "Metadata set: %(metadata_set)s delete error: %(error)s"
msgstr "Набор метаданных: %(metadata_set)s ошибка удаления: %(error)s"
-#: views.py:496
+#: views.py:519
#, python-format
msgid "Are you sure you wish to delete the metadata set: %s?"
msgstr "Вы действительно хотите удалить набор метаданных: %s?"
-#: views.py:554
+#: views.py:538 views.py:556
+msgid "Metadata types"
+msgstr "Типы метаданных"
+
+#: views.py:594
#, python-format
msgid "non members of document type: %s"
msgstr "не относится к типу документа: %s."
-#: views.py:555
+#: views.py:595
#, python-format
msgid "members of document type: %s"
msgstr "относится к типу документа: %s."
@@ -440,10 +435,7 @@ msgid ""
"A metadata set is a group of one or more metadata types. Metadata sets are "
"useful when creating new documents; selecing a metadata set automatically "
"attaches it's member metadata types to said document."
-msgstr ""
-"Набор метаданных это группа из одного или более типов метаданных. Наборы "
-"метаданных полезны при создании новых документов; указание набора "
-"метаданных автоматически добавляет метаданные набора к документу."
+msgstr "Набор метаданных это группа из одного или более типов метаданных. Наборы метаданных полезны при создании новых документов; указание набора метаданных автоматически добавляет метаданные набора к документу."
#: templates/metadata_type_help.html:3
msgid "What are metadata types?"
@@ -451,25 +443,13 @@ msgstr "Что такое типы метаданных?"
#: templates/metadata_type_help.html:4
msgid ""
-"A metadata type defines the characteristics of a value of some kind that can "
-"be attached to a document. Examples of metadata types are: a client name, a "
-"date, or a project to which several documents belong. A metadata type's "
+"A metadata type defines the characteristics of a value of some kind that can"
+" be attached to a document. Examples of metadata types are: a client name, "
+"a date, or a project to which several documents belong. A metadata type's "
"name is the internal identifier with which it can be referenced to by other "
-"modules such as the indexing module, the title is the value that is shown to "
-"the users, the default value is the value an instance of this metadata type "
-"will have initially, and the lookup value turns an instance of a metadata of "
-"this type into a choice list which options are the result of the lookup's "
-"code execution."
-msgstr ""
-"Тип метаданных определяет характеристики информации которая может быть "
-"присоединена к документу. Примеры типов метаданных : имя клиента, дата или "
-"проект, к которому принадлежат несколько документов. Имя типа метаданных "
-"является внутренним идентификатором, на который могут ссылаться другие "
-"модули, такие как модуль индексирования\n"
-"\n"
-"Имя это значение, которое показано пользователям\n"
-"\n"
-"Значение по умолчанию - значение экземпляра этого типа метаданных будет на "
-"начальном этапе,\n"
-"\n"
-"Краткое имя служит для выбора из списка значений в результатах поиска."
+"modules such as the indexing module, the title is the value that is shown to"
+" the users, the default value is the value an instance of this metadata type"
+" will have initially, and the lookup value turns an instance of a metadata "
+"of this type into a choice list which options are the result of the lookup's"
+" code execution."
+msgstr "Тип метаданных определяет характеристики информации которая может быть присоединена к документу. Примеры типов метаданных : имя клиента, дата или проект, к которому принадлежат несколько документов. Имя типа метаданных является внутренним идентификатором, на который могут ссылаться другие модули, такие как модуль индексирования\n\nИмя это значение, которое показано пользователям\n\nЗначение по умолчанию - значение экземпляра этого типа метаданных будет на начальном этапе,\n\nКраткое имя служит для выбора из списка значений в результатах поиска."
diff --git a/apps/metadata/models.py b/apps/metadata/models.py
index 8b3d6463ea..5e13f65c48 100644
--- a/apps/metadata/models.py
+++ b/apps/metadata/models.py
@@ -1,10 +1,11 @@
+from __future__ import absolute_import
+
from django.db import models
from django.utils.translation import ugettext_lazy as _
from documents.models import Document, DocumentType
-from metadata.conf.settings import AVAILABLE_MODELS
-from metadata.conf.settings import AVAILABLE_FUNCTIONS
+from .conf.settings import (AVAILABLE_MODELS, AVAILABLE_FUNCTIONS)
available_models_string = (_(u' Available models: %s') % u','.join([name for name, model in AVAILABLE_MODELS.items()])) if AVAILABLE_MODELS else u''
available_functions_string = (_(u' Available functions: %s') % u','.join([u'%s()' % name for name, function in AVAILABLE_FUNCTIONS.items()])) if AVAILABLE_FUNCTIONS else u''
@@ -13,7 +14,7 @@ available_functions_string = (_(u' Available functions: %s') % u','.join([u'%s()
class MetadataType(models.Model):
"""
Define a type of metadata
- """
+ """
name = models.CharField(unique=True, max_length=48, verbose_name=_(u'name'), help_text=_(u'Do not use python reserved words, or spaces.'))
title = models.CharField(max_length=48, verbose_name=_(u'title'), blank=True, null=True)
default = models.CharField(max_length=128, blank=True, null=True,
@@ -86,7 +87,7 @@ class DocumentTypeDefaults(models.Model):
"""
Default preselected metadata types and metadata set per document
type
- """
+ """
document_type = models.ForeignKey(DocumentType, verbose_name=_(u'document type'))
default_metadata_sets = models.ManyToManyField(MetadataSet, blank=True, verbose_name=_(u'default metadata sets'))
default_metadata = models.ManyToManyField(MetadataType, blank=True, verbose_name=_(u'default metadata'))
diff --git a/apps/metadata/permissions.py b/apps/metadata/permissions.py
new file mode 100644
index 0000000000..9f6ff38a76
--- /dev/null
+++ b/apps/metadata/permissions.py
@@ -0,0 +1,22 @@
+from __future__ import absolute_import
+
+from django.utils.translation import ugettext_lazy as _
+
+from permissions.models import Permission, PermissionNamespace
+
+metadata_namespace = PermissionNamespace('metadata', _(u'Metadata'))
+PERMISSION_METADATA_DOCUMENT_EDIT = Permission.objects.register(metadata_namespace, 'metadata_document_edit', _(u'Edit a document\'s metadata'))
+PERMISSION_METADATA_DOCUMENT_ADD = Permission.objects.register(metadata_namespace, 'metadata_document_add', _(u'Add metadata to a document'))
+PERMISSION_METADATA_DOCUMENT_REMOVE = Permission.objects.register(metadata_namespace, 'metadata_document_remove', _(u'Remove metadata from a document'))
+PERMISSION_METADATA_DOCUMENT_VIEW = Permission.objects.register(metadata_namespace, 'metadata_document_view', _(u'View metadata from a document'))
+
+metadata_setup_namespace = PermissionNamespace('metadata_setup', _(u'Metadata setup'))
+PERMISSION_METADATA_TYPE_EDIT = Permission.objects.register(metadata_setup_namespace, 'metadata_type_edit', _(u'Edit metadata types'))
+PERMISSION_METADATA_TYPE_CREATE = Permission.objects.register(metadata_setup_namespace, 'metadata_type_create', _(u'Create new metadata types'))
+PERMISSION_METADATA_TYPE_DELETE = Permission.objects.register(metadata_setup_namespace, 'metadata_type_delete', _(u'Delete metadata types'))
+PERMISSION_METADATA_TYPE_VIEW = Permission.objects.register(metadata_setup_namespace, 'metadata_type_view', _(u'View metadata types'))
+
+PERMISSION_METADATA_SET_EDIT = Permission.objects.register(metadata_setup_namespace, 'metadata_set_edit', _(u'Edit metadata sets'))
+PERMISSION_METADATA_SET_CREATE = Permission.objects.register(metadata_setup_namespace, 'metadata_set_create', _(u'Create new metadata sets'))
+PERMISSION_METADATA_SET_DELETE = Permission.objects.register(metadata_setup_namespace, 'metadata_set_delete', _(u'Delete metadata sets'))
+PERMISSION_METADATA_SET_VIEW = Permission.objects.register(metadata_setup_namespace, 'metadata_set_view', _(u'View metadata sets'))
diff --git a/apps/metadata/tests.py b/apps/metadata/tests.py
deleted file mode 100644
index 2247054b35..0000000000
--- a/apps/metadata/tests.py
+++ /dev/null
@@ -1,23 +0,0 @@
-"""
-This file demonstrates two different styles of tests (one doctest and one
-unittest). These will both pass when you run "manage.py test".
-
-Replace these with more appropriate tests for your application.
-"""
-
-from django.test import TestCase
-
-class SimpleTest(TestCase):
- def test_basic_addition(self):
- """
- Tests that 1 + 1 always equals 2.
- """
- self.failUnlessEqual(1 + 1, 2)
-
-__test__ = {"doctest": """
-Another way to test that 1 + 1 is equal to 2.
-
->>> 1 + 1 == 2
-True
-"""}
-
diff --git a/apps/metadata/views.py b/apps/metadata/views.py
index 028700a46d..31e9a74549 100644
--- a/apps/metadata/views.py
+++ b/apps/metadata/views.py
@@ -1,3 +1,5 @@
+from __future__ import absolute_import
+
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.utils.translation import ugettext_lazy as _
@@ -6,32 +8,33 @@ from django.contrib import messages
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from django.utils.http import urlencode
+from django.core.exceptions import PermissionDenied
-from documents.literals import PERMISSION_DOCUMENT_TYPE_EDIT
+from documents.permissions import PERMISSION_DOCUMENT_TYPE_EDIT
from documents.models import Document, RecentDocument, DocumentType
-from permissions.api import check_permissions
+from permissions.models import Permission
from document_indexing.api import update_indexes, delete_indexes
+from acls.models import AccessEntry
-from common.utils import generate_choices_w_labels, encapsulate
+from common.utils import generate_choices_w_labels, encapsulate, get_object_name
from common.views import assign_remove
-from metadata import PERMISSION_METADATA_DOCUMENT_VIEW, \
- PERMISSION_METADATA_DOCUMENT_EDIT, \
- PERMISSION_METADATA_DOCUMENT_ADD, PERMISSION_METADATA_DOCUMENT_REMOVE, \
- PERMISSION_METADATA_TYPE_EDIT, PERMISSION_METADATA_TYPE_CREATE, \
- PERMISSION_METADATA_TYPE_DELETE, PERMISSION_METADATA_TYPE_VIEW, \
- PERMISSION_METADATA_SET_EDIT, PERMISSION_METADATA_SET_CREATE, \
- PERMISSION_METADATA_SET_DELETE, PERMISSION_METADATA_SET_VIEW
-from metadata.forms import MetadataFormSet, AddMetadataForm, \
- MetadataRemoveFormSet, MetadataTypeForm, MetadataSetForm
-from metadata.api import save_metadata_list
-from metadata.models import DocumentMetadata, MetadataType, MetadataSet, \
- MetadataSetItem, DocumentTypeDefaults
+from .permissions import (PERMISSION_METADATA_DOCUMENT_EDIT,
+ PERMISSION_METADATA_DOCUMENT_ADD, PERMISSION_METADATA_DOCUMENT_REMOVE,
+ PERMISSION_METADATA_DOCUMENT_VIEW, PERMISSION_METADATA_TYPE_EDIT,
+ PERMISSION_METADATA_TYPE_CREATE, PERMISSION_METADATA_TYPE_DELETE,
+ PERMISSION_METADATA_TYPE_VIEW, PERMISSION_METADATA_SET_EDIT,
+ PERMISSION_METADATA_SET_CREATE, PERMISSION_METADATA_SET_DELETE,
+ PERMISSION_METADATA_SET_VIEW)
+from .forms import (MetadataFormSet, AddMetadataForm,
+ MetadataRemoveFormSet, MetadataTypeForm, MetadataSetForm)
+from .api import save_metadata_list
+from .models import (DocumentMetadata, MetadataType, MetadataSet,
+ MetadataSetItem, DocumentTypeDefaults)
+from .classes import MetadataObjectWrapper
def metadata_edit(request, document_id=None, document_id_list=None):
- check_permissions(request.user, [PERMISSION_METADATA_DOCUMENT_EDIT])
-
if document_id:
documents = [get_object_or_404(Document, pk=document_id)]
if documents[0].documentmetadata_set.count() == 0:
@@ -39,7 +42,13 @@ def metadata_edit(request, document_id=None, document_id_list=None):
return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))
elif document_id_list:
documents = [get_object_or_404(Document, pk=document_id) for document_id in document_id_list.split(',')]
- else:
+
+ try:
+ Permission.objects.check_permissions(request.user, [PERMISSION_METADATA_DOCUMENT_EDIT])
+ except PermissionDenied:
+ documents = AccessEntry.objects.filter_objects_by_access(PERMISSION_METADATA_DOCUMENT_EDIT, request.user, documents)
+
+ if not documents:
messages.error(request, _(u'Must provide at least one document.'))
return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))
@@ -121,13 +130,17 @@ def metadata_multiple_edit(request):
def metadata_add(request, document_id=None, document_id_list=None):
- check_permissions(request.user, [PERMISSION_METADATA_DOCUMENT_ADD])
-
if document_id:
documents = [get_object_or_404(Document, pk=document_id)]
elif document_id_list:
documents = [get_object_or_404(Document, pk=document_id) for document_id in document_id_list.split(',')]
- else:
+
+ try:
+ Permission.objects.check_permissions(request.user, [PERMISSION_METADATA_DOCUMENT_ADD])
+ except PermissionDenied:
+ documents = AccessEntry.objects.filter_objects_by_access(PERMISSION_METADATA_DOCUMENT_ADD, request.user, documents)
+
+ if not documents:
messages.error(request, _(u'Must provide at least one document.'))
return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))
@@ -185,8 +198,6 @@ def metadata_multiple_add(request):
def metadata_remove(request, document_id=None, document_id_list=None):
- check_permissions(request.user, [PERMISSION_METADATA_DOCUMENT_REMOVE])
-
if document_id:
documents = [get_object_or_404(Document, pk=document_id)]
if documents[0].documentmetadata_set.count() == 0:
@@ -195,7 +206,13 @@ def metadata_remove(request, document_id=None, document_id_list=None):
elif document_id_list:
documents = [get_object_or_404(Document, pk=document_id) for document_id in document_id_list.split(',')]
- else:
+
+ try:
+ Permission.objects.check_permissions(request.user, [PERMISSION_METADATA_DOCUMENT_REMOVE])
+ except PermissionDenied:
+ documents = AccessEntry.objects.filter_objects_by_access(PERMISSION_METADATA_DOCUMENT_REMOVE, request.user, documents)
+
+ if not documents:
messages.error(request, _(u'Must provide at least one document.'))
return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))
@@ -274,9 +291,13 @@ def metadata_multiple_remove(request):
def metadata_view(request, document_id):
- check_permissions(request.user, [PERMISSION_METADATA_DOCUMENT_VIEW])
document = get_object_or_404(Document, pk=document_id)
+ try:
+ Permission.objects.check_permissions(request.user, [PERMISSION_METADATA_DOCUMENT_VIEW])
+ except PermissionDenied:
+ AccessEntry.objects.check_access(PERMISSION_METADATA_DOCUMENT_VIEW, request.user, document)
+
return render_to_response('generic_list.html', {
'title': _(u'metadata for: %s') % document,
'object_list': document.documentmetadata_set.all(),
@@ -284,10 +305,11 @@ def metadata_view(request, document_id):
'hide_link': True,
'object': document,
}, context_instance=RequestContext(request))
-
+
+# Setup views
def setup_metadata_type_list(request):
- check_permissions(request.user, [PERMISSION_METADATA_TYPE_VIEW])
+ Permission.objects.check_permissions(request.user, [PERMISSION_METADATA_TYPE_VIEW])
context = {
'object_list': MetadataType.objects.all(),
@@ -302,12 +324,12 @@ def setup_metadata_type_list(request):
}
return render_to_response('generic_list.html', context,
- context_instance=RequestContext(request))
+ context_instance=RequestContext(request))
def setup_metadata_type_edit(request, metadatatype_id):
- check_permissions(request.user, [PERMISSION_METADATA_TYPE_EDIT])
-
+ Permission.objects.check_permissions(request.user, [PERMISSION_METADATA_TYPE_EDIT])
+
metadata_type = get_object_or_404(MetadataType, pk=metadatatype_id)
if request.method == 'POST':
@@ -330,12 +352,12 @@ def setup_metadata_type_edit(request, metadatatype_id):
'object': metadata_type,
'object_name': _(u'metadata type'),
},
- context_instance=RequestContext(request))
-
-
+ context_instance=RequestContext(request))
+
+
def setup_metadata_type_create(request):
- check_permissions(request.user, [PERMISSION_METADATA_TYPE_CREATE])
-
+ Permission.objects.check_permissions(request.user, [PERMISSION_METADATA_TYPE_CREATE])
+
if request.method == 'POST':
form = MetadataTypeForm(request.POST)
if form.is_valid():
@@ -353,8 +375,8 @@ def setup_metadata_type_create(request):
def setup_metadata_type_delete(request, metadatatype_id):
- check_permissions(request.user, [PERMISSION_METADATA_TYPE_DELETE])
-
+ Permission.objects.check_permissions(request.user, [PERMISSION_METADATA_TYPE_DELETE])
+
metadata_type = get_object_or_404(MetadataType, pk=metadatatype_id)
post_action_redirect = reverse('setup_metadata_type_list')
@@ -387,7 +409,7 @@ def setup_metadata_type_delete(request, metadatatype_id):
def setup_metadata_set_list(request):
- check_permissions(request.user, [PERMISSION_METADATA_SET_VIEW])
+ Permission.objects.check_permissions(request.user, [PERMISSION_METADATA_SET_VIEW])
context = {
'object_list': MetadataSet.objects.all(),
@@ -402,7 +424,7 @@ def setup_metadata_set_list(request):
}
return render_to_response('generic_list.html', context,
- context_instance=RequestContext(request))
+ context_instance=RequestContext(request))
def get_set_members(metadata_set):
@@ -429,14 +451,14 @@ def remove_set_member(metadata_set, selection):
def setup_metadata_set_edit(request, metadata_set_id):
- check_permissions(request.user, [PERMISSION_METADATA_SET_EDIT])
+ Permission.objects.check_permissions(request.user, [PERMISSION_METADATA_SET_EDIT])
metadata_set = get_object_or_404(MetadataSet, pk=metadata_set_id)
return assign_remove(
request,
- left_list=lambda: generate_choices_w_labels(get_non_set_members(metadata_set)),
- right_list=lambda: generate_choices_w_labels(get_set_members(metadata_set)),
+ left_list=lambda: generate_choices_w_labels(get_non_set_members(metadata_set), display_object_type=False),
+ right_list=lambda: generate_choices_w_labels(get_set_members(metadata_set), display_object_type=False),
add_method=lambda x: add_set_member(metadata_set, x),
remove_method=lambda x: remove_set_member(metadata_set, x),
left_list_title=_(u'non members of metadata set: %s') % metadata_set,
@@ -449,8 +471,8 @@ def setup_metadata_set_edit(request, metadata_set_id):
def setup_metadata_set_create(request):
- check_permissions(request.user, [PERMISSION_METADATA_SET_CREATE])
-
+ Permission.objects.check_permissions(request.user, [PERMISSION_METADATA_SET_CREATE])
+
if request.method == 'POST':
form = MetadataSetForm(request.POST)
if form.is_valid():
@@ -468,8 +490,8 @@ def setup_metadata_set_create(request):
def setup_metadata_set_delete(request, metadata_set_id):
- check_permissions(request.user, [PERMISSION_METADATA_SET_DELETE])
-
+ Permission.objects.check_permissions(request.user, [PERMISSION_METADATA_SET_DELETE])
+
metadata_set = get_object_or_404(MetadataSet, pk=metadata_set_id)
post_action_redirect = reverse('setup_metadata_set_list')
@@ -502,54 +524,71 @@ def setup_metadata_set_delete(request, metadata_set_id):
context_instance=RequestContext(request))
-def get_document_type_metadata_members(document_type):
- metadata_types = set(document_type.documenttypedefaults_set.get().default_metadata.all())
- metadata_sets = set(document_type.documenttypedefaults_set.get().default_metadata_sets.all())
- return list(metadata_types | metadata_sets)
+def _as_choice_list(items):
+ return sorted([(MetadataObjectWrapper.encapsulate(item).gid, get_object_name(item, display_object_type=False)) for item in items], key=lambda x: x[1])
def get_document_type_metadata_non_members(document_type):
- members = set(get_document_type_metadata_members(document_type))
- all_metadata_objects = set(MetadataType.objects.all()) | set(MetadataSet.objects.all())
- return list(all_metadata_objects - members)
+ metadata_types, metadata_sets = get_document_type_metadata_members(document_type, separate=True)
+ metadata_types = set(MetadataType.objects.all()) - set(metadata_types)
+ metadata_sets = set(MetadataSet.objects.all()) - set(metadata_sets)
+
+ non_members = []
+ if metadata_types:
+ non_members.append((_(u'Metadata types'), _as_choice_list(list(metadata_types))))
+
+ if metadata_sets:
+ non_members.append((_(u'Metadata sets'), _as_choice_list(list(metadata_sets))))
+
+ return non_members
+
+
+def get_document_type_metadata_members(document_type, separate=False):
+ metadata_types = set(document_type.documenttypedefaults_set.get().default_metadata.all())
+ metadata_sets = set(document_type.documenttypedefaults_set.get().default_metadata_sets.all())
+
+ if separate:
+ return metadata_types, metadata_sets
+ else:
+ members = []
+
+ if metadata_types:
+ members.append((_(u'Metadata types'), _as_choice_list(list(metadata_types))))
+
+ if metadata_sets:
+ members.append((_(u'Metadata sets'), _as_choice_list(list(metadata_sets))))
+
+ return members
def add_document_type_metadata(document_type, selection):
- model, pk = selection.split(u',')
- if model == 'metadata type':
- metadata_type = get_object_or_404(MetadataType, pk=pk)
- document_type.documenttypedefaults_set.get().default_metadata.add(metadata_type)
- elif model == 'metadata set':
- metadata_set = get_object_or_404(MetadataSet, pk=pk)
- document_type.documenttypedefaults_set.get().default_metadata_sets.add(metadata_set)
- else:
- raise Exception
+ metadata_object = MetadataObjectWrapper.get(selection).source_object
+ try:
+ document_type.documenttypedefaults_set.get().default_metadata.add(metadata_object)
+ except TypeError:
+ document_type.documenttypedefaults_set.get().default_metadata_sets.add(metadata_object)
def remove_document_type_metadata(document_type, selection):
- model, pk = selection.split(u',')
- if model == 'metadata type':
- metadata_type = get_object_or_404(MetadataType, pk=pk)
- document_type.documenttypedefaults_set.get().default_metadata.remove(metadata_type)
- elif model == 'metadata set':
- metadata_set = get_object_or_404(MetadataSet, pk=pk)
- document_type.documenttypedefaults_set.get().default_metadata_sets.remove(metadata_set)
+ metadata_object = MetadataObjectWrapper.get(selection).source_object
+ if isinstance(metadata_object, MetadataType):
+ document_type.documenttypedefaults_set.get().default_metadata.remove(metadata_object)
else:
- raise Exception
+ document_type.documenttypedefaults_set.get().default_metadata_sets.remove(metadata_object)
def setup_document_type_metadata(request, document_type_id):
- check_permissions(request.user, [PERMISSION_DOCUMENT_TYPE_EDIT])
+ Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TYPE_EDIT])
document_type = get_object_or_404(DocumentType, pk=document_type_id)
# Initialize defaults
DocumentTypeDefaults.objects.get_or_create(document_type=document_type)
-
+
return assign_remove(
request,
- left_list=lambda: generate_choices_w_labels(get_document_type_metadata_non_members(document_type)),
- right_list=lambda: generate_choices_w_labels(get_document_type_metadata_members(document_type)),
+ left_list=lambda: get_document_type_metadata_non_members(document_type),
+ right_list=lambda: get_document_type_metadata_members(document_type),
add_method=lambda x: add_document_type_metadata(document_type, x),
remove_method=lambda x: remove_document_type_metadata(document_type, x),
left_list_title=_(u'non members of document type: %s') % document_type,
@@ -559,4 +598,5 @@ def setup_document_type_metadata(request, document_type_id):
'navigation_object_name': 'document_type',
'object_name': _(u'document type'),
},
+ grouped=True,
)
diff --git a/apps/mimetype/api.py b/apps/mimetype/api.py
index 5790bce8a2..cc7e93db32 100644
--- a/apps/mimetype/api.py
+++ b/apps/mimetype/api.py
@@ -83,10 +83,11 @@ def get_error_icon_file_path():
else:
return os.path.join(settings.STATIC_ROOT, MIMETYPE_ICONS_DIRECTORY_NAME, ERROR_FILE_NAME)
+
def get_error_icon_url():
return os.path.join(MIMETYPE_ICONS_DIRECTORY_NAME, ERROR_FILE_NAME)
-
+
def get_mimetype(file_description, filepath, mimetype_only=False):
"""
Determine a file's mimetype by calling the system's libmagic
diff --git a/apps/mimetype/tests.py b/apps/mimetype/tests.py
deleted file mode 100644
index 2247054b35..0000000000
--- a/apps/mimetype/tests.py
+++ /dev/null
@@ -1,23 +0,0 @@
-"""
-This file demonstrates two different styles of tests (one doctest and one
-unittest). These will both pass when you run "manage.py test".
-
-Replace these with more appropriate tests for your application.
-"""
-
-from django.test import TestCase
-
-class SimpleTest(TestCase):
- def test_basic_addition(self):
- """
- Tests that 1 + 1 always equals 2.
- """
- self.failUnlessEqual(1 + 1, 2)
-
-__test__ = {"doctest": """
-Another way to test that 1 + 1 is equal to 2.
-
->>> 1 + 1 == 2
-True
-"""}
-
diff --git a/apps/navigation/api.py b/apps/navigation/api.py
index 8939370cb9..56bb037245 100644
--- a/apps/navigation/api.py
+++ b/apps/navigation/api.py
@@ -1,5 +1,3 @@
-import copy
-
object_navigation = {}
multi_object_navigation = {}
model_list_columns = {}
@@ -46,7 +44,7 @@ def register_links(src, links, menu_name=None, position=None):
object_navigation[menu_name][src]['links'].extend(links)
-def register_top_menu(name, link, children_views=None,
+def register_top_menu(name, link, children_views=None,
children_path_regex=None, children_view_regex=None,
position=None):
"""
@@ -70,6 +68,8 @@ def register_top_menu(name, link, children_views=None,
top_menu_entries.append(entry)
sort_menu_entries()
+
+ return entry
def sort_menu_entries():
diff --git a/apps/navigation/locale/en/LC_MESSAGES/django.po b/apps/navigation/locale/en/LC_MESSAGES/django.po
index 073df2fae0..5b3c695fac 100644
--- a/apps/navigation/locale/en/LC_MESSAGES/django.po
+++ b/apps/navigation/locale/en/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-11-22 11:26-0400\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -21,10 +21,10 @@ msgstr ""
msgid "Multi item action"
msgstr ""
-#: widgets.py:28
+#: widgets.py:48
msgid "icon"
msgstr ""
-#: templatetags/navigation_tags.py:275
+#: templatetags/navigation_tags.py:278
msgid "Selected item actions:"
msgstr ""
diff --git a/apps/navigation/locale/es/LC_MESSAGES/django.mo b/apps/navigation/locale/es/LC_MESSAGES/django.mo
index 6091110708..7ab9cf55c5 100644
Binary files a/apps/navigation/locale/es/LC_MESSAGES/django.mo and b/apps/navigation/locale/es/LC_MESSAGES/django.mo differ
diff --git a/apps/navigation/locale/es/LC_MESSAGES/django.po b/apps/navigation/locale/es/LC_MESSAGES/django.po
index 4fa778b876..3079e51a80 100644
--- a/apps/navigation/locale/es/LC_MESSAGES/django.po
+++ b/apps/navigation/locale/es/LC_MESSAGES/django.po
@@ -8,9 +8,9 @@ msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-11-22 11:26-0400\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: 2011-11-04 16:58+0000\n"
-"Last-Translator: rosarior \n"
+"Last-Translator: Roberto Rosario \n"
"Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/"
"mayan-edms/team/es/)\n"
"Language: es\n"
@@ -23,10 +23,10 @@ msgstr ""
msgid "Multi item action"
msgstr "Acción para multiple artículos"
-#: widgets.py:28
+#: widgets.py:48
msgid "icon"
msgstr "emblema"
-#: templatetags/navigation_tags.py:275
+#: templatetags/navigation_tags.py:278
msgid "Selected item actions:"
msgstr "Acciones para el artículo seleccionado:"
diff --git a/apps/navigation/locale/it/LC_MESSAGES/django.mo b/apps/navigation/locale/it/LC_MESSAGES/django.mo
new file mode 100644
index 0000000000..bdb151f775
Binary files /dev/null and b/apps/navigation/locale/it/LC_MESSAGES/django.mo differ
diff --git a/apps/navigation/locale/it/LC_MESSAGES/django.po b/apps/navigation/locale/it/LC_MESSAGES/django.po
new file mode 100644
index 0000000000..957fcd5f25
--- /dev/null
+++ b/apps/navigation/locale/it/LC_MESSAGES/django.po
@@ -0,0 +1,32 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# , 2011.
+msgid ""
+msgstr ""
+"Project-Id-Version: Mayan EDMS\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
+"PO-Revision-Date: 2011-12-09 18:00+0000\n"
+"Last-Translator: Pierpaolo Baldan \n"
+"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/"
+"it/)\n"
+"Language: it\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+
+#: forms.py:14
+msgid "Multi item action"
+msgstr "Voce per azioni multiple"
+
+#: widgets.py:48
+msgid "icon"
+msgstr "icon"
+
+#: templatetags/navigation_tags.py:278
+msgid "Selected item actions:"
+msgstr "Selezione le azioni multiple"
diff --git a/apps/navigation/locale/pl/LC_MESSAGES/django.mo b/apps/navigation/locale/pl/LC_MESSAGES/django.mo
new file mode 100644
index 0000000000..d4e9505785
Binary files /dev/null and b/apps/navigation/locale/pl/LC_MESSAGES/django.mo differ
diff --git a/apps/navigation/locale/pl/LC_MESSAGES/django.po b/apps/navigation/locale/pl/LC_MESSAGES/django.po
new file mode 100644
index 0000000000..ce02d46463
--- /dev/null
+++ b/apps/navigation/locale/pl/LC_MESSAGES/django.po
@@ -0,0 +1,31 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# , 2012.
+msgid ""
+msgstr ""
+"Project-Id-Version: Mayan EDMS\n"
+"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
+"PO-Revision-Date: 2012-02-21 20:59+0000\n"
+"Last-Translator: mic \n"
+"Language-Team: Polish (http://www.transifex.net/projects/p/mayan-edms/language/pl/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: pl\n"
+"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
+
+#: forms.py:14
+msgid "Multi item action"
+msgstr "Multi item action"
+
+#: widgets.py:48
+msgid "icon"
+msgstr "ikona"
+
+#: templatetags/navigation_tags.py:278
+msgid "Selected item actions:"
+msgstr "Selected item actions:"
diff --git a/apps/navigation/locale/pt/LC_MESSAGES/django.mo b/apps/navigation/locale/pt/LC_MESSAGES/django.mo
index da6beaf7ea..268de030a2 100644
Binary files a/apps/navigation/locale/pt/LC_MESSAGES/django.mo and b/apps/navigation/locale/pt/LC_MESSAGES/django.mo differ
diff --git a/apps/navigation/locale/pt/LC_MESSAGES/django.po b/apps/navigation/locale/pt/LC_MESSAGES/django.po
index 7f003b944a..4392ccf2c6 100644
--- a/apps/navigation/locale/pt/LC_MESSAGES/django.po
+++ b/apps/navigation/locale/pt/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-11-22 11:26-0400\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: 2011-11-02 01:24+0000\n"
"Last-Translator: emersonsoares \n"
"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/"
@@ -23,10 +23,10 @@ msgstr ""
msgid "Multi item action"
msgstr "Ação de vários itens"
-#: widgets.py:28
+#: widgets.py:48
msgid "icon"
msgstr "ícone"
-#: templatetags/navigation_tags.py:275
+#: templatetags/navigation_tags.py:278
msgid "Selected item actions:"
msgstr "Ações de item selecionadas:"
diff --git a/apps/navigation/locale/ru/LC_MESSAGES/django.mo b/apps/navigation/locale/ru/LC_MESSAGES/django.mo
index 8dec51de24..fa4dd7336e 100644
Binary files a/apps/navigation/locale/ru/LC_MESSAGES/django.mo and b/apps/navigation/locale/ru/LC_MESSAGES/django.mo differ
diff --git a/apps/navigation/locale/ru/LC_MESSAGES/django.po b/apps/navigation/locale/ru/LC_MESSAGES/django.po
index ac633acf3c..dffe342d8a 100644
--- a/apps/navigation/locale/ru/LC_MESSAGES/django.po
+++ b/apps/navigation/locale/ru/LC_MESSAGES/django.po
@@ -8,9 +8,9 @@ msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-11-22 11:26-0400\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: 2011-11-19 21:05+0000\n"
-"Last-Translator: gsv70 \n"
+"Last-Translator: Sergey Glita \n"
"Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/team/"
"ru/)\n"
"Language: ru\n"
@@ -24,10 +24,10 @@ msgstr ""
msgid "Multi item action"
msgstr "Массовое действие"
-#: widgets.py:28
+#: widgets.py:48
msgid "icon"
msgstr "значок"
-#: templatetags/navigation_tags.py:275
+#: templatetags/navigation_tags.py:278
msgid "Selected item actions:"
msgstr "Действия с выбранными пунктами: "
diff --git a/apps/navigation/templates/generic_link_instance.html b/apps/navigation/templates/generic_link_instance.html
index 808ed2f65b..098810ee13 100644
--- a/apps/navigation/templates/generic_link_instance.html
+++ b/apps/navigation/templates/generic_link_instance.html
@@ -3,7 +3,7 @@
{% get_main_setting "DISABLE_ICONS" as disable_icons %}
{% if link.disabled %}
- {% if link.famfam and not disable_icons %}{% endif %}{{ link.text|capfirst }}{% if link.error %} - {{ link.error }}{% endif %}{% if link.active and not hide_active_anchor %}{% endif %}{% if horizontal %}{% if not forloop.last %} | {% endif %}{% endif %}
+ {% if link.famfam and not disable_icons %}{% endif %}{{ link.text|capfirst }}{% if link.error %} - {{ link.error }}{% endif %}{% if link.active and not hide_active_anchor %}{% endif %}{% if horizontal %}{% if not forloop.last %} | {% endif %}{% endif %}
{% else %}
{% if link.famfam and not disable_icons %}{% endif %}{{ link.text|capfirst }}{% if link.error %} - {{ link.error }}{% endif %}{% if link.active and not hide_active_anchor %}{% endif %}{% if horizontal %}{% if not forloop.last %} | {% endif %}{% endif %}
{% endif %}
diff --git a/apps/navigation/templates/generic_subnavigation.html b/apps/navigation/templates/generic_subnavigation.html
index cac3301f00..eac581d5e0 100644
--- a/apps/navigation/templates/generic_subnavigation.html
+++ b/apps/navigation/templates/generic_subnavigation.html
@@ -1,9 +1,12 @@
{% load permission_tags %}
{% load navigation_tags %}
+{% load acl_tags %}
{% with link.permissions as permissions %}
{% check_permissions request.user permissions %}
- {% if permission %}
+ {% check_access permissions request.user object %}
+
+ {% if permission or access %}
{% if as_li %}
{% endif %}
diff --git a/apps/navigation/templatetags/navigation_tags.py b/apps/navigation/templatetags/navigation_tags.py
index 815af1ea0d..f3b989a511 100644
--- a/apps/navigation/templatetags/navigation_tags.py
+++ b/apps/navigation/templatetags/navigation_tags.py
@@ -1,19 +1,21 @@
+from __future__ import absolute_import
+
import copy
import re
import urlparse
from django.core.urlresolvers import reverse, NoReverseMatch
-from django.template import TemplateSyntaxError, Library, \
- VariableDoesNotExist, Node, Variable
+from django.template import (TemplateSyntaxError, Library,
+ VariableDoesNotExist, Node, Variable)
from django.utils.text import unescape_string_literal
from django.utils.translation import ugettext as _
from common.utils import urlquote
-from navigation.api import object_navigation, multi_object_navigation, \
- top_menu_entries, sidebar_templates
-from navigation.forms import MultiItemForm
-from navigation.utils import resolve_to_name
+from ..api import (object_navigation, multi_object_navigation,
+ top_menu_entries, sidebar_templates)
+from ..forms import MultiItemForm
+from ..utils import resolve_to_name
register = Library()
@@ -36,7 +38,7 @@ class TopMenuNavigationNode(Node):
menu_links[index]['active'] = True
for children_view_regex in link.get('children_view_regex', []):
- if re.compile(children_view_regex).match(children_view_regex):
+ if re.compile(children_view_regex).match(current_view):
menu_links[index]['active'] = True
context['menu_links'] = menu_links
@@ -249,13 +251,14 @@ def get_object_navigation_links(parser, token):
@register.inclusion_tag('generic_navigation.html', takes_context=True)
def object_navigation_template(context):
- return {
- 'request': context['request'],
+ new_context = copy.copy(context)
+ new_context.update({
'horizontal': True,
- 'object_navigation_links': _get_object_navigation_links(context)
- }
-
-
+ 'object_navigation_links': _get_object_navigation_links(context)
+ })
+ return new_context
+
+
@register.tag
def get_multi_item_links(parser, token):
tag_name, arg = token.contents.split(None, 1)
diff --git a/apps/navigation/tests.py b/apps/navigation/tests.py
deleted file mode 100644
index 2247054b35..0000000000
--- a/apps/navigation/tests.py
+++ /dev/null
@@ -1,23 +0,0 @@
-"""
-This file demonstrates two different styles of tests (one doctest and one
-unittest). These will both pass when you run "manage.py test".
-
-Replace these with more appropriate tests for your application.
-"""
-
-from django.test import TestCase
-
-class SimpleTest(TestCase):
- def test_basic_addition(self):
- """
- Tests that 1 + 1 always equals 2.
- """
- self.failUnlessEqual(1 + 1, 2)
-
-__test__ = {"doctest": """
-Another way to test that 1 + 1 is equal to 2.
-
->>> 1 + 1 == 2
-True
-"""}
-
diff --git a/apps/navigation/widgets.py b/apps/navigation/widgets.py
index 949fae4dd3..f587fc6ebb 100644
--- a/apps/navigation/widgets.py
+++ b/apps/navigation/widgets.py
@@ -1,29 +1,51 @@
+from __future__ import absolute_import
+
+import urlparse
+
from django.utils.safestring import mark_safe
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
from django.core.urlresolvers import reverse
from django.template.defaultfilters import capfirst
from django.core.exceptions import PermissionDenied
+from django.template import RequestContext, Variable
-from permissions.api import check_permissions
+from permissions.models import Permission
+
+from .templatetags.navigation_tags import resolve_links
+from .utils import resolve_to_name
def button_navigation_widget(request, link):
if 'permissions' in link:
try:
- check_permissions(request.user, link['permissions'])
- return render_widget(link)
+ Permission.objects.check_permissions(request.user, link['permissions'])
+ return render_widget(request, link)
except PermissionDenied:
return u''
else:
- return render_widget(link)
+ return render_widget(request, link)
-
-def render_widget(link):
- return mark_safe(u'' % {
- 'url': reverse(link['view']) if 'view' in link else link['url'],
- 'icon': link.get('icon', 'link_button.png'),
- 'static_url': settings.STATIC_URL,
- 'string': capfirst(link['text']),
- 'image_alt': _(u'icon'),
- })
+
+def render_widget(request, link):
+ context = RequestContext(request)
+
+ request = Variable('request').resolve(context)
+ current_path = request.META['PATH_INFO']
+ current_view = resolve_to_name(current_path)
+
+ query_string = urlparse.urlparse(request.get_full_path()).query or urlparse.urlparse(request.META.get('HTTP_REFERER', u'/')).query
+ parsed_query_string = urlparse.parse_qs(query_string)
+
+ links = resolve_links(context, [link], current_view, current_path, parsed_query_string)
+ if links:
+ link = links[0]
+ return mark_safe(u'' % {
+ 'url': reverse(link['view']) if 'view' in link else link['url'],
+ 'icon': link.get('icon', 'link_button.png'),
+ 'static_url': settings.STATIC_URL,
+ 'string': capfirst(link['text']),
+ 'image_alt': _(u'icon'),
+ })
+ else:
+ return u''
diff --git a/apps/ocr/__init__.py b/apps/ocr/__init__.py
index f35c7cbe30..3a3b0ac7c9 100644
--- a/apps/ocr/__init__.py
+++ b/apps/ocr/__init__.py
@@ -1,45 +1,33 @@
+from __future__ import absolute_import
+
import logging
-
-from django.core.exceptions import ImproperlyConfigured
+
from django.db import transaction
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ugettext
-from django.db.utils import DatabaseError
from django.db.models.signals import post_save, post_syncdb
from django.dispatch import receiver
+from django.db.utils import DatabaseError
-from navigation.api import register_links, register_top_menu, register_multi_item_links
-from permissions.api import register_permission, set_namespace_title
-from documents.models import Document
+from navigation.api import register_links, register_multi_item_links
+from documents.models import Document, DocumentVersion
from main.api import register_maintenance_links
from project_tools.api import register_tool
+from acls.api import class_permissions
from scheduler.api import register_interval_job
-from ocr.conf.settings import AUTOMATIC_OCR
-from ocr.conf.settings import QUEUE_PROCESSING_INTERVAL
-from ocr.models import DocumentQueue, QueueTransformation, QueueDocument
-from ocr.tasks import task_process_document_queues
-from ocr import models as ocr_models
+from .conf.settings import (AUTOMATIC_OCR, QUEUE_PROCESSING_INTERVAL)
+from .models import DocumentQueue, QueueTransformation
+from .tasks import task_process_document_queues
+from .permissions import (PERMISSION_OCR_DOCUMENT,
+ PERMISSION_OCR_DOCUMENT_DELETE, PERMISSION_OCR_QUEUE_ENABLE_DISABLE,
+ PERMISSION_OCR_CLEAN_ALL_PAGES)
+from .exceptions import AlreadyQueued
+from . import models as ocr_models
logger = logging.getLogger(__name__)
-#Permissions
-PERMISSION_OCR_DOCUMENT = {'namespace': 'ocr', 'name': 'ocr_document', 'label': _(u'Submit document for OCR')}
-PERMISSION_OCR_DOCUMENT_DELETE = {'namespace': 'ocr', 'name': 'ocr_document_delete', 'label': _(u'Delete document for OCR queue')}
-PERMISSION_OCR_QUEUE_ENABLE_DISABLE = {'namespace': 'ocr', 'name': 'ocr_queue_enable_disable', 'label': _(u'Can enable/disable an OCR queue')}
-PERMISSION_OCR_CLEAN_ALL_PAGES = {'namespace': 'ocr', 'name': 'ocr_clean_all_pages', 'label': _(u'Can execute an OCR clean up on all document pages')}
-PERMISSION_OCR_QUEUE_EDIT = {'namespace': 'ocr_setup', 'name': 'ocr_queue_edit', 'label': _(u'Can edit an OCR queue properties')}
-
-set_namespace_title('ocr', _(u'OCR'))
-register_permission(PERMISSION_OCR_DOCUMENT)
-register_permission(PERMISSION_OCR_DOCUMENT_DELETE)
-register_permission(PERMISSION_OCR_QUEUE_ENABLE_DISABLE)
-register_permission(PERMISSION_OCR_CLEAN_ALL_PAGES)
-
-set_namespace_title('ocr_setup', _(u'OCR Setup'))
-register_permission(PERMISSION_OCR_QUEUE_EDIT)
-
#Links
submit_document = {'text': _('submit to OCR queue'), 'view': 'submit_document', 'args': 'object.id', 'famfam': 'hourglass_add', 'permissions': [PERMISSION_OCR_DOCUMENT]}
submit_document_multiple = {'text': _('submit to OCR queue'), 'view': 'submit_document_multiple', 'famfam': 'hourglass_add', 'permissions': [PERMISSION_OCR_DOCUMENT]}
@@ -54,9 +42,7 @@ document_queue_enable = {'text': _(u'activate queue'), 'view': 'document_queue_e
all_document_ocr_cleanup = {'text': _(u'clean up pages content'), 'view': 'all_document_ocr_cleanup', 'famfam': 'text_strikethrough', 'permissions': [PERMISSION_OCR_CLEAN_ALL_PAGES], 'description': _(u'Runs a language filter to remove common OCR mistakes from document pages content.')}
queue_document_list = {'text': _(u'queue document list'), 'view': 'queue_document_list', 'famfam': 'hourglass', 'permissions': [PERMISSION_OCR_DOCUMENT]}
-ocr_tool_link = {'text': _(u'OCR'), 'view': 'queue_document_list', 'famfam': 'hourglass', 'icon': 'text.png', 'permissions': [PERMISSION_OCR_DOCUMENT]}
-
-node_active_list = {'text': _(u'active tasks'), 'view': 'node_active_list', 'famfam': 'server_chart', 'permissions': [PERMISSION_OCR_DOCUMENT]}
+ocr_tool_link = {'text': _(u'OCR'), 'view': 'queue_document_list', 'famfam': 'hourglass', 'icon': 'text.png', 'permissions': [PERMISSION_OCR_DOCUMENT], 'children_view_regex': [r'queue_', r'document_queue']}
setup_queue_transformation_list = {'text': _(u'transformations'), 'view': 'setup_queue_transformation_list', 'args': 'queue.pk', 'famfam': 'shape_move_front'}
setup_queue_transformation_create = {'text': _(u'add transformation'), 'view': 'setup_queue_transformation_create', 'args': 'queue.pk', 'famfam': 'shape_square_add'}
@@ -71,7 +57,7 @@ register_links(QueueTransformation, [setup_queue_transformation_edit, setup_queu
register_multi_item_links(['queue_document_list'], [re_queue_multiple_document, queue_document_multiple_delete])
-register_links(['setup_queue_transformation_create', 'setup_queue_transformation_edit', 'setup_queue_transformation_delete', 'document_queue_disable', 'document_queue_enable', 'queue_document_list', 'node_active_list', 'setup_queue_transformation_list'], [queue_document_list, node_active_list], menu_name='secondary_menu')
+register_links(['setup_queue_transformation_create', 'setup_queue_transformation_edit', 'setup_queue_transformation_delete', 'document_queue_disable', 'document_queue_enable', 'queue_document_list', 'setup_queue_transformation_list'], [queue_document_list], menu_name='secondary_menu')
register_links(['setup_queue_transformation_edit', 'setup_queue_transformation_delete', 'setup_queue_transformation_list', 'setup_queue_transformation_create'], [setup_queue_transformation_create], menu_name='sidebar')
register_maintenance_links([all_document_ocr_cleanup], namespace='ocr', title=_(u'OCR'))
@@ -79,26 +65,33 @@ register_maintenance_links([all_document_ocr_cleanup], namespace='ocr', title=_(
@transaction.commit_on_success
def create_default_queue():
- default_queue, created = DocumentQueue.objects.get_or_create(name='default')
- if created:
- default_queue.label = ugettext(u'Default')
- default_queue.save()
+ try:
+ default_queue, created = DocumentQueue.objects.get_or_create(name='default')
+ except DatabaseError:
+ transaction.rollback()
+ else:
+ if created:
+ default_queue.label = ugettext(u'Default')
+ default_queue.save()
+@receiver(post_save, dispatch_uid='document_post_save', sender=DocumentVersion)
def document_post_save(sender, instance, **kwargs):
+ logger.debug('received post save signal')
+ logger.debug('instance: %s' % instance)
if kwargs.get('created', False):
if AUTOMATIC_OCR:
- DocumentQueue.objects.queue_document(instance)
-
-post_save.connect(document_post_save, sender=Document)
-
+ try:
+ DocumentQueue.objects.queue_document(instance.document)
+ except AlreadyQueued:
+ pass
# Disabled because it appears Django execute signals using the same
-# process effectively blocking the view until the OCR process completes
-# which could take several minutes :/
+# process of the signal emiter effectively blocking the view until
+# the OCR process completes which could take several minutes :/
#@receiver(post_save, dispatch_uid='call_queue', sender=QueueDocument)
#def call_queue(sender, **kwargs):
-# if kwargs.get('created', False):
+# if kwargs.get('created', False):
# logger.debug('got call_queue signal: %s' % kwargs)
# task_process_document_queues()
@@ -109,3 +102,7 @@ def create_default_queue_signal_handler(sender, **kwargs):
register_interval_job('task_process_document_queues', _(u'Checks the OCR queue for pending documents.'), task_process_document_queues, seconds=QUEUE_PROCESSING_INTERVAL)
register_tool(ocr_tool_link)
+
+class_permissions(Document, [
+ PERMISSION_OCR_DOCUMENT,
+])
diff --git a/apps/ocr/api.py b/apps/ocr/api.py
index 958ff864eb..33450b0862 100644
--- a/apps/ocr/api.py
+++ b/apps/ocr/api.py
@@ -1,4 +1,5 @@
#Some code from http://wiki.github.com/hoffstaetter/python-tesseract
+from __future__ import absolute_import
import codecs
import os
@@ -13,14 +14,12 @@ from common.conf.settings import TEMPORARY_DIRECTORY
from converter.api import convert
from documents.models import DocumentPage
-from ocr.conf.settings import TESSERACT_PATH
-from ocr.conf.settings import TESSERACT_LANGUAGE
-from ocr.exceptions import TesseractError, UnpaperError
-from ocr.conf.settings import UNPAPER_PATH
-from ocr.parsers import parse_document_page
-from ocr.parsers.exceptions import ParserError, ParserUnknownFile
-from ocr.literals import DEFAULT_OCR_FILE_FORMAT, UNPAPER_FILE_FORMAT, \
- DEFAULT_OCR_FILE_EXTENSION
+from .conf.settings import (TESSERACT_PATH, TESSERACT_LANGUAGE, UNPAPER_PATH)
+from .exceptions import TesseractError, UnpaperError
+from .parsers import parse_document_page
+from .parsers.exceptions import ParserError, ParserUnknownFile
+from .literals import (DEFAULT_OCR_FILE_FORMAT, UNPAPER_FILE_FORMAT,
+ DEFAULT_OCR_FILE_EXTENSION)
def get_language_backend():
diff --git a/apps/ocr/conf/settings.py b/apps/ocr/conf/settings.py
index ff2f7ca04d..31e2c908b8 100644
--- a/apps/ocr/conf/settings.py
+++ b/apps/ocr/conf/settings.py
@@ -14,7 +14,6 @@ register_settings(
{'name': u'NODE_CONCURRENT_EXECUTION', 'global_name': u'OCR_NODE_CONCURRENT_EXECUTION', 'default': 1, 'description': _(u'Maximum amount of concurrent document OCRs a node can perform.')},
{'name': u'AUTOMATIC_OCR', 'global_name': u'OCR_AUTOMATIC_OCR', 'default': False, 'description': _(u'Automatically queue newly created documents for OCR.')},
{'name': u'QUEUE_PROCESSING_INTERVAL', 'global_name': u'OCR_QUEUE_PROCESSING_INTERVAL', 'default': 10},
- {'name': u'CACHE_URI', 'global_name': u'OCR_CACHE_URI', 'default': None, 'description': _(u'URI in the form: "memcached://127.0.0.1:11211/" to specify a cache backend to use for locking. Multiple hosts can be specified separated by a semicolon.')},
{'name': u'UNPAPER_PATH', 'global_name': u'OCR_UNPAPER_PATH', 'default': u'/usr/bin/unpaper', 'description': _(u'File path to unpaper program.'), 'exists': True},
]
)
diff --git a/apps/ocr/exceptions.py b/apps/ocr/exceptions.py
index 704e0ae9c7..32ec4c4c07 100644
--- a/apps/ocr/exceptions.py
+++ b/apps/ocr/exceptions.py
@@ -1,8 +1,14 @@
class AlreadyQueued(Exception):
+ """
+ Raised when a trying to queue document already in the queue
+ """
pass
class TesseractError(Exception):
+ """
+ Raised by tesseract
+ """
pass
diff --git a/apps/ocr/locale/en/LC_MESSAGES/django.po b/apps/ocr/locale/en/LC_MESSAGES/django.po
index 8aa482cb75..47baef0ce4 100644
--- a/apps/ocr/locale/en/LC_MESSAGES/django.po
+++ b/apps/ocr/locale/en/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-11-22 11:26-0400\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -17,93 +17,65 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: __init__.py:28
-msgid "Submit document for OCR"
-msgstr ""
-
-#: __init__.py:29
-msgid "Delete document for OCR queue"
-msgstr ""
-
-#: __init__.py:30
-msgid "Can enable/disable an OCR queue"
-msgstr ""
-
-#: __init__.py:31
-msgid "Can execute an OCR clean up on all document pages"
-msgstr ""
-
-#: __init__.py:32
-msgid "Can edit an OCR queue properties"
-msgstr ""
-
-#: __init__.py:34 __init__.py:56 __init__.py:74
-msgid "OCR"
-msgstr ""
-
-#: __init__.py:40
-msgid "OCR Setup"
-msgstr ""
-
-#: __init__.py:44
+#: __init__.py:32 __init__.py:33
msgid "submit to OCR queue"
msgstr ""
-#: __init__.py:45 __init__.py:46
+#: __init__.py:34 __init__.py:35
msgid "re-queue"
msgstr ""
-#: __init__.py:47 __init__.py:48 __init__.py:63
+#: __init__.py:36 __init__.py:37 __init__.py:50
msgid "delete"
msgstr ""
-#: __init__.py:50
+#: __init__.py:39
msgid "stop queue"
msgstr ""
-#: __init__.py:51
+#: __init__.py:40
msgid "activate queue"
msgstr ""
-#: __init__.py:53
+#: __init__.py:42
msgid "clean up pages content"
msgstr ""
-#: __init__.py:53
+#: __init__.py:42
msgid ""
"Runs a language filter to remove common OCR mistakes from document pages "
"content."
msgstr ""
-#: __init__.py:55
+#: __init__.py:44
msgid "queue document list"
msgstr ""
-#: __init__.py:58 views.py:316
-msgid "active tasks"
+#: __init__.py:45 __init__.py:63 permissions.py:7
+msgid "OCR"
msgstr ""
-#: __init__.py:60
+#: __init__.py:47
msgid "transformations"
msgstr ""
-#: __init__.py:61
+#: __init__.py:48
msgid "add transformation"
msgstr ""
-#: __init__.py:62
+#: __init__.py:49
msgid "edit"
msgstr ""
-#: __init__.py:82
+#: __init__.py:74
msgid "Default"
msgstr ""
-#: __init__.py:104
+#: __init__.py:102
msgid "Checks the OCR queue for pending documents."
msgstr ""
-#: api.py:119
+#: api.py:122
msgid "Text from OCR"
msgstr ""
@@ -127,88 +99,108 @@ msgstr ""
msgid "error"
msgstr ""
-#: models.py:22
+#: models.py:26
msgid "name"
msgstr ""
-#: models.py:23
+#: models.py:27
msgid "label"
msgstr ""
-#: models.py:27 models.py:47
+#: models.py:31 models.py:51
msgid "state"
msgstr ""
-#: models.py:32 models.py:40 views.py:44 views.py:337 views.py:378
-#: views.py:408 views.py:444
+#: models.py:36 models.py:44 views.py:45 views.py:315 views.py:356
+#: views.py:386 views.py:422
msgid "document queue"
msgstr ""
-#: models.py:33
+#: models.py:37
msgid "document queues"
msgstr ""
-#: models.py:41
+#: models.py:45
msgid "document"
msgstr ""
-#: models.py:42
+#: models.py:46
msgid "date time submitted"
msgstr ""
-#: models.py:43
+#: models.py:47
msgid "delay ocr"
msgstr ""
-#: models.py:48
+#: models.py:52
msgid "result"
msgstr ""
-#: models.py:49
+#: models.py:53
msgid "node name"
msgstr ""
-#: models.py:53
+#: models.py:57
msgid "queue document"
msgstr ""
-#: models.py:54
+#: models.py:58
msgid "queue documents"
msgstr ""
-#: models.py:63 views.py:48
+#: models.py:78 views.py:49
msgid "Missing document."
msgstr ""
-#: models.py:67
+#: models.py:82
msgid "Enter a valid value."
msgstr ""
-#: models.py:95 views.py:341
+#: models.py:110 views.py:319
msgid "order"
msgstr ""
-#: models.py:96 views.py:342 views.py:379 views.py:409
+#: models.py:111 views.py:320 views.py:357 views.py:387
msgid "transformation"
msgstr ""
-#: models.py:97 views.py:343
+#: models.py:112 views.py:321
msgid "arguments"
msgstr ""
-#: models.py:97
+#: models.py:112
#, python-format
msgid "Use dictionaries to indentify arguments, example: %s"
msgstr ""
-#: models.py:107
+#: models.py:122
msgid "document queue transformation"
msgstr ""
-#: models.py:108
+#: models.py:123
msgid "document queue transformations"
msgstr ""
+#: permissions.py:8
+msgid "Submit documents for OCR"
+msgstr ""
+
+#: permissions.py:9
+msgid "Delete documents from OCR queue"
+msgstr ""
+
+#: permissions.py:10
+msgid "Can enable/disable the OCR queue"
+msgstr ""
+
+#: permissions.py:11
+msgid "Can execute the OCR clean up on all document pages"
+msgstr ""
+
+#: permissions.py:12
+msgid "Can edit an OCR queue properties"
+msgstr ""
+
#: statistics.py:8
#, python-format
msgid "Document queues: %d"
@@ -223,195 +215,179 @@ msgstr ""
msgid "OCR statistics"
msgstr ""
-#: views.py:41
+#: views.py:42
#, python-format
msgid "documents in queue: %s"
msgstr ""
-#: views.py:49
+#: views.py:50
msgid "thumbnail"
msgstr ""
-#: views.py:62
+#: views.py:63
msgid "document queue properties"
msgstr ""
-#: views.py:63
+#: views.py:64
#, python-format
msgid "Current state: %s"
msgstr ""
-#: views.py:79 views.py:154
+#: views.py:80 views.py:168
msgid "Must provide at least one queue document."
msgstr ""
-#: views.py:89
+#: views.py:90
#, python-format
msgid "Document: %s is being processed and can't be deleted."
msgstr ""
-#: views.py:92
+#: views.py:93
#, python-format
msgid "Queue document: %(document)s deleted successfully."
msgstr ""
-#: views.py:96
+#: views.py:97
#, python-format
msgid "Error deleting document: %(document)s; %(error)s"
msgstr ""
-#: views.py:109
+#: views.py:110
#, python-format
msgid "Are you sure you wish to delete queue document: %s?"
msgstr ""
-#: views.py:111
+#: views.py:112
#, python-format
msgid "Are you sure you wish to delete queue documents: %s?"
msgstr ""
-#: views.py:134
+#: views.py:148
#, python-format
msgid "Document: %(document)s was added to the OCR queue: %(queue)s."
msgstr ""
-#: views.py:137
+#: views.py:151
#, python-format
msgid "Document: %(document)s is already queued."
msgstr ""
-#: views.py:165
-#, python-format
-msgid "Document: %s is already being processed and can't be re-queded."
-msgstr ""
-
-#: views.py:173
+#: views.py:180
#, python-format
msgid "Document: %(document)s was re-queued to the OCR queue: %(queue)s"
msgstr ""
-#: views.py:176
+#: views.py:186
#, python-format
msgid "Document id#: %d, no longer exists."
msgstr ""
-#: views.py:189
+#: views.py:190
+#, python-format
+msgid "Document: %s is already being processed and can't be re-queded."
+msgstr ""
+
+#: views.py:202
#, python-format
msgid "Are you sure you wish to re-queue document: %s?"
msgstr ""
-#: views.py:191
+#: views.py:204
#, python-format
msgid "Are you sure you wish to re-queue documents: %s?"
msgstr ""
-#: views.py:209
+#: views.py:222
#, python-format
msgid "Document queue: %s, already stopped."
msgstr ""
-#: views.py:215
+#: views.py:228
#, python-format
msgid "Document queue: %s, stopped successfully."
msgstr ""
-#: views.py:221
+#: views.py:234
#, python-format
msgid "Are you sure you wish to disable document queue: %s"
msgstr ""
-#: views.py:236
+#: views.py:249
#, python-format
msgid "Document queue: %s, already active."
msgstr ""
-#: views.py:242
+#: views.py:255
#, python-format
msgid "Document queue: %s, activated successfully."
msgstr ""
-#: views.py:248
+#: views.py:261
#, python-format
msgid "Are you sure you wish to activate document queue: %s"
msgstr ""
-#: views.py:265
+#: views.py:278
msgid "Are you sure you wish to clean up all the pages content?"
msgstr ""
-#: views.py:266
+#: views.py:279
msgid "On large databases this operation may take some time to execute."
msgstr ""
-#: views.py:272
+#: views.py:285
msgid "Document pages content clean up complete."
msgstr ""
-#: views.py:274
+#: views.py:287
#, python-format
msgid "Document pages content clean up error: %s"
msgstr ""
-#: views.py:320
-msgid "node"
-msgstr ""
-
-#: views.py:321
-msgid "task id"
-msgstr ""
-
-#: views.py:322
-msgid "task name"
-msgstr ""
-
-#: views.py:323
-msgid "related object"
-msgstr ""
-
-#: views.py:335
+#: views.py:313
#, python-format
msgid "transformations for: %s"
msgstr ""
-#: views.py:365
+#: views.py:343
msgid "Queue transformation edited successfully"
msgstr ""
-#: views.py:368
+#: views.py:346
#, python-format
msgid "Error editing queue transformation; %s"
msgstr ""
-#: views.py:373
+#: views.py:351
#, python-format
msgid "Edit transformation: %s"
msgstr ""
-#: views.py:396
+#: views.py:374
msgid "Queue transformation deleted successfully."
msgstr ""
-#: views.py:398
+#: views.py:376
#, python-format
msgid "Error deleting queue transformation; %(error)s"
msgstr ""
-#: views.py:411
+#: views.py:389
#, python-format
msgid ""
"Are you sure you wish to delete queue transformation \"%(transformation)s\""
msgstr ""
-#: views.py:434
+#: views.py:412
msgid "Queue transformation created successfully"
msgstr ""
-#: views.py:437
+#: views.py:415
#, python-format
msgid "Error creating queue transformation; %s"
msgstr ""
-#: views.py:446
+#: views.py:424
#, python-format
msgid "Create new transformation for queue: %s"
msgstr ""
@@ -431,15 +407,9 @@ msgid "Automatically queue newly created documents for OCR."
msgstr ""
#: conf/settings.py:17
-msgid ""
-"URI in the form: \"memcached://127.0.0.1:11211/\" to specify a cache backend "
-"to use for locking. Multiple hosts can be specified separated by a semicolon."
-msgstr ""
-
-#: conf/settings.py:18
msgid "File path to unpaper program."
msgstr ""
-#: parsers/__init__.py:23
+#: parsers/__init__.py:37
msgid "Text extracted from PDF"
msgstr ""
diff --git a/apps/ocr/locale/es/LC_MESSAGES/django.mo b/apps/ocr/locale/es/LC_MESSAGES/django.mo
index 9c4c0ed1f3..4b72681b3c 100644
Binary files a/apps/ocr/locale/es/LC_MESSAGES/django.mo and b/apps/ocr/locale/es/LC_MESSAGES/django.mo differ
diff --git a/apps/ocr/locale/es/LC_MESSAGES/django.po b/apps/ocr/locale/es/LC_MESSAGES/django.po
index 6905387d1e..4c81e3a84c 100644
--- a/apps/ocr/locale/es/LC_MESSAGES/django.po
+++ b/apps/ocr/locale/es/LC_MESSAGES/django.po
@@ -1,79 +1,48 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
-#
+#
# Translators:
-# Roberto Rosario , 2011.
+# Roberto Rosario , 2011, 2012.
msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-11-22 11:26-0400\n"
-"PO-Revision-Date: 2011-11-07 04:17+0000\n"
-"Last-Translator: rosarior \n"
-"Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/"
-"mayan-edms/team/es/)\n"
-"Language: es\n"
+"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
+"PO-Revision-Date: 2012-02-12 19:29+0000\n"
+"Last-Translator: Roberto Rosario \n"
+"Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/mayan-edms/team/es/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
+"Language: es\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
-#: __init__.py:28
-msgid "Submit document for OCR"
-msgstr "Enviar documento para OCR"
-
-#: __init__.py:29
-msgid "Delete document for OCR queue"
-msgstr "Eliminar documento de la cola de OCR"
-
-#: __init__.py:30
-msgid "Can enable/disable an OCR queue"
-msgstr "Puede activar / desactivar una cola de OCR"
-
-#: __init__.py:31
-msgid "Can execute an OCR clean up on all document pages"
-msgstr ""
-"Puede ejecutar un programa de OCR de limpieza en todas las páginas de los "
-"documentos"
-
-#: __init__.py:32
-msgid "Can edit an OCR queue properties"
-msgstr "Puede editar las propiedades de un cola de OCR"
-
-#: __init__.py:34 __init__.py:56 __init__.py:74
-msgid "OCR"
-msgstr "OCR"
-
-#: __init__.py:40
-msgid "OCR Setup"
-msgstr "Configuración de OCR"
-
-#: __init__.py:44
+#: __init__.py:32 __init__.py:33
msgid "submit to OCR queue"
msgstr "enviar a lista de OCR"
-#: __init__.py:45 __init__.py:46
+#: __init__.py:34 __init__.py:35
msgid "re-queue"
msgstr "volver a la cola"
-#: __init__.py:47 __init__.py:48 __init__.py:63
+#: __init__.py:36 __init__.py:37 __init__.py:50
msgid "delete"
msgstr "eliminar"
-#: __init__.py:50
+#: __init__.py:39
msgid "stop queue"
msgstr "detener cola"
-#: __init__.py:51
+#: __init__.py:40
msgid "activate queue"
msgstr "activar cola"
-#: __init__.py:53
+#: __init__.py:42
msgid "clean up pages content"
msgstr "limpiar el contenido"
-#: __init__.py:53
+#: __init__.py:42
msgid ""
"Runs a language filter to remove common OCR mistakes from document pages "
"content."
@@ -81,35 +50,35 @@ msgstr ""
"Ejecuta un filtro de lenguaje para eliminar los errores más comunes de OCR "
"del contenido de las paginas del documento."
-#: __init__.py:55
+#: __init__.py:44
msgid "queue document list"
msgstr "lista de documentos en la cola"
-#: __init__.py:58 views.py:316
-msgid "active tasks"
-msgstr "tareas activas"
+#: __init__.py:45 __init__.py:63 permissions.py:7
+msgid "OCR"
+msgstr "OCR"
-#: __init__.py:60
+#: __init__.py:47
msgid "transformations"
msgstr "transformaciones"
-#: __init__.py:61
+#: __init__.py:48
msgid "add transformation"
msgstr "añadir transformación"
-#: __init__.py:62
+#: __init__.py:49
msgid "edit"
msgstr "editar"
-#: __init__.py:82
+#: __init__.py:74
msgid "Default"
msgstr "Por defecto"
-#: __init__.py:104
+#: __init__.py:102
msgid "Checks the OCR queue for pending documents."
msgstr "Comprueba la cola de OCR para documentos pendientes."
-#: api.py:119
+#: api.py:122
msgid "Text from OCR"
msgstr "Texto de OCR"
@@ -133,88 +102,108 @@ msgstr "en procesamiento"
msgid "error"
msgstr "error"
-#: models.py:22
+#: models.py:26
msgid "name"
msgstr "nombre"
-#: models.py:23
+#: models.py:27
msgid "label"
msgstr "etiqueta"
-#: models.py:27 models.py:47
+#: models.py:31 models.py:51
msgid "state"
msgstr "estado"
-#: models.py:32 models.py:40 views.py:44 views.py:337 views.py:378
-#: views.py:408 views.py:444
+#: models.py:36 models.py:44 views.py:45 views.py:315 views.py:356
+#: views.py:386 views.py:422
msgid "document queue"
msgstr "cola de documento"
-#: models.py:33
+#: models.py:37
msgid "document queues"
msgstr "colas de documentos"
-#: models.py:41
+#: models.py:45
msgid "document"
msgstr "documento"
-#: models.py:42
+#: models.py:46
msgid "date time submitted"
msgstr "fecha y hora sometido"
-#: models.py:43
+#: models.py:47
msgid "delay ocr"
msgstr "retraso ocr"
-#: models.py:48
+#: models.py:52
msgid "result"
msgstr "resultado"
-#: models.py:49
+#: models.py:53
msgid "node name"
msgstr "nombre del nodo"
-#: models.py:53
+#: models.py:57
msgid "queue document"
msgstr "documento en la cola"
-#: models.py:54
+#: models.py:58
msgid "queue documents"
msgstr "documentos en la cola"
-#: models.py:63 views.py:48
+#: models.py:78 views.py:49
msgid "Missing document."
msgstr "Documento no encontrado."
-#: models.py:67
+#: models.py:82
msgid "Enter a valid value."
msgstr "Introduzca un valor válido."
-#: models.py:95 views.py:341
+#: models.py:110 views.py:319
msgid "order"
msgstr "orden"
-#: models.py:96 views.py:342 views.py:379 views.py:409
+#: models.py:111 views.py:320 views.py:357 views.py:387
msgid "transformation"
msgstr "transformación"
-#: models.py:97 views.py:343
+#: models.py:112 views.py:321
msgid "arguments"
msgstr "argumentos"
-#: models.py:97
+#: models.py:112
#, python-format
msgid "Use dictionaries to indentify arguments, example: %s"
msgstr "Utilize diccionarios para indentificar argumentos, por ejemplo: %s"
-#: models.py:107
+#: models.py:122
msgid "document queue transformation"
msgstr "transformación de cola de documentos"
-#: models.py:108
+#: models.py:123
msgid "document queue transformations"
msgstr "transformaciones de cola de documentos"
+#: permissions.py:8
+msgid "Submit documents for OCR"
+msgstr "Enviar documentos para OCR"
+
+#: permissions.py:9
+msgid "Delete documents from OCR queue"
+msgstr "Eliminar documentos de la cola de OCR"
+
+#: permissions.py:10
+msgid "Can enable/disable the OCR queue"
+msgstr "Puede activar/desactivar la cola de OCR"
+
+#: permissions.py:11
+msgid "Can execute the OCR clean up on all document pages"
+msgstr "Se puede ejecutar limpieza de OCR en todas las páginas de documentos"
+
+#: permissions.py:12
+msgid "Can edit an OCR queue properties"
+msgstr "Puede editar las propiedades de un cola de OCR"
+
#: statistics.py:8
#, python-format
msgid "Document queues: %d"
@@ -229,204 +218,189 @@ msgstr "Documentos en la cola: %d"
msgid "OCR statistics"
msgstr "Estadísticas de OCR"
-#: views.py:41
+#: views.py:42
#, python-format
msgid "documents in queue: %s"
msgstr "documentos en la cola: %s"
-#: views.py:49
+#: views.py:50
msgid "thumbnail"
msgstr "miniatura"
-#: views.py:62
+#: views.py:63
msgid "document queue properties"
msgstr "propiedades de la cola de documentos"
-#: views.py:63
+#: views.py:64
#, python-format
msgid "Current state: %s"
msgstr "Estado actual: %s"
-#: views.py:79 views.py:154
+#: views.py:80 views.py:168
msgid "Must provide at least one queue document."
msgstr "Debe proveer al menos un documento en cola."
-#: views.py:89
+#: views.py:90
#, python-format
msgid "Document: %s is being processed and can't be deleted."
msgstr "El documento: %s ya está en proceso y no se puede se eliminado."
-#: views.py:92
+#: views.py:93
#, python-format
msgid "Queue document: %(document)s deleted successfully."
msgstr "Documento de la cola: %(document)s eliminado exitosamente."
-#: views.py:96
+#: views.py:97
#, python-format
msgid "Error deleting document: %(document)s; %(error)s"
msgstr "Error al eliminar el documento: %(document)s; %(error)s "
-#: views.py:109
+#: views.py:110
#, python-format
msgid "Are you sure you wish to delete queue document: %s?"
msgstr "¿Está seguro que desea eliminar de la cola el documento: %s?"
-#: views.py:111
+#: views.py:112
#, python-format
msgid "Are you sure you wish to delete queue documents: %s?"
msgstr "¿Está seguro que desea eliminar de la cola los documentos: %s?"
-#: views.py:134
+#: views.py:148
#, python-format
msgid "Document: %(document)s was added to the OCR queue: %(queue)s."
msgstr ""
"Documento: %(document)s ha sido añadido a la cola de reconocimiento óptico "
"de caracteres: %(queue)s."
-#: views.py:137
+#: views.py:151
#, python-format
msgid "Document: %(document)s is already queued."
msgstr "Documento: %(document)s ya está en cola."
-#: views.py:165
-#, python-format
-msgid "Document: %s is already being processed and can't be re-queded."
-msgstr ""
-"El documento: %s ya está en proceso y no se puede volver a agregar a la cola."
-
-#: views.py:173
+#: views.py:180
#, python-format
msgid "Document: %(document)s was re-queued to the OCR queue: %(queue)s"
msgstr ""
"Documento: %(document)s fue puesto de vuelta en la cola de reconocimiento "
"óptico de caracteres: %(queue)s "
-#: views.py:176
+#: views.py:186
#, python-format
msgid "Document id#: %d, no longer exists."
msgstr "Documento de #: %d, ya no existe."
-#: views.py:189
+#: views.py:190
+#, python-format
+msgid "Document: %s is already being processed and can't be re-queded."
+msgstr ""
+"El documento: %s ya está en proceso y no se puede volver a agregar a la "
+"cola."
+
+#: views.py:202
#, python-format
msgid "Are you sure you wish to re-queue document: %s?"
msgstr "¿Está seguro desea volver a agregar a la cola el documento: %s?"
-#: views.py:191
+#: views.py:204
#, python-format
msgid "Are you sure you wish to re-queue documents: %s?"
msgstr "¿Está seguro desea volver a agregar a la cola los documento: %s?"
-#: views.py:209
+#: views.py:222
#, python-format
msgid "Document queue: %s, already stopped."
msgstr "Cola de documento: %s, ya esta detenida."
-#: views.py:215
+#: views.py:228
#, python-format
msgid "Document queue: %s, stopped successfully."
msgstr "Cola de documento: %s, se ha detenido con éxito."
-#: views.py:221
+#: views.py:234
#, python-format
msgid "Are you sure you wish to disable document queue: %s"
msgstr "¿Está seguro de que desea desactivar la cola de documento: %s?"
-#: views.py:236
+#: views.py:249
#, python-format
msgid "Document queue: %s, already active."
msgstr "Cola de documento: %s, ya esta activa."
-#: views.py:242
+#: views.py:255
#, python-format
msgid "Document queue: %s, activated successfully."
msgstr "Cola de documento: %s, activada con éxito."
-#: views.py:248
+#: views.py:261
#, python-format
msgid "Are you sure you wish to activate document queue: %s"
msgstr "¿Estás seguro de que desea activar la cola de documento: %s?"
-#: views.py:265
+#: views.py:278
msgid "Are you sure you wish to clean up all the pages content?"
msgstr "¿Está seguro que desea limpiar el contenido de todas las páginas?"
-#: views.py:266
+#: views.py:279
msgid "On large databases this operation may take some time to execute."
msgstr ""
"En grandes bases de datos esta operación puede tardar algún tiempo en "
"ejecutarse."
-#: views.py:272
+#: views.py:285
msgid "Document pages content clean up complete."
msgstr "Limpieza de contenido completada."
-#: views.py:274
+#: views.py:287
#, python-format
msgid "Document pages content clean up error: %s"
msgstr "Error en limpieza de contenido: %s"
-#: views.py:320
-msgid "node"
-msgstr "nodo"
-
-#: views.py:321
-msgid "task id"
-msgstr "Identificación de tarea"
-
-#: views.py:322
-msgid "task name"
-msgstr "nombre de tarea"
-
-#: views.py:323
-msgid "related object"
-msgstr "objeto relacionado"
-
-#: views.py:335
+#: views.py:313
#, python-format
msgid "transformations for: %s"
msgstr "transformaciones para: %s"
-#: views.py:365
+#: views.py:343
msgid "Queue transformation edited successfully"
msgstr "Transformación de la cola editada con exitosamente"
-#: views.py:368
+#: views.py:346
#, python-format
msgid "Error editing queue transformation; %s"
msgstr "Error al modificar la transformación de cola; %s"
-#: views.py:373
+#: views.py:351
#, python-format
msgid "Edit transformation: %s"
msgstr "Editar transformación: %s"
-#: views.py:396
+#: views.py:374
msgid "Queue transformation deleted successfully."
msgstr "Transformación de la cola borrada exitosamente."
-#: views.py:398
+#: views.py:376
#, python-format
msgid "Error deleting queue transformation; %(error)s"
msgstr "Error al tratar de borrar la transformación de cola; %(error)s "
-#: views.py:411
+#: views.py:389
#, python-format
msgid ""
"Are you sure you wish to delete queue transformation \"%(transformation)s\""
msgstr ""
-"¿Está seguro que desea borrar la transformación de cola \"%(transformation)s"
-"\""
+"¿Está seguro que desea borrar la transformación de cola "
+"\"%(transformation)s\""
-#: views.py:434
+#: views.py:412
msgid "Queue transformation created successfully"
msgstr "Transformación de cola creada exitosamente"
-#: views.py:437
+#: views.py:415
#, python-format
msgid "Error creating queue transformation; %s"
msgstr "Error al crear la transformación de cola; %s"
-#: views.py:446
+#: views.py:424
#, python-format
msgid "Create new transformation for queue: %s"
msgstr "Crear nueva transformación para la cola: %s"
@@ -450,18 +424,11 @@ msgid "Automatically queue newly created documents for OCR."
msgstr "Agregar automáticamente la cola de OCR los documentos creados."
#: conf/settings.py:17
-msgid ""
-"URI in the form: \"memcached://127.0.0.1:11211/\" to specify a cache backend "
-"to use for locking. Multiple hosts can be specified separated by a semicolon."
-msgstr ""
-"URI de la forma: \"memcached:/ /127.0.0.1:11211/\" para especificar un "
-"servidor de caché para usar de bloqueo. Multiple servidores se pueden "
-"especificar separados por un punto y coma."
-
-#: conf/settings.py:18
msgid "File path to unpaper program."
msgstr "La ruta de archivo del programa unpaper."
-#: parsers/__init__.py:23
+#: parsers/__init__.py:37
msgid "Text extracted from PDF"
msgstr "Texto extraído de PDF"
+
+
diff --git a/apps/ocr/locale/it/LC_MESSAGES/django.mo b/apps/ocr/locale/it/LC_MESSAGES/django.mo
new file mode 100644
index 0000000000..75ac3ea7ef
Binary files /dev/null and b/apps/ocr/locale/it/LC_MESSAGES/django.mo differ
diff --git a/apps/ocr/locale/it/LC_MESSAGES/django.po b/apps/ocr/locale/it/LC_MESSAGES/django.po
new file mode 100644
index 0000000000..18fd6b973a
--- /dev/null
+++ b/apps/ocr/locale/it/LC_MESSAGES/django.po
@@ -0,0 +1,426 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# , 2011.
+msgid ""
+msgstr ""
+"Project-Id-Version: Mayan EDMS\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
+"PO-Revision-Date: 2012-02-02 18:19+0000\n"
+"Last-Translator: Roberto Rosario \n"
+"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/"
+"it/)\n"
+"Language: it\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+
+#: __init__.py:32 __init__.py:33
+msgid "submit to OCR queue"
+msgstr "Sottoponi una coda di OCR"
+
+#: __init__.py:34 __init__.py:35
+msgid "re-queue"
+msgstr "riaccoda"
+
+#: __init__.py:36 __init__.py:37 __init__.py:50
+msgid "delete"
+msgstr "cancella"
+
+#: __init__.py:39
+msgid "stop queue"
+msgstr "stoppa la coda"
+
+#: __init__.py:40
+msgid "activate queue"
+msgstr "attiva la coda"
+
+#: __init__.py:42
+msgid "clean up pages content"
+msgstr "ripulisci il contenuto delle pagine"
+
+#: __init__.py:42
+msgid ""
+"Runs a language filter to remove common OCR mistakes from document pages "
+"content."
+msgstr ""
+"Esegue un filtro per rimuovere i comuni errori di OCR dal contenuto del "
+"documento pagine."
+
+#: __init__.py:44
+msgid "queue document list"
+msgstr "lista dei documenti in coda"
+
+#: __init__.py:45 __init__.py:63 permissions.py:7
+msgid "OCR"
+msgstr "OCR"
+
+#: __init__.py:47
+msgid "transformations"
+msgstr "transformazioni"
+
+#: __init__.py:48
+msgid "add transformation"
+msgstr "aggiungi trasformazione"
+
+#: __init__.py:49
+msgid "edit"
+msgstr "modifica"
+
+#: __init__.py:74
+msgid "Default"
+msgstr "Default"
+
+#: __init__.py:102
+msgid "Checks the OCR queue for pending documents."
+msgstr "Controlla i documenti nella coda dell'OCR"
+
+#: api.py:122
+msgid "Text from OCR"
+msgstr "testo dall'OCR"
+
+#: literals.py:8
+msgid "stopped"
+msgstr "fermato"
+
+#: literals.py:9
+msgid "active"
+msgstr "attivo"
+
+#: literals.py:18
+msgid "pending"
+msgstr "in esecuzione"
+
+#: literals.py:19
+msgid "processing"
+msgstr "in elaborazione"
+
+#: literals.py:20
+msgid "error"
+msgstr "errore"
+
+#: models.py:26
+msgid "name"
+msgstr "nome"
+
+#: models.py:27
+msgid "label"
+msgstr "etichetta"
+
+#: models.py:31 models.py:51
+msgid "state"
+msgstr "stato"
+
+#: models.py:36 models.py:44 views.py:45 views.py:315 views.py:356
+#: views.py:386 views.py:422
+msgid "document queue"
+msgstr "coda del documento"
+
+#: models.py:37
+msgid "document queues"
+msgstr "code di documenti"
+
+#: models.py:45
+msgid "document"
+msgstr "documento"
+
+#: models.py:46
+msgid "date time submitted"
+msgstr "orario di esecuzione"
+
+#: models.py:47
+msgid "delay ocr"
+msgstr "proroga ocr"
+
+#: models.py:52
+msgid "result"
+msgstr "risultato"
+
+#: models.py:53
+msgid "node name"
+msgstr "nome del nodo"
+
+#: models.py:57
+msgid "queue document"
+msgstr "coda del documento"
+
+#: models.py:58
+msgid "queue documents"
+msgstr "code dei documenti"
+
+#: models.py:78 views.py:49
+msgid "Missing document."
+msgstr "Documento perso"
+
+#: models.py:82
+msgid "Enter a valid value."
+msgstr "Inserisci un valore valido"
+
+#: models.py:110 views.py:319
+msgid "order"
+msgstr "ordina"
+
+#: models.py:111 views.py:320 views.py:357 views.py:387
+msgid "transformation"
+msgstr "trasforma"
+
+#: models.py:112 views.py:321
+msgid "arguments"
+msgstr "argomenti"
+
+#: models.py:112
+#, python-format
+msgid "Use dictionaries to indentify arguments, example: %s"
+msgstr "Usa un dizionario per identificare gli argomenti, esempio: %s"
+
+#: models.py:122
+msgid "document queue transformation"
+msgstr "coda del documento in trasformazione"
+
+#: models.py:123
+msgid "document queue transformations"
+msgstr "code dei documenti in trasformazione"
+
+#: permissions.py:8
+msgid "Submit documents for OCR"
+msgstr ""
+
+#: permissions.py:9
+msgid "Delete documents from OCR queue"
+msgstr ""
+
+#: permissions.py:10
+msgid "Can enable/disable the OCR queue"
+msgstr ""
+
+#: permissions.py:11
+msgid "Can execute the OCR clean up on all document pages"
+msgstr ""
+
+#: permissions.py:12
+msgid "Can edit an OCR queue properties"
+msgstr "Posso modificare le proprità della coda di OCR"
+
+#: statistics.py:8
+#, python-format
+msgid "Document queues: %d"
+msgstr "Coda documento:%d"
+
+#: statistics.py:9
+#, python-format
+msgid "Queued documents: %d"
+msgstr "Code di documenti:%d"
+
+#: statistics.py:13
+msgid "OCR statistics"
+msgstr "Statistiche OCR"
+
+#: views.py:42
+#, python-format
+msgid "documents in queue: %s"
+msgstr "documenti in coda: %s"
+
+#: views.py:50
+msgid "thumbnail"
+msgstr "thumbnail"
+
+#: views.py:63
+msgid "document queue properties"
+msgstr "proprietà della coda documenti"
+
+#: views.py:64
+#, python-format
+msgid "Current state: %s"
+msgstr "Stato corrente: %s"
+
+#: views.py:80 views.py:168
+msgid "Must provide at least one queue document."
+msgstr "Deve fornire almeno un documento di coda."
+
+#: views.py:90
+#, python-format
+msgid "Document: %s is being processed and can't be deleted."
+msgstr "Il document: %s è in elaborazione e non può essere cancellato."
+
+#: views.py:93
+#, python-format
+msgid "Queue document: %(document)s deleted successfully."
+msgstr "Coda documento: %(document)s cancellata con successo."
+
+#: views.py:97
+#, python-format
+msgid "Error deleting document: %(document)s; %(error)s"
+msgstr "Errore nella cancellazione del documento: %(document)s; %(error)s"
+
+#: views.py:110
+#, python-format
+msgid "Are you sure you wish to delete queue document: %s?"
+msgstr "Sei sicuro di voler cancellare questa coda documento: %s?"
+
+#: views.py:112
+#, python-format
+msgid "Are you sure you wish to delete queue documents: %s?"
+msgstr "Sei sicuro di voler cancellare queste code documento: %s?"
+
+#: views.py:148
+#, python-format
+msgid "Document: %(document)s was added to the OCR queue: %(queue)s."
+msgstr ""
+"Il documento: %(document)s è stato aggiunto alla coda %(queue)s per OCR."
+
+#: views.py:151
+#, python-format
+msgid "Document: %(document)s is already queued."
+msgstr "Il documento: %(document)s è gia stato elaborato."
+
+#: views.py:180
+#, python-format
+msgid "Document: %(document)s was re-queued to the OCR queue: %(queue)s"
+msgstr "Il documento: %(document)s è stato riprocessato %(queue)s per OCR."
+
+#: views.py:186
+#, python-format
+msgid "Document id#: %d, no longer exists."
+msgstr "il documento id#: %d,non esiste più."
+
+#: views.py:190
+#, python-format
+msgid "Document: %s is already being processed and can't be re-queded."
+msgstr "Il documento: %s è gia stato processato non può essere riprocessato."
+
+#: views.py:202
+#, python-format
+msgid "Are you sure you wish to re-queue document: %s?"
+msgstr "Sei sicuro di volere riprocessare il documento: %s?"
+
+#: views.py:204
+#, python-format
+msgid "Are you sure you wish to re-queue documents: %s?"
+msgstr "Sei sicuro di volere riprocessare questi documenti: %s?"
+
+#: views.py:222
+#, python-format
+msgid "Document queue: %s, already stopped."
+msgstr "Questa coda: %s, è stata appena fermata."
+
+#: views.py:228
+#, python-format
+msgid "Document queue: %s, stopped successfully."
+msgstr "Questa coda: %s,è stata fermata con successo."
+
+#: views.py:234
+#, python-format
+msgid "Are you sure you wish to disable document queue: %s"
+msgstr "Sei sicuro di voler fermare la coda per il documento: %s"
+
+#: views.py:249
+#, python-format
+msgid "Document queue: %s, already active."
+msgstr "La coda per questo documento: %s, è già attiva."
+
+#: views.py:255
+#, python-format
+msgid "Document queue: %s, activated successfully."
+msgstr "Coda documento: %s, attivata con successo."
+
+#: views.py:261
+#, python-format
+msgid "Are you sure you wish to activate document queue: %s"
+msgstr "Sei sicuro di voler attivare questa coda documento: %s"
+
+#: views.py:278
+msgid "Are you sure you wish to clean up all the pages content?"
+msgstr "Sei sicuro di voler ripulire tutto il contenuto delle pagine?"
+
+#: views.py:279
+msgid "On large databases this operation may take some time to execute."
+msgstr "Nei database grandi questa operazione può richiedere del tempo."
+
+#: views.py:285
+msgid "Document pages content clean up complete."
+msgstr "Pulizia del contenuto delle pagine completata."
+
+#: views.py:287
+#, python-format
+msgid "Document pages content clean up error: %s"
+msgstr "Errore nella pulizia del contenuto delle pagine: %s"
+
+#: views.py:313
+#, python-format
+msgid "transformations for: %s"
+msgstr "trasformazione per: %s"
+
+#: views.py:343
+msgid "Queue transformation edited successfully"
+msgstr "Modifica della coda di trasformazione effettuata con successo"
+
+#: views.py:346
+#, python-format
+msgid "Error editing queue transformation; %s"
+msgstr "Errore nella modifica alla coda di trasformazione; %s"
+
+#: views.py:351
+#, python-format
+msgid "Edit transformation: %s"
+msgstr "Modifica trasformazioni:%s"
+
+#: views.py:374
+msgid "Queue transformation deleted successfully."
+msgstr "Coda di trasformazione cancellata con successo"
+
+#: views.py:376
+#, python-format
+msgid "Error deleting queue transformation; %(error)s"
+msgstr "Errore nella cancellazione della coda di trasformazione; %(error)s"
+
+#: views.py:389
+#, python-format
+msgid ""
+"Are you sure you wish to delete queue transformation \"%(transformation)s\""
+msgstr ""
+"Sei sicuro di voler cancellare la coda di trasformazione \"%(transformation)s"
+"\""
+
+#: views.py:412
+msgid "Queue transformation created successfully"
+msgstr "Coda di trasformazione creata con successo"
+
+#: views.py:415
+#, python-format
+msgid "Error creating queue transformation; %s"
+msgstr "Errore creano la coda di trasformazione; %s"
+
+#: views.py:424
+#, python-format
+msgid "Create new transformation for queue: %s"
+msgstr "Crea una nuova coda di trasformazione:%s"
+
+#: conf/settings.py:13
+msgid ""
+"Amount of seconds to delay OCR of documents to allow for the node's storage "
+"replication overhead."
+msgstr ""
+"Quantità di secondi di ritardo OCR di documenti per consentire lo stoccaggio "
+"nel nodo di replica."
+
+#: conf/settings.py:14
+msgid "Maximum amount of concurrent document OCRs a node can perform."
+msgstr ""
+"Importo massimo di documenti concorrenti per OCR che un nodo è in grado di "
+"eseguire."
+
+#: conf/settings.py:15
+msgid "Automatically queue newly created documents for OCR."
+msgstr "Automaticamente crea una coda appena si sottomone un documento ad OCR."
+
+#: conf/settings.py:17
+msgid "File path to unpaper program."
+msgstr "File path per il programma unpaper"
+
+#: parsers/__init__.py:37
+msgid "Text extracted from PDF"
+msgstr "Testo estratto da PDF"
diff --git a/apps/ocr/locale/pl/LC_MESSAGES/django.mo b/apps/ocr/locale/pl/LC_MESSAGES/django.mo
new file mode 100644
index 0000000000..25c2414931
Binary files /dev/null and b/apps/ocr/locale/pl/LC_MESSAGES/django.mo differ
diff --git a/apps/ocr/locale/pl/LC_MESSAGES/django.po b/apps/ocr/locale/pl/LC_MESSAGES/django.po
new file mode 100644
index 0000000000..a42db9d45d
--- /dev/null
+++ b/apps/ocr/locale/pl/LC_MESSAGES/django.po
@@ -0,0 +1,415 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+msgid ""
+msgstr ""
+"Project-Id-Version: Mayan EDMS\n"
+"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
+"PO-Revision-Date: 2011-09-30 04:41+0000\n"
+"Last-Translator: FULL NAME \n"
+"Language-Team: Polish (http://www.transifex.net/projects/p/mayan-edms/language/pl/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: pl\n"
+"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
+
+#: __init__.py:32 __init__.py:33
+msgid "submit to OCR queue"
+msgstr ""
+
+#: __init__.py:34 __init__.py:35
+msgid "re-queue"
+msgstr ""
+
+#: __init__.py:36 __init__.py:37 __init__.py:50
+msgid "delete"
+msgstr ""
+
+#: __init__.py:39
+msgid "stop queue"
+msgstr ""
+
+#: __init__.py:40
+msgid "activate queue"
+msgstr ""
+
+#: __init__.py:42
+msgid "clean up pages content"
+msgstr ""
+
+#: __init__.py:42
+msgid ""
+"Runs a language filter to remove common OCR mistakes from document pages "
+"content."
+msgstr ""
+
+#: __init__.py:44
+msgid "queue document list"
+msgstr ""
+
+#: __init__.py:45 __init__.py:63 permissions.py:7
+msgid "OCR"
+msgstr ""
+
+#: __init__.py:47
+msgid "transformations"
+msgstr ""
+
+#: __init__.py:48
+msgid "add transformation"
+msgstr ""
+
+#: __init__.py:49
+msgid "edit"
+msgstr ""
+
+#: __init__.py:74
+msgid "Default"
+msgstr ""
+
+#: __init__.py:102
+msgid "Checks the OCR queue for pending documents."
+msgstr ""
+
+#: api.py:122
+msgid "Text from OCR"
+msgstr ""
+
+#: literals.py:8
+msgid "stopped"
+msgstr ""
+
+#: literals.py:9
+msgid "active"
+msgstr ""
+
+#: literals.py:18
+msgid "pending"
+msgstr ""
+
+#: literals.py:19
+msgid "processing"
+msgstr ""
+
+#: literals.py:20
+msgid "error"
+msgstr ""
+
+#: models.py:26
+msgid "name"
+msgstr ""
+
+#: models.py:27
+msgid "label"
+msgstr ""
+
+#: models.py:31 models.py:51
+msgid "state"
+msgstr ""
+
+#: models.py:36 models.py:44 views.py:45 views.py:315 views.py:356
+#: views.py:386 views.py:422
+msgid "document queue"
+msgstr ""
+
+#: models.py:37
+msgid "document queues"
+msgstr ""
+
+#: models.py:45
+msgid "document"
+msgstr ""
+
+#: models.py:46
+msgid "date time submitted"
+msgstr ""
+
+#: models.py:47
+msgid "delay ocr"
+msgstr ""
+
+#: models.py:52
+msgid "result"
+msgstr ""
+
+#: models.py:53
+msgid "node name"
+msgstr ""
+
+#: models.py:57
+msgid "queue document"
+msgstr ""
+
+#: models.py:58
+msgid "queue documents"
+msgstr ""
+
+#: models.py:78 views.py:49
+msgid "Missing document."
+msgstr ""
+
+#: models.py:82
+msgid "Enter a valid value."
+msgstr ""
+
+#: models.py:110 views.py:319
+msgid "order"
+msgstr ""
+
+#: models.py:111 views.py:320 views.py:357 views.py:387
+msgid "transformation"
+msgstr ""
+
+#: models.py:112 views.py:321
+msgid "arguments"
+msgstr ""
+
+#: models.py:112
+#, python-format
+msgid "Use dictionaries to indentify arguments, example: %s"
+msgstr ""
+
+#: models.py:122
+msgid "document queue transformation"
+msgstr ""
+
+#: models.py:123
+msgid "document queue transformations"
+msgstr ""
+
+#: permissions.py:8
+msgid "Submit documents for OCR"
+msgstr ""
+
+#: permissions.py:9
+msgid "Delete documents from OCR queue"
+msgstr ""
+
+#: permissions.py:10
+msgid "Can enable/disable the OCR queue"
+msgstr ""
+
+#: permissions.py:11
+msgid "Can execute the OCR clean up on all document pages"
+msgstr ""
+
+#: permissions.py:12
+msgid "Can edit an OCR queue properties"
+msgstr ""
+
+#: statistics.py:8
+#, python-format
+msgid "Document queues: %d"
+msgstr ""
+
+#: statistics.py:9
+#, python-format
+msgid "Queued documents: %d"
+msgstr ""
+
+#: statistics.py:13
+msgid "OCR statistics"
+msgstr ""
+
+#: views.py:42
+#, python-format
+msgid "documents in queue: %s"
+msgstr ""
+
+#: views.py:50
+msgid "thumbnail"
+msgstr ""
+
+#: views.py:63
+msgid "document queue properties"
+msgstr ""
+
+#: views.py:64
+#, python-format
+msgid "Current state: %s"
+msgstr ""
+
+#: views.py:80 views.py:168
+msgid "Must provide at least one queue document."
+msgstr ""
+
+#: views.py:90
+#, python-format
+msgid "Document: %s is being processed and can't be deleted."
+msgstr ""
+
+#: views.py:93
+#, python-format
+msgid "Queue document: %(document)s deleted successfully."
+msgstr ""
+
+#: views.py:97
+#, python-format
+msgid "Error deleting document: %(document)s; %(error)s"
+msgstr ""
+
+#: views.py:110
+#, python-format
+msgid "Are you sure you wish to delete queue document: %s?"
+msgstr ""
+
+#: views.py:112
+#, python-format
+msgid "Are you sure you wish to delete queue documents: %s?"
+msgstr ""
+
+#: views.py:148
+#, python-format
+msgid "Document: %(document)s was added to the OCR queue: %(queue)s."
+msgstr ""
+
+#: views.py:151
+#, python-format
+msgid "Document: %(document)s is already queued."
+msgstr ""
+
+#: views.py:180
+#, python-format
+msgid "Document: %(document)s was re-queued to the OCR queue: %(queue)s"
+msgstr ""
+
+#: views.py:186
+#, python-format
+msgid "Document id#: %d, no longer exists."
+msgstr ""
+
+#: views.py:190
+#, python-format
+msgid "Document: %s is already being processed and can't be re-queded."
+msgstr ""
+
+#: views.py:202
+#, python-format
+msgid "Are you sure you wish to re-queue document: %s?"
+msgstr ""
+
+#: views.py:204
+#, python-format
+msgid "Are you sure you wish to re-queue documents: %s?"
+msgstr ""
+
+#: views.py:222
+#, python-format
+msgid "Document queue: %s, already stopped."
+msgstr ""
+
+#: views.py:228
+#, python-format
+msgid "Document queue: %s, stopped successfully."
+msgstr ""
+
+#: views.py:234
+#, python-format
+msgid "Are you sure you wish to disable document queue: %s"
+msgstr ""
+
+#: views.py:249
+#, python-format
+msgid "Document queue: %s, already active."
+msgstr ""
+
+#: views.py:255
+#, python-format
+msgid "Document queue: %s, activated successfully."
+msgstr ""
+
+#: views.py:261
+#, python-format
+msgid "Are you sure you wish to activate document queue: %s"
+msgstr ""
+
+#: views.py:278
+msgid "Are you sure you wish to clean up all the pages content?"
+msgstr ""
+
+#: views.py:279
+msgid "On large databases this operation may take some time to execute."
+msgstr ""
+
+#: views.py:285
+msgid "Document pages content clean up complete."
+msgstr ""
+
+#: views.py:287
+#, python-format
+msgid "Document pages content clean up error: %s"
+msgstr ""
+
+#: views.py:313
+#, python-format
+msgid "transformations for: %s"
+msgstr ""
+
+#: views.py:343
+msgid "Queue transformation edited successfully"
+msgstr ""
+
+#: views.py:346
+#, python-format
+msgid "Error editing queue transformation; %s"
+msgstr ""
+
+#: views.py:351
+#, python-format
+msgid "Edit transformation: %s"
+msgstr ""
+
+#: views.py:374
+msgid "Queue transformation deleted successfully."
+msgstr ""
+
+#: views.py:376
+#, python-format
+msgid "Error deleting queue transformation; %(error)s"
+msgstr ""
+
+#: views.py:389
+#, python-format
+msgid ""
+"Are you sure you wish to delete queue transformation \"%(transformation)s\""
+msgstr ""
+
+#: views.py:412
+msgid "Queue transformation created successfully"
+msgstr ""
+
+#: views.py:415
+#, python-format
+msgid "Error creating queue transformation; %s"
+msgstr ""
+
+#: views.py:424
+#, python-format
+msgid "Create new transformation for queue: %s"
+msgstr ""
+
+#: conf/settings.py:13
+msgid ""
+"Amount of seconds to delay OCR of documents to allow for the node's storage "
+"replication overhead."
+msgstr ""
+
+#: conf/settings.py:14
+msgid "Maximum amount of concurrent document OCRs a node can perform."
+msgstr ""
+
+#: conf/settings.py:15
+msgid "Automatically queue newly created documents for OCR."
+msgstr ""
+
+#: conf/settings.py:17
+msgid "File path to unpaper program."
+msgstr ""
+
+#: parsers/__init__.py:37
+msgid "Text extracted from PDF"
+msgstr ""
diff --git a/apps/ocr/locale/pt/LC_MESSAGES/django.mo b/apps/ocr/locale/pt/LC_MESSAGES/django.mo
index 065b53a37a..7bf81b457b 100644
Binary files a/apps/ocr/locale/pt/LC_MESSAGES/django.mo and b/apps/ocr/locale/pt/LC_MESSAGES/django.mo differ
diff --git a/apps/ocr/locale/pt/LC_MESSAGES/django.po b/apps/ocr/locale/pt/LC_MESSAGES/django.po
index a7d598736f..c6418c4f40 100644
--- a/apps/ocr/locale/pt/LC_MESSAGES/django.po
+++ b/apps/ocr/locale/pt/LC_MESSAGES/django.po
@@ -9,9 +9,9 @@ msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-11-22 11:26-0400\n"
-"PO-Revision-Date: 2011-11-02 05:10+0000\n"
-"Last-Translator: emersonsoares \n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
+"PO-Revision-Date: 2012-02-02 18:19+0000\n"
+"Last-Translator: Roberto Rosario \n"
"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/"
"team/pt/)\n"
"Language: pt\n"
@@ -20,59 +20,31 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
-#: __init__.py:28
-msgid "Submit document for OCR"
-msgstr "Submeter documento para OCR"
-
-#: __init__.py:29
-msgid "Delete document for OCR queue"
-msgstr "Excluir documento da lista de OCR"
-
-#: __init__.py:30
-msgid "Can enable/disable an OCR queue"
-msgstr "Pode ativar/desativar uma lista de OCR"
-
-#: __init__.py:31
-msgid "Can execute an OCR clean up on all document pages"
-msgstr "Pode executar uma limpeza de OCR em todas as páginas do documento"
-
-#: __init__.py:32
-msgid "Can edit an OCR queue properties"
-msgstr "Pode editar uma lista de propriedades OCR"
-
-#: __init__.py:34 __init__.py:56 __init__.py:74
-msgid "OCR"
-msgstr "OCR"
-
-#: __init__.py:40
-msgid "OCR Setup"
-msgstr "Configuração de OCR"
-
-#: __init__.py:44
+#: __init__.py:32 __init__.py:33
msgid "submit to OCR queue"
msgstr "submeter à lista de OCR"
-#: __init__.py:45 __init__.py:46
+#: __init__.py:34 __init__.py:35
msgid "re-queue"
msgstr "re-enfileirar"
-#: __init__.py:47 __init__.py:48 __init__.py:63
+#: __init__.py:36 __init__.py:37 __init__.py:50
msgid "delete"
msgstr "excluir"
-#: __init__.py:50
+#: __init__.py:39
msgid "stop queue"
msgstr "parar lista"
-#: __init__.py:51
+#: __init__.py:40
msgid "activate queue"
msgstr "ativar lista"
-#: __init__.py:53
+#: __init__.py:42
msgid "clean up pages content"
msgstr "limpar conteúdo das páginas"
-#: __init__.py:53
+#: __init__.py:42
msgid ""
"Runs a language filter to remove common OCR mistakes from document pages "
"content."
@@ -80,35 +52,35 @@ msgstr ""
"Executa um filtro de linguagem para remover erros comuns de OCR do conteúdo "
"das páginas do documento."
-#: __init__.py:55
+#: __init__.py:44
msgid "queue document list"
msgstr "lista de documentos da fila"
-#: __init__.py:58 views.py:316
-msgid "active tasks"
-msgstr "tarefas ativas"
+#: __init__.py:45 __init__.py:63 permissions.py:7
+msgid "OCR"
+msgstr "OCR"
-#: __init__.py:60
+#: __init__.py:47
msgid "transformations"
msgstr "transformações"
-#: __init__.py:61
+#: __init__.py:48
msgid "add transformation"
msgstr "adicionar transformação"
-#: __init__.py:62
+#: __init__.py:49
msgid "edit"
msgstr "editar"
-#: __init__.py:82
+#: __init__.py:74
msgid "Default"
msgstr "Padrão"
-#: __init__.py:104
+#: __init__.py:102
msgid "Checks the OCR queue for pending documents."
msgstr "Verifica a lista de OCR para documentos pendentes."
-#: api.py:119
+#: api.py:122
msgid "Text from OCR"
msgstr "Texto de OCR"
@@ -132,88 +104,108 @@ msgstr "processamento"
msgid "error"
msgstr "erro"
-#: models.py:22
+#: models.py:26
msgid "name"
msgstr "nome"
-#: models.py:23
+#: models.py:27
msgid "label"
msgstr "rótulo"
-#: models.py:27 models.py:47
+#: models.py:31 models.py:51
msgid "state"
msgstr "estado"
-#: models.py:32 models.py:40 views.py:44 views.py:337 views.py:378
-#: views.py:408 views.py:444
+#: models.py:36 models.py:44 views.py:45 views.py:315 views.py:356
+#: views.py:386 views.py:422
msgid "document queue"
msgstr "lista de documento"
-#: models.py:33
+#: models.py:37
msgid "document queues"
msgstr "listas de documento"
-#: models.py:41
+#: models.py:45
msgid "document"
msgstr "documento"
-#: models.py:42
+#: models.py:46
msgid "date time submitted"
msgstr "data e hora submetido"
-#: models.py:43
+#: models.py:47
msgid "delay ocr"
msgstr "atraso ocr"
-#: models.py:48
+#: models.py:52
msgid "result"
msgstr "resultado"
-#: models.py:49
+#: models.py:53
msgid "node name"
msgstr "nome do nó"
-#: models.py:53
+#: models.py:57
msgid "queue document"
msgstr "enfileirar documento"
-#: models.py:54
+#: models.py:58
msgid "queue documents"
msgstr "enfileirar documentos"
-#: models.py:63 views.py:48
+#: models.py:78 views.py:49
msgid "Missing document."
msgstr "Falta de documento."
-#: models.py:67
+#: models.py:82
msgid "Enter a valid value."
msgstr "Digite um valor válido."
-#: models.py:95 views.py:341
+#: models.py:110 views.py:319
msgid "order"
msgstr "ordem"
-#: models.py:96 views.py:342 views.py:379 views.py:409
+#: models.py:111 views.py:320 views.py:357 views.py:387
msgid "transformation"
msgstr "transformação"
-#: models.py:97 views.py:343
+#: models.py:112 views.py:321
msgid "arguments"
msgstr "argumentos"
-#: models.py:97
+#: models.py:112
#, python-format
msgid "Use dictionaries to indentify arguments, example: %s"
msgstr "Use dicionários para identificar argumentos, exemplo: %s"
-#: models.py:107
+#: models.py:122
msgid "document queue transformation"
msgstr "transformação de lista de documento ocr"
-#: models.py:108
+#: models.py:123
msgid "document queue transformations"
msgstr "transformações de listas de documentos"
+#: permissions.py:8
+msgid "Submit documents for OCR"
+msgstr ""
+
+#: permissions.py:9
+msgid "Delete documents from OCR queue"
+msgstr ""
+
+#: permissions.py:10
+msgid "Can enable/disable the OCR queue"
+msgstr ""
+
+#: permissions.py:11
+msgid "Can execute the OCR clean up on all document pages"
+msgstr ""
+
+#: permissions.py:12
+msgid "Can edit an OCR queue properties"
+msgstr "Pode editar uma lista de propriedades OCR"
+
#: statistics.py:8
#, python-format
msgid "Document queues: %d"
@@ -228,182 +220,166 @@ msgstr "Documentos na lista: %d"
msgid "OCR statistics"
msgstr "estatísticas de OCR"
-#: views.py:41
+#: views.py:42
#, python-format
msgid "documents in queue: %s"
msgstr "documentos na lista: %s"
-#: views.py:49
+#: views.py:50
msgid "thumbnail"
msgstr "miniatura"
-#: views.py:62
+#: views.py:63
msgid "document queue properties"
msgstr "propriedades da lista de documento"
-#: views.py:63
+#: views.py:64
#, python-format
msgid "Current state: %s"
msgstr "Estado atual: %s"
-#: views.py:79 views.py:154
+#: views.py:80 views.py:168
msgid "Must provide at least one queue document."
msgstr "Deve fornecer pelo menos um documento da lista."
-#: views.py:89
+#: views.py:90
#, python-format
msgid "Document: %s is being processed and can't be deleted."
msgstr "Documento: %s está sendo processado e não pode ser excluído."
-#: views.py:92
+#: views.py:93
#, python-format
msgid "Queue document: %(document)s deleted successfully."
msgstr "Lista de documento: %(document)s removido com sucesso."
-#: views.py:96
+#: views.py:97
#, python-format
msgid "Error deleting document: %(document)s; %(error)s"
msgstr "Erro ao excluir documento: %(document)s; %(error)s "
-#: views.py:109
+#: views.py:110
#, python-format
msgid "Are you sure you wish to delete queue document: %s?"
msgstr "Você tem certeza que deseja deletar o documento da lista: %s?"
-#: views.py:111
+#: views.py:112
#, python-format
msgid "Are you sure you wish to delete queue documents: %s?"
msgstr "Tem certeza de que deseja excluir os documentos da lista: %s?"
-#: views.py:134
+#: views.py:148
#, python-format
msgid "Document: %(document)s was added to the OCR queue: %(queue)s."
msgstr "Documento: %(document)s foi adicionado à lista de OCR: %(queue)s ."
-#: views.py:137
+#: views.py:151
#, python-format
msgid "Document: %(document)s is already queued."
msgstr "Documento: %(document)s já está na lista."
-#: views.py:165
-#, python-format
-msgid "Document: %s is already being processed and can't be re-queded."
-msgstr "Documento: %s já está sendo processado e não pode ser re-enfileirado."
-
-#: views.py:173
+#: views.py:180
#, python-format
msgid "Document: %(document)s was re-queued to the OCR queue: %(queue)s"
msgstr ""
"Documento: %(document)s foi re-enfileirado para a lista de OCR: %(queue)s "
-#: views.py:176
+#: views.py:186
#, python-format
msgid "Document id#: %d, no longer exists."
msgstr "#ID do documento: %d, não existe mais."
-#: views.py:189
+#: views.py:190
+#, python-format
+msgid "Document: %s is already being processed and can't be re-queded."
+msgstr "Documento: %s já está sendo processado e não pode ser re-enfileirado."
+
+#: views.py:202
#, python-format
msgid "Are you sure you wish to re-queue document: %s?"
msgstr "Tem certeza de que deseja re-enfileirar o documento: %s?"
-#: views.py:191
+#: views.py:204
#, python-format
msgid "Are you sure you wish to re-queue documents: %s?"
msgstr "Tem certeza de que deseja voltar a lista de documentos: %s?"
-#: views.py:209
+#: views.py:222
#, python-format
msgid "Document queue: %s, already stopped."
msgstr "Lista de documento: %s, já está parado."
-#: views.py:215
+#: views.py:228
#, python-format
msgid "Document queue: %s, stopped successfully."
msgstr "Lista de documento: %s, parada com êxito."
-#: views.py:221
+#: views.py:234
#, python-format
msgid "Are you sure you wish to disable document queue: %s"
msgstr "Tem certeza de que deseja desativar a lista de documento: %s"
-#: views.py:236
+#: views.py:249
#, python-format
msgid "Document queue: %s, already active."
msgstr "Lista de documento: %s, já está ativa."
-#: views.py:242
+#: views.py:255
#, python-format
msgid "Document queue: %s, activated successfully."
msgstr "Lista de documento: %s, ativada com sucesso."
-#: views.py:248
+#: views.py:261
#, python-format
msgid "Are you sure you wish to activate document queue: %s"
msgstr "Tem certeza de que deseja ativar a lista de documento: %s"
-#: views.py:265
+#: views.py:278
msgid "Are you sure you wish to clean up all the pages content?"
msgstr "Tem certeza de que deseja limpar todo o conteúdo das páginas?"
-#: views.py:266
+#: views.py:279
msgid "On large databases this operation may take some time to execute."
msgstr ""
"Em grandes bases de dados esta operação pode levar algum tempo para executar."
-#: views.py:272
+#: views.py:285
msgid "Document pages content clean up complete."
msgstr "Limpeza do conteúdo das páginas do documento completa."
-#: views.py:274
+#: views.py:287
#, python-format
msgid "Document pages content clean up error: %s"
msgstr "Erro ao limpar o conteúdo das páginas do documento: %s"
-#: views.py:320
-msgid "node"
-msgstr "nó"
-
-#: views.py:321
-msgid "task id"
-msgstr "id da tarefa"
-
-#: views.py:322
-msgid "task name"
-msgstr "nome da tarefa"
-
-#: views.py:323
-msgid "related object"
-msgstr "objeto relacionado"
-
-#: views.py:335
+#: views.py:313
#, python-format
msgid "transformations for: %s"
msgstr "transformações para: %s"
-#: views.py:365
+#: views.py:343
msgid "Queue transformation edited successfully"
msgstr "Transformação da lista editada com sucesso"
-#: views.py:368
+#: views.py:346
#, python-format
msgid "Error editing queue transformation; %s"
msgstr "Erro ao editar transformação da lista; %s"
-#: views.py:373
+#: views.py:351
#, python-format
msgid "Edit transformation: %s"
msgstr "Editar Transformação: %s"
-#: views.py:396
+#: views.py:374
msgid "Queue transformation deleted successfully."
msgstr "Transformação de lista apagada com sucesso."
-#: views.py:398
+#: views.py:376
#, python-format
msgid "Error deleting queue transformation; %(error)s"
msgstr "Erro ao deletar transformação de lista; %(error)s "
-#: views.py:411
+#: views.py:389
#, python-format
msgid ""
"Are you sure you wish to delete queue transformation \"%(transformation)s\""
@@ -411,16 +387,16 @@ msgstr ""
"Tem certeza que deseja deletar a transformação de lista \"%(transformation)s"
"\""
-#: views.py:434
+#: views.py:412
msgid "Queue transformation created successfully"
msgstr "Transformação de lista criada com sucesso"
-#: views.py:437
+#: views.py:415
#, python-format
msgid "Error creating queue transformation; %s"
msgstr "Erro ao criar a transformação de lista; %s"
-#: views.py:446
+#: views.py:424
#, python-format
msgid "Create new transformation for queue: %s"
msgstr "Criar nova transformação para a lista: %s"
@@ -443,18 +419,9 @@ msgid "Automatically queue newly created documents for OCR."
msgstr "Listar automaticamente os novos documentos criados para OCR "
#: conf/settings.py:17
-msgid ""
-"URI in the form: \"memcached://127.0.0.1:11211/\" to specify a cache backend "
-"to use for locking. Multiple hosts can be specified separated by a semicolon."
-msgstr ""
-"URI na forma: \"memcached: / / 127.0.0.1:11211 /\" para especificar um "
-"backend de cache para usar para o bloqueio. Hosts múltiplos podem ser "
-"especificados separados por ponto-evírgula."
-
-#: conf/settings.py:18
msgid "File path to unpaper program."
msgstr "Caminho do arquivo para o programa unpaper."
-#: parsers/__init__.py:23
+#: parsers/__init__.py:37
msgid "Text extracted from PDF"
msgstr "Texto extraído de PDF"
diff --git a/apps/ocr/locale/ru/LC_MESSAGES/django.mo b/apps/ocr/locale/ru/LC_MESSAGES/django.mo
index 2532ba2c71..bfb70a6258 100644
Binary files a/apps/ocr/locale/ru/LC_MESSAGES/django.mo and b/apps/ocr/locale/ru/LC_MESSAGES/django.mo differ
diff --git a/apps/ocr/locale/ru/LC_MESSAGES/django.po b/apps/ocr/locale/ru/LC_MESSAGES/django.po
index e4dd103e6d..0990e65ad2 100644
--- a/apps/ocr/locale/ru/LC_MESSAGES/django.po
+++ b/apps/ocr/locale/ru/LC_MESSAGES/django.po
@@ -8,9 +8,9 @@ msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-11-22 11:26-0400\n"
-"PO-Revision-Date: 2011-11-04 10:48+0000\n"
-"Last-Translator: gsv70 \n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
+"PO-Revision-Date: 2012-02-02 18:19+0000\n"
+"Last-Translator: Roberto Rosario \n"
"Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/team/"
"ru/)\n"
"Language: ru\n"
@@ -20,59 +20,31 @@ msgstr ""
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
-#: __init__.py:28
-msgid "Submit document for OCR"
-msgstr "Отправить документ для распознавания текста"
-
-#: __init__.py:29
-msgid "Delete document for OCR queue"
-msgstr "Удалить документ из очереди распознавания"
-
-#: __init__.py:30
-msgid "Can enable/disable an OCR queue"
-msgstr "Можно включить / выключить очереди распознавания"
-
-#: __init__.py:31
-msgid "Can execute an OCR clean up on all document pages"
-msgstr "Невозможно выполнить распознавание на всех страницах документа"
-
-#: __init__.py:32
-msgid "Can edit an OCR queue properties"
-msgstr "Можно редактировать свойства очереди распознавания"
-
-#: __init__.py:34 __init__.py:56 __init__.py:74
-msgid "OCR"
-msgstr "Распознавание текста"
-
-#: __init__.py:40
-msgid "OCR Setup"
-msgstr "Настройки распознавания "
-
-#: __init__.py:44
+#: __init__.py:32 __init__.py:33
msgid "submit to OCR queue"
msgstr "отправить на распознавание"
-#: __init__.py:45 __init__.py:46
+#: __init__.py:34 __init__.py:35
msgid "re-queue"
msgstr "переотправить"
-#: __init__.py:47 __init__.py:48 __init__.py:63
+#: __init__.py:36 __init__.py:37 __init__.py:50
msgid "delete"
msgstr "удалить"
-#: __init__.py:50
+#: __init__.py:39
msgid "stop queue"
msgstr "остановка очереди"
-#: __init__.py:51
+#: __init__.py:40
msgid "activate queue"
msgstr "активировать очередь"
-#: __init__.py:53
+#: __init__.py:42
msgid "clean up pages content"
msgstr "очистка содержимого страниц"
-#: __init__.py:53
+#: __init__.py:42
msgid ""
"Runs a language filter to remove common OCR mistakes from document pages "
"content."
@@ -80,35 +52,35 @@ msgstr ""
"Применить языковый фильтр для удаления общих ошибок распознавания "
"содержимого страниц документа."
-#: __init__.py:55
+#: __init__.py:44
msgid "queue document list"
msgstr "список очереди документов"
-#: __init__.py:58 views.py:316
-msgid "active tasks"
-msgstr "активные задачи"
+#: __init__.py:45 __init__.py:63 permissions.py:7
+msgid "OCR"
+msgstr "Распознавание текста"
-#: __init__.py:60
+#: __init__.py:47
msgid "transformations"
msgstr "преобразования"
-#: __init__.py:61
+#: __init__.py:48
msgid "add transformation"
msgstr "добавить преобразование"
-#: __init__.py:62
+#: __init__.py:49
msgid "edit"
msgstr "редактировать"
-#: __init__.py:82
+#: __init__.py:74
msgid "Default"
msgstr "Умолчание"
-#: __init__.py:104
+#: __init__.py:102
msgid "Checks the OCR queue for pending documents."
msgstr "Проверить очередь документов ожидающих распознавания ."
-#: api.py:119
+#: api.py:122
msgid "Text from OCR"
msgstr "Распознанный текст"
@@ -132,88 +104,108 @@ msgstr "обработка"
msgid "error"
msgstr "ошибка"
-#: models.py:22
+#: models.py:26
msgid "name"
msgstr "имя"
-#: models.py:23
+#: models.py:27
msgid "label"
msgstr "этикетка"
-#: models.py:27 models.py:47
+#: models.py:31 models.py:51
msgid "state"
msgstr "состояние"
-#: models.py:32 models.py:40 views.py:44 views.py:337 views.py:378
-#: views.py:408 views.py:444
+#: models.py:36 models.py:44 views.py:45 views.py:315 views.py:356
+#: views.py:386 views.py:422
msgid "document queue"
msgstr "очередь документов"
-#: models.py:33
+#: models.py:37
msgid "document queues"
msgstr "очереди документов"
-#: models.py:41
+#: models.py:45
msgid "document"
msgstr "документ"
-#: models.py:42
+#: models.py:46
msgid "date time submitted"
msgstr "дата и время отправления"
-#: models.py:43
+#: models.py:47
msgid "delay ocr"
msgstr "задержка распознавания"
-#: models.py:48
+#: models.py:52
msgid "result"
msgstr "результат"
-#: models.py:49
+#: models.py:53
msgid "node name"
msgstr "имя узла"
-#: models.py:53
+#: models.py:57
msgid "queue document"
msgstr "документ очереди"
-#: models.py:54
+#: models.py:58
msgid "queue documents"
msgstr "документы очереди"
-#: models.py:63 views.py:48
+#: models.py:78 views.py:49
msgid "Missing document."
msgstr "Документа отсутствует."
-#: models.py:67
+#: models.py:82
msgid "Enter a valid value."
msgstr "Введите допустимое значение."
-#: models.py:95 views.py:341
+#: models.py:110 views.py:319
msgid "order"
msgstr "порядок"
-#: models.py:96 views.py:342 views.py:379 views.py:409
+#: models.py:111 views.py:320 views.py:357 views.py:387
msgid "transformation"
msgstr "преобразование"
-#: models.py:97 views.py:343
+#: models.py:112 views.py:321
msgid "arguments"
msgstr "аргументы"
-#: models.py:97
+#: models.py:112
#, python-format
msgid "Use dictionaries to indentify arguments, example: %s"
msgstr "Использование словарей для определения аргументов, например: %s"
-#: models.py:107
+#: models.py:122
msgid "document queue transformation"
msgstr "преобразование очереди документов "
-#: models.py:108
+#: models.py:123
msgid "document queue transformations"
msgstr "преобразование очереди документов "
+#: permissions.py:8
+msgid "Submit documents for OCR"
+msgstr ""
+
+#: permissions.py:9
+msgid "Delete documents from OCR queue"
+msgstr ""
+
+#: permissions.py:10
+msgid "Can enable/disable the OCR queue"
+msgstr ""
+
+#: permissions.py:11
+msgid "Can execute the OCR clean up on all document pages"
+msgstr ""
+
+#: permissions.py:12
+msgid "Can edit an OCR queue properties"
+msgstr "Можно редактировать свойства очереди распознавания"
+
#: statistics.py:8
#, python-format
msgid "Document queues: %d"
@@ -228,200 +220,184 @@ msgstr "Документов в очереди : %d"
msgid "OCR statistics"
msgstr "статистика распознавания"
-#: views.py:41
+#: views.py:42
#, python-format
msgid "documents in queue: %s"
msgstr "документы в очереди: %s"
-#: views.py:49
+#: views.py:50
msgid "thumbnail"
msgstr "миниатюра"
-#: views.py:62
+#: views.py:63
msgid "document queue properties"
msgstr "свойства очереди документов"
-#: views.py:63
+#: views.py:64
#, python-format
msgid "Current state: %s"
msgstr "Текущее состояние:%s"
-#: views.py:79 views.py:154
+#: views.py:80 views.py:168
msgid "Must provide at least one queue document."
msgstr "Должна быть хотя бы одна очередь документов."
-#: views.py:89
+#: views.py:90
#, python-format
msgid "Document: %s is being processed and can't be deleted."
msgstr "Документ: %s обрабатывается и не может быть удален."
-#: views.py:92
+#: views.py:93
#, python-format
msgid "Queue document: %(document)s deleted successfully."
msgstr "Очередь документов: %(document)s успешно удалён."
-#: views.py:96
+#: views.py:97
#, python-format
msgid "Error deleting document: %(document)s; %(error)s"
msgstr "Ошибка при удалении документа:%(document)s; %(error)s"
-#: views.py:109
+#: views.py:110
#, python-format
msgid "Are you sure you wish to delete queue document: %s?"
msgstr "Вы действительно хотите удалить очередь документа: %s?"
-#: views.py:111
+#: views.py:112
#, python-format
msgid "Are you sure you wish to delete queue documents: %s?"
msgstr "Вы действительно хотите удалить очереди документов: %s?"
-#: views.py:134
+#: views.py:148
#, python-format
msgid "Document: %(document)s was added to the OCR queue: %(queue)s."
msgstr ""
"Документ: %(document)s добавлен для распознавания в очередь: %(queue)s."
-#: views.py:137
+#: views.py:151
#, python-format
msgid "Document: %(document)s is already queued."
msgstr "Документ: %(document)s уже находится в очереди."
-#: views.py:165
+#: views.py:180
+#, python-format
+msgid "Document: %(document)s was re-queued to the OCR queue: %(queue)s"
+msgstr "Документ: %(document)s повторно добавлен в очередь: %(queue)s"
+
+#: views.py:186
+#, python-format
+msgid "Document id#: %d, no longer exists."
+msgstr "Документ №: %d больше не существует."
+
+#: views.py:190
#, python-format
msgid "Document: %s is already being processed and can't be re-queded."
msgstr ""
"Документ: %s уже обработан и не может быть повторно добавлен в очередь."
-#: views.py:173
-#, python-format
-msgid "Document: %(document)s was re-queued to the OCR queue: %(queue)s"
-msgstr "Документ: %(document)s повторно добавлен в очередь: %(queue)s"
-
-#: views.py:176
-#, python-format
-msgid "Document id#: %d, no longer exists."
-msgstr "Документ №: %d больше не существует."
-
-#: views.py:189
+#: views.py:202
#, python-format
msgid "Are you sure you wish to re-queue document: %s?"
msgstr "Вы действительно хотите повторно добавить документ в очередь: %s?"
-#: views.py:191
+#: views.py:204
#, python-format
msgid "Are you sure you wish to re-queue documents: %s?"
msgstr "Вы действительно хотите повторно добавить документы в очередь: %s?"
-#: views.py:209
+#: views.py:222
#, python-format
msgid "Document queue: %s, already stopped."
msgstr "Очередь документов: %s, уже остановлена."
-#: views.py:215
+#: views.py:228
#, python-format
msgid "Document queue: %s, stopped successfully."
msgstr "Очередь документов: %s успешно остановлена."
-#: views.py:221
+#: views.py:234
#, python-format
msgid "Are you sure you wish to disable document queue: %s"
msgstr "Вы действительно хотите отключить очередь документов: %s "
-#: views.py:236
+#: views.py:249
#, python-format
msgid "Document queue: %s, already active."
msgstr "Очередь документов %s уже активна."
-#: views.py:242
+#: views.py:255
#, python-format
msgid "Document queue: %s, activated successfully."
msgstr "Очередь документов %s успешно активирована."
-#: views.py:248
+#: views.py:261
#, python-format
msgid "Are you sure you wish to activate document queue: %s"
msgstr "Вы действительно хотите активировать очередь документов %s"
-#: views.py:265
+#: views.py:278
msgid "Are you sure you wish to clean up all the pages content?"
msgstr "Вы уверены, что хотите очистить все содержимое страниц?"
-#: views.py:266
+#: views.py:279
msgid "On large databases this operation may take some time to execute."
msgstr ""
"В больших базах данных эта операция может занять некоторое время для "
"выполнения."
-#: views.py:272
+#: views.py:285
msgid "Document pages content clean up complete."
msgstr "Чистка содержимого страниц документа завершена."
-#: views.py:274
+#: views.py:287
#, python-format
msgid "Document pages content clean up error: %s"
msgstr "Ошибка:%s при чистка содержимого страниц документа"
-#: views.py:320
-msgid "node"
-msgstr "узел"
-
-#: views.py:321
-msgid "task id"
-msgstr "идентификатор задачи"
-
-#: views.py:322
-msgid "task name"
-msgstr "имя задачи"
-
-#: views.py:323
-msgid "related object"
-msgstr "связанный объект"
-
-#: views.py:335
+#: views.py:313
#, python-format
msgid "transformations for: %s"
msgstr "преобразования для: %s"
-#: views.py:365
+#: views.py:343
msgid "Queue transformation edited successfully"
msgstr "Преобразование очереди изменено"
-#: views.py:368
+#: views.py:346
#, python-format
msgid "Error editing queue transformation; %s"
msgstr "Ошибка редактирования преобразования очереди; %s"
-#: views.py:373
+#: views.py:351
#, python-format
msgid "Edit transformation: %s"
msgstr "Изменить преобразование: %s"
-#: views.py:396
+#: views.py:374
msgid "Queue transformation deleted successfully."
msgstr "Преобразование очереди успешно удалено."
-#: views.py:398
+#: views.py:376
#, python-format
msgid "Error deleting queue transformation; %(error)s"
msgstr "Ошибка при удалении преобразования очереди; %(error)s"
-#: views.py:411
+#: views.py:389
#, python-format
msgid ""
"Are you sure you wish to delete queue transformation \"%(transformation)s\""
msgstr ""
"Вы действительно хотите удалить преобразование очереди \"%(transformation)s\""
-#: views.py:434
+#: views.py:412
msgid "Queue transformation created successfully"
msgstr "Преобразование очереди создано"
-#: views.py:437
+#: views.py:415
#, python-format
msgid "Error creating queue transformation; %s"
msgstr "Ошибка при создании преобразования очереди; %s"
-#: views.py:446
+#: views.py:424
#, python-format
msgid "Create new transformation for queue: %s"
msgstr "Создать новое преобразование для очереди:% s."
@@ -445,18 +421,9 @@ msgstr ""
"Автоматически ставить в очередь новые документы для распознавания текста."
#: conf/settings.py:17
-msgid ""
-"URI in the form: \"memcached://127.0.0.1:11211/\" to specify a cache backend "
-"to use for locking. Multiple hosts can be specified separated by a semicolon."
-msgstr ""
-"URI в виде: \"memcached://127.0.0.1:11211/\", для определения обработчика, "
-"используемого для блокирования. Несколько хостов могут быть указаны через "
-"точку с запятой."
-
-#: conf/settings.py:18
msgid "File path to unpaper program."
msgstr "Путь к программе unpaper."
-#: parsers/__init__.py:23
+#: parsers/__init__.py:37
msgid "Text extracted from PDF"
msgstr "Текст, извлеченный из PDF"
diff --git a/apps/ocr/managers.py b/apps/ocr/managers.py
index a1fdb80b8c..b4596356d6 100644
--- a/apps/ocr/managers.py
+++ b/apps/ocr/managers.py
@@ -1,13 +1,15 @@
+from __future__ import absolute_import
+
from django.db import models
-from ocr.exceptions import AlreadyQueued
+from .exceptions import AlreadyQueued
class DocumentQueueManager(models.Manager):
- """
+ '''
Module manager class to handle adding documents to an OCR document
queue
- """
+ '''
def queue_document(self, document, queue_name='default'):
document_queue = self.model.objects.get(name=queue_name)
if document_queue.queuedocument_set.filter(document=document):
diff --git a/apps/ocr/models.py b/apps/ocr/models.py
index f33ee3fb35..3717f0ffe9 100644
--- a/apps/ocr/models.py
+++ b/apps/ocr/models.py
@@ -1,3 +1,5 @@
+from __future__ import absolute_import
+
from ast import literal_eval
from datetime import datetime
@@ -13,11 +15,11 @@ from documents.models import Document
from converter.api import get_available_transformations_choices
from sources.managers import SourceTransformationManager
-from ocr.literals import DOCUMENTQUEUE_STATE_STOPPED, \
- DOCUMENTQUEUE_STATE_CHOICES, QUEUEDOCUMENT_STATE_PENDING, \
- QUEUEDOCUMENT_STATE_CHOICES, QUEUEDOCUMENT_STATE_PROCESSING
-from ocr.managers import DocumentQueueManager
-from ocr.exceptions import ReQueueError
+from .literals import (DOCUMENTQUEUE_STATE_STOPPED,
+ DOCUMENTQUEUE_STATE_CHOICES, QUEUEDOCUMENT_STATE_PENDING,
+ QUEUEDOCUMENT_STATE_CHOICES, QUEUEDOCUMENT_STATE_PROCESSING)
+from .managers import DocumentQueueManager
+from .exceptions import ReQueueError
class DocumentQueue(models.Model):
@@ -87,9 +89,9 @@ class ArgumentsValidator(object):
self.code = code
def __call__(self, value):
- """
+ '''
Validates that the input evaluates correctly.
- """
+ '''
value = value.strip()
try:
literal_eval(value)
@@ -98,10 +100,10 @@ class ArgumentsValidator(object):
class QueueTransformation(models.Model):
- """
+ '''
Model that stores the transformation and transformation arguments
for a given document queue
- """
+ '''
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
diff --git a/apps/ocr/parsers/__init__.py b/apps/ocr/parsers/__init__.py
index 3d5a39635e..6a91d392d4 100644
--- a/apps/ocr/parsers/__init__.py
+++ b/apps/ocr/parsers/__init__.py
@@ -3,10 +3,9 @@ import logging
from django.utils.translation import ugettext as _
-from converter import office_converter
from converter import office_converter
from converter.office_converter import OfficeConverter
-from converter.exceptions import OfficeBackendError, OfficeConversionError
+from converter.exceptions import OfficeConversionError
from documents.utils import document_save_to_temp_dir
from ocr.parsers.exceptions import ParserError, ParserUnknownFile
@@ -27,7 +26,7 @@ def register_parser(function, mimetype=None, mimetypes=None):
def pdf_parser(document_page, descriptor=None):
if not descriptor:
descriptor = document_page.document_version.open()
-
+
pdf_pages = slate.PDF(descriptor)
descriptor.close()
@@ -45,7 +44,7 @@ def office_parser(document_page):
office_converter = OfficeConverter()
document_file = document_save_to_temp_dir(document_page.document, document_page.document.checksum)
logger.debug('document_file: %s', document_file)
-
+
office_converter.convert(document_file, mimetype=document_page.document.file_mimetype)
if office_converter.exists:
input_filepath = office_converter.output_filepath
@@ -58,7 +57,7 @@ def office_parser(document_page):
except OfficeConversionError, msg:
print msg
raise ParserError
-
+
def parse_document_page(document_page):
logger.debug('executing')
diff --git a/apps/ocr/permissions.py b/apps/ocr/permissions.py
new file mode 100644
index 0000000000..f74f1ec267
--- /dev/null
+++ b/apps/ocr/permissions.py
@@ -0,0 +1,12 @@
+from __future__ import absolute_import
+
+from django.utils.translation import ugettext_lazy as _
+
+from permissions.models import Permission, PermissionNamespace
+
+ocr_namespace = PermissionNamespace('ocr', _(u'OCR'))
+PERMISSION_OCR_DOCUMENT = Permission.objects.register(ocr_namespace, 'ocr_document', _(u'Submit documents for OCR'))
+PERMISSION_OCR_DOCUMENT_DELETE = Permission.objects.register(ocr_namespace, 'ocr_document_delete', _(u'Delete documents from OCR queue'))
+PERMISSION_OCR_QUEUE_ENABLE_DISABLE = Permission.objects.register(ocr_namespace, 'ocr_queue_enable_disable', _(u'Can enable/disable the OCR queue'))
+PERMISSION_OCR_CLEAN_ALL_PAGES = Permission.objects.register(ocr_namespace, 'ocr_clean_all_pages', _(u'Can execute the OCR clean up on all document pages'))
+PERMISSION_OCR_QUEUE_EDIT = Permission.objects.register(ocr_namespace, 'ocr_queue_edit', _(u'Can edit an OCR queue properties'))
diff --git a/apps/ocr/tasks.py b/apps/ocr/tasks.py
index 7c01a36e4d..800d0623d2 100644
--- a/apps/ocr/tasks.py
+++ b/apps/ocr/tasks.py
@@ -1,7 +1,7 @@
+from __future__ import absolute_import
+
from datetime import timedelta, datetime
import platform
-from time import sleep
-from random import random
import logging
from django.db.models import Q
@@ -9,15 +9,13 @@ from django.db.models import Q
from job_processor.api import process_job
from lock_manager import Lock, LockError
-from ocr.api import do_document_ocr
-from ocr.literals import QUEUEDOCUMENT_STATE_PENDING, \
- QUEUEDOCUMENT_STATE_PROCESSING, DOCUMENTQUEUE_STATE_ACTIVE, \
- QUEUEDOCUMENT_STATE_ERROR
-from ocr.models import QueueDocument, DocumentQueue
-from ocr.conf.settings import NODE_CONCURRENT_EXECUTION
-from ocr.conf.settings import REPLICATION_DELAY
-from ocr.conf.settings import CACHE_URI
-from ocr.conf.settings import QUEUE_PROCESSING_INTERVAL
+from .api import do_document_ocr
+from .literals import (QUEUEDOCUMENT_STATE_PENDING,
+ QUEUEDOCUMENT_STATE_PROCESSING, DOCUMENTQUEUE_STATE_ACTIVE,
+ QUEUEDOCUMENT_STATE_ERROR)
+from .models import QueueDocument, DocumentQueue
+from .conf.settings import (NODE_CONCURRENT_EXECUTION, REPLICATION_DELAY,
+ QUEUE_PROCESSING_INTERVAL)
LOCK_EXPIRE = 60 * 10 # Lock expires in 10 minutes
# TODO: Tie LOCK_EXPIRATION with hard task timeout
@@ -42,44 +40,16 @@ def task_process_queue_document(queue_document_id):
queue_document.state = QUEUEDOCUMENT_STATE_ERROR
queue_document.result = e
queue_document.save()
-
+
lock.release()
except LockError:
logger.debug('unable to obtain lock')
pass
-def reset_orphans():
- pass
- '''
- i = inspect().active()
- active_tasks = []
- orphans = []
-
- if i:
- for host, instances in i.items():
- for instance in instances:
- active_tasks.append(instance['id'])
-
- for document_queue in DocumentQueue.objects.filter(state=DOCUMENTQUEUE_STATE_ACTIVE):
- orphans = document_queue.queuedocument_set.\
- filter(state=QUEUEDOCUMENT_STATE_PROCESSING).\
- exclude(result__in=active_tasks)
-
- for orphan in orphans:
- orphan.result = _(u'Orphaned')
- orphan.state = QUEUEDOCUMENT_STATE_PENDING
- orphan.delay = False
- orphan.node_name = None
- orphan.save()
- '''
-
-
def task_process_document_queues():
logger.debug('executed')
- # reset_orphans()
- # Causes problems with big clusters increased latency
- # Disabled until better solution
+ # TODO: reset_orphans()
q_pending = Q(state=QUEUEDOCUMENT_STATE_PENDING)
q_delayed = Q(delay=True)
q_delay_interval = Q(datetime_submitted__lt=datetime.now() - timedelta(seconds=REPLICATION_DELAY))
@@ -100,7 +70,7 @@ def task_process_document_queues():
#print 'DocumentQueueWatcher exception: %s' % e
finally:
# Don't process anymore from this queryset, might be stale
- break;
+ break
else:
logger.debug('already processing maximun')
else:
diff --git a/apps/ocr/tests.py b/apps/ocr/tests.py
deleted file mode 100644
index 2247054b35..0000000000
--- a/apps/ocr/tests.py
+++ /dev/null
@@ -1,23 +0,0 @@
-"""
-This file demonstrates two different styles of tests (one doctest and one
-unittest). These will both pass when you run "manage.py test".
-
-Replace these with more appropriate tests for your application.
-"""
-
-from django.test import TestCase
-
-class SimpleTest(TestCase):
- def test_basic_addition(self):
- """
- Tests that 1 + 1 always equals 2.
- """
- self.failUnlessEqual(1 + 1, 2)
-
-__test__ = {"doctest": """
-Another way to test that 1 + 1 is equal to 2.
-
->>> 1 + 1 == 2
-True
-"""}
-
diff --git a/apps/ocr/urls.py b/apps/ocr/urls.py
index dd8529119b..d77be818f8 100644
--- a/apps/ocr/urls.py
+++ b/apps/ocr/urls.py
@@ -13,7 +13,6 @@ urlpatterns = patterns('ocr.views',
url(r'^queue/(?P\d+)/disable/$', 'document_queue_disable', (), 'document_queue_disable'),
url(r'^document/all/clean_up/$', 'all_document_ocr_cleanup', (), 'all_document_ocr_cleanup'),
- url(r'^node/active/list/$', 'node_active_list', (), 'node_active_list'),
url(r'^queue/(?P\d+)/transformation/list/$', 'setup_queue_transformation_list', (), 'setup_queue_transformation_list'),
url(r'^queue/(?P\w+)/transformation/create/$', 'setup_queue_transformation_create', (), 'setup_queue_transformation_create'),
diff --git a/apps/ocr/views.py b/apps/ocr/views.py
index 8fbc40d444..92772ad03e 100644
--- a/apps/ocr/views.py
+++ b/apps/ocr/views.py
@@ -1,4 +1,4 @@
-import socket
+from __future__ import absolute_import
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response, get_object_or_404
@@ -7,28 +7,28 @@ from django.contrib import messages
from django.views.generic.list_detail import object_list
from django.utils.translation import ugettext_lazy as _
from django.core.urlresolvers import reverse
+from django.core.exceptions import PermissionDenied
-from celery.task.control import inspect
-from permissions.api import check_permissions
+from permissions.models import Permission
from documents.models import Document
from documents.widgets import document_link, document_thumbnail
from common.utils import encapsulate
+from acls.models import AccessEntry
-from ocr import PERMISSION_OCR_DOCUMENT, PERMISSION_OCR_DOCUMENT_DELETE, \
- PERMISSION_OCR_QUEUE_ENABLE_DISABLE, PERMISSION_OCR_CLEAN_ALL_PAGES, \
- PERMISSION_OCR_QUEUE_EDIT
-
-from ocr.models import DocumentQueue, QueueDocument, QueueTransformation
-from ocr.literals import QUEUEDOCUMENT_STATE_PENDING, \
- QUEUEDOCUMENT_STATE_PROCESSING, DOCUMENTQUEUE_STATE_STOPPED, \
- DOCUMENTQUEUE_STATE_ACTIVE
-from ocr.exceptions import AlreadyQueued, ReQueueError
-from ocr.api import clean_pages
-from ocr.forms import QueueTransformationForm, QueueTransformationForm_create
+from .permissions import (PERMISSION_OCR_DOCUMENT,
+ PERMISSION_OCR_DOCUMENT_DELETE, PERMISSION_OCR_QUEUE_ENABLE_DISABLE,
+ PERMISSION_OCR_CLEAN_ALL_PAGES, PERMISSION_OCR_QUEUE_EDIT)
+from .models import DocumentQueue, QueueDocument, QueueTransformation
+from .literals import (QUEUEDOCUMENT_STATE_PENDING,
+ QUEUEDOCUMENT_STATE_PROCESSING, DOCUMENTQUEUE_STATE_STOPPED,
+ DOCUMENTQUEUE_STATE_ACTIVE)
+from .exceptions import AlreadyQueued, ReQueueError
+from .api import clean_pages
+from .forms import QueueTransformationForm, QueueTransformationForm_create
def queue_document_list(request, queue_name='default'):
- check_permissions(request.user, [PERMISSION_OCR_DOCUMENT])
+ Permission.objects.check_permissions(request.user, [PERMISSION_OCR_DOCUMENT])
document_queue = get_object_or_404(DocumentQueue, name=queue_name)
@@ -68,7 +68,7 @@ def queue_document_list(request, queue_name='default'):
def queue_document_delete(request, queue_document_id=None, queue_document_id_list=None):
- check_permissions(request.user, [PERMISSION_OCR_DOCUMENT_DELETE])
+ Permission.objects.check_permissions(request.user, [PERMISSION_OCR_DOCUMENT_DELETE])
if queue_document_id:
queue_documents = [get_object_or_404(QueueDocument, pk=queue_document_id)]
@@ -120,20 +120,26 @@ def queue_document_multiple_delete(request):
def submit_document_multiple(request):
for item_id in request.GET.get('id_list', '').split(','):
submit_document(request, item_id)
-
+
return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))
-
+
def submit_document(request, document_id):
- check_permissions(request.user, [PERMISSION_OCR_DOCUMENT])
-
document = get_object_or_404(Document, pk=document_id)
+
+ try:
+ Permission.objects.check_permissions(request.user, [PERMISSION_OCR_DOCUMENT])
+ except PermissionDenied:
+ AccessEntry.objects.check_access(PERMISSION_OCR_DOCUMENT, request.user, document)
+
return submit_document_to_queue(request, document=document,
post_submit_redirect=request.META.get('HTTP_REFERER', '/'))
def submit_document_to_queue(request, document, post_submit_redirect=None):
- """This view is meant to be reusable"""
+ '''
+ This view is meant to be reusable
+ '''
try:
document_queue = DocumentQueue.objects.queue_document(document)
@@ -150,7 +156,7 @@ def submit_document_to_queue(request, document, post_submit_redirect=None):
def re_queue_document(request, queue_document_id=None, queue_document_id_list=None):
- check_permissions(request.user, [PERMISSION_OCR_DOCUMENT])
+ Permission.objects.check_permissions(request.user, [PERMISSION_OCR_DOCUMENT])
if queue_document_id:
queue_documents = [get_object_or_404(QueueDocument, pk=queue_document_id)]
@@ -204,7 +210,7 @@ def re_queue_multiple_document(request):
def document_queue_disable(request, document_queue_id):
- check_permissions(request.user, [PERMISSION_OCR_QUEUE_ENABLE_DISABLE])
+ Permission.objects.check_permissions(request.user, [PERMISSION_OCR_QUEUE_ENABLE_DISABLE])
next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', None)))
previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', None)))
@@ -231,7 +237,7 @@ def document_queue_disable(request, document_queue_id):
def document_queue_enable(request, document_queue_id):
- check_permissions(request.user, [PERMISSION_OCR_QUEUE_ENABLE_DISABLE])
+ Permission.objects.check_permissions(request.user, [PERMISSION_OCR_QUEUE_ENABLE_DISABLE])
next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', None)))
previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', None)))
@@ -258,7 +264,7 @@ def document_queue_enable(request, document_queue_id):
def all_document_ocr_cleanup(request):
- check_permissions(request.user, [PERMISSION_OCR_CLEAN_ALL_PAGES])
+ Permission.objects.check_permissions(request.user, [PERMISSION_OCR_CLEAN_ALL_PAGES])
previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', None)))
next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', None)))
@@ -294,44 +300,9 @@ def display_link(obj):
return obj
-def node_active_list(request):
- check_permissions(request.user, [PERMISSION_OCR_DOCUMENT])
-
- i = inspect()
- active_tasks = []
- try:
- active_nodes = i.active()
- if active_nodes:
- for node, tasks in active_nodes.items():
- for task in tasks:
- task_info = {
- 'node': node,
- 'task_name': task['name'],
- 'task_id': task['id'],
- 'related_object': None,
- }
- if task['name'] == u'ocr.tasks.task_process_queue_document':
- task_info['related_object'] = QueueDocument.objects.get(pk=eval(task['args'])[0]).document
- active_tasks.append(task_info)
- except socket.error:
- active_tasks = []
-
- return render_to_response('generic_list.html', {
- 'object_list': active_tasks,
- 'title': _(u'active tasks'),
- 'hide_links': True,
- 'hide_object': True,
- 'extra_columns': [
- {'name': _(u'node'), 'attribute': 'node'},
- {'name': _(u'task id'), 'attribute': 'task_id'},
- {'name': _(u'task name'), 'attribute': 'task_name'},
- {'name': _(u'related object'), 'attribute': lambda x: display_link(x['related_object']) if x['related_object'] else u''}
- ],
- }, context_instance=RequestContext(request))
-
-
+# Setup views
def setup_queue_transformation_list(request, document_queue_id):
- check_permissions(request.user, [PERMISSION_OCR_QUEUE_EDIT])
+ Permission.objects.check_permissions(request.user, [PERMISSION_OCR_QUEUE_EDIT])
document_queue = get_object_or_404(DocumentQueue, pk=document_queue_id)
@@ -356,7 +327,7 @@ def setup_queue_transformation_list(request, document_queue_id):
def setup_queue_transformation_edit(request, transformation_id):
- check_permissions(request.user, [PERMISSION_OCR_QUEUE_EDIT])
+ Permission.objects.check_permissions(request.user, [PERMISSION_OCR_QUEUE_EDIT])
transformation = get_object_or_404(QueueTransformation, pk=transformation_id)
redirect_view = reverse('setup_queue_transformation_list', args=[transformation.content_object.pk])
@@ -389,7 +360,7 @@ def setup_queue_transformation_edit(request, transformation_id):
def setup_queue_transformation_delete(request, transformation_id):
- check_permissions(request.user, [PERMISSION_OCR_QUEUE_EDIT])
+ Permission.objects.check_permissions(request.user, [PERMISSION_OCR_QUEUE_EDIT])
transformation = get_object_or_404(QueueTransformation, pk=transformation_id)
redirect_view = reverse('setup_queue_transformation_list', args=[transformation.content_object.pk])
@@ -423,7 +394,7 @@ def setup_queue_transformation_delete(request, transformation_id):
def setup_queue_transformation_create(request, document_queue_id):
- check_permissions(request.user, [PERMISSION_OCR_QUEUE_EDIT])
+ Permission.objects.check_permissions(request.user, [PERMISSION_OCR_QUEUE_EDIT])
document_queue = get_object_or_404(DocumentQueue, pk=document_queue_id)
diff --git a/apps/permissions/__init__.py b/apps/permissions/__init__.py
index e143c8bbb8..73731a97db 100644
--- a/apps/permissions/__init__.py
+++ b/apps/permissions/__init__.py
@@ -1,3 +1,5 @@
+from __future__ import absolute_import
+
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.core.exceptions import ObjectDoesNotExist
@@ -6,17 +8,13 @@ from django.utils.translation import ugettext_lazy as _
from navigation.api import register_links, register_multi_item_links
from project_setup.api import register_setup
-from permissions.conf.settings import DEFAULT_ROLES
-from permissions.models import Role
+from .conf.settings import DEFAULT_ROLES
+from .models import Role, Permission, PermissionNamespace
+from .permissions import (PERMISSION_ROLE_VIEW, PERMISSION_ROLE_EDIT,
+ PERMISSION_ROLE_CREATE, PERMISSION_ROLE_DELETE,
+ PERMISSION_PERMISSION_GRANT, PERMISSION_PERMISSION_REVOKE)
-PERMISSION_ROLE_VIEW = {'namespace': 'permissions', 'name': 'role_view', 'label': _(u'View roles')}
-PERMISSION_ROLE_EDIT = {'namespace': 'permissions', 'name': 'role_edit', 'label': _(u'Edit roles')}
-PERMISSION_ROLE_CREATE = {'namespace': 'permissions', 'name': 'role_create', 'label': _(u'Create roles')}
-PERMISSION_ROLE_DELETE = {'namespace': 'permissions', 'name': 'role_delete', 'label': _(u'Delete roles')}
-PERMISSION_PERMISSION_GRANT = {'namespace': 'permissions', 'name': 'permission_grant', 'label': _(u'Grant permissions')}
-PERMISSION_PERMISSION_REVOKE = {'namespace': 'permissions', 'name': 'permission_revoke', 'label': _(u'Revoke permissions')}
-
-role_list = {'text': _(u'roles'), 'view': 'role_list', 'famfam': 'medal_gold_1', 'icon': 'medal_gold_1.png', 'permissions': [PERMISSION_ROLE_VIEW]}
+role_list = {'text': _(u'roles'), 'view': 'role_list', 'famfam': 'medal_gold_1', 'icon': 'medal_gold_1.png', 'permissions': [PERMISSION_ROLE_VIEW], 'children_view_regex': [r'^permission_', r'^role_']}
role_create = {'text': _(u'create new role'), 'view': 'role_create', 'famfam': 'medal_gold_add', 'permissions': [PERMISSION_ROLE_CREATE]}
role_edit = {'text': _(u'edit'), 'view': 'role_edit', 'args': 'object.id', 'famfam': 'medal_gold_1', 'permissions': [PERMISSION_ROLE_EDIT]}
role_members = {'text': _(u'members'), 'view': 'role_members', 'args': 'object.id', 'famfam': 'group_key', 'permissions': [PERMISSION_ROLE_EDIT]}
@@ -27,7 +25,7 @@ permission_grant = {'text': _(u'grant'), 'view': 'permission_multiple_grant', 'f
permission_revoke = {'text': _(u'revoke'), 'view': 'permission_multiple_revoke', 'famfam': 'key_delete', 'permissions': [PERMISSION_PERMISSION_REVOKE]}
register_links(Role, [role_edit, role_delete, role_permissions, role_members])
-register_links(['role_members', 'role_list', 'role_view', 'role_create', 'role_edit', 'role_permissions', 'role_delete'], [role_list, role_create], menu_name='sidebar')
+register_links([Role, 'role_list', 'role_create'], [role_list, role_create], menu_name='secondary_menu')
register_multi_item_links(['role_permissions'], [permission_grant, permission_revoke])
permission_views = ['role_list', 'role_create', 'role_edit', 'role_members', 'role_permissions', 'role_delete']
diff --git a/apps/permissions/admin.py b/apps/permissions/admin.py
index 1728199d71..e38f1f81d0 100644
--- a/apps/permissions/admin.py
+++ b/apps/permissions/admin.py
@@ -1,6 +1,8 @@
+from __future__ import absolute_import
+
from django.contrib import admin
-from permissions.models import Permission, PermissionHolder, Role, RoleMember
+from .models import StoredPermission, PermissionHolder, Role, RoleMember
class PermissionHolderInline(admin.StackedInline):
@@ -12,7 +14,7 @@ class PermissionHolderInline(admin.StackedInline):
class PermissionAdmin(admin.ModelAdmin):
inlines = [PermissionHolderInline]
- list_display = ('namespace', 'name', 'label')
+ list_display = ('namespace', 'name')
list_display_links = list_display
@@ -27,5 +29,5 @@ class RoleAdmin(admin.ModelAdmin):
inlines = [RoleMemberInline]
-admin.site.register(Permission, PermissionAdmin)
+admin.site.register(StoredPermission, PermissionAdmin)
admin.site.register(Role, RoleAdmin)
diff --git a/apps/permissions/api.py b/apps/permissions/api.py
index 13efbbed28..e69de29bb2 100644
--- a/apps/permissions/api.py
+++ b/apps/permissions/api.py
@@ -1,62 +0,0 @@
-try:
- from psycopg2 import OperationalError
-except ImportError:
- class OperationalError(Exception):
- pass
-
-from django.core.exceptions import ImproperlyConfigured
-from django.db import transaction
-from django.db.utils import DatabaseError
-from django.shortcuts import get_object_or_404
-from django.utils.translation import ugettext
-from django.core.exceptions import PermissionDenied
-from django.utils.translation import ugettext_lazy as _
-
-from permissions import PERMISSION_ROLE_VIEW, PERMISSION_ROLE_EDIT, \
- PERMISSION_ROLE_CREATE, PERMISSION_ROLE_DELETE, \
- PERMISSION_PERMISSION_GRANT, PERMISSION_PERMISSION_REVOKE
-
-from permissions.models import Permission
-
-namespace_titles = {
- 'permissions': _(u'Permissions')
-}
-
-
-def set_namespace_title(namespace, title):
- namespace_titles.setdefault(namespace, title)
-
-
-@transaction.commit_manually
-def register_permission(permission):
- try:
- permission_obj, created = Permission.objects.get_or_create(
- namespace=permission['namespace'], name=permission['name'])
- permission_obj.label = unicode(permission['label'])
- permission_obj.save()
- except DatabaseError:
- transaction.rollback()
- # Special case for ./manage.py syncdb
- except (OperationalError, ImproperlyConfigured):
- transaction.rollback()
- # Special for DjangoZoom, which executes collectstatic media
- # doing syncdb and creating the database tables
- else:
- transaction.commit()
-
-
-def check_permissions(requester, permission_list):
- for permission_item in permission_list:
- permission = get_object_or_404(Permission,
- namespace=permission_item['namespace'], name=permission_item['name'])
- if permission.has_permission(requester):
- return True
-
- raise PermissionDenied(ugettext(u'Insufficient permissions.'))
-
-register_permission(PERMISSION_ROLE_VIEW)
-register_permission(PERMISSION_ROLE_EDIT)
-register_permission(PERMISSION_ROLE_CREATE)
-register_permission(PERMISSION_ROLE_DELETE)
-register_permission(PERMISSION_PERMISSION_GRANT)
-register_permission(PERMISSION_PERMISSION_REVOKE)
diff --git a/apps/permissions/forms.py b/apps/permissions/forms.py
index 87da905a83..b0a6a89008 100644
--- a/apps/permissions/forms.py
+++ b/apps/permissions/forms.py
@@ -1,8 +1,10 @@
+from __future__ import absolute_import
+
from django import forms
from common.forms import DetailForm
-from permissions.models import Role
+from .models import Role
class RoleForm(forms.ModelForm):
diff --git a/apps/permissions/locale/en/LC_MESSAGES/django.po b/apps/permissions/locale/en/LC_MESSAGES/django.po
index a2354e2728..634c035eee 100644
--- a/apps/permissions/locale/en/LC_MESSAGES/django.po
+++ b/apps/permissions/locale/en/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-11-22 11:26-0400\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -17,162 +17,174 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: __init__.py:12
-msgid "View roles"
-msgstr ""
-
-#: __init__.py:13
-msgid "Edit roles"
-msgstr ""
-
-#: __init__.py:14
-msgid "Create roles"
-msgstr ""
-
-#: __init__.py:15
-msgid "Delete roles"
-msgstr ""
-
-#: __init__.py:16
-msgid "Grant permissions"
-msgstr ""
-
-#: __init__.py:17
-msgid "Revoke permissions"
-msgstr ""
-
-#: __init__.py:19 models.py:87 views.py:38
+#: __init__.py:17 models.py:209 views.py:40
msgid "roles"
msgstr ""
-#: __init__.py:20
+#: __init__.py:18
msgid "create new role"
msgstr ""
-#: __init__.py:21
+#: __init__.py:19
msgid "edit"
msgstr ""
-#: __init__.py:22
+#: __init__.py:20
msgid "members"
msgstr ""
-#: __init__.py:23
+#: __init__.py:21
msgid "role permissions"
msgstr ""
-#: __init__.py:24
+#: __init__.py:22
msgid "delete"
msgstr ""
-#: __init__.py:26
+#: __init__.py:24
msgid "grant"
msgstr ""
-#: __init__.py:27
+#: __init__.py:25
msgid "revoke"
msgstr ""
-#: api.py:22
-msgid "Permissions"
-msgstr ""
-
-#: api.py:55
+#: models.py:51
msgid "Insufficient permissions."
msgstr ""
-#: models.py:11 views.py:58
+#: models.py:123 views.py:60
msgid "namespace"
msgstr ""
-#: models.py:12 views.py:59
+#: models.py:124 views.py:61
msgid "name"
msgstr ""
-#: models.py:13 models.py:82
-msgid "label"
-msgstr ""
-
-#: models.py:20 models.py:65 views.py:145 views.py:204
+#: models.py:131 models.py:187 views.py:152 views.py:215
msgid "permission"
msgstr ""
-#: models.py:21 views.py:55 views.py:147 views.py:206
+#: models.py:132 views.py:57 views.py:154 views.py:217
msgid "permissions"
msgstr ""
-#: models.py:73
+#: models.py:195
msgid "permission holder"
msgstr ""
-#: models.py:74
+#: models.py:196
msgid "permission holders"
msgstr ""
-#: models.py:86 models.py:104 views.py:74 views.py:91 views.py:115
-#: views.py:282
+#: models.py:204
+msgid "label"
+msgstr ""
+
+#: models.py:208 models.py:239 views.py:76 views.py:93 views.py:117
+#: views.py:334
msgid "role"
msgstr ""
-#: models.py:115
+#: models.py:255
msgid "role member"
msgstr ""
-#: models.py:116
+#: models.py:256
msgid "role members"
msgstr ""
-#: views.py:61
+#: permissions.py:7
+msgid "Permissions"
+msgstr ""
+
+#: permissions.py:9
+msgid "View roles"
+msgstr ""
+
+#: permissions.py:10
+msgid "Edit roles"
+msgstr ""
+
+#: permissions.py:11
+msgid "Create roles"
+msgstr ""
+
+#: permissions.py:12
+msgid "Delete roles"
+msgstr ""
+
+#: permissions.py:13
+msgid "Grant permissions"
+msgstr ""
+
+#: permissions.py:14
+msgid "Revoke permissions"
+msgstr ""
+
+#: views.py:63
msgid "has permission"
msgstr ""
-#: views.py:142 views.py:201
+#: views.py:149 views.py:212
msgid " and "
msgstr ""
-#: views.py:142 views.py:201
+#: views.py:149 views.py:212
#, python-format
msgid "%(permissions)s to %(requester)s"
msgstr ""
-#: views.py:152
+#: views.py:159
#, python-format
msgid "Permission \"%(permission)s\" granted to: %(requester)s."
msgstr ""
-#: views.py:155
+#: views.py:162
#, python-format
msgid "%(requester)s, already had the permission \"%(permission)s\" granted."
msgstr ""
-#: views.py:167
+#: views.py:173
#, python-format
msgid ""
"Are you sure you wish to grant the %(permissions_label)s %(title_suffix)s?"
msgstr ""
-#: views.py:211
+#: views.py:222
#, python-format
msgid "Permission \"%(permission)s\" revoked from: %(requester)s."
msgstr ""
-#: views.py:214
+#: views.py:225
#, python-format
msgid "%(requester)s, doesn't have the permission \"%(permission)s\" granted."
msgstr ""
-#: views.py:226
+#: views.py:236
#, python-format
msgid ""
"Are you sure you wish to revoke the %(permissions_label)s %(title_suffix)s?"
msgstr ""
-#: views.py:278
+#: views.py:271 views.py:295
+msgid "Users"
+msgstr ""
+
+#: views.py:274 views.py:298
+msgid "Groups"
+msgstr ""
+
+#: views.py:277 views.py:301
+msgid "Special"
+msgstr ""
+
+#: views.py:330
#, python-format
msgid "non members of role: %s"
msgstr ""
-#: views.py:279
+#: views.py:331
#, python-format
msgid "members of role: %s"
msgstr ""
diff --git a/apps/permissions/locale/es/LC_MESSAGES/django.mo b/apps/permissions/locale/es/LC_MESSAGES/django.mo
index ddd24a555b..21e0374d21 100644
Binary files a/apps/permissions/locale/es/LC_MESSAGES/django.mo and b/apps/permissions/locale/es/LC_MESSAGES/django.mo differ
diff --git a/apps/permissions/locale/es/LC_MESSAGES/django.po b/apps/permissions/locale/es/LC_MESSAGES/django.po
index 2ae5d18ed6..ab9efdf661 100644
--- a/apps/permissions/locale/es/LC_MESSAGES/django.po
+++ b/apps/permissions/locale/es/LC_MESSAGES/django.po
@@ -1,181 +1,194 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
-#
+#
# Translators:
-# Roberto Rosario , 2011.
+# Roberto Rosario , 2011, 2012.
msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
-"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
-"POT-Creation-Date: 2011-11-22 11:26-0400\n"
-"PO-Revision-Date: 2011-11-22 15:37+0000\n"
-"Last-Translator: rosarior \n"
-"Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/mayan-edms/team/es/)\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
+"PO-Revision-Date: 2012-02-12 00:25+0000\n"
+"Last-Translator: Roberto Rosario \n"
+"Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/"
+"mayan-edms/team/es/)\n"
+"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Language: es\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
-#: __init__.py:12
-msgid "View roles"
-msgstr "Ver las funciones"
-
-#: __init__.py:13
-msgid "Edit roles"
-msgstr "Modificar las funciones"
-
-#: __init__.py:14
-msgid "Create roles"
-msgstr "Crear funciones"
-
-#: __init__.py:15
-msgid "Delete roles"
-msgstr "Eliminar funciones"
-
-#: __init__.py:16
-msgid "Grant permissions"
-msgstr "Conceder permisos"
-
-#: __init__.py:17
-msgid "Revoke permissions"
-msgstr "Revocar permisos"
-
-#: __init__.py:19 models.py:87 views.py:38
+#: __init__.py:17 models.py:209 views.py:40
msgid "roles"
msgstr "funciones"
-#: __init__.py:20
+#: __init__.py:18
msgid "create new role"
msgstr "crear nueva función"
-#: __init__.py:21
+#: __init__.py:19
msgid "edit"
msgstr "editar"
-#: __init__.py:22
+#: __init__.py:20
msgid "members"
msgstr "miembros"
-#: __init__.py:23
+#: __init__.py:21
msgid "role permissions"
msgstr "permisos de la funcion"
-#: __init__.py:24
+#: __init__.py:22
msgid "delete"
msgstr "eliminar"
-#: __init__.py:26
+#: __init__.py:24
msgid "grant"
msgstr "otorgar"
-#: __init__.py:27
+#: __init__.py:25
msgid "revoke"
msgstr "revocar"
-#: api.py:22
-msgid "Permissions"
-msgstr "Permisos"
-
-#: api.py:55
+#: models.py:51
msgid "Insufficient permissions."
msgstr "Permisos insuficientes."
-#: models.py:11 views.py:58
+#: models.py:123 views.py:60
msgid "namespace"
msgstr "espacio de nombres"
-#: models.py:12 views.py:59
+#: models.py:124 views.py:61
msgid "name"
msgstr "nombre"
-#: models.py:13 models.py:82
-msgid "label"
-msgstr "etiqueta"
-
-#: models.py:20 models.py:65 views.py:145 views.py:204
+#: models.py:131 models.py:187 views.py:152 views.py:215
msgid "permission"
msgstr "permiso"
-#: models.py:21 views.py:55 views.py:147 views.py:206
+#: models.py:132 views.py:57 views.py:154 views.py:217
msgid "permissions"
msgstr "permisos"
-#: models.py:73
+#: models.py:195
msgid "permission holder"
msgstr "titular de la autorización"
-#: models.py:74
+#: models.py:196
msgid "permission holders"
msgstr "titulares de autorización"
-#: models.py:86 models.py:104 views.py:74 views.py:91 views.py:115
-#: views.py:282
+#: models.py:204
+msgid "label"
+msgstr "etiqueta"
+
+#: models.py:208 models.py:239 views.py:76 views.py:93 views.py:117
+#: views.py:334
msgid "role"
msgstr "función"
-#: models.py:115
+#: models.py:255
msgid "role member"
msgstr "miembro de la función"
-#: models.py:116
+#: models.py:256
msgid "role members"
msgstr "miembros de las functiones"
-#: views.py:61
+#: permissions.py:7
+msgid "Permissions"
+msgstr "Permisos"
+
+#: permissions.py:9
+msgid "View roles"
+msgstr "Ver las funciones"
+
+#: permissions.py:10
+msgid "Edit roles"
+msgstr "Modificar las funciones"
+
+#: permissions.py:11
+msgid "Create roles"
+msgstr "Crear funciones"
+
+#: permissions.py:12
+msgid "Delete roles"
+msgstr "Eliminar funciones"
+
+#: permissions.py:13
+msgid "Grant permissions"
+msgstr "Conceder permisos"
+
+#: permissions.py:14
+msgid "Revoke permissions"
+msgstr "Revocar permisos"
+
+#: views.py:63
msgid "has permission"
msgstr "tiene permiso"
-#: views.py:142 views.py:201
+#: views.py:149 views.py:212
msgid " and "
msgstr "y"
-#: views.py:142 views.py:201
+#: views.py:149 views.py:212
#, python-format
msgid "%(permissions)s to %(requester)s"
msgstr "%(permissions)s a %(requester)s"
-#: views.py:152
+#: views.py:159
#, python-format
msgid "Permission \"%(permission)s\" granted to: %(requester)s."
msgstr "Permiso \"%(permission)s\" otorgado a: %(requester)s."
-#: views.py:155
+#: views.py:162
#, python-format
msgid "%(requester)s, already had the permission \"%(permission)s\" granted."
msgstr "%(requester)s, ya tenía el permiso \"%(permission)s\" concedido."
-#: views.py:167
+#: views.py:173
#, python-format
msgid ""
"Are you sure you wish to grant the %(permissions_label)s %(title_suffix)s?"
msgstr ""
"¿Está seguro que desea otorgar el %(permissions_label)s %(title_suffix)s?"
-#: views.py:211
+#: views.py:222
#, python-format
msgid "Permission \"%(permission)s\" revoked from: %(requester)s."
msgstr "Permiso \"%(permission)s\" revocado de: %(requester)s."
-#: views.py:214
+#: views.py:225
#, python-format
msgid "%(requester)s, doesn't have the permission \"%(permission)s\" granted."
msgstr "%(requester)s, no tiene el permiso \"%(permission)s\" concedido."
-#: views.py:226
+#: views.py:236
#, python-format
msgid ""
"Are you sure you wish to revoke the %(permissions_label)s %(title_suffix)s?"
msgstr ""
"¿Estás seguro que quiere revocar el %(permissions_label)s %(title_suffix)s?"
-#: views.py:278
+#: views.py:271 views.py:295
+msgid "Users"
+msgstr "Usuarios"
+
+#: views.py:274 views.py:298
+msgid "Groups"
+msgstr "Grupos"
+
+#: views.py:277 views.py:301
+msgid "Special"
+msgstr "Especial"
+
+#: views.py:330
#, python-format
msgid "non members of role: %s"
msgstr "no miembros de la función: %s"
-#: views.py:279
+#: views.py:331
#, python-format
msgid "members of role: %s"
msgstr "miembros de la función: %s"
@@ -195,5 +208,3 @@ msgid ""
msgstr ""
"Una lista de funciones existentes que se asignan automáticamente a los "
"usuarios nuevos"
-
-
diff --git a/apps/permissions/locale/it/LC_MESSAGES/django.mo b/apps/permissions/locale/it/LC_MESSAGES/django.mo
new file mode 100644
index 0000000000..1662db40f5
Binary files /dev/null and b/apps/permissions/locale/it/LC_MESSAGES/django.mo differ
diff --git a/apps/permissions/locale/it/LC_MESSAGES/django.po b/apps/permissions/locale/it/LC_MESSAGES/django.po
new file mode 100644
index 0000000000..c9c70931c1
--- /dev/null
+++ b/apps/permissions/locale/it/LC_MESSAGES/django.po
@@ -0,0 +1,212 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# , 2011.
+msgid ""
+msgstr ""
+"Project-Id-Version: Mayan EDMS\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
+"PO-Revision-Date: 2012-02-02 18:18+0000\n"
+"Last-Translator: Roberto Rosario \n"
+"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/"
+"it/)\n"
+"Language: it\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+
+#: __init__.py:17 models.py:209 views.py:40
+msgid "roles"
+msgstr "ruoli"
+
+#: __init__.py:18
+msgid "create new role"
+msgstr "crea nuovo ruolo"
+
+#: __init__.py:19
+msgid "edit"
+msgstr "modifica"
+
+#: __init__.py:20
+msgid "members"
+msgstr "membri"
+
+#: __init__.py:21
+msgid "role permissions"
+msgstr "permessi dei ruoli"
+
+#: __init__.py:22
+msgid "delete"
+msgstr "cancella"
+
+#: __init__.py:24
+msgid "grant"
+msgstr "concessione"
+
+#: __init__.py:25
+msgid "revoke"
+msgstr "revoca"
+
+#: models.py:51
+msgid "Insufficient permissions."
+msgstr "Permessi insufficienti"
+
+#: models.py:123 views.py:60
+msgid "namespace"
+msgstr "namespace"
+
+#: models.py:124 views.py:61
+msgid "name"
+msgstr "nome"
+
+#: models.py:131 models.py:187 views.py:152 views.py:215
+msgid "permission"
+msgstr "permesso"
+
+#: models.py:132 views.py:57 views.py:154 views.py:217
+msgid "permissions"
+msgstr "permessi"
+
+#: models.py:195
+msgid "permission holder"
+msgstr "titolare del permesso"
+
+#: models.py:196
+msgid "permission holders"
+msgstr "titolari dei permessi"
+
+#: models.py:204
+msgid "label"
+msgstr "etichetta"
+
+#: models.py:208 models.py:239 views.py:76 views.py:93 views.py:117
+#: views.py:334
+msgid "role"
+msgstr "ruolo"
+
+#: models.py:255
+msgid "role member"
+msgstr "membro del ruolo"
+
+#: models.py:256
+msgid "role members"
+msgstr "membri del ruolo"
+
+#: permissions.py:7
+msgid "Permissions"
+msgstr "Permessi"
+
+#: permissions.py:9
+msgid "View roles"
+msgstr "Vedi i ruoli"
+
+#: permissions.py:10
+msgid "Edit roles"
+msgstr "Modifica i ruoli"
+
+#: permissions.py:11
+msgid "Create roles"
+msgstr "Crea ruoli"
+
+#: permissions.py:12
+msgid "Delete roles"
+msgstr "Cancella i ruoli"
+
+#: permissions.py:13
+msgid "Grant permissions"
+msgstr "Concedere le autorizzazioni"
+
+#: permissions.py:14
+msgid "Revoke permissions"
+msgstr "Revoca le autorizzazioni"
+
+#: views.py:63
+msgid "has permission"
+msgstr "ha il permesso"
+
+#: views.py:149 views.py:212
+msgid " and "
+msgstr " and "
+
+#: views.py:149 views.py:212
+#, python-format
+msgid "%(permissions)s to %(requester)s"
+msgstr "%(permissions)s a %(requester)s"
+
+#: views.py:159
+#, python-format
+msgid "Permission \"%(permission)s\" granted to: %(requester)s."
+msgstr "Permesso \"%(permission)s\" concesso a: %(requester)s."
+
+#: views.py:162
+#, python-format
+msgid "%(requester)s, already had the permission \"%(permission)s\" granted."
+msgstr "%(requester)s, ha già il permesso \"%(permission)s\" concesso."
+
+#: views.py:173
+#, python-format
+msgid ""
+"Are you sure you wish to grant the %(permissions_label)s %(title_suffix)s?"
+msgstr ""
+"Sei sicuro che tu voglia concedere questo permesso %(permissions_label)s "
+"%(title_suffix)s?"
+
+#: views.py:222
+#, python-format
+msgid "Permission \"%(permission)s\" revoked from: %(requester)s."
+msgstr "Permesso \"%(permission)s\" revocato per: %(requester)s."
+
+#: views.py:225
+#, python-format
+msgid "%(requester)s, doesn't have the permission \"%(permission)s\" granted."
+msgstr "%(requester)s, non ha i permessi \"%(permission)s\" consentiti."
+
+#: views.py:236
+#, python-format
+msgid ""
+"Are you sure you wish to revoke the %(permissions_label)s %(title_suffix)s?"
+msgstr ""
+"Sei sicuro di voler revocare questo permesso %(permissions_label)s "
+"%(title_suffix)s?"
+
+#: views.py:271 views.py:295
+msgid "Users"
+msgstr ""
+
+#: views.py:274 views.py:298
+msgid "Groups"
+msgstr ""
+
+#: views.py:277 views.py:301
+msgid "Special"
+msgstr ""
+
+#: views.py:330
+#, python-format
+msgid "non members of role: %s"
+msgstr "nessun menbro per il ruolo:%s"
+
+#: views.py:331
+#, python-format
+msgid "members of role: %s"
+msgstr "membri per il ruolo:%s"
+
+#: widgets.py:16
+msgid "Revoke"
+msgstr "Revoca"
+
+#: widgets.py:21
+msgid "Grant"
+msgstr "Concessione"
+
+#: conf/settings.py:10
+msgid ""
+"A list of existing roles that are automatically assigned to newly created "
+"users"
+msgstr ""
+"Un elenco di ruoli esistenti che vengono automaticamente assegnati agli "
+"utenti appena creati"
diff --git a/apps/permissions/locale/pl/LC_MESSAGES/django.mo b/apps/permissions/locale/pl/LC_MESSAGES/django.mo
new file mode 100644
index 0000000000..41353099df
Binary files /dev/null and b/apps/permissions/locale/pl/LC_MESSAGES/django.mo differ
diff --git a/apps/permissions/locale/pl/LC_MESSAGES/django.po b/apps/permissions/locale/pl/LC_MESSAGES/django.po
new file mode 100644
index 0000000000..1818fe2c69
--- /dev/null
+++ b/apps/permissions/locale/pl/LC_MESSAGES/django.po
@@ -0,0 +1,205 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# , 2012.
+msgid ""
+msgstr ""
+"Project-Id-Version: Mayan EDMS\n"
+"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
+"PO-Revision-Date: 2012-02-20 16:08+0000\n"
+"Last-Translator: mic \n"
+"Language-Team: Polish (http://www.transifex.net/projects/p/mayan-edms/language/pl/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: pl\n"
+"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
+
+#: __init__.py:17 models.py:209 views.py:40
+msgid "roles"
+msgstr ""
+
+#: __init__.py:18
+msgid "create new role"
+msgstr ""
+
+#: __init__.py:19
+msgid "edit"
+msgstr ""
+
+#: __init__.py:20
+msgid "members"
+msgstr ""
+
+#: __init__.py:21
+msgid "role permissions"
+msgstr ""
+
+#: __init__.py:22
+msgid "delete"
+msgstr ""
+
+#: __init__.py:24
+msgid "grant"
+msgstr "przyznać"
+
+#: __init__.py:25
+msgid "revoke"
+msgstr "odwołać"
+
+#: models.py:51
+msgid "Insufficient permissions."
+msgstr "Niewystarczające uprawnienia."
+
+#: models.py:123 views.py:60
+msgid "namespace"
+msgstr ""
+
+#: models.py:124 views.py:61
+msgid "name"
+msgstr "nazwa"
+
+#: models.py:131 models.py:187 views.py:152 views.py:215
+msgid "permission"
+msgstr "uprawnienie"
+
+#: models.py:132 views.py:57 views.py:154 views.py:217
+msgid "permissions"
+msgstr "uprawnienia"
+
+#: models.py:195
+msgid "permission holder"
+msgstr ""
+
+#: models.py:196
+msgid "permission holders"
+msgstr ""
+
+#: models.py:204
+msgid "label"
+msgstr "etykieta"
+
+#: models.py:208 models.py:239 views.py:76 views.py:93 views.py:117
+#: views.py:334
+msgid "role"
+msgstr ""
+
+#: models.py:255
+msgid "role member"
+msgstr ""
+
+#: models.py:256
+msgid "role members"
+msgstr ""
+
+#: permissions.py:7
+msgid "Permissions"
+msgstr "Uprawnienia"
+
+#: permissions.py:9
+msgid "View roles"
+msgstr ""
+
+#: permissions.py:10
+msgid "Edit roles"
+msgstr ""
+
+#: permissions.py:11
+msgid "Create roles"
+msgstr ""
+
+#: permissions.py:12
+msgid "Delete roles"
+msgstr ""
+
+#: permissions.py:13
+msgid "Grant permissions"
+msgstr ""
+
+#: permissions.py:14
+msgid "Revoke permissions"
+msgstr ""
+
+#: views.py:63
+msgid "has permission"
+msgstr "ma uprawnienie"
+
+#: views.py:149 views.py:212
+msgid " and "
+msgstr "i"
+
+#: views.py:149 views.py:212
+#, python-format
+msgid "%(permissions)s to %(requester)s"
+msgstr ""
+
+#: views.py:159
+#, python-format
+msgid "Permission \"%(permission)s\" granted to: %(requester)s."
+msgstr ""
+
+#: views.py:162
+#, python-format
+msgid "%(requester)s, already had the permission \"%(permission)s\" granted."
+msgstr ""
+
+#: views.py:173
+#, python-format
+msgid ""
+"Are you sure you wish to grant the %(permissions_label)s %(title_suffix)s?"
+msgstr ""
+
+#: views.py:222
+#, python-format
+msgid "Permission \"%(permission)s\" revoked from: %(requester)s."
+msgstr ""
+
+#: views.py:225
+#, python-format
+msgid "%(requester)s, doesn't have the permission \"%(permission)s\" granted."
+msgstr ""
+
+#: views.py:236
+#, python-format
+msgid ""
+"Are you sure you wish to revoke the %(permissions_label)s %(title_suffix)s?"
+msgstr ""
+
+#: views.py:271 views.py:295
+msgid "Users"
+msgstr "Użytkownicy"
+
+#: views.py:274 views.py:298
+msgid "Groups"
+msgstr "Grupy"
+
+#: views.py:277 views.py:301
+msgid "Special"
+msgstr "Specjalny"
+
+#: views.py:330
+#, python-format
+msgid "non members of role: %s"
+msgstr ""
+
+#: views.py:331
+#, python-format
+msgid "members of role: %s"
+msgstr ""
+
+#: widgets.py:16
+msgid "Revoke"
+msgstr "Odwołać"
+
+#: widgets.py:21
+msgid "Grant"
+msgstr ""
+
+#: conf/settings.py:10
+msgid ""
+"A list of existing roles that are automatically assigned to newly created "
+"users"
+msgstr ""
diff --git a/apps/permissions/locale/pt/LC_MESSAGES/django.mo b/apps/permissions/locale/pt/LC_MESSAGES/django.mo
index 715b0f389b..04280bb198 100644
Binary files a/apps/permissions/locale/pt/LC_MESSAGES/django.mo and b/apps/permissions/locale/pt/LC_MESSAGES/django.mo differ
diff --git a/apps/permissions/locale/pt/LC_MESSAGES/django.po b/apps/permissions/locale/pt/LC_MESSAGES/django.po
index dd93d53119..f3e0abc0ae 100644
--- a/apps/permissions/locale/pt/LC_MESSAGES/django.po
+++ b/apps/permissions/locale/pt/LC_MESSAGES/django.po
@@ -8,9 +8,9 @@ msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-11-22 11:26-0400\n"
-"PO-Revision-Date: 2011-11-02 04:52+0000\n"
-"Last-Translator: emersonsoares \n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
+"PO-Revision-Date: 2012-02-02 18:18+0000\n"
+"Last-Translator: Roberto Rosario \n"
"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/"
"team/pt/)\n"
"Language: pt\n"
@@ -19,172 +19,174 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
-#: __init__.py:12
-msgid "View roles"
-msgstr "Ver funções"
-
-#: __init__.py:13
-msgid "Edit roles"
-msgstr "Editar funções"
-
-#: __init__.py:14
-msgid "Create roles"
-msgstr "Criar funções"
-
-#: __init__.py:15
-msgid "Delete roles"
-msgstr "Deletar funções"
-
-#: __init__.py:16
-msgid "Grant permissions"
-msgstr "Conceder permissões"
-
-#: __init__.py:17
-msgid "Revoke permissions"
-msgstr "Revogar as permissões"
-
-#: __init__.py:19 models.py:87 views.py:38
+#: __init__.py:17 models.py:209 views.py:40
msgid "roles"
msgstr "funções"
-#: __init__.py:20
+#: __init__.py:18
msgid "create new role"
msgstr "criar nova função"
-#: __init__.py:21
+#: __init__.py:19
msgid "edit"
msgstr "editar"
-#: __init__.py:22
+#: __init__.py:20
msgid "members"
msgstr "membros"
-#: __init__.py:23
+#: __init__.py:21
msgid "role permissions"
msgstr "permissões de função"
-#: __init__.py:24
+#: __init__.py:22
msgid "delete"
msgstr "excluir"
-#: __init__.py:26
-#, fuzzy
+#: __init__.py:24
msgid "grant"
-msgstr "Conceder"
+msgstr ""
-#: __init__.py:27
-#, fuzzy
+#: __init__.py:25
msgid "revoke"
-msgstr "Revogar"
+msgstr ""
-#: api.py:22
-msgid "Permissions"
-msgstr "Permissões"
-
-#: api.py:55
+#: models.py:51
msgid "Insufficient permissions."
msgstr "Permissões insuficientes."
-#: models.py:11 views.py:58
+#: models.py:123 views.py:60
msgid "namespace"
msgstr "namespace"
-#: models.py:12 views.py:59
+#: models.py:124 views.py:61
msgid "name"
msgstr "nome"
-#: models.py:13 models.py:82
-msgid "label"
-msgstr "rótulo"
-
-#: models.py:20 models.py:65 views.py:145 views.py:204
+#: models.py:131 models.py:187 views.py:152 views.py:215
msgid "permission"
msgstr "permissão"
-#: models.py:21 views.py:55 views.py:147 views.py:206
+#: models.py:132 views.py:57 views.py:154 views.py:217
msgid "permissions"
msgstr "permissões"
-#: models.py:73
+#: models.py:195
msgid "permission holder"
msgstr "titular de permissão"
-#: models.py:74
+#: models.py:196
msgid "permission holders"
msgstr "titulares de permissões"
-#: models.py:86 models.py:104 views.py:74 views.py:91 views.py:115
-#: views.py:282
+#: models.py:204
+msgid "label"
+msgstr "rótulo"
+
+#: models.py:208 models.py:239 views.py:76 views.py:93 views.py:117
+#: views.py:334
msgid "role"
msgstr "função"
-#: models.py:115
+#: models.py:255
msgid "role member"
msgstr "membro da função"
-#: models.py:116
+#: models.py:256
msgid "role members"
msgstr "membros da função"
-#: views.py:61
-#, fuzzy
-msgid "has permission"
-msgstr "permissão"
+#: permissions.py:7
+msgid "Permissions"
+msgstr "Permissões"
-#: views.py:142 views.py:201
+#: permissions.py:9
+msgid "View roles"
+msgstr "Ver funções"
+
+#: permissions.py:10
+msgid "Edit roles"
+msgstr "Editar funções"
+
+#: permissions.py:11
+msgid "Create roles"
+msgstr "Criar funções"
+
+#: permissions.py:12
+msgid "Delete roles"
+msgstr "Deletar funções"
+
+#: permissions.py:13
+msgid "Grant permissions"
+msgstr "Conceder permissões"
+
+#: permissions.py:14
+msgid "Revoke permissions"
+msgstr "Revogar as permissões"
+
+#: views.py:63
+msgid "has permission"
+msgstr ""
+
+#: views.py:149 views.py:212
msgid " and "
msgstr ""
-#: views.py:142 views.py:201
-#, fuzzy, python-format
+#: views.py:149 views.py:212
+#, python-format
msgid "%(permissions)s to %(requester)s"
msgstr ""
-"Permissão \"%(permission)s\" concedida para %(ct_name)s: %(requester)s."
-#: views.py:152
-#, fuzzy, python-format
+#: views.py:159
+#, python-format
msgid "Permission \"%(permission)s\" granted to: %(requester)s."
msgstr ""
-"Permissão \"%(permission)s\" concedida para %(ct_name)s: %(requester)s."
-#: views.py:155
-#, fuzzy, python-format
+#: views.py:162
+#, python-format
msgid "%(requester)s, already had the permission \"%(permission)s\" granted."
msgstr ""
-"%(ct_name)s: %(requester)s, já tem permissão \"%(permission)s\" concedida."
-#: views.py:167
-#, fuzzy, python-format
+#: views.py:173
+#, python-format
msgid ""
"Are you sure you wish to grant the %(permissions_label)s %(title_suffix)s?"
msgstr ""
-"Tem certeza que deseja conceder permissão \"%(permission)s\" para "
-"%(ct_name)s: %(requester)s"
-#: views.py:211
-#, fuzzy, python-format
+#: views.py:222
+#, python-format
msgid "Permission \"%(permission)s\" revoked from: %(requester)s."
-msgstr "Permissão \"%(permission)s\" revogada de %(ct_name)s: %(requester)s."
+msgstr ""
-#: views.py:214
-#, fuzzy, python-format
+#: views.py:225
+#, python-format
msgid "%(requester)s, doesn't have the permission \"%(permission)s\" granted."
-msgstr "%(ct_name)s: %(requester)s não tem a permissão \"%(permission)s\"."
+msgstr ""
-#: views.py:226
-#, fuzzy, python-format
+#: views.py:236
+#, python-format
msgid ""
"Are you sure you wish to revoke the %(permissions_label)s %(title_suffix)s?"
msgstr ""
-"Tem certeza que deseja revogar a permissão \"%(permission)s\" de "
-"%(ct_name)s: %(requester)s"
-#: views.py:278
+#: views.py:271 views.py:295
+msgid "Users"
+msgstr ""
+
+#: views.py:274 views.py:298
+msgid "Groups"
+msgstr ""
+
+#: views.py:277 views.py:301
+msgid "Special"
+msgstr ""
+
+#: views.py:330
#, python-format
msgid "non members of role: %s"
msgstr "não membros da função: %s"
-#: views.py:279
+#: views.py:331
#, python-format
msgid "members of role: %s"
msgstr "membros da função: %s"
@@ -204,6 +206,3 @@ msgid ""
msgstr ""
"A lista de funções existentes que são automaticamente designados para "
"usuários recém-criados"
-
-#~ msgid "state"
-#~ msgstr "estado"
diff --git a/apps/permissions/locale/ru/LC_MESSAGES/django.mo b/apps/permissions/locale/ru/LC_MESSAGES/django.mo
index 8f8ad487ab..9ab687cace 100644
Binary files a/apps/permissions/locale/ru/LC_MESSAGES/django.mo and b/apps/permissions/locale/ru/LC_MESSAGES/django.mo differ
diff --git a/apps/permissions/locale/ru/LC_MESSAGES/django.po b/apps/permissions/locale/ru/LC_MESSAGES/django.po
index b30891a80f..ecf7a2a65d 100644
--- a/apps/permissions/locale/ru/LC_MESSAGES/django.po
+++ b/apps/permissions/locale/ru/LC_MESSAGES/django.po
@@ -1,179 +1,193 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
-#
+#
# Translators:
# Sergey Glita , 2011.
msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
-"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
-"POT-Creation-Date: 2011-11-22 11:26-0400\n"
-"PO-Revision-Date: 2011-11-22 18:57+0000\n"
-"Last-Translator: gsv70 \n"
-"Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/team/ru/)\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
+"PO-Revision-Date: 2012-02-02 18:18+0000\n"
+"Last-Translator: Roberto Rosario \n"
+"Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/team/"
+"ru/)\n"
+"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Language: ru\n"
-"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
+"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
+"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
-#: __init__.py:12
-msgid "View roles"
-msgstr "Просмотр ролей"
-
-#: __init__.py:13
-msgid "Edit roles"
-msgstr "Изменить роли"
-
-#: __init__.py:14
-msgid "Create roles"
-msgstr "Создание ролей"
-
-#: __init__.py:15
-msgid "Delete roles"
-msgstr "Удаление ролей"
-
-#: __init__.py:16
-msgid "Grant permissions"
-msgstr "Предоставление разрешений"
-
-#: __init__.py:17
-msgid "Revoke permissions"
-msgstr "Отмена разрешений"
-
-#: __init__.py:19 models.py:87 views.py:38
+#: __init__.py:17 models.py:209 views.py:40
msgid "roles"
msgstr "роли"
-#: __init__.py:20
+#: __init__.py:18
msgid "create new role"
msgstr "создать новую роль"
-#: __init__.py:21
+#: __init__.py:19
msgid "edit"
msgstr "редактировать"
-#: __init__.py:22
+#: __init__.py:20
msgid "members"
msgstr "участники"
-#: __init__.py:23
+#: __init__.py:21
msgid "role permissions"
msgstr "разрешения роли"
-#: __init__.py:24
+#: __init__.py:22
msgid "delete"
msgstr "удалить"
-#: __init__.py:26
+#: __init__.py:24
msgid "grant"
msgstr "предоставить"
-#: __init__.py:27
+#: __init__.py:25
msgid "revoke"
msgstr "отозвать"
-#: api.py:22
-msgid "Permissions"
-msgstr "Разрешения"
-
-#: api.py:55
+#: models.py:51
msgid "Insufficient permissions."
msgstr "Недостаточно разрешений."
-#: models.py:11 views.py:58
+#: models.py:123 views.py:60
msgid "namespace"
msgstr "пространство имен"
-#: models.py:12 views.py:59
+#: models.py:124 views.py:61
msgid "name"
msgstr "имя"
-#: models.py:13 models.py:82
-msgid "label"
-msgstr "надпись"
-
-#: models.py:20 models.py:65 views.py:145 views.py:204
+#: models.py:131 models.py:187 views.py:152 views.py:215
msgid "permission"
msgstr "разрешение"
-#: models.py:21 views.py:55 views.py:147 views.py:206
+#: models.py:132 views.py:57 views.py:154 views.py:217
msgid "permissions"
msgstr "разрешения"
-#: models.py:73
+#: models.py:195
msgid "permission holder"
msgstr "владелец разрешения"
-#: models.py:74
+#: models.py:196
msgid "permission holders"
msgstr "владельцы разрешения "
-#: models.py:86 models.py:104 views.py:74 views.py:91 views.py:115
-#: views.py:282
+#: models.py:204
+msgid "label"
+msgstr "надпись"
+
+#: models.py:208 models.py:239 views.py:76 views.py:93 views.py:117
+#: views.py:334
msgid "role"
msgstr "роль"
-#: models.py:115
+#: models.py:255
msgid "role member"
msgstr "участник"
-#: models.py:116
+#: models.py:256
msgid "role members"
msgstr "участники"
-#: views.py:61
+#: permissions.py:7
+msgid "Permissions"
+msgstr "Разрешения"
+
+#: permissions.py:9
+msgid "View roles"
+msgstr "Просмотр ролей"
+
+#: permissions.py:10
+msgid "Edit roles"
+msgstr "Изменить роли"
+
+#: permissions.py:11
+msgid "Create roles"
+msgstr "Создание ролей"
+
+#: permissions.py:12
+msgid "Delete roles"
+msgstr "Удаление ролей"
+
+#: permissions.py:13
+msgid "Grant permissions"
+msgstr "Предоставление разрешений"
+
+#: permissions.py:14
+msgid "Revoke permissions"
+msgstr "Отмена разрешений"
+
+#: views.py:63
msgid "has permission"
msgstr "имеет право"
-#: views.py:142 views.py:201
+#: views.py:149 views.py:212
msgid " and "
msgstr "и"
-#: views.py:142 views.py:201
+#: views.py:149 views.py:212
#, python-format
msgid "%(permissions)s to %(requester)s"
msgstr "%(permissions)s для %(requester)s"
-#: views.py:152
+#: views.py:159
#, python-format
msgid "Permission \"%(permission)s\" granted to: %(requester)s."
msgstr "Право \"%(permission)s\" предоставлено %(requester)s."
-#: views.py:155
+#: views.py:162
#, python-format
msgid "%(requester)s, already had the permission \"%(permission)s\" granted."
msgstr "%(requester)s уже имеет право \"%(permission)s\"."
-#: views.py:167
+#: views.py:173
#, python-format
msgid ""
"Are you sure you wish to grant the %(permissions_label)s %(title_suffix)s?"
msgstr "Вы хотите разрешить %(permissions_label)s %(title_suffix)s?"
-#: views.py:211
+#: views.py:222
#, python-format
msgid "Permission \"%(permission)s\" revoked from: %(requester)s."
msgstr "Право \"%(permission)s\" отозвано у %(requester)s."
-#: views.py:214
+#: views.py:225
#, python-format
msgid "%(requester)s, doesn't have the permission \"%(permission)s\" granted."
msgstr "%(requester)s не имеет права \"%(permission)s\"."
-#: views.py:226
+#: views.py:236
#, python-format
msgid ""
"Are you sure you wish to revoke the %(permissions_label)s %(title_suffix)s?"
msgstr "Вы хотите отозвать %(permissions_label)s %(title_suffix)s?"
-#: views.py:278
+#: views.py:271 views.py:295
+msgid "Users"
+msgstr ""
+
+#: views.py:274 views.py:298
+msgid "Groups"
+msgstr ""
+
+#: views.py:277 views.py:301
+msgid "Special"
+msgstr ""
+
+#: views.py:330
#, python-format
msgid "non members of role: %s"
msgstr "не входит в %s"
-#: views.py:279
+#: views.py:331
#, python-format
msgid "members of role: %s"
msgstr "входит в %s"
@@ -193,5 +207,3 @@ msgid ""
msgstr ""
"Список существующих ролей, которые автоматически назначаются вновь "
"создаваемым пользователям"
-
-
diff --git a/apps/permissions/managers.py b/apps/permissions/managers.py
index e4cfd1fdf5..2284f55e01 100644
--- a/apps/permissions/managers.py
+++ b/apps/permissions/managers.py
@@ -1,14 +1,27 @@
+import logging
+
from django.db import models
from django.contrib.contenttypes.models import ContentType
+from django.db import transaction
+from django.core.exceptions import PermissionDenied
+from django.shortcuts import get_object_or_404
+from django.db.utils import IntegrityError
+from django.core.exceptions import ImproperlyConfigured
+
+from common.models import AnonymousUserSingleton
+
+
+logger = logging.getLogger(__name__)
class RoleMemberManager(models.Manager):
def get_roles_for_member(self, member_obj):
+ member_obj = AnonymousUserSingleton.objects.passthru_check(member_obj)
member_type = ContentType.objects.get_for_model(member_obj)
return [role_member.role for role_member in self.model.objects.filter(member_type=member_type, member_id=member_obj.pk)]
-class PermissionManager(models.Manager):
+class StoredPermissionManager(models.Manager):
def get_for_holder(self, holder):
ct = ContentType.objects.get_for_model(holder)
return self.model.objects.filter(permissionholder__holder_type=ct).filter(permissionholder__holder_id=holder.pk)
diff --git a/apps/permissions/migrations/0001_initial.py b/apps/permissions/migrations/0001_initial.py
new file mode 100644
index 0000000000..e69a10a4db
--- /dev/null
+++ b/apps/permissions/migrations/0001_initial.py
@@ -0,0 +1,105 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Adding model 'Permission'
+ db.create_table('permissions_permission', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('namespace', self.gf('django.db.models.fields.CharField')(max_length=64)),
+ ('name', self.gf('django.db.models.fields.CharField')(max_length=64)),
+ ('label', self.gf('django.db.models.fields.CharField')(max_length=96)),
+ ))
+ db.send_create_signal('permissions', ['Permission'])
+
+ # Adding unique constraint on 'Permission', fields ['namespace', 'name']
+ db.create_unique('permissions_permission', ['namespace', 'name'])
+
+ # Adding model 'PermissionHolder'
+ db.create_table('permissions_permissionholder', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('permission', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['permissions.Permission'])),
+ ('holder_type', self.gf('django.db.models.fields.related.ForeignKey')(related_name='permission_holder', to=orm['contenttypes.ContentType'])),
+ ('holder_id', self.gf('django.db.models.fields.PositiveIntegerField')()),
+ ))
+ db.send_create_signal('permissions', ['PermissionHolder'])
+
+ # Adding model 'Role'
+ db.create_table('permissions_role', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('name', self.gf('django.db.models.fields.CharField')(unique=True, max_length=64)),
+ ('label', self.gf('django.db.models.fields.CharField')(unique=True, max_length=64)),
+ ))
+ db.send_create_signal('permissions', ['Role'])
+
+ # Adding model 'RoleMember'
+ db.create_table('permissions_rolemember', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('role', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['permissions.Role'])),
+ ('member_type', self.gf('django.db.models.fields.related.ForeignKey')(related_name='role_member', to=orm['contenttypes.ContentType'])),
+ ('member_id', self.gf('django.db.models.fields.PositiveIntegerField')()),
+ ))
+ db.send_create_signal('permissions', ['RoleMember'])
+
+
+ def backwards(self, orm):
+
+ # Removing unique constraint on 'Permission', fields ['namespace', 'name']
+ db.delete_unique('permissions_permission', ['namespace', 'name'])
+
+ # Deleting model 'Permission'
+ db.delete_table('permissions_permission')
+
+ # Deleting model 'PermissionHolder'
+ db.delete_table('permissions_permissionholder')
+
+ # Deleting model 'Role'
+ db.delete_table('permissions_role')
+
+ # Deleting model 'RoleMember'
+ db.delete_table('permissions_rolemember')
+
+
+ models = {
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'permissions.permission': {
+ 'Meta': {'ordering': "('namespace', 'label')", 'unique_together': "(('namespace', 'name'),)", 'object_name': 'Permission'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'label': ('django.db.models.fields.CharField', [], {'max_length': '96'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'namespace': ('django.db.models.fields.CharField', [], {'max_length': '64'})
+ },
+ 'permissions.permissionholder': {
+ 'Meta': {'object_name': 'PermissionHolder'},
+ 'holder_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'holder_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'permission_holder'", 'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'permission': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['permissions.Permission']"})
+ },
+ 'permissions.role': {
+ 'Meta': {'ordering': "('label',)", 'object_name': 'Role'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'label': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '64'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '64'})
+ },
+ 'permissions.rolemember': {
+ 'Meta': {'object_name': 'RoleMember'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'member_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'member_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'role_member'", 'to': "orm['contenttypes.ContentType']"}),
+ 'role': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['permissions.Role']"})
+ }
+ }
+
+ complete_apps = ['permissions']
diff --git a/apps/permissions/migrations/0002_auto__add_storedpermission__add_unique_storedpermission_namespace_name.py b/apps/permissions/migrations/0002_auto__add_storedpermission__add_unique_storedpermission_namespace_name.py
new file mode 100644
index 0000000000..0109b2548e
--- /dev/null
+++ b/apps/permissions/migrations/0002_auto__add_storedpermission__add_unique_storedpermission_namespace_name.py
@@ -0,0 +1,81 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Adding model 'StoredPermission'
+ db.create_table('permissions_storedpermission', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('namespace', self.gf('django.db.models.fields.CharField')(max_length=64)),
+ ('name', self.gf('django.db.models.fields.CharField')(max_length=64)),
+ ))
+ db.send_create_signal('permissions', ['StoredPermission'])
+
+ # Adding unique constraint on 'StoredPermission', fields ['namespace', 'name']
+ db.create_unique('permissions_storedpermission', ['namespace', 'name'])
+
+ # Changing field 'PermissionHolder.permission'
+ db.alter_column('permissions_permissionholder', 'permission_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['permissions.StoredPermission']))
+
+
+ def backwards(self, orm):
+
+ # Removing unique constraint on 'StoredPermission', fields ['namespace', 'name']
+ db.delete_unique('permissions_storedpermission', ['namespace', 'name'])
+
+ # Deleting model 'StoredPermission'
+ db.delete_table('permissions_storedpermission')
+
+ # Changing field 'PermissionHolder.permission'
+ db.alter_column('permissions_permissionholder', 'permission_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['permissions.Permission']))
+
+
+ models = {
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'permissions.permission': {
+ 'Meta': {'ordering': "('namespace',)", 'unique_together': "(('namespace', 'name'),)", 'object_name': 'Permission'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'label': ('django.db.models.fields.CharField', [], {'max_length': '96'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'namespace': ('django.db.models.fields.CharField', [], {'max_length': '64'})
+ },
+ 'permissions.permissionholder': {
+ 'Meta': {'object_name': 'PermissionHolder'},
+ 'holder_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'holder_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'permission_holder'", 'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'permission': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['permissions.StoredPermission']"})
+ },
+ 'permissions.role': {
+ 'Meta': {'ordering': "('label',)", 'object_name': 'Role'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'label': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '64'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '64'})
+ },
+ 'permissions.rolemember': {
+ 'Meta': {'object_name': 'RoleMember'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'member_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'member_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'role_member'", 'to': "orm['contenttypes.ContentType']"}),
+ 'role': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['permissions.Role']"})
+ },
+ 'permissions.storedpermission': {
+ 'Meta': {'ordering': "('namespace',)", 'unique_together': "(('namespace', 'name'),)", 'object_name': 'StoredPermission'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'namespace': ('django.db.models.fields.CharField', [], {'max_length': '64'})
+ }
+ }
+
+ complete_apps = ['permissions']
diff --git a/apps/permissions/migrations/0003_clear_permission_holders.py b/apps/permissions/migrations/0003_clear_permission_holders.py
new file mode 100644
index 0000000000..b745b97a3a
--- /dev/null
+++ b/apps/permissions/migrations/0003_clear_permission_holders.py
@@ -0,0 +1,61 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import DataMigration
+from django.db import models
+
+class Migration(DataMigration):
+
+ def forwards(self, orm):
+ for permission_holder in orm.PermissionHolder.objects.all():
+ permission_holder.delete()
+
+
+ def backwards(self, orm):
+ raise RuntimeError("Cannot reverse this migration.")
+
+
+ models = {
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'permissions.permission': {
+ 'Meta': {'ordering': "('namespace',)", 'unique_together': "(('namespace', 'name'),)", 'object_name': 'Permission'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'label': ('django.db.models.fields.CharField', [], {'max_length': '96'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'namespace': ('django.db.models.fields.CharField', [], {'max_length': '64'})
+ },
+ 'permissions.permissionholder': {
+ 'Meta': {'object_name': 'PermissionHolder'},
+ 'holder_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'holder_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'permission_holder'", 'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'permission': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['permissions.StoredPermission']"})
+ },
+ 'permissions.role': {
+ 'Meta': {'ordering': "('label',)", 'object_name': 'Role'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'label': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '64'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '64'})
+ },
+ 'permissions.rolemember': {
+ 'Meta': {'object_name': 'RoleMember'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'member_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'member_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'role_member'", 'to': "orm['contenttypes.ContentType']"}),
+ 'role': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['permissions.Role']"})
+ },
+ 'permissions.storedpermission': {
+ 'Meta': {'ordering': "('namespace',)", 'unique_together': "(('namespace', 'name'),)", 'object_name': 'StoredPermission'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'namespace': ('django.db.models.fields.CharField', [], {'max_length': '64'})
+ }
+ }
+
+ complete_apps = ['permissions']
diff --git a/apps/permissions/migrations/0004_auto__del_permission__del_unique_permission_namespace_name.py b/apps/permissions/migrations/0004_auto__del_permission__del_unique_permission_namespace_name.py
new file mode 100644
index 0000000000..adb93d9490
--- /dev/null
+++ b/apps/permissions/migrations/0004_auto__del_permission__del_unique_permission_namespace_name.py
@@ -0,0 +1,69 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Removing unique constraint on 'Permission', fields ['namespace', 'name']
+ db.delete_unique('permissions_permission', ['namespace', 'name'])
+
+ # Deleting model 'Permission'
+ db.delete_table('permissions_permission')
+
+
+ def backwards(self, orm):
+
+ # Adding model 'Permission'
+ db.create_table('permissions_permission', (
+ ('namespace', self.gf('django.db.models.fields.CharField')(max_length=64)),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('name', self.gf('django.db.models.fields.CharField')(max_length=64)),
+ ('label', self.gf('django.db.models.fields.CharField')(max_length=96)),
+ ))
+ db.send_create_signal('permissions', ['Permission'])
+
+ # Adding unique constraint on 'Permission', fields ['namespace', 'name']
+ db.create_unique('permissions_permission', ['namespace', 'name'])
+
+
+ models = {
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'permissions.permissionholder': {
+ 'Meta': {'object_name': 'PermissionHolder'},
+ 'holder_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'holder_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'permission_holder'", 'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'permission': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['permissions.StoredPermission']"})
+ },
+ 'permissions.role': {
+ 'Meta': {'ordering': "('label',)", 'object_name': 'Role'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'label': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '64'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '64'})
+ },
+ 'permissions.rolemember': {
+ 'Meta': {'object_name': 'RoleMember'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'member_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'member_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'role_member'", 'to': "orm['contenttypes.ContentType']"}),
+ 'role': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['permissions.Role']"})
+ },
+ 'permissions.storedpermission': {
+ 'Meta': {'ordering': "('namespace',)", 'unique_together': "(('namespace', 'name'),)", 'object_name': 'StoredPermission'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'namespace': ('django.db.models.fields.CharField', [], {'max_length': '64'})
+ }
+ }
+
+ complete_apps = ['permissions']
diff --git a/apps/permissions/migrations/__init__.py b/apps/permissions/migrations/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/apps/permissions/models.py b/apps/permissions/models.py
index 637a59efab..ff7dfd957f 100644
--- a/apps/permissions/models.py
+++ b/apps/permissions/models.py
@@ -1,60 +1,182 @@
+from __future__ import absolute_import
+
+import logging
+
from django.db import models
from django.utils.translation import ugettext_lazy as _
+from django.utils.translation import ugettext
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
from django.contrib.auth.models import User
+from django.core.exceptions import PermissionDenied
-from permissions.managers import RoleMemberManager, PermissionManager
+from common.models import AnonymousUserSingleton
+
+from .managers import (RoleMemberManager, StoredPermissionManager)
+
+logger = logging.getLogger(__name__)
-class Permission(models.Model):
+class PermissionNamespace(object):
+ def __init__(self, name, label):
+ self.name = name
+ self.label = label
+
+ def __unicode__(self):
+ return unicode(self.label)
+
+
+class PermissionDoesNotExists(Exception):
+ pass
+
+
+class PermissionManager(object):
+ _permissions = {}
+ DoesNotExist = PermissionDoesNotExists()
+
+ @classmethod
+ def register(cls, namespace, name, label):
+ permission = Permission(namespace, name, label)
+ cls._permissions[permission.uuid] = permission
+ return permission
+
+ @classmethod
+ def check_permissions(cls, requester, permission_list):
+ for permission in permission_list:
+ if permission.requester_has_this(requester):
+ return True
+
+ logger.debug('no permission')
+
+ raise PermissionDenied(ugettext(u'Insufficient permissions.'))
+
+ @classmethod
+ def get_for_holder(cls, holder):
+ return StoredPermission.objects.get_for_holder(holder)
+
+ @classmethod
+ def all(cls):
+ # Return sorted permisions by namespace.name
+ return sorted(cls._permissions.values(), key=lambda x: x.namespace.name)
+
+ @classmethod
+ def get(cls, get_dict, proxy_only=False):
+ if 'pk' in get_dict:
+ try:
+ if proxy_only:
+ return cls._permissions[get_dict['pk']]
+ else:
+ return cls._permissions[get_dict['pk']].get_stored_permission()
+ except KeyError:
+ raise Permission.DoesNotExist
+
+
+ def __init__(self, model):
+ self.model = model
+
+
+class Permission(object):
+ DoesNotExist = PermissionDoesNotExists
+
+ def __init__(self, namespace, name, label):
+ self.namespace = namespace
+ self.name = name
+ self.label = label
+ self.pk = self.uuid
+
+ def __unicode__(self):
+ return unicode(self.label)
+
+ def __str__(self):
+ return str(self.__unicode__())
+
+ @property
+ def uuid(self):
+ return u'%s.%s' % (self.namespace.name, self.name)
+
+ @property
+ def stored_permission(self):
+ return self.get_stored_permission()
+
+ def get_stored_permission(self):
+ stored_permission, created = StoredPermission.objects.get_or_create(
+ namespace=self.namespace.name,
+ name=self.name,
+ )
+ stored_permission.label = self.label
+ stored_permission.save()
+ stored_permission.volatile_permission = self
+ return stored_permission
+
+ def requester_has_this(self, requester):
+ stored_permission = self.get_stored_permission()
+ return stored_permission.requester_has_this(requester)
+
+ def save(self, *args, **kwargs):
+ return self.get_stored_permission()
+
+Permission.objects = PermissionManager(Permission)
+Permission._default_manager = Permission.objects
+
+
+class StoredPermission(models.Model):
namespace = models.CharField(max_length=64, verbose_name=_(u'namespace'))
name = models.CharField(max_length=64, verbose_name=_(u'name'))
- label = models.CharField(max_length=96, verbose_name=_(u'label'))
- objects = PermissionManager()
+ objects = StoredPermissionManager()
class Meta:
- ordering = ('namespace', 'label')
+ ordering = ('namespace', )
unique_together = ('namespace', 'name')
verbose_name = _(u'permission')
verbose_name_plural = _(u'permissions')
+ def __init__(self, *args, **kwargs):
+ super(StoredPermission, self).__init__(*args, **kwargs)
+ self.volatile_permission = Permission.objects.get({'pk': '%s.%s' % (self.namespace, self.name)}, proxy_only=True)
+
def __unicode__(self):
- return self.label
+ return unicode(getattr(self, 'volatile_permission', self.name))
def get_holders(self):
return [holder.holder_object for holder in self.permissionholder_set.all()]
- def has_permission(self, requester):
- if isinstance(requester, User):
- if requester.is_superuser or requester.is_staff:
+ def requester_has_this(self, actor):
+ actor = AnonymousUserSingleton.objects.passthru_check(actor)
+ logger.debug('actor: %s' % actor)
+ if isinstance(actor, User):
+ if actor.is_superuser or actor.is_staff:
return True
# Request is one of the permission's holders?
- if requester in self.get_holders():
+ if actor in self.get_holders():
return True
# If not check if the requesters memberships objects is one of
# the permission's holder?
- roles = RoleMember.objects.get_roles_for_member(requester)
+ roles = RoleMember.objects.get_roles_for_member(actor)
- if isinstance(requester, User):
- groups = requester.groups.all()
+ if isinstance(actor, User):
+ groups = actor.groups.all()
else:
groups = []
for membership in list(set(roles) | set(groups)):
- if self.has_permission(membership):
+ if self.requester_has_this(membership):
return True
- def grant_to(self, requester):
- permission_holder, created = PermissionHolder.objects.get_or_create(permission=self, holder_type=ContentType.objects.get_for_model(requester), holder_id=requester.pk)
+ logger.debug('Fallthru')
+ return False
+
+ def grant_to(self, actor):
+ actor = AnonymousUserSingleton.objects.passthru_check(actor)
+ permission_holder, created = PermissionHolder.objects.get_or_create(permission=self, holder_type=ContentType.objects.get_for_model(actor), holder_id=actor.pk)
return created
- def revoke_from(self, holder):
+ def revoke_from(self, actor):
+ actor = AnonymousUserSingleton.objects.passthru_check(actor)
try:
- permission_holder = PermissionHolder.objects.get(permission=self, holder_type=ContentType.objects.get_for_model(holder), holder_id=holder.pk)
+ permission_holder = PermissionHolder.objects.get(permission=self, holder_type=ContentType.objects.get_for_model(actor), holder_id=actor.pk)
permission_holder.delete()
return True
except PermissionHolder.DoesNotExist:
@@ -62,7 +184,7 @@ class Permission(models.Model):
class PermissionHolder(models.Model):
- permission = models.ForeignKey(Permission, verbose_name=_(u'permission'))
+ permission = models.ForeignKey(StoredPermission, verbose_name=_(u'permission'))
holder_type = models.ForeignKey(ContentType,
related_name='permission_holder',
limit_choices_to={'model__in': ('user', 'group', 'role')})
@@ -86,12 +208,6 @@ class Role(models.Model):
verbose_name = _(u'role')
verbose_name_plural = _(u'roles')
- def add_member(self, member):
- role_member, created = RoleMember.objects.get_or_create(
- role=self,
- member_type=ContentType.objects.get_for_model(member),
- member_id=member.pk)
-
def __unicode__(self):
return self.label
@@ -99,12 +215,36 @@ class Role(models.Model):
def get_absolute_url(self):
return ('role_list',)
+ def add_member(self, member):
+ member = AnonymousUserSingleton.objects.passthru_check(member)
+ role_member, created = RoleMember.objects.get_or_create(
+ role=self,
+ member_type=ContentType.objects.get_for_model(member),
+ member_id=member.pk)
+ if not created:
+ raise Exception('Unable to add member to role')
+
+ def remove_member(self, member):
+ member = AnonymousUserSingleton.objects.passthru_check(member)
+ member_type=ContentType.objects.get_for_model(member)
+ role_member = RoleMember.objects.get(role=self, member_type=member_type, member_id=member.pk)
+ role_member.delete()
+
+ def members(self, filter_dict=None):
+ filter_dict = filter_dict or {}
+ return [member.member_object for member in self.rolemember_set.filter(**filter_dict)]
+
class RoleMember(models.Model):
role = models.ForeignKey(Role, verbose_name=_(u'role'))
member_type = models.ForeignKey(ContentType,
related_name='role_member',
- limit_choices_to={'model__in': ('user', 'group')})
+ limit_choices_to={
+ 'model__in': (
+ 'user', 'group', 'anonymoususersingleton'
+ )
+ }
+ )
member_id = models.PositiveIntegerField()
member_object = generic.GenericForeignKey(ct_field='member_type', fk_field='member_id')
diff --git a/apps/permissions/permissions.py b/apps/permissions/permissions.py
new file mode 100644
index 0000000000..ce97e1e150
--- /dev/null
+++ b/apps/permissions/permissions.py
@@ -0,0 +1,14 @@
+from __future__ import absolute_import
+
+from django.utils.translation import ugettext_lazy as _
+
+from .models import Permission, PermissionNamespace
+
+permissions_namespace = PermissionNamespace('permissions', _(u'Permissions'))
+
+PERMISSION_ROLE_VIEW = Permission.objects.register(permissions_namespace, 'role_view', _(u'View roles'))
+PERMISSION_ROLE_EDIT = Permission.objects.register(permissions_namespace, 'role_edit', _(u'Edit roles'))
+PERMISSION_ROLE_CREATE = Permission.objects.register(permissions_namespace, 'role_create', _(u'Create roles'))
+PERMISSION_ROLE_DELETE = Permission.objects.register(permissions_namespace, 'role_delete', _(u'Delete roles'))
+PERMISSION_PERMISSION_GRANT = Permission.objects.register(permissions_namespace, 'permission_grant', _(u'Grant permissions'))
+PERMISSION_PERMISSION_REVOKE = Permission.objects.register(permissions_namespace, 'permission_revoke', _(u'Revoke permissions'))
diff --git a/apps/permissions/runtime.py b/apps/permissions/runtime.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/apps/permissions/templatetags/permission_tags.py b/apps/permissions/templatetags/permission_tags.py
index fecffa2796..0d0974145b 100644
--- a/apps/permissions/templatetags/permission_tags.py
+++ b/apps/permissions/templatetags/permission_tags.py
@@ -1,8 +1,7 @@
from django.core.exceptions import PermissionDenied
-from django.template import TemplateSyntaxError, Library, \
- Node, Variable
+from django.template import TemplateSyntaxError, Library, Node, Variable
-from permissions.api import check_permissions as check_permission_function
+from permissions.models import Permission
register = Library()
@@ -21,7 +20,7 @@ class CheckPermissionsNode(Node):
return u''
requester = Variable(self.requester).resolve(context)
try:
- check_permission_function(requester, permission_list)
+ Permission.objects.check_permissions(requester, permission_list)
context[u'permission'] = True
return u''
except PermissionDenied:
diff --git a/apps/permissions/tests.py b/apps/permissions/tests.py
deleted file mode 100644
index 2247054b35..0000000000
--- a/apps/permissions/tests.py
+++ /dev/null
@@ -1,23 +0,0 @@
-"""
-This file demonstrates two different styles of tests (one doctest and one
-unittest). These will both pass when you run "manage.py test".
-
-Replace these with more appropriate tests for your application.
-"""
-
-from django.test import TestCase
-
-class SimpleTest(TestCase):
- def test_basic_addition(self):
- """
- Tests that 1 + 1 always equals 2.
- """
- self.failUnlessEqual(1 + 1, 2)
-
-__test__ = {"doctest": """
-Another way to test that 1 + 1 is equal to 2.
-
->>> 1 + 1 == 2
-True
-"""}
-
diff --git a/apps/permissions/urls.py b/apps/permissions/urls.py
index ed85c44527..a052f1471b 100644
--- a/apps/permissions/urls.py
+++ b/apps/permissions/urls.py
@@ -7,7 +7,7 @@ urlpatterns = patterns('permissions.views',
url(r'^role/(?P\d+)/edit/$', 'role_edit', (), 'role_edit'),
url(r'^role/(?P\d+)/delete/$', 'role_delete', (), 'role_delete'),
url(r'^role/(?P\d+)/members/$', 'role_members', (), 'role_members'),
-
+
url(r'^permissions/multiple/grant/$', 'permission_grant', (), 'permission_multiple_grant'),
url(r'^permissions/multiple/revoke/$', 'permission_revoke', (), 'permission_multiple_revoke'),
)
diff --git a/apps/permissions/views.py b/apps/permissions/views.py
index 3f58846eb9..6e8673de12 100644
--- a/apps/permissions/views.py
+++ b/apps/permissions/views.py
@@ -1,8 +1,10 @@
+from __future__ import absolute_import
+
import operator
import itertools
from django.utils.translation import ugettext_lazy as _
-from django.http import HttpResponseRedirect
+from django.http import HttpResponseRedirect, Http404
from django.shortcuts import render_to_response, get_object_or_404
from django.template import RequestContext
from django.contrib import messages
@@ -11,24 +13,24 @@ from django.core.urlresolvers import reverse
from django.views.generic.create_update import create_object, delete_object, update_object
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.models import User, Group
-from django.contrib.contenttypes.models import ContentType
from django.utils.simplejson import loads
from common.views import assign_remove
-from common.utils import generate_choices_w_labels, encapsulate
+from common.utils import generate_choices_w_labels, encapsulate, get_object_name
from common.widgets import two_state_template
+from common.models import AnonymousUserSingleton
+from acls.classes import EncapsulatedObject
-from permissions.models import Role, Permission, PermissionHolder, RoleMember
-from permissions.forms import RoleForm, RoleForm_view
-from permissions import PERMISSION_ROLE_VIEW, PERMISSION_ROLE_EDIT, \
- PERMISSION_ROLE_CREATE, PERMISSION_ROLE_DELETE, PERMISSION_PERMISSION_GRANT, \
- PERMISSION_PERMISSION_REVOKE
-from permissions.api import check_permissions, namespace_titles
-from permissions.widgets import role_permission_link
+from .models import Role, Permission, PermissionHolder, RoleMember
+from .forms import RoleForm, RoleForm_view
+from .permissions import (PERMISSION_ROLE_VIEW, PERMISSION_ROLE_EDIT,
+ PERMISSION_ROLE_CREATE, PERMISSION_ROLE_DELETE,
+ PERMISSION_PERMISSION_GRANT, PERMISSION_PERMISSION_REVOKE)
+from .widgets import role_permission_link
def role_list(request):
- check_permissions(request.user, [PERMISSION_ROLE_VIEW])
+ Permission.objects.check_permissions(request.user, [PERMISSION_ROLE_VIEW])
return object_list(
request,
@@ -42,7 +44,7 @@ def role_list(request):
def role_permissions(request, role_id):
- check_permissions(request.user, [PERMISSION_PERMISSION_GRANT, PERMISSION_PERMISSION_REVOKE])
+ Permission.objects.check_permissions(request.user, [PERMISSION_PERMISSION_GRANT, PERMISSION_PERMISSION_REVOKE])
role = get_object_or_404(Role, pk=role_id)
form = RoleForm_view(instance=role)
@@ -55,11 +57,11 @@ def role_permissions(request, role_id):
'title': _(u'permissions'),
'object_list': Permission.objects.all(),
'extra_columns': [
- {'name': _(u'namespace'), 'attribute': encapsulate(lambda x: namespace_titles[x.namespace] if x.namespace in namespace_titles else x.namespace)},
- {'name': _(u'name'), 'attribute': u'label'},
+ {'name': _(u'namespace'), 'attribute': encapsulate(lambda x: x.namespace)},
+ {'name': _(u'name'), 'attribute': encapsulate(lambda x: x.label)},
{
'name':_(u'has permission'),
- 'attribute': encapsulate(lambda x: two_state_template(x.has_permission(role))),
+ 'attribute': encapsulate(lambda x: two_state_template(x.requester_has_this(role))),
},
],
'hide_link': True,
@@ -84,7 +86,7 @@ def role_permissions(request, role_id):
def role_edit(request, role_id):
- check_permissions(request.user, [PERMISSION_ROLE_EDIT])
+ Permission.objects.check_permissions(request.user, [PERMISSION_ROLE_EDIT])
return update_object(request, template_name='generic_form.html',
form_class=RoleForm, object_id=role_id, extra_context={
@@ -92,7 +94,7 @@ def role_edit(request, role_id):
def role_create(request):
- check_permissions(request.user, [PERMISSION_ROLE_CREATE])
+ Permission.objects.check_permissions(request.user, [PERMISSION_ROLE_CREATE])
return create_object(request, model=Role,
template_name='generic_form.html',
@@ -100,7 +102,7 @@ def role_create(request):
def role_delete(request, role_id):
- check_permissions(request.user, [PERMISSION_ROLE_DELETE])
+ Permission.objects.check_permissions(request.user, [PERMISSION_ROLE_DELETE])
next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', '/')))
previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', '/')))
@@ -118,7 +120,7 @@ def role_delete(request, role_id):
def permission_grant(request):
- check_permissions(request.user, [PERMISSION_PERMISSION_GRANT])
+ Permission.objects.check_permissions(request.user, [PERMISSION_PERMISSION_GRANT])
items_property_list = loads(request.GET.get('items_property_list', []))
post_action_redirect = None
@@ -127,20 +129,25 @@ def permission_grant(request):
items = []
for item_properties in items_property_list:
- permission = get_object_or_404(Permission, pk=item_properties['permission_id'])
+ #permission = get_object_or_404(Permission, pk=item_properties['permission_id'])
+ try:
+ permission = Permission.objects.get({'pk': item_properties['permission_id']})
+ except Permission.DoesNotExist:
+ raise Http404
+
ct = get_object_or_404(ContentType, app_label=item_properties['requester_app_label'], model=item_properties['requester_model'])
requester_model = ct.model_class()
requester = get_object_or_404(requester_model, pk=item_properties['requester_id'])
items.append({'requester': requester, 'permission': permission})
-
+
sorted_items = sorted(items, key=operator.itemgetter('requester'))
# Group items by requester
groups = itertools.groupby(sorted_items, key=operator.itemgetter('requester'))
grouped_items = [(grouper, [permission['permission'] for permission in group_data]) for grouper, group_data in groups]
-
+
# Warning: trial and error black magic ahead
title_suffix = _(u' and ').join([_(u'%(permissions)s to %(requester)s') % {'permissions': ', '.join(['"%s"' % unicode(ps) for ps in p]), 'requester': unicode(r)} for r, p in grouped_items])
-
+
if len(grouped_items) == 1 and len(grouped_items[0][1]) == 1:
permissions_label = _(u'permission')
else:
@@ -158,7 +165,6 @@ def permission_grant(request):
return HttpResponseRedirect(next)
context = {
- 'delete_view': True,
'previous': previous,
'next': next,
'form_icon': u'key_add.png',
@@ -168,16 +174,16 @@ def permission_grant(request):
'permissions_label': permissions_label,
'title_suffix': title_suffix,
}
-
+
if len(grouped_items) == 1:
context['object'] = grouped_items[0][0]
return render_to_response('generic_confirm.html', context,
context_instance=RequestContext(request))
-
+
def permission_revoke(request):
- check_permissions(request.user, [PERMISSION_PERMISSION_REVOKE])
+ Permission.objects.check_permissions(request.user, [PERMISSION_PERMISSION_REVOKE])
items_property_list = loads(request.GET.get('items_property_list', []))
post_action_redirect = None
@@ -186,20 +192,25 @@ def permission_revoke(request):
items = []
for item_properties in items_property_list:
- permission = get_object_or_404(Permission, pk=item_properties['permission_id'])
+ #permission = get_object_or_404(Permission, pk=item_properties['permission_id'])
+ try:
+ permission = Permission.objects.get({'pk': item_properties['permission_id']})
+ except Permission.DoesNotExist:
+ raise Http404
+
ct = get_object_or_404(ContentType, app_label=item_properties['requester_app_label'], model=item_properties['requester_model'])
requester_model = ct.model_class()
requester = get_object_or_404(requester_model, pk=item_properties['requester_id'])
items.append({'requester': requester, 'permission': permission})
-
+
sorted_items = sorted(items, key=operator.itemgetter('requester'))
# Group items by requester
groups = itertools.groupby(sorted_items, key=operator.itemgetter('requester'))
grouped_items = [(grouper, [permission['permission'] for permission in group_data]) for grouper, group_data in groups]
-
+
# Warning: trial and error black magic ahead
title_suffix = _(u' and ').join([_(u'%(permissions)s to %(requester)s') % {'permissions': ', '.join(['"%s"' % unicode(ps) for ps in p]), 'requester': unicode(r)} for r, p in grouped_items])
-
+
if len(grouped_items) == 1 and len(grouped_items[0][1]) == 1:
permissions_label = _(u'permission')
else:
@@ -217,7 +228,6 @@ def permission_revoke(request):
return HttpResponseRedirect(next)
context = {
- 'delete_view': True,
'previous': previous,
'next': next,
'form_icon': u'key_delete.png',
@@ -227,7 +237,7 @@ def permission_revoke(request):
'permissions_label': permissions_label,
'title_suffix': title_suffix,
}
-
+
if len(grouped_items) == 1:
context['object'] = grouped_items[0][0]
@@ -235,44 +245,86 @@ def permission_revoke(request):
context_instance=RequestContext(request))
-def get_role_members(role):
+class Member(EncapsulatedObject):
+ source_object_name = u'member_object'
+
+
+def _as_choice_list(items):
+ return sorted([(Member.encapsulate(item).gid, get_object_name(item, display_object_type=False)) for item in items], key=lambda x: x[1])
+
+
+def get_role_members(role, separate=False):
user_ct = ContentType.objects.get(model='user')
group_ct = ContentType.objects.get(model='group')
- return [member.member_object for member in role.rolemember_set.filter(member_type__in=[user_ct, group_ct])]
+ anonymous = ContentType.objects.get(model='anonymoususersingleton')
+
+ users = role.members(filter_dict={'member_type': user_ct})
+ groups = role.members(filter_dict={'member_type': group_ct})
+ anonymous = role.members(filter_dict={'member_type': anonymous})
+
+ if separate:
+ return users, groups, anonymous
+ else:
+ members = []
+
+ if users:
+ members.append((_(u'Users'), _as_choice_list(list(users))))
+
+ if groups:
+ members.append((_(u'Groups'), _as_choice_list(list(groups))))
+
+ if anonymous:
+ members.append((_(u'Special'), _as_choice_list(list(anonymous))))
+
+ return members
def get_non_role_members(role):
#non members = all users - members - staff - super users
+ member_users, member_groups, member_anonymous = get_role_members(role, separate=True)
+
staff_users = User.objects.filter(is_staff=True)
super_users = User.objects.filter(is_superuser=True)
- users = set(User.objects.exclude(pk__in=[member.pk for member in get_role_members(role)])) - set(staff_users) - set(super_users)
- groups = set(Group.objects.exclude(pk__in=[member.pk for member in get_role_members(role)]))
- return list(users | groups)
+
+ users = set(User.objects.all()) - set(member_users) - set(staff_users) - set(super_users)
+ groups = set(Group.objects.all()) - set(member_groups)
+ anonymous = set([AnonymousUserSingleton.objects.get()]) - set(member_anonymous)
+
+ non_members = []
+ if users:
+ non_members.append((_(u'Users'), _as_choice_list(list(users))))
+
+ if groups:
+ non_members.append((_(u'Groups'), _as_choice_list(list(groups))))
+
+ if anonymous:
+ non_members.append((_(u'Special'), _as_choice_list(list(anonymous))))
+
+ #non_holder_list.append((_(u'Special'), _as_choice_list([AnonymousUserSingleton.objects.get()])))
+
+ return non_members
def add_role_member(role, selection):
- model, pk = selection.split(u',')
- ct = ContentType.objects.get(model=model)
- new_member, created = RoleMember.objects.get_or_create(role=role, member_type=ct, member_id=pk)
- if not created:
- raise Exception
+ member = Member.get(selection).source_object
+ role.add_member(member)
def remove_role_member(role, selection):
- model, pk = selection.split(u',')
- ct = ContentType.objects.get(model=model)
- member = RoleMember.objects.get(role=role, member_type=ct, member_id=pk)
- member.delete()
+ member = Member.get(selection).source_object
+ role.remove_member(member)
def role_members(request, role_id):
- check_permissions(request.user, [PERMISSION_ROLE_EDIT])
+ Permission.objects.check_permissions(request.user, [PERMISSION_ROLE_EDIT])
role = get_object_or_404(Role, pk=role_id)
return assign_remove(
request,
- left_list=lambda: generate_choices_w_labels(get_non_role_members(role)),
- right_list=lambda: generate_choices_w_labels(get_role_members(role)),
+ #left_list=lambda: generate_choices_w_labels(get_non_role_members(role)),
+ left_list=lambda: get_non_role_members(role),
+ #right_list=lambda: generate_choices_w_labels(get_role_members(role)),
+ right_list=lambda: get_role_members(role),
add_method=lambda x: add_role_member(role, x),
remove_method=lambda x: remove_role_member(role, x),
left_list_title=_(u'non members of role: %s') % role,
@@ -280,5 +332,6 @@ def role_members(request, role_id):
extra_context={
'object': role,
'object_name': _(u'role'),
- }
+ },
+ grouped=True,
)
diff --git a/apps/project_setup/__init__.py b/apps/project_setup/__init__.py
index 7f160810a2..c8eca31d1f 100644
--- a/apps/project_setup/__init__.py
+++ b/apps/project_setup/__init__.py
@@ -2,5 +2,4 @@ from django.utils.translation import ugettext_lazy as _
from navigation.api import register_top_menu
-#TODO: FIXME dynamic children_path_regext on api register_setup
-register_top_menu('setup_menu', link={'text': _(u'setup'), 'view': 'setup_list', 'famfam': 'cog'}, children_path_regex=[r'^settings/', r'^user_management/', r'^permissions', r'^documents/type', r'^metadata/setup', r'sources/setup', r'grouping/setup'], position=-2)
+setup_link = register_top_menu('setup_menu', link={'text': _(u'setup'), 'view': 'setup_list', 'famfam': 'cog'}, position=-2)
diff --git a/apps/project_setup/api.py b/apps/project_setup/api.py
index 424d250915..1d11179701 100644
--- a/apps/project_setup/api.py
+++ b/apps/project_setup/api.py
@@ -1,5 +1,13 @@
+from __future__ import absolute_import
+
+from . import setup_link
+
setup_items = []
def register_setup(link):
setup_items.append(link)
+
+ # Append the link's children_view_regex to the setup main menu children view regex
+ setup_link.setdefault('children_view_regex', [])
+ setup_link['children_view_regex'].extend(link.get('children_view_regex', []))
diff --git a/apps/project_setup/locale/en/LC_MESSAGES/django.po b/apps/project_setup/locale/en/LC_MESSAGES/django.po
index 2a81c4bb2a..9a6e1c4017 100644
--- a/apps/project_setup/locale/en/LC_MESSAGES/django.po
+++ b/apps/project_setup/locale/en/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-11-22 11:26-0400\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -21,6 +21,6 @@ msgstr ""
msgid "setup"
msgstr ""
-#: views.py:13
+#: views.py:15
msgid "setup items"
msgstr ""
diff --git a/apps/project_setup/locale/es/LC_MESSAGES/django.mo b/apps/project_setup/locale/es/LC_MESSAGES/django.mo
index 37f3fb8053..8094ae0b61 100644
Binary files a/apps/project_setup/locale/es/LC_MESSAGES/django.mo and b/apps/project_setup/locale/es/LC_MESSAGES/django.mo differ
diff --git a/apps/project_setup/locale/es/LC_MESSAGES/django.po b/apps/project_setup/locale/es/LC_MESSAGES/django.po
index 022627b88d..82e75e203a 100644
--- a/apps/project_setup/locale/es/LC_MESSAGES/django.po
+++ b/apps/project_setup/locale/es/LC_MESSAGES/django.po
@@ -8,9 +8,9 @@ msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-11-22 11:26-0400\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: 2011-11-04 01:03+0000\n"
-"Last-Translator: rosarior \n"
+"Last-Translator: Roberto Rosario \n"
"Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/"
"mayan-edms/team/es/)\n"
"Language: es\n"
@@ -23,6 +23,6 @@ msgstr ""
msgid "setup"
msgstr "configuración"
-#: views.py:13
+#: views.py:15
msgid "setup items"
msgstr "elementos de configuración"
diff --git a/apps/project_setup/locale/it/LC_MESSAGES/django.mo b/apps/project_setup/locale/it/LC_MESSAGES/django.mo
new file mode 100644
index 0000000000..8147693df5
Binary files /dev/null and b/apps/project_setup/locale/it/LC_MESSAGES/django.mo differ
diff --git a/apps/project_setup/locale/it/LC_MESSAGES/django.po b/apps/project_setup/locale/it/LC_MESSAGES/django.po
new file mode 100644
index 0000000000..647c2314ad
--- /dev/null
+++ b/apps/project_setup/locale/it/LC_MESSAGES/django.po
@@ -0,0 +1,28 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# , 2011.
+msgid ""
+msgstr ""
+"Project-Id-Version: Mayan EDMS\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
+"PO-Revision-Date: 2011-12-09 18:08+0000\n"
+"Last-Translator: Pierpaolo Baldan \n"
+"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/"
+"it/)\n"
+"Language: it\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+
+#: __init__.py:6
+msgid "setup"
+msgstr "configura"
+
+#: views.py:15
+msgid "setup items"
+msgstr "parametri di configurazione"
diff --git a/apps/project_setup/locale/pl/LC_MESSAGES/django.mo b/apps/project_setup/locale/pl/LC_MESSAGES/django.mo
new file mode 100644
index 0000000000..278fc3c122
Binary files /dev/null and b/apps/project_setup/locale/pl/LC_MESSAGES/django.mo differ
diff --git a/apps/project_setup/locale/pl/LC_MESSAGES/django.po b/apps/project_setup/locale/pl/LC_MESSAGES/django.po
new file mode 100644
index 0000000000..d908334073
--- /dev/null
+++ b/apps/project_setup/locale/pl/LC_MESSAGES/django.po
@@ -0,0 +1,29 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# mic , 2012.
+# , 2012.
+# , 2012.
+msgid ""
+msgstr ""
+"Project-Id-Version: Mayan EDMS\n"
+"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
+"PO-Revision-Date: 2012-02-20 21:42+0000\n"
+"Last-Translator: mic \n"
+"Language-Team: Polish (http://www.transifex.net/projects/p/mayan-edms/language/pl/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: pl\n"
+"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
+
+#: __init__.py:6
+msgid "setup"
+msgstr "ustawienia"
+
+#: views.py:15
+msgid "setup items"
+msgstr "elementy konfiguracji"
diff --git a/apps/project_setup/locale/pt/LC_MESSAGES/django.mo b/apps/project_setup/locale/pt/LC_MESSAGES/django.mo
index 7c88252009..0686fd6a3c 100644
Binary files a/apps/project_setup/locale/pt/LC_MESSAGES/django.mo and b/apps/project_setup/locale/pt/LC_MESSAGES/django.mo differ
diff --git a/apps/project_setup/locale/pt/LC_MESSAGES/django.po b/apps/project_setup/locale/pt/LC_MESSAGES/django.po
index 7ffd621c32..b345be074d 100644
--- a/apps/project_setup/locale/pt/LC_MESSAGES/django.po
+++ b/apps/project_setup/locale/pt/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-11-22 11:26-0400\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: 2011-11-02 01:26+0000\n"
"Last-Translator: emersonsoares \n"
"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/"
@@ -23,6 +23,6 @@ msgstr ""
msgid "setup"
msgstr "instalação"
-#: views.py:13
+#: views.py:15
msgid "setup items"
msgstr "itens de configuração"
diff --git a/apps/project_setup/locale/ru/LC_MESSAGES/django.mo b/apps/project_setup/locale/ru/LC_MESSAGES/django.mo
index 6eafab0493..1be87c998b 100644
Binary files a/apps/project_setup/locale/ru/LC_MESSAGES/django.mo and b/apps/project_setup/locale/ru/LC_MESSAGES/django.mo differ
diff --git a/apps/project_setup/locale/ru/LC_MESSAGES/django.po b/apps/project_setup/locale/ru/LC_MESSAGES/django.po
index e6069f5616..f0c539bbd6 100644
--- a/apps/project_setup/locale/ru/LC_MESSAGES/django.po
+++ b/apps/project_setup/locale/ru/LC_MESSAGES/django.po
@@ -8,9 +8,9 @@ msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-11-22 11:26-0400\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: 2011-11-19 20:30+0000\n"
-"Last-Translator: gsv70 \n"
+"Last-Translator: Sergey Glita \n"
"Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/team/"
"ru/)\n"
"Language: ru\n"
@@ -24,6 +24,6 @@ msgstr ""
msgid "setup"
msgstr "настройки"
-#: views.py:13
+#: views.py:15
msgid "setup items"
msgstr "настроек"
diff --git a/apps/project_setup/tests.py b/apps/project_setup/tests.py
deleted file mode 100644
index 2247054b35..0000000000
--- a/apps/project_setup/tests.py
+++ /dev/null
@@ -1,23 +0,0 @@
-"""
-This file demonstrates two different styles of tests (one doctest and one
-unittest). These will both pass when you run "manage.py test".
-
-Replace these with more appropriate tests for your application.
-"""
-
-from django.test import TestCase
-
-class SimpleTest(TestCase):
- def test_basic_addition(self):
- """
- Tests that 1 + 1 always equals 2.
- """
- self.failUnlessEqual(1 + 1, 2)
-
-__test__ = {"doctest": """
-Another way to test that 1 + 1 is equal to 2.
-
->>> 1 + 1 == 2
-True
-"""}
-
diff --git a/apps/project_setup/views.py b/apps/project_setup/views.py
index 82f45ac40a..8ab0426572 100644
--- a/apps/project_setup/views.py
+++ b/apps/project_setup/views.py
@@ -1,10 +1,12 @@
+from __future__ import absolute_import
+
from django.shortcuts import render_to_response, get_object_or_404
from django.template import RequestContext
from django.utils.translation import ugettext_lazy as _
from navigation.widgets import button_navigation_widget
-from project_setup.api import setup_items
+from .api import setup_items
def setup_list(request):
diff --git a/apps/project_tools/__init__.py b/apps/project_tools/__init__.py
index 176afc9fd6..3fc34151c1 100644
--- a/apps/project_tools/__init__.py
+++ b/apps/project_tools/__init__.py
@@ -2,6 +2,4 @@ from django.utils.translation import ugettext_lazy as _
from navigation.api import register_top_menu
-
-#TODO: FIXME dynamic children_path_regext on api register_setup
-register_top_menu('tools', link={'text': _(u'tools'), 'view': 'tools_list', 'famfam': 'wrench'}, children_views=['statistics', 'history_list', 'formats_list'], position=-3)
+tool_link = register_top_menu('tools', link={'text': _(u'tools'), 'view': 'tools_list', 'famfam': 'wrench'}, position=-3)
diff --git a/apps/project_tools/api.py b/apps/project_tools/api.py
index 873a901af4..d8e66ab7d0 100644
--- a/apps/project_tools/api.py
+++ b/apps/project_tools/api.py
@@ -1,5 +1,12 @@
-tool_items = []
+from __future__ import absolute_import
+from . import tool_link
+
+tool_items = []
def register_tool(link):
tool_items.append(link)
+
+ # Append the link's children_view_regex to the tool main menu children view regex
+ tool_link.setdefault('children_view_regex', [])
+ tool_link['children_view_regex'].extend(link.get('children_view_regex', []))
diff --git a/apps/project_tools/locale/en/LC_MESSAGES/django.po b/apps/project_tools/locale/en/LC_MESSAGES/django.po
index 255cb9e18c..7ac152f443 100644
--- a/apps/project_tools/locale/en/LC_MESSAGES/django.po
+++ b/apps/project_tools/locale/en/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-11-22 11:26-0400\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -17,6 +17,6 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: __init__.py:7 views.py:13
+#: __init__.py:7 views.py:15
msgid "tools"
msgstr ""
diff --git a/apps/project_tools/locale/es/LC_MESSAGES/django.mo b/apps/project_tools/locale/es/LC_MESSAGES/django.mo
index 9416fb42f7..7387ce96d9 100644
Binary files a/apps/project_tools/locale/es/LC_MESSAGES/django.mo and b/apps/project_tools/locale/es/LC_MESSAGES/django.mo differ
diff --git a/apps/project_tools/locale/es/LC_MESSAGES/django.po b/apps/project_tools/locale/es/LC_MESSAGES/django.po
index 9db820eb03..714f2f9f66 100644
--- a/apps/project_tools/locale/es/LC_MESSAGES/django.po
+++ b/apps/project_tools/locale/es/LC_MESSAGES/django.po
@@ -8,9 +8,9 @@ msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-11-22 11:26-0400\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: 2011-09-30 05:22+0000\n"
-"Last-Translator: rosarior \n"
+"Last-Translator: Roberto Rosario \n"
"Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/"
"mayan-edms/team/es/)\n"
"Language: es\n"
@@ -19,6 +19,6 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
-#: __init__.py:7 views.py:13
+#: __init__.py:7 views.py:15
msgid "tools"
msgstr "herramientas"
diff --git a/apps/project_tools/locale/it/LC_MESSAGES/django.mo b/apps/project_tools/locale/it/LC_MESSAGES/django.mo
new file mode 100644
index 0000000000..de891e390b
Binary files /dev/null and b/apps/project_tools/locale/it/LC_MESSAGES/django.mo differ
diff --git a/apps/project_tools/locale/it/LC_MESSAGES/django.po b/apps/project_tools/locale/it/LC_MESSAGES/django.po
new file mode 100644
index 0000000000..ca3f7d9be2
--- /dev/null
+++ b/apps/project_tools/locale/it/LC_MESSAGES/django.po
@@ -0,0 +1,24 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# , 2011.
+msgid ""
+msgstr ""
+"Project-Id-Version: Mayan EDMS\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
+"PO-Revision-Date: 2011-12-09 18:01+0000\n"
+"Last-Translator: Pierpaolo Baldan \n"
+"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/"
+"it/)\n"
+"Language: it\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+
+#: __init__.py:7 views.py:15
+msgid "tools"
+msgstr "strumenti"
diff --git a/apps/project_tools/locale/pl/LC_MESSAGES/django.mo b/apps/project_tools/locale/pl/LC_MESSAGES/django.mo
new file mode 100644
index 0000000000..9c7f96b33b
Binary files /dev/null and b/apps/project_tools/locale/pl/LC_MESSAGES/django.mo differ
diff --git a/apps/project_tools/locale/pl/LC_MESSAGES/django.po b/apps/project_tools/locale/pl/LC_MESSAGES/django.po
new file mode 100644
index 0000000000..d6ff720ee6
--- /dev/null
+++ b/apps/project_tools/locale/pl/LC_MESSAGES/django.po
@@ -0,0 +1,23 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# , 2012.
+msgid ""
+msgstr ""
+"Project-Id-Version: Mayan EDMS\n"
+"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
+"PO-Revision-Date: 2012-02-20 16:08+0000\n"
+"Last-Translator: mic \n"
+"Language-Team: Polish (http://www.transifex.net/projects/p/mayan-edms/language/pl/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: pl\n"
+"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
+
+#: __init__.py:7 views.py:15
+msgid "tools"
+msgstr "narzędzia"
diff --git a/apps/project_tools/locale/pt/LC_MESSAGES/django.mo b/apps/project_tools/locale/pt/LC_MESSAGES/django.mo
index 424ab9c3ee..b11a377f8d 100644
Binary files a/apps/project_tools/locale/pt/LC_MESSAGES/django.mo and b/apps/project_tools/locale/pt/LC_MESSAGES/django.mo differ
diff --git a/apps/project_tools/locale/pt/LC_MESSAGES/django.po b/apps/project_tools/locale/pt/LC_MESSAGES/django.po
index da0f490f89..d56141c08f 100644
--- a/apps/project_tools/locale/pt/LC_MESSAGES/django.po
+++ b/apps/project_tools/locale/pt/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-11-22 11:26-0400\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: 2011-11-02 01:25+0000\n"
"Last-Translator: emersonsoares \n"
"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/"
@@ -19,6 +19,6 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
-#: __init__.py:7 views.py:13
+#: __init__.py:7 views.py:15
msgid "tools"
msgstr "ferramentas"
diff --git a/apps/project_tools/locale/ru/LC_MESSAGES/django.mo b/apps/project_tools/locale/ru/LC_MESSAGES/django.mo
index 99daa2c0af..cedcf43ffc 100644
Binary files a/apps/project_tools/locale/ru/LC_MESSAGES/django.mo and b/apps/project_tools/locale/ru/LC_MESSAGES/django.mo differ
diff --git a/apps/project_tools/locale/ru/LC_MESSAGES/django.po b/apps/project_tools/locale/ru/LC_MESSAGES/django.po
index b4158a9108..6cc3064eb2 100644
--- a/apps/project_tools/locale/ru/LC_MESSAGES/django.po
+++ b/apps/project_tools/locale/ru/LC_MESSAGES/django.po
@@ -1,24 +1,25 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
-# FIRST AUTHOR , YEAR.
#
-#, fuzzy
+# Translators:
+# Sergey Glita , 2011.
msgid ""
msgstr ""
-"Project-Id-Version: PACKAGE VERSION\n"
+"Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-11-22 11:26-0400\n"
-"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-"Last-Translator: FULL NAME \n"
-"Language-Team: LANGUAGE \n"
-"Language: \n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
+"PO-Revision-Date: 2011-11-03 17:24+0000\n"
+"Last-Translator: Sergey Glita \n"
+"Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/team/"
+"ru/)\n"
+"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
-#: __init__.py:7 views.py:13
+#: __init__.py:7 views.py:15
msgid "tools"
-msgstr ""
+msgstr "инструменты"
diff --git a/apps/project_tools/tests.py b/apps/project_tools/tests.py
deleted file mode 100644
index 2247054b35..0000000000
--- a/apps/project_tools/tests.py
+++ /dev/null
@@ -1,23 +0,0 @@
-"""
-This file demonstrates two different styles of tests (one doctest and one
-unittest). These will both pass when you run "manage.py test".
-
-Replace these with more appropriate tests for your application.
-"""
-
-from django.test import TestCase
-
-class SimpleTest(TestCase):
- def test_basic_addition(self):
- """
- Tests that 1 + 1 always equals 2.
- """
- self.failUnlessEqual(1 + 1, 2)
-
-__test__ = {"doctest": """
-Another way to test that 1 + 1 is equal to 2.
-
->>> 1 + 1 == 2
-True
-"""}
-
diff --git a/apps/project_tools/views.py b/apps/project_tools/views.py
index 8bba4fc024..61693a100c 100644
--- a/apps/project_tools/views.py
+++ b/apps/project_tools/views.py
@@ -1,10 +1,12 @@
+from __future__ import absolute_import
+
from django.shortcuts import render_to_response, get_object_or_404
from django.template import RequestContext
from django.utils.translation import ugettext_lazy as _
from navigation.widgets import button_navigation_widget
-from project_tools.api import tool_items
+from .api import tool_items
def tools_list(request):
diff --git a/apps/rest_api/urls.py b/apps/rest_api/urls.py
index 34553951a6..315bd5f1bc 100644
--- a/apps/rest_api/urls.py
+++ b/apps/rest_api/urls.py
@@ -1,10 +1,12 @@
+from __future__ import absolute_import
+
from django.conf.urls.defaults import patterns, url
from djangorestframework.views import ListModelView
from djangorestframework.views import ListOrCreateModelView, InstanceModelView
-from rest_api.views import APIBase, Version_0, ReadOnlyInstanceModelView, IsZoomable
-from rest_api.resources import DocumentResourceSimple
+from .views import APIBase, Version_0, ReadOnlyInstanceModelView, IsZoomable
+from .resources import DocumentResourceSimple
urlpatterns = patterns('',
url(r'^$', APIBase.as_view(), name='api-root'),
diff --git a/apps/scheduler/__init__.py b/apps/scheduler/__init__.py
index 8b13789179..80c406fd3b 100644
--- a/apps/scheduler/__init__.py
+++ b/apps/scheduler/__init__.py
@@ -1 +1,32 @@
+from __future__ import absolute_import
+import logging
+
+from .runtime import scheduler
+
+from django.db.models.signals import post_syncdb
+from django.dispatch import receiver
+
+from south.signals import pre_migrate
+
+from signaler.signals import pre_collectstatic
+
+logger = logging.getLogger(__name__)
+
+
+@receiver(post_syncdb, dispatch_uid='scheduler_shutdown_post_syncdb')
+def scheduler_shutdown_post_syncdb(sender, **kwargs):
+ logger.debug('Scheduler shut down on post syncdb signal')
+ scheduler.shutdown()
+
+
+@receiver(pre_collectstatic, dispatch_uid='sheduler_shutdown_pre_collectstatic')
+def sheduler_shutdown_pre_collectstatic(sender, **kwargs):
+ logger.debug('Scheduler shut down on collectstatic signal')
+ scheduler.shutdown()
+
+
+@receiver(pre_migrate, dispatch_uid='sheduler_shutdown_pre_migrate')
+def sheduler_shutdown_pre_migrate(sender, **kwargs):
+ logger.debug('Scheduler shut down on pre_migrate signal')
+ scheduler.shutdown()
diff --git a/apps/scheduler/api.py b/apps/scheduler/api.py
index 5f79d2433b..148320c3ab 100644
--- a/apps/scheduler/api.py
+++ b/apps/scheduler/api.py
@@ -1,5 +1,7 @@
-from scheduler.runtime import scheduler
-from scheduler.exceptions import AlreadyScheduled
+from __future__ import absolute_import
+
+from .runtime import scheduler
+from .exceptions import AlreadyScheduled
registered_jobs = {}
diff --git a/apps/scheduler/tests.py b/apps/scheduler/tests.py
deleted file mode 100644
index 2247054b35..0000000000
--- a/apps/scheduler/tests.py
+++ /dev/null
@@ -1,23 +0,0 @@
-"""
-This file demonstrates two different styles of tests (one doctest and one
-unittest). These will both pass when you run "manage.py test".
-
-Replace these with more appropriate tests for your application.
-"""
-
-from django.test import TestCase
-
-class SimpleTest(TestCase):
- def test_basic_addition(self):
- """
- Tests that 1 + 1 always equals 2.
- """
- self.failUnlessEqual(1 + 1, 2)
-
-__test__ = {"doctest": """
-Another way to test that 1 + 1 is equal to 2.
-
->>> 1 + 1 == 2
-True
-"""}
-
diff --git a/apps/rest_api/tests.py b/apps/signaler/__init__.py
similarity index 100%
rename from apps/rest_api/tests.py
rename to apps/signaler/__init__.py
diff --git a/apps/signaler/management/__init__.py b/apps/signaler/management/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/apps/signaler/management/commands/__init__.py b/apps/signaler/management/commands/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/apps/signaler/management/commands/collectstatic.py b/apps/signaler/management/commands/collectstatic.py
new file mode 100644
index 0000000000..28b63cd9f2
--- /dev/null
+++ b/apps/signaler/management/commands/collectstatic.py
@@ -0,0 +1,13 @@
+from django.contrib.staticfiles.management.commands import collectstatic
+
+from signaler.signals import pre_collectstatic
+
+
+class Command(collectstatic.Command):
+ """
+ Wrapper for the collectstatic command
+ """
+
+ def handle_noargs(self, *args, **kwargs):
+ pre_collectstatic.send(sender=self)
+ super(Command, self).handle_noargs(*args, **kwargs)
diff --git a/apps/signaler/models.py b/apps/signaler/models.py
new file mode 100644
index 0000000000..71a8362390
--- /dev/null
+++ b/apps/signaler/models.py
@@ -0,0 +1,3 @@
+from django.db import models
+
+# Create your models here.
diff --git a/apps/signaler/signals.py b/apps/signaler/signals.py
new file mode 100644
index 0000000000..c102b00357
--- /dev/null
+++ b/apps/signaler/signals.py
@@ -0,0 +1,3 @@
+from django.dispatch import Signal
+
+pre_collectstatic = Signal()
diff --git a/apps/smart_settings/__init__.py b/apps/smart_settings/__init__.py
index 5926e68754..bfc495e54d 100644
--- a/apps/smart_settings/__init__.py
+++ b/apps/smart_settings/__init__.py
@@ -2,9 +2,10 @@ from django.utils.translation import ugettext_lazy as _
from project_setup.api import register_setup
+
def is_superuser(context):
return context['request'].user.is_staff or context['request'].user.is_superuser
-check_settings = {'text': _(u'settings'), 'view': 'setting_list', 'famfam': 'cog', 'icon': 'cog.png', 'condition': is_superuser}
+check_settings = {'text': _(u'settings'), 'view': 'setting_list', 'famfam': 'cog', 'icon': 'cog.png', 'condition': is_superuser, 'children_view_regex': [r'^setting_']}
register_setup(check_settings)
diff --git a/apps/smart_settings/locale/en/LC_MESSAGES/django.po b/apps/smart_settings/locale/en/LC_MESSAGES/django.po
index d0e511720a..3e123c6230 100644
--- a/apps/smart_settings/locale/en/LC_MESSAGES/django.po
+++ b/apps/smart_settings/locale/en/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-11-22 11:26-0400\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -17,18 +17,18 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: __init__.py:8 views.py:26
+#: __init__.py:9 views.py:28
msgid "settings"
msgstr ""
-#: views.py:31
+#: views.py:33
msgid "name"
msgstr ""
-#: views.py:32
+#: views.py:34
msgid "default"
msgstr ""
-#: views.py:33
+#: views.py:35
msgid "value"
msgstr ""
diff --git a/apps/smart_settings/locale/es/LC_MESSAGES/django.mo b/apps/smart_settings/locale/es/LC_MESSAGES/django.mo
index 71eba7fd8b..23f3eb628b 100644
Binary files a/apps/smart_settings/locale/es/LC_MESSAGES/django.mo and b/apps/smart_settings/locale/es/LC_MESSAGES/django.mo differ
diff --git a/apps/smart_settings/locale/es/LC_MESSAGES/django.po b/apps/smart_settings/locale/es/LC_MESSAGES/django.po
index 2188ccd324..70fb0f67bb 100644
--- a/apps/smart_settings/locale/es/LC_MESSAGES/django.po
+++ b/apps/smart_settings/locale/es/LC_MESSAGES/django.po
@@ -7,9 +7,9 @@ msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-11-22 11:26-0400\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: 2011-09-30 05:09+0000\n"
-"Last-Translator: rosarior \n"
+"Last-Translator: Roberto Rosario \n"
"Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/"
"mayan-edms/team/es/)\n"
"Language: es\n"
@@ -18,18 +18,18 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
-#: __init__.py:8 views.py:26
+#: __init__.py:9 views.py:28
msgid "settings"
msgstr "configuración"
-#: views.py:31
+#: views.py:33
msgid "name"
msgstr "nombre"
-#: views.py:32
+#: views.py:34
msgid "default"
msgstr "por defecto"
-#: views.py:33
+#: views.py:35
msgid "value"
msgstr "valor"
diff --git a/apps/smart_settings/locale/it/LC_MESSAGES/django.mo b/apps/smart_settings/locale/it/LC_MESSAGES/django.mo
new file mode 100644
index 0000000000..d36c2eacdc
Binary files /dev/null and b/apps/smart_settings/locale/it/LC_MESSAGES/django.mo differ
diff --git a/apps/smart_settings/locale/it/LC_MESSAGES/django.po b/apps/smart_settings/locale/it/LC_MESSAGES/django.po
new file mode 100644
index 0000000000..ddd908c065
--- /dev/null
+++ b/apps/smart_settings/locale/it/LC_MESSAGES/django.po
@@ -0,0 +1,36 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# , 2011.
+msgid ""
+msgstr ""
+"Project-Id-Version: Mayan EDMS\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
+"PO-Revision-Date: 2011-12-09 17:38+0000\n"
+"Last-Translator: Pierpaolo Baldan \n"
+"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/"
+"it/)\n"
+"Language: it\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+
+#: __init__.py:9 views.py:28
+msgid "settings"
+msgstr "configurazione"
+
+#: views.py:33
+msgid "name"
+msgstr "nome"
+
+#: views.py:34
+msgid "default"
+msgstr "default"
+
+#: views.py:35
+msgid "value"
+msgstr "valore"
diff --git a/apps/smart_settings/locale/pl/LC_MESSAGES/django.mo b/apps/smart_settings/locale/pl/LC_MESSAGES/django.mo
new file mode 100644
index 0000000000..2ce2fce94d
Binary files /dev/null and b/apps/smart_settings/locale/pl/LC_MESSAGES/django.mo differ
diff --git a/apps/smart_settings/locale/pl/LC_MESSAGES/django.po b/apps/smart_settings/locale/pl/LC_MESSAGES/django.po
new file mode 100644
index 0000000000..d07a0fe587
--- /dev/null
+++ b/apps/smart_settings/locale/pl/LC_MESSAGES/django.po
@@ -0,0 +1,37 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# mic , 2012.
+# , 2012.
+# , 2012.
+msgid ""
+msgstr ""
+"Project-Id-Version: Mayan EDMS\n"
+"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
+"PO-Revision-Date: 2012-02-20 21:27+0000\n"
+"Last-Translator: mic \n"
+"Language-Team: Polish (http://www.transifex.net/projects/p/mayan-edms/language/pl/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: pl\n"
+"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
+
+#: __init__.py:9 views.py:28
+msgid "settings"
+msgstr "ustawienia"
+
+#: views.py:33
+msgid "name"
+msgstr "nazwa"
+
+#: views.py:34
+msgid "default"
+msgstr "domyślny"
+
+#: views.py:35
+msgid "value"
+msgstr "wartość"
diff --git a/apps/smart_settings/locale/pt/LC_MESSAGES/django.mo b/apps/smart_settings/locale/pt/LC_MESSAGES/django.mo
index 868ac5ecd2..bd58bb60a2 100644
Binary files a/apps/smart_settings/locale/pt/LC_MESSAGES/django.mo and b/apps/smart_settings/locale/pt/LC_MESSAGES/django.mo differ
diff --git a/apps/smart_settings/locale/pt/LC_MESSAGES/django.po b/apps/smart_settings/locale/pt/LC_MESSAGES/django.po
index 9e0ed5e9ea..175a5f859c 100644
--- a/apps/smart_settings/locale/pt/LC_MESSAGES/django.po
+++ b/apps/smart_settings/locale/pt/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-11-22 11:26-0400\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: 2011-11-02 01:22+0000\n"
"Last-Translator: emersonsoares \n"
"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/"
@@ -19,18 +19,18 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
-#: __init__.py:8 views.py:26
+#: __init__.py:9 views.py:28
msgid "settings"
msgstr "configurações"
-#: views.py:31
+#: views.py:33
msgid "name"
msgstr "nome"
-#: views.py:32
+#: views.py:34
msgid "default"
msgstr "padrão"
-#: views.py:33
+#: views.py:35
msgid "value"
msgstr "valor"
diff --git a/apps/smart_settings/locale/ru/LC_MESSAGES/django.mo b/apps/smart_settings/locale/ru/LC_MESSAGES/django.mo
index d8be586181..e4856bc7ca 100644
Binary files a/apps/smart_settings/locale/ru/LC_MESSAGES/django.mo and b/apps/smart_settings/locale/ru/LC_MESSAGES/django.mo differ
diff --git a/apps/smart_settings/locale/ru/LC_MESSAGES/django.po b/apps/smart_settings/locale/ru/LC_MESSAGES/django.po
index be3705264a..3c14af4fdd 100644
--- a/apps/smart_settings/locale/ru/LC_MESSAGES/django.po
+++ b/apps/smart_settings/locale/ru/LC_MESSAGES/django.po
@@ -8,9 +8,9 @@ msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-11-22 11:26-0400\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: 2011-11-03 17:15+0000\n"
-"Last-Translator: gsv70 \n"
+"Last-Translator: Sergey Glita \n"
"Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/team/"
"ru/)\n"
"Language: ru\n"
@@ -20,18 +20,18 @@ msgstr ""
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
-#: __init__.py:8 views.py:26
+#: __init__.py:9 views.py:28
msgid "settings"
msgstr "настройки"
-#: views.py:31
+#: views.py:33
msgid "name"
msgstr "имя"
-#: views.py:32
+#: views.py:34
msgid "default"
msgstr "по умолчанию"
-#: views.py:33
+#: views.py:35
msgid "value"
msgstr "значение"
diff --git a/apps/smart_settings/tests.py b/apps/smart_settings/tests.py
deleted file mode 100644
index 2247054b35..0000000000
--- a/apps/smart_settings/tests.py
+++ /dev/null
@@ -1,23 +0,0 @@
-"""
-This file demonstrates two different styles of tests (one doctest and one
-unittest). These will both pass when you run "manage.py test".
-
-Replace these with more appropriate tests for your application.
-"""
-
-from django.test import TestCase
-
-class SimpleTest(TestCase):
- def test_basic_addition(self):
- """
- Tests that 1 + 1 always equals 2.
- """
- self.failUnlessEqual(1 + 1, 2)
-
-__test__ = {"doctest": """
-Another way to test that 1 + 1 is equal to 2.
-
->>> 1 + 1 == 2
-True
-"""}
-
diff --git a/apps/smart_settings/views.py b/apps/smart_settings/views.py
index e4d1b4d75a..a08872d053 100644
--- a/apps/smart_settings/views.py
+++ b/apps/smart_settings/views.py
@@ -1,3 +1,5 @@
+from __future__ import absolute_import
+
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.utils.translation import ugettext_lazy as _
@@ -6,7 +8,7 @@ from django.utils.safestring import mark_safe
from common.utils import return_type, encapsulate
from common.widgets import exists_with_famfam
-from smart_settings.api import settings
+from .api import settings
def setting_list(request):
@@ -28,7 +30,7 @@ def setting_list(request):
'hide_link': True,
'hide_object': True,
'extra_columns': [
- {'name': _(u'name'), 'attribute': encapsulate(lambda x: mark_safe(u'%s %s' % (x.get('global_name'), x.get('description'))))},
+ {'name': _(u'name'), 'attribute': encapsulate(lambda x: mark_safe(u'%s %s' % (x.get('global_name'), x.get('description'))))},
{'name': _(u'default'), 'attribute': encapsulate(lambda x: return_type(x['default']))},
{'name': _(u'value'), 'attribute': encapsulate(lambda x: mark_safe(u'
%s %s
' % (
return_type(getattr(x['module'], x['name'])),
diff --git a/apps/sources/__init__.py b/apps/sources/__init__.py
index faca4f075c..d9612a6f9d 100644
--- a/apps/sources/__init__.py
+++ b/apps/sources/__init__.py
@@ -1,49 +1,41 @@
+from __future__ import absolute_import
+
from django.utils.translation import ugettext_lazy as _
-from navigation.api import register_links, \
- register_model_list_columns
-from permissions.api import register_permission, set_namespace_title
+from navigation.api import (register_links,
+ register_model_list_columns)
from common.utils import encapsulate
from project_setup.api import register_setup
-from documents.models import Document
-from documents.literals import PERMISSION_DOCUMENT_CREATE
+from documents.permissions import PERMISSION_DOCUMENT_NEW_VERSION
-from sources.staging import StagingFile
-from sources.models import WebForm, StagingFolder, SourceTransformation, \
- WatchFolder
-from sources.widgets import staging_file_thumbnail
-
-PERMISSION_SOURCES_SETUP_VIEW = {'namespace': 'sources_setup', 'name': 'sources_setup_view', 'label': _(u'View existing document sources')}
-PERMISSION_SOURCES_SETUP_EDIT = {'namespace': 'sources_setup', 'name': 'sources_setup_edit', 'label': _(u'Edit document sources')}
-PERMISSION_SOURCES_SETUP_DELETE = {'namespace': 'sources_setup', 'name': 'sources_setup_delete', 'label': _(u'Delete document sources')}
-PERMISSION_SOURCES_SETUP_CREATE = {'namespace': 'sources_setup', 'name': 'sources_setup_create', 'label': _(u'Create new document sources')}
-
-set_namespace_title('sources_setup', _(u'Sources setup'))
-register_permission(PERMISSION_SOURCES_SETUP_VIEW)
-register_permission(PERMISSION_SOURCES_SETUP_EDIT)
-register_permission(PERMISSION_SOURCES_SETUP_DELETE)
-register_permission(PERMISSION_SOURCES_SETUP_CREATE)
+from .staging import StagingFile
+from .models import (WebForm, StagingFolder, SourceTransformation,
+ WatchFolder)
+from .widgets import staging_file_thumbnail
+from .permissions import (PERMISSION_SOURCES_SETUP_VIEW,
+ PERMISSION_SOURCES_SETUP_EDIT, PERMISSION_SOURCES_SETUP_DELETE,
+ PERMISSION_SOURCES_SETUP_CREATE)
staging_file_preview = {'text': _(u'preview'), 'class': 'fancybox-noscaling', 'view': 'staging_file_preview', 'args': ['source.source_type', 'source.pk', 'object.id'], 'famfam': 'zoom'}
staging_file_delete = {'text': _(u'delete'), 'view': 'staging_file_delete', 'args': ['source.source_type', 'source.pk', 'object.id'], 'famfam': 'delete', 'keep_query': True}
-setup_sources = {'text': _(u'sources'), 'view': 'setup_web_form_list', 'famfam': 'application_form', 'icon': 'application_form.png', 'children_classes': [WebForm]}
-setup_web_form_list = {'text': _(u'web forms'), 'view': 'setup_web_form_list', 'famfam': 'application_form', 'icon': 'application_form.png', 'children_classes': [WebForm]}
-setup_staging_folder_list = {'text': _(u'staging folders'), 'view': 'setup_staging_folder_list', 'famfam': 'folder_camera', 'children_classes': [StagingFolder]}
-setup_watch_folder_list = {'text': _(u'watch folders'), 'view': 'setup_watch_folder_list', 'famfam': 'folder_magnify', 'children_classes': [WatchFolder]}
+setup_sources = {'text': _(u'sources'), 'view': 'setup_web_form_list', 'famfam': 'application_form', 'icon': 'application_form.png', 'children_classes': [WebForm], 'permissions': [PERMISSION_SOURCES_SETUP_VIEW], 'children_view_regex': [r'setup_web_form', r'setup_staging_folder', r'setup_source_']}
+setup_web_form_list = {'text': _(u'web forms'), 'view': 'setup_web_form_list', 'famfam': 'application_form', 'icon': 'application_form.png', 'children_classes': [WebForm], 'permissions': [PERMISSION_SOURCES_SETUP_VIEW]}
+setup_staging_folder_list = {'text': _(u'staging folders'), 'view': 'setup_staging_folder_list', 'famfam': 'folder_camera', 'children_classes': [StagingFolder], 'permissions': [PERMISSION_SOURCES_SETUP_VIEW]}
+setup_watch_folder_list = {'text': _(u'watch folders'), 'view': 'setup_watch_folder_list', 'famfam': 'folder_magnify', 'children_classes': [WatchFolder], 'permissions': [PERMISSION_SOURCES_SETUP_VIEW]}
-setup_source_edit = {'text': _(u'edit'), 'view': 'setup_source_edit', 'args': ['source.source_type', 'source.pk'], 'famfam': 'application_form_edit'}
-setup_source_delete = {'text': _(u'delete'), 'view': 'setup_source_delete', 'args': ['source.source_type', 'source.pk'], 'famfam': 'application_form_delete'}
-setup_source_create = {'text': _(u'add new source'), 'view': 'setup_source_create', 'args': 'source_type', 'famfam': 'application_form_add'}
+setup_source_edit = {'text': _(u'edit'), 'view': 'setup_source_edit', 'args': ['source.source_type', 'source.pk'], 'famfam': 'application_form_edit', 'permissions': [PERMISSION_SOURCES_SETUP_EDIT]}
+setup_source_delete = {'text': _(u'delete'), 'view': 'setup_source_delete', 'args': ['source.source_type', 'source.pk'], 'famfam': 'application_form_delete', 'permissions': [PERMISSION_SOURCES_SETUP_DELETE]}
+setup_source_create = {'text': _(u'add new source'), 'view': 'setup_source_create', 'args': 'source_type', 'famfam': 'application_form_add', 'permissions': [PERMISSION_SOURCES_SETUP_CREATE]}
-setup_source_transformation_list = {'text': _(u'transformations'), 'view': 'setup_source_transformation_list', 'args': ['source.source_type', 'source.pk'], 'famfam': 'shape_move_front'}
-setup_source_transformation_create = {'text': _(u'add transformation'), 'view': 'setup_source_transformation_create', 'args': ['source.source_type', 'source.pk'], 'famfam': 'shape_square_add'}
-setup_source_transformation_edit = {'text': _(u'edit'), 'view': 'setup_source_transformation_edit', 'args': 'transformation.pk', 'famfam': 'shape_square_edit'}
-setup_source_transformation_delete = {'text': _(u'delete'), 'view': 'setup_source_transformation_delete', 'args': 'transformation.pk', 'famfam': 'shape_square_delete'}
+setup_source_transformation_list = {'text': _(u'transformations'), 'view': 'setup_source_transformation_list', 'args': ['source.source_type', 'source.pk'], 'famfam': 'shape_move_front', 'permissions': [PERMISSION_SOURCES_SETUP_EDIT]}
+setup_source_transformation_create = {'text': _(u'add transformation'), 'view': 'setup_source_transformation_create', 'args': ['source.source_type', 'source.pk'], 'famfam': 'shape_square_add', 'permissions': [PERMISSION_SOURCES_SETUP_EDIT]}
+setup_source_transformation_edit = {'text': _(u'edit'), 'view': 'setup_source_transformation_edit', 'args': 'transformation.pk', 'famfam': 'shape_square_edit', 'permissions': [PERMISSION_SOURCES_SETUP_EDIT]}
+setup_source_transformation_delete = {'text': _(u'delete'), 'view': 'setup_source_transformation_delete', 'args': 'transformation.pk', 'famfam': 'shape_square_delete', 'permissions': [PERMISSION_SOURCES_SETUP_EDIT]}
-source_list = {'text': _(u'Document sources'), 'view': 'setup_web_form_list', 'famfam': 'page_add', 'children_url_regex': [r'sources/setup']}
+source_list = {'text': _(u'Document sources'), 'view': 'setup_web_form_list', 'famfam': 'page_add', 'children_url_regex': [r'sources/setup'], 'permissions': [PERMISSION_SOURCES_SETUP_VIEW]}
-upload_version = {'text': _(u'upload new version'), 'view': 'upload_version', 'args': 'object.pk', 'famfam': 'page_add', 'permissions': [PERMISSION_DOCUMENT_CREATE]}
+upload_version = {'text': _(u'upload new version'), 'view': 'upload_version', 'args': 'object.pk', 'famfam': 'page_add', 'permissions': [PERMISSION_DOCUMENT_NEW_VERSION]}
register_links(StagingFile, [staging_file_delete])
@@ -78,5 +70,4 @@ register_model_list_columns(StagingFile, [
},
])
-
register_setup(setup_sources)
diff --git a/apps/sources/admin.py b/apps/sources/admin.py
index ac03e7c9f8..987ce6d89b 100644
--- a/apps/sources/admin.py
+++ b/apps/sources/admin.py
@@ -1,6 +1,8 @@
+from __future__ import absolute_import
+
from django.contrib import admin
-from sources.models import StagingFolder, WebForm, SourceTransformation
+from .models import StagingFolder, WebForm, SourceTransformation
admin.site.register(StagingFolder)
admin.site.register(WebForm)
diff --git a/apps/sources/forms.py b/apps/sources/forms.py
index 4b046994cf..714343530b 100644
--- a/apps/sources/forms.py
+++ b/apps/sources/forms.py
@@ -1,13 +1,15 @@
+from __future__ import absolute_import
+
from django import forms
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ugettext
from documents.forms import DocumentForm
-from sources.models import WebForm, StagingFolder, SourceTransformation, \
- WatchFolder
-from sources.widgets import FamFamRadioSelect
-from sources.utils import validate_whitelist_blacklist
+from .models import (WebForm, StagingFolder, SourceTransformation,
+ WatchFolder)
+from .widgets import FamFamRadioSelect
+from .utils import validate_whitelist_blacklist
class StagingDocumentForm(DocumentForm):
@@ -37,7 +39,7 @@ class StagingDocumentForm(DocumentForm):
staging_list_index = self.fields.keyOrder.index('staging_file_id')
staging_list = self.fields.keyOrder.pop(staging_list_index)
self.fields.keyOrder.insert(0, staging_list)
-
+
staging_file_id = forms.ChoiceField(label=_(u'Staging file'))
class Meta(DocumentForm.Meta):
@@ -61,7 +63,7 @@ class WebFormForm(DocumentForm):
# Move the file filed to the top
self.fields.keyOrder.remove('file')
self.fields.keyOrder.insert(0, 'file')
-
+
def clean_file(self):
data = self.cleaned_data['file']
validate_whitelist_blacklist(data.name, self.source.whitelist.split(','), self.source.blacklist.split(','))
diff --git a/apps/sources/locale/en/LC_MESSAGES/django.po b/apps/sources/locale/en/LC_MESSAGES/django.po
index 609adf9151..9e37468a16 100644
--- a/apps/sources/locale/en/LC_MESSAGES/django.po
+++ b/apps/sources/locale/en/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-11-22 11:26-0400\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -17,86 +17,74 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: __init__.py:14
-msgid "View existing document sources"
-msgstr ""
-
-#: __init__.py:15
-msgid "Edit document sources"
-msgstr ""
-
-#: __init__.py:16
-msgid "Delete document sources"
-msgstr ""
-
-#: __init__.py:17
-msgid "Create new document sources"
-msgstr ""
-
#: __init__.py:19
-msgid "Sources setup"
-msgstr ""
-
-#: __init__.py:25
msgid "preview"
msgstr ""
-#: __init__.py:26 __init__.py:34 __init__.py:40
+#: __init__.py:20 __init__.py:28 __init__.py:34
msgid "delete"
msgstr ""
-#: __init__.py:28
+#: __init__.py:22
msgid "sources"
msgstr ""
-#: __init__.py:29 literals.py:53 models.py:159
+#: __init__.py:23 literals.py:53 models.py:203
msgid "web forms"
msgstr ""
-#: __init__.py:30 models.py:130
+#: __init__.py:24 models.py:174
msgid "staging folders"
msgstr ""
-#: __init__.py:31 models.py:194
+#: __init__.py:25 models.py:238
msgid "watch folders"
msgstr ""
-#: __init__.py:33 __init__.py:39
+#: __init__.py:27 __init__.py:33
msgid "edit"
msgstr ""
-#: __init__.py:35
+#: __init__.py:29
msgid "add new source"
msgstr ""
-#: __init__.py:37
+#: __init__.py:31
msgid "transformations"
msgstr ""
-#: __init__.py:38
+#: __init__.py:32
msgid "add transformation"
msgstr ""
-#: __init__.py:42
+#: __init__.py:36
msgid "Document sources"
msgstr ""
-#: __init__.py:69 widgets.py:39
+#: __init__.py:38
+msgid "upload new version"
+msgstr ""
+
+#: __init__.py:68 widgets.py:39
msgid "thumbnail"
msgstr ""
-#: forms.py:32 forms.py:55
+#: forms.py:34 forms.py:59
msgid "Expand compressed files"
msgstr ""
-#: forms.py:33 forms.py:56
+#: forms.py:35 forms.py:60
msgid "Upload a compressed file's contained files as individual documents"
msgstr ""
-#: forms.py:41
+#: forms.py:43
msgid "Staging file"
msgstr ""
+#: forms.py:50
+msgid "File"
+msgstr ""
+
#: literals.py:8 literals.py:13
msgid "Always"
msgstr ""
@@ -149,7 +137,7 @@ msgstr ""
msgid "Empty printer"
msgstr ""
-#: literals.py:47 models.py:158
+#: literals.py:47 models.py:202
msgid "web form"
msgstr ""
@@ -169,127 +157,151 @@ msgstr ""
msgid "server watch folders"
msgstr ""
-#: models.py:29
+#: models.py:37
msgid "title"
msgstr ""
-#: models.py:30
+#: models.py:38
msgid "enabled"
msgstr ""
-#: models.py:31
+#: models.py:39
msgid "whitelist"
msgstr ""
-#: models.py:32
+#: models.py:40
msgid "blacklist"
msgstr ""
-#: models.py:98
+#: models.py:142
msgid "icon"
msgstr ""
-#: models.py:98
+#: models.py:142
msgid "An icon to visually distinguish this source."
msgstr ""
-#: models.py:114 models.py:166
+#: models.py:158 models.py:210
msgid "folder path"
msgstr ""
-#: models.py:114 models.py:166
+#: models.py:158 models.py:210
msgid "Server side filesystem path."
msgstr ""
-#: models.py:115
+#: models.py:159
msgid "preview width"
msgstr ""
-#: models.py:115
+#: models.py:159
msgid "Width value to be passed to the converter backend."
msgstr ""
-#: models.py:116
+#: models.py:160
msgid "preview height"
msgstr ""
-#: models.py:116
+#: models.py:160
msgid "Height value to be passed to the converter backend."
msgstr ""
-#: models.py:117 models.py:154 models.py:167
+#: models.py:161 models.py:198 models.py:211
msgid "uncompress"
msgstr ""
-#: models.py:117 models.py:154 models.py:167
+#: models.py:161 models.py:198 models.py:211
msgid "Whether to expand or not compressed archives."
msgstr ""
-#: models.py:118 models.py:168
+#: models.py:162 models.py:212
msgid "delete after upload"
msgstr ""
-#: models.py:118 models.py:168
+#: models.py:162 models.py:212
msgid "Delete the file after is has been successfully uploaded."
msgstr ""
-#: models.py:129
+#: models.py:173
msgid "staging folder"
msgstr ""
-#: models.py:169
+#: models.py:213
msgid "interval"
msgstr ""
-#: models.py:169
+#: models.py:213
msgid ""
"Inverval in seconds where the watch folder path is checked for new documents."
msgstr ""
-#: models.py:193
+#: models.py:237
msgid "watch folder"
msgstr ""
-#: models.py:198
+#: models.py:242
msgid "Enter a valid value."
msgstr ""
-#: models.py:226 views.py:487
+#: models.py:270 views.py:589
msgid "order"
msgstr ""
-#: models.py:227 views.py:488 views.py:525 views.py:555
+#: models.py:271 views.py:590 views.py:627 views.py:657
msgid "transformation"
msgstr ""
-#: models.py:228 views.py:489
+#: models.py:272 views.py:591
msgid "arguments"
msgstr ""
-#: models.py:228
+#: models.py:272
#, python-format
msgid "Use dictionaries to indentify arguments, example: %s"
msgstr ""
-#: models.py:239
+#: models.py:283
msgid "document source transformation"
msgstr ""
-#: models.py:240
+#: models.py:284
msgid "document source transformations"
msgstr ""
-#: staging.py:42
+#: models.py:290 models.py:291
+msgid "out of process"
+msgstr ""
+
+#: permissions.py:7
+msgid "Sources setup"
+msgstr ""
+
+#: permissions.py:8
+msgid "View existing document sources"
+msgstr ""
+
+#: permissions.py:9
+msgid "Edit document sources"
+msgstr ""
+
+#: permissions.py:10
+msgid "Delete document sources"
+msgstr ""
+
+#: permissions.py:11
+msgid "Create new document sources"
+msgstr ""
+
+#: staging.py:44
#, python-format
msgid "Unable get list of staging files: %s"
msgstr ""
-#: staging.py:127
+#: staging.py:129
#, python-format
msgid "Unable to upload staging file: %s"
msgstr ""
-#: staging.py:137
+#: staging.py:139
#, python-format
msgid "Unable to delete staging file: %s"
msgstr ""
@@ -298,162 +310,213 @@ msgstr ""
msgid "Whitelist Blacklist validation error."
msgstr ""
-#: views.py:80
+#: views.py:98
msgid "here"
msgstr ""
-#: views.py:85
+#: views.py:103
msgid "Upload sources"
msgstr ""
-#: views.py:87
+#: views.py:105
msgid ""
"No interactive document sources have been defined or none have been enabled."
msgstr ""
-#: views.py:88
+#: views.py:106
#, python-format
msgid "Click %(setup_link)s to add or enable some document sources."
msgstr ""
-#: views.py:136
-msgid "Document uploaded successfully."
+#: views.py:163
+msgid "New document version uploaded successfully."
msgstr ""
-#: views.py:152
+#: views.py:167
+msgid "File uploaded successfully."
+msgstr ""
+
+#: views.py:170
+msgid "File uncompressed successfully and uploaded as individual files."
+msgstr ""
+
+#: views.py:173
+msgid "File was not a compressed file, uploaded as it was."
+msgstr ""
+
+#: views.py:179 views.py:258
+#, python-format
+msgid "Unhandled exception: %s"
+msgstr ""
+
+#: views.py:188
+#, python-format
+msgid "upload a new version from source: %s"
+msgstr ""
+
+#: views.py:190
#, python-format
msgid "upload a local document from source: %s"
msgstr ""
-#: views.py:182
+#: views.py:236
+#, python-format
+msgid "Document version from staging file: %s, uploaded successfully."
+msgstr ""
+
+#: views.py:239
#, python-format
msgid "Staging file: %s, uploaded successfully."
msgstr ""
-#: views.py:187
+#: views.py:242
+#, python-format
+msgid ""
+"Staging file: %s, uncompressed successfully and uploaded as individual files."
+msgstr ""
+
+#: views.py:245
+#, python-format
+msgid "Staging file: %s, was not compressed, uploaded as a single file."
+msgstr ""
+
+#: views.py:250
#, python-format
msgid "Staging file: %s, deleted successfully."
msgstr ""
-#: views.py:209
+#: views.py:273
+#, python-format
+msgid "upload a new version from staging source: %s"
+msgstr ""
+
+#: views.py:275
#, python-format
msgid "upload a document from staging source: %s"
msgstr ""
-#: views.py:215
+#: views.py:288
msgid "files in staging path"
msgstr ""
-#: views.py:229
+#: views.py:320
+msgid "Current document type"
+msgstr ""
+
+#: views.py:321
+msgid "None"
+msgstr ""
+
+#: views.py:328
msgid "Current metadata"
msgstr ""
-#: views.py:265 views.py:284
+#: views.py:366 views.py:385
#, python-format
msgid "Staging file transformation error: %(error)s"
msgstr ""
-#: views.py:307
+#: views.py:408
msgid "Staging file delete successfully."
msgstr ""
-#: views.py:309
-#, python-format
-msgid "Staging file delete error; %s."
-msgstr ""
-
-#: views.py:368
-msgid "Source edited successfully"
-msgstr ""
-
-#: views.py:371
-#, python-format
-msgid "Error editing source; %s"
-msgstr ""
-
-#: views.py:376
-#, python-format
-msgid "edit source: %s"
-msgstr ""
-
-#: views.py:381 views.py:421 views.py:483 views.py:524 views.py:554
-#: views.py:597
-msgid "source"
-msgstr ""
-
#: views.py:410
#, python-format
+msgid "Staging file delete error; %s."
+msgstr ""
+
+#: views.py:470
+msgid "Source edited successfully"
+msgstr ""
+
+#: views.py:473
+#, python-format
+msgid "Error editing source; %s"
+msgstr ""
+
+#: views.py:478
+#, python-format
+msgid "edit source: %s"
+msgstr ""
+
+#: views.py:483 views.py:523 views.py:585 views.py:626 views.py:656
+#: views.py:699
+msgid "source"
+msgstr ""
+
+#: views.py:512
+#, python-format
msgid "Source \"%s\" deleted successfully."
msgstr ""
-#: views.py:412
-#, python-format
-msgid "Error deleting source \"%(source)s\": %(error)s"
-msgstr ""
-
-#: views.py:419
-#, python-format
-msgid "Are you sure you wish to delete the source: %s?"
-msgstr ""
-
-#: views.py:451
-msgid "Source created successfully"
-msgstr ""
-
-#: views.py:454
-#, python-format
-msgid "Error creating source; %s"
-msgstr ""
-
-#: views.py:459
-#, python-format
-msgid "Create new source of type: %s"
-msgstr ""
-
-#: views.py:481
-#, python-format
-msgid "transformations for: %s"
-msgstr ""
-
-#: views.py:511
-msgid "Source transformation edited successfully"
-msgstr ""
-
#: views.py:514
#, python-format
+msgid "Error deleting source \"%(source)s\": %(error)s"
+msgstr ""
+
+#: views.py:521
+#, python-format
+msgid "Are you sure you wish to delete the source: %s?"
+msgstr ""
+
+#: views.py:553
+msgid "Source created successfully"
+msgstr ""
+
+#: views.py:556
+#, python-format
+msgid "Error creating source; %s"
+msgstr ""
+
+#: views.py:561
+#, python-format
+msgid "Create new source of type: %s"
+msgstr ""
+
+#: views.py:583
+#, python-format
+msgid "transformations for: %s"
+msgstr ""
+
+#: views.py:613
+msgid "Source transformation edited successfully"
+msgstr ""
+
+#: views.py:616
+#, python-format
msgid "Error editing source transformation; %s"
msgstr ""
-#: views.py:519
+#: views.py:621
#, python-format
msgid "Edit transformation: %s"
msgstr ""
-#: views.py:542
+#: views.py:644
msgid "Source transformation deleted successfully."
msgstr ""
-#: views.py:544
+#: views.py:646
#, python-format
msgid "Error deleting source transformation; %(error)s"
msgstr ""
-#: views.py:557
+#: views.py:659
#, python-format
msgid ""
"Are you sure you wish to delete source transformation \"%(transformation)s\""
msgstr ""
-#: views.py:587
+#: views.py:689
msgid "Source transformation created successfully"
msgstr ""
-#: views.py:590
+#: views.py:692
#, python-format
msgid "Error creating source transformation; %s"
msgstr ""
-#: views.py:599
+#: views.py:701
#, python-format
msgid "Create new transformation for source: %s"
msgstr ""
diff --git a/apps/sources/locale/es/LC_MESSAGES/django.mo b/apps/sources/locale/es/LC_MESSAGES/django.mo
index 4395893c48..7cdd8eb998 100644
Binary files a/apps/sources/locale/es/LC_MESSAGES/django.mo and b/apps/sources/locale/es/LC_MESSAGES/django.mo differ
diff --git a/apps/sources/locale/es/LC_MESSAGES/django.po b/apps/sources/locale/es/LC_MESSAGES/django.po
index b71b65dc33..9074aeb8ad 100644
--- a/apps/sources/locale/es/LC_MESSAGES/django.po
+++ b/apps/sources/locale/es/LC_MESSAGES/django.po
@@ -3,14 +3,14 @@
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
-# Roberto Rosario , 2011.
+# Roberto Rosario , 2011, 2012.
msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
-"POT-Creation-Date: 2011-11-22 11:26-0400\n"
-"PO-Revision-Date: 2011-11-22 21:02+0000\n"
-"Last-Translator: rosarior \n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
+"PO-Revision-Date: 2012-02-12 19:28+0000\n"
+"Last-Translator: Roberto Rosario \n"
"Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/mayan-edms/team/es/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -18,87 +18,75 @@ msgstr ""
"Language: es\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
-#: __init__.py:14
-msgid "View existing document sources"
-msgstr "Ver fuentes de documento existentes"
-
-#: __init__.py:15
-msgid "Edit document sources"
-msgstr "Editar fuentes de documentos"
-
-#: __init__.py:16
-msgid "Delete document sources"
-msgstr "Eliminar fuentes de documentos"
-
-#: __init__.py:17
-msgid "Create new document sources"
-msgstr "Crear nuevas fuentes de documentos"
-
#: __init__.py:19
-msgid "Sources setup"
-msgstr "Configuración de fuentes de documentos"
-
-#: __init__.py:25
msgid "preview"
msgstr "muestra"
-#: __init__.py:26 __init__.py:34 __init__.py:40
+#: __init__.py:20 __init__.py:28 __init__.py:34
msgid "delete"
msgstr "borrar"
-#: __init__.py:28
+#: __init__.py:22
msgid "sources"
msgstr "fuentes"
-#: __init__.py:29 literals.py:53 models.py:159
+#: __init__.py:23 literals.py:53 models.py:203
msgid "web forms"
msgstr "formularios web"
-#: __init__.py:30 models.py:130
+#: __init__.py:24 models.py:174
msgid "staging folders"
msgstr "carpetas de archivos provisionales"
-#: __init__.py:31 models.py:194
+#: __init__.py:25 models.py:238
msgid "watch folders"
msgstr "carpetas bajo observación"
-#: __init__.py:33 __init__.py:39
+#: __init__.py:27 __init__.py:33
msgid "edit"
msgstr "editar"
-#: __init__.py:35
+#: __init__.py:29
msgid "add new source"
msgstr "agregar nueva fuente"
-#: __init__.py:37
+#: __init__.py:31
msgid "transformations"
msgstr "transformaciones"
-#: __init__.py:38
+#: __init__.py:32
msgid "add transformation"
msgstr "añadir transformación"
-#: __init__.py:42
+#: __init__.py:36
msgid "Document sources"
msgstr "Fuentes de documentos"
-#: __init__.py:69 widgets.py:39
+#: __init__.py:38
+msgid "upload new version"
+msgstr "subir nueva versión"
+
+#: __init__.py:68 widgets.py:39
msgid "thumbnail"
msgstr "muestra"
-#: forms.py:32 forms.py:55
+#: forms.py:34 forms.py:59
msgid "Expand compressed files"
msgstr "Expandir archivos comprimidos"
-#: forms.py:33 forms.py:56
+#: forms.py:35 forms.py:60
msgid "Upload a compressed file's contained files as individual documents"
msgstr ""
"Subir los archivos de un archivo comprimido como documentos individuales"
-#: forms.py:41
+#: forms.py:43
msgid "Staging file"
msgstr "Archivo provisional"
+#: forms.py:50
+msgid "File"
+msgstr "Archivo"
+
#: literals.py:8 literals.py:13
msgid "Always"
msgstr "Siempre"
@@ -151,7 +139,7 @@ msgstr "Impresora"
msgid "Empty printer"
msgstr "Impresora vacia"
-#: literals.py:47 models.py:158
+#: literals.py:47 models.py:202
msgid "web form"
msgstr "formulario web"
@@ -171,79 +159,79 @@ msgstr "carpetas de archivos provisionales de servidor"
msgid "server watch folders"
msgstr "carpetas observadas de servidor"
-#: models.py:29
+#: models.py:37
msgid "title"
msgstr "título"
-#: models.py:30
+#: models.py:38
msgid "enabled"
msgstr "activado"
-#: models.py:31
+#: models.py:39
msgid "whitelist"
msgstr "lista blanca"
-#: models.py:32
+#: models.py:40
msgid "blacklist"
msgstr "lista negra"
-#: models.py:98
+#: models.py:142
msgid "icon"
msgstr "icono"
-#: models.py:98
+#: models.py:142
msgid "An icon to visually distinguish this source."
msgstr "Un icono para distinguir visualmente esta fuente."
-#: models.py:114 models.py:166
+#: models.py:158 models.py:210
msgid "folder path"
msgstr "ruta de la carpeta"
-#: models.py:114 models.py:166
+#: models.py:158 models.py:210
msgid "Server side filesystem path."
msgstr "Camino a los archivos en el servidor."
-#: models.py:115
+#: models.py:159
msgid "preview width"
msgstr "ancho de muestra"
-#: models.py:115
+#: models.py:159
msgid "Width value to be passed to the converter backend."
msgstr "Valor de la anchura que se pasa al backend convertidor."
-#: models.py:116
+#: models.py:160
msgid "preview height"
msgstr "alto de muestra"
-#: models.py:116
+#: models.py:160
msgid "Height value to be passed to the converter backend."
msgstr "Valor de la altura que se pasa al backend convertidor."
-#: models.py:117 models.py:154 models.py:167
+#: models.py:161 models.py:198 models.py:211
msgid "uncompress"
msgstr "descomprimir"
-#: models.py:117 models.py:154 models.py:167
+#: models.py:161 models.py:198 models.py:211
msgid "Whether to expand or not compressed archives."
msgstr "La posibilidad de ampliar o no archivos comprimidos."
-#: models.py:118 models.py:168
+#: models.py:162 models.py:212
msgid "delete after upload"
msgstr "eliminar después de subir"
-#: models.py:118 models.py:168
+#: models.py:162 models.py:212
msgid "Delete the file after is has been successfully uploaded."
msgstr "Eliminar el archivo después de que se haya cargado exitosamente."
-#: models.py:129
+#: models.py:173
msgid "staging folder"
msgstr "carpeta de archivos provisionales"
-#: models.py:169
+#: models.py:213
msgid "interval"
msgstr "intervalo"
-#: models.py:169
+#: models.py:213
msgid ""
"Inverval in seconds where the watch folder path is checked for new "
"documents."
@@ -251,50 +239,74 @@ msgstr ""
"Inverval es segundos, donde se comprueba la ruta de la carpeta para detectar"
" nuevos documentos."
-#: models.py:193
+#: models.py:237
msgid "watch folder"
msgstr "carpeta observada"
-#: models.py:198
+#: models.py:242
msgid "Enter a valid value."
msgstr "Introduzca un valor válido."
-#: models.py:226 views.py:487
+#: models.py:270 views.py:589
msgid "order"
msgstr "orden"
-#: models.py:227 views.py:488 views.py:525 views.py:555
+#: models.py:271 views.py:590 views.py:627 views.py:657
msgid "transformation"
msgstr "transformación"
-#: models.py:228 views.py:489
+#: models.py:272 views.py:591
msgid "arguments"
msgstr "argumentos"
-#: models.py:228
+#: models.py:272
#, python-format
msgid "Use dictionaries to indentify arguments, example: %s"
msgstr "Utilizar diccionarios para identificar argumentos, por ejemplo: %s"
-#: models.py:239
+#: models.py:283
msgid "document source transformation"
msgstr "transformación de fuente de documentos"
-#: models.py:240
+#: models.py:284
msgid "document source transformations"
msgstr "transformaciones de fuentes de documentos"
-#: staging.py:42
+#: models.py:290 models.py:291
+msgid "out of process"
+msgstr "fuera de proceso"
+
+#: permissions.py:7
+msgid "Sources setup"
+msgstr "Configuración de fuentes de documentos"
+
+#: permissions.py:8
+msgid "View existing document sources"
+msgstr "Ver fuentes de documento existentes"
+
+#: permissions.py:9
+msgid "Edit document sources"
+msgstr "Editar fuentes de documentos"
+
+#: permissions.py:10
+msgid "Delete document sources"
+msgstr "Eliminar fuentes de documentos"
+
+#: permissions.py:11
+msgid "Create new document sources"
+msgstr "Crear nuevas fuentes de documentos"
+
+#: staging.py:44
#, python-format
msgid "Unable get list of staging files: %s"
msgstr "No es posible obtener la lista de los archivos provisionales: %s"
-#: staging.py:127
+#: staging.py:129
#, python-format
msgid "Unable to upload staging file: %s"
msgstr "No se puede cargar archivo provisional: %s"
-#: staging.py:137
+#: staging.py:139
#, python-format
msgid "Unable to delete staging file: %s"
msgstr "No se puede eliminar archivo provisional: %s"
@@ -303,151 +315,208 @@ msgstr "No se puede eliminar archivo provisional: %s"
msgid "Whitelist Blacklist validation error."
msgstr "Error de validación de Lista Negra Lista Blanca"
-#: views.py:80
+#: views.py:98
msgid "here"
msgstr "aquí"
-#: views.py:85
+#: views.py:103
msgid "Upload sources"
msgstr "Upload sources"
-#: views.py:87
+#: views.py:105
msgid ""
"No interactive document sources have been defined or none have been enabled."
msgstr ""
"No hay fuentes de documentos interactivos definidos o ninguna de ellas ha "
"sido activada."
-#: views.py:88
+#: views.py:106
#, python-format
msgid "Click %(setup_link)s to add or enable some document sources."
msgstr ""
"Haga clic en %(setup_link)s para agregar o habilitar algunas fuentes de "
"documentos."
-#: views.py:136
-msgid "Document uploaded successfully."
-msgstr "Documento cargado con exitosamente."
+#: views.py:163
+msgid "New document version uploaded successfully."
+msgstr "Nueva versión del documento subida exitosamente."
-#: views.py:152
+#: views.py:167
+msgid "File uploaded successfully."
+msgstr "Archivo subido correctamente."
+
+#: views.py:170
+msgid "File uncompressed successfully and uploaded as individual files."
+msgstr ""
+"Archivo descomprimido exitosamente y subido como archivos individuales."
+
+#: views.py:173
+msgid "File was not a compressed file, uploaded as it was."
+msgstr "El archivo no era un archivo comprimido, cargado como estaba."
+
+#: views.py:179 views.py:258
+#, python-format
+msgid "Unhandled exception: %s"
+msgstr "Excepción sin manejar: %s"
+
+#: views.py:188
+#, python-format
+msgid "upload a new version from source: %s"
+msgstr "subir una nueva versión desde la fuente: %s"
+
+#: views.py:190
#, python-format
msgid "upload a local document from source: %s"
msgstr "subir un documento local de la fuente: %s"
-#: views.py:182
+#: views.py:236
+#, python-format
+msgid "Document version from staging file: %s, uploaded successfully."
+msgstr ""
+"Versión de documento del archivo provisional: %s, subido exitosamente."
+
+#: views.py:239
#, python-format
msgid "Staging file: %s, uploaded successfully."
msgstr "Archivo provisional: %s, subido exitosamente."
-#: views.py:187
+#: views.py:242
+#, python-format
+msgid ""
+"Staging file: %s, uncompressed successfully and uploaded as individual "
+"files."
+msgstr ""
+"Archivo provisional: %s, descomprido exitosamente y subido como documentos "
+"individuales."
+
+#: views.py:245
+#, python-format
+msgid "Staging file: %s, was not compressed, uploaded as a single file."
+msgstr ""
+"Archivo provisional: %s, no esta comprimido, subido como un solo documento."
+
+#: views.py:250
#, python-format
msgid "Staging file: %s, deleted successfully."
msgstr "Archivo provisional: %s, borrado exitosamente."
-#: views.py:209
+#: views.py:273
+#, python-format
+msgid "upload a new version from staging source: %s"
+msgstr "subir una versión nueva de la fuente de archivo provisionales: %s"
+
+#: views.py:275
#, python-format
msgid "upload a document from staging source: %s"
msgstr "cargar un documento de la fuente de archivos provisionales: %s"
-#: views.py:215
+#: views.py:288
msgid "files in staging path"
msgstr "archivos en la direccion de archivos provisionales"
-#: views.py:229
+#: views.py:320
+msgid "Current document type"
+msgstr "Tipo de documento actual"
+
+#: views.py:321
+msgid "None"
+msgstr "Ninguno"
+
+#: views.py:328
msgid "Current metadata"
msgstr "Metadatos actuales"
-#: views.py:265 views.py:284
+#: views.py:366 views.py:385
#, python-format
msgid "Staging file transformation error: %(error)s"
msgstr "Error de transformación de archivo provisional: %(error)s"
-#: views.py:307
+#: views.py:408
msgid "Staging file delete successfully."
msgstr "Archivos provisional borrado exitosamente."
-#: views.py:309
+#: views.py:410
#, python-format
msgid "Staging file delete error; %s."
msgstr "Error al borrar archivo provisional; %s."
-#: views.py:368
+#: views.py:470
msgid "Source edited successfully"
msgstr "Fuente editada exitosamente"
-#: views.py:371
+#: views.py:473
#, python-format
msgid "Error editing source; %s"
msgstr "Error editando fuente; %s"
-#: views.py:376
+#: views.py:478
#, python-format
msgid "edit source: %s"
msgstr "editar fuente: %s"
-#: views.py:381 views.py:421 views.py:483 views.py:524 views.py:554
-#: views.py:597
+#: views.py:483 views.py:523 views.py:585 views.py:626 views.py:656
+#: views.py:699
msgid "source"
msgstr "fuente"
-#: views.py:410
+#: views.py:512
#, python-format
msgid "Source \"%s\" deleted successfully."
msgstr "Fuente \"%s\" borrada exitosamente."
-#: views.py:412
+#: views.py:514
#, python-format
msgid "Error deleting source \"%(source)s\": %(error)s"
msgstr "Error borrando fuente \"%(source)s\": %(error)s"
-#: views.py:419
+#: views.py:521
#, python-format
msgid "Are you sure you wish to delete the source: %s?"
msgstr "¿Está seguro que desea eliminar la fuente: %s?"
-#: views.py:451
+#: views.py:553
msgid "Source created successfully"
msgstr "Fuente creada exitosamente"
-#: views.py:454
+#: views.py:556
#, python-format
msgid "Error creating source; %s"
msgstr "Error creando fuente; %s"
-#: views.py:459
+#: views.py:561
#, python-format
msgid "Create new source of type: %s"
msgstr "Crear nuevo tipo de fuente: %s"
-#: views.py:481
+#: views.py:583
#, python-format
msgid "transformations for: %s"
msgstr "transformaciones para: %s"
-#: views.py:511
+#: views.py:613
msgid "Source transformation edited successfully"
msgstr "Transformación de la fuente editada exitosamente"
-#: views.py:514
+#: views.py:616
#, python-format
msgid "Error editing source transformation; %s"
msgstr "Error al editar la transformación de la fuente; %s"
-#: views.py:519
+#: views.py:621
#, python-format
msgid "Edit transformation: %s"
msgstr "Editar transformación: %s"
-#: views.py:542
+#: views.py:644
msgid "Source transformation deleted successfully."
msgstr "Transformación de la fuente borrada exitosamente."
-#: views.py:544
+#: views.py:646
#, python-format
msgid "Error deleting source transformation; %(error)s"
msgstr "Error borrando la transformación de la fuente; %(error)s"
-#: views.py:557
+#: views.py:659
#, python-format
msgid ""
"Are you sure you wish to delete source transformation \"%(transformation)s\""
@@ -455,16 +524,16 @@ msgstr ""
"¿Está seguro que desea eliminar la transformación de la fuente "
"\"%(transformation)s\""
-#: views.py:587
+#: views.py:689
msgid "Source transformation created successfully"
msgstr "Transformación de la fuente creado exitosamente"
-#: views.py:590
+#: views.py:692
#, python-format
msgid "Error creating source transformation; %s"
msgstr "Error al crear la transformación de la fuente; %s"
-#: views.py:599
+#: views.py:701
#, python-format
msgid "Create new transformation for source: %s"
msgstr "Crear una nueva transformación para la fuente: %s"
diff --git a/apps/sources/locale/it/LC_MESSAGES/django.mo b/apps/sources/locale/it/LC_MESSAGES/django.mo
new file mode 100644
index 0000000000..73223cfe1a
Binary files /dev/null and b/apps/sources/locale/it/LC_MESSAGES/django.mo differ
diff --git a/apps/sources/locale/it/LC_MESSAGES/django.po b/apps/sources/locale/it/LC_MESSAGES/django.po
new file mode 100644
index 0000000000..3905bd9f58
--- /dev/null
+++ b/apps/sources/locale/it/LC_MESSAGES/django.po
@@ -0,0 +1,538 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# , 2011.
+msgid ""
+msgstr ""
+"Project-Id-Version: Mayan EDMS\n"
+"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
+"PO-Revision-Date: 2012-02-12 19:23+0000\n"
+"Last-Translator: Roberto Rosario \n"
+"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/it/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: it\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+
+#: __init__.py:19
+msgid "preview"
+msgstr "anteprima"
+
+#: __init__.py:20 __init__.py:28 __init__.py:34
+msgid "delete"
+msgstr "cancella"
+
+#: __init__.py:22
+msgid "sources"
+msgstr "sorgenti"
+
+#: __init__.py:23 literals.py:53 models.py:203
+msgid "web forms"
+msgstr "web forms"
+
+#: __init__.py:24 models.py:174
+msgid "staging folders"
+msgstr "cartelle per la gestione temporanea"
+
+#: __init__.py:25 models.py:238
+msgid "watch folders"
+msgstr "cartelle di"
+
+#: __init__.py:27 __init__.py:33
+msgid "edit"
+msgstr "modifica"
+
+#: __init__.py:29
+msgid "add new source"
+msgstr "aggiungi una nuova sorgente"
+
+#: __init__.py:31
+msgid "transformations"
+msgstr "trasformazioni"
+
+#: __init__.py:32
+msgid "add transformation"
+msgstr "aggiungi una trasformazione"
+
+#: __init__.py:36
+msgid "Document sources"
+msgstr "Sorgente del documento"
+
+#: __init__.py:38
+msgid "upload new version"
+msgstr ""
+
+#: __init__.py:68 widgets.py:39
+msgid "thumbnail"
+msgstr "thumbnail"
+
+#: forms.py:34 forms.py:59
+msgid "Expand compressed files"
+msgstr "Espandi"
+
+#: forms.py:35 forms.py:60
+msgid "Upload a compressed file's contained files as individual documents"
+msgstr "Pubblicare un file compresso contenente singoli documenti"
+
+#: forms.py:43
+msgid "Staging file"
+msgstr "Mostra file"
+
+#: forms.py:50
+msgid "File"
+msgstr ""
+
+#: literals.py:8 literals.py:13
+msgid "Always"
+msgstr "Sempre"
+
+#: literals.py:9 literals.py:14
+msgid "Never"
+msgstr "Mai"
+
+#: literals.py:15
+msgid "Ask user"
+msgstr "Chiedi all'utente"
+
+#: literals.py:30
+msgid "Disk"
+msgstr "Disco"
+
+#: literals.py:31
+msgid "Database"
+msgstr "Database"
+
+#: literals.py:32
+msgid "Drive"
+msgstr "Drive"
+
+#: literals.py:33
+msgid "Network drive"
+msgstr "Disco di rete"
+
+#: literals.py:34
+msgid "User drive"
+msgstr "Disco locale"
+
+#: literals.py:35
+msgid "Envelope"
+msgstr "Busta"
+
+#: literals.py:36
+msgid "Folder"
+msgstr "Cartella"
+
+#: literals.py:37
+msgid "World"
+msgstr "Mondo"
+
+#: literals.py:38
+msgid "Printer"
+msgstr "Stampante"
+
+#: literals.py:39
+msgid "Empty printer"
+msgstr "Stampante vuota"
+
+#: literals.py:47 models.py:202
+msgid "web form"
+msgstr "web form"
+
+#: literals.py:48
+msgid "server staging folder"
+msgstr "server per la gestione temporanea della cartella"
+
+#: literals.py:49
+msgid "server watch folder"
+msgstr "server di salvataggio cartella"
+
+#: literals.py:54
+msgid "server staging folders"
+msgstr "server per la gestione temporanea delle cartelle"
+
+#: literals.py:55
+msgid "server watch folders"
+msgstr "server di salvataggio delle cartelle"
+
+#: models.py:37
+msgid "title"
+msgstr "titolo"
+
+#: models.py:38
+msgid "enabled"
+msgstr "abilitato"
+
+#: models.py:39
+msgid "whitelist"
+msgstr "whitelist"
+
+#: models.py:40
+msgid "blacklist"
+msgstr "blacklist"
+
+#: models.py:142
+msgid "icon"
+msgstr "icona"
+
+#: models.py:142
+msgid "An icon to visually distinguish this source."
+msgstr "Un'icona per distinguere visivamente questa fonte."
+
+#: models.py:158 models.py:210
+msgid "folder path"
+msgstr "path della cartella"
+
+#: models.py:158 models.py:210
+msgid "Server side filesystem path."
+msgstr "Path del server di filesystem"
+
+#: models.py:159
+msgid "preview width"
+msgstr "anteprima larghezza"
+
+#: models.py:159
+msgid "Width value to be passed to the converter backend."
+msgstr ""
+"valore della larghezza da passare per le operazioni di conversione in "
+"backend"
+
+#: models.py:160
+msgid "preview height"
+msgstr "anteprima altezza"
+
+#: models.py:160
+msgid "Height value to be passed to the converter backend."
+msgstr ""
+"valore dell'altezza da passare per le operazioni di conversione in backend"
+
+#: models.py:161 models.py:198 models.py:211
+msgid "uncompress"
+msgstr "decomprimere"
+
+#: models.py:161 models.py:198 models.py:211
+msgid "Whether to expand or not compressed archives."
+msgstr "Se espandere o meno degli archivi compressi."
+
+#: models.py:162 models.py:212
+msgid "delete after upload"
+msgstr "cancella dopo il caricamento"
+
+#: models.py:162 models.py:212
+msgid "Delete the file after is has been successfully uploaded."
+msgstr "Cancella il file dopo essere stato caricato"
+
+#: models.py:173
+msgid "staging folder"
+msgstr "Cartella di conservazione"
+
+#: models.py:213
+msgid "interval"
+msgstr "intervallo"
+
+#: models.py:213
+msgid ""
+"Inverval in seconds where the watch folder path is checked for new "
+"documents."
+msgstr ""
+"Invervallo di pochi secondi in cui viene controllato il percorso cartella di"
+" controllo per i nuovi documenti."
+
+#: models.py:237
+msgid "watch folder"
+msgstr "controlla cartella"
+
+#: models.py:242
+msgid "Enter a valid value."
+msgstr "Inserisci un valore valido"
+
+#: models.py:270 views.py:589
+msgid "order"
+msgstr "ordine"
+
+#: models.py:271 views.py:590 views.py:627 views.py:657
+msgid "transformation"
+msgstr "trasformazione"
+
+#: models.py:272 views.py:591
+msgid "arguments"
+msgstr "argomenti"
+
+#: models.py:272
+#, python-format
+msgid "Use dictionaries to indentify arguments, example: %s"
+msgstr "Usa dei dizionari per identificare gli argomenti , esempio: %s"
+
+#: models.py:283
+msgid "document source transformation"
+msgstr "trasformazione del documento sorgente"
+
+#: models.py:284
+msgid "document source transformations"
+msgstr "trasformazioni dei documenti sorgente"
+
+#: models.py:290 models.py:291
+msgid "out of process"
+msgstr ""
+
+#: permissions.py:7
+msgid "Sources setup"
+msgstr "Setup sorgente"
+
+#: permissions.py:8
+msgid "View existing document sources"
+msgstr "Visualizza sorgenti documento esistente"
+
+#: permissions.py:9
+msgid "Edit document sources"
+msgstr "Modifica sorgenti dei documenti"
+
+#: permissions.py:10
+msgid "Delete document sources"
+msgstr "Cancella sorgenti dei documenti"
+
+#: permissions.py:11
+msgid "Create new document sources"
+msgstr "Crea nuova sorgente dei documenti"
+
+#: staging.py:44
+#, python-format
+msgid "Unable get list of staging files: %s"
+msgstr "Impossibile ottenere lista dei file di gestione temporanea: %s"
+
+#: staging.py:129
+#, python-format
+msgid "Unable to upload staging file: %s"
+msgstr "Impossibile caricare file di gestione temporanea: %s"
+
+#: staging.py:139
+#, python-format
+msgid "Unable to delete staging file: %s"
+msgstr "Impossibile eliminare file di gestione temporanea: %s"
+
+#: utils.py:40
+msgid "Whitelist Blacklist validation error."
+msgstr "Errori di validazione nelle Whitelist e Blacklist."
+
+#: views.py:98
+msgid "here"
+msgstr "qui"
+
+#: views.py:103
+msgid "Upload sources"
+msgstr "Sorgenti caricamento"
+
+#: views.py:105
+msgid ""
+"No interactive document sources have been defined or none have been enabled."
+msgstr ""
+"Nessuna fonte interattiva dei documenti sono state definite o non ne sono "
+"state attivate."
+
+#: views.py:106
+#, python-format
+msgid "Click %(setup_link)s to add or enable some document sources."
+msgstr ""
+"Click %(setup_link)s per aggiungere o abilitare una sorgente documenti."
+
+#: views.py:163
+msgid "New document version uploaded successfully."
+msgstr ""
+
+#: views.py:167
+msgid "File uploaded successfully."
+msgstr ""
+
+#: views.py:170
+msgid "File uncompressed successfully and uploaded as individual files."
+msgstr ""
+
+#: views.py:173
+msgid "File was not a compressed file, uploaded as it was."
+msgstr ""
+
+#: views.py:179 views.py:258
+#, python-format
+msgid "Unhandled exception: %s"
+msgstr ""
+
+#: views.py:188
+#, python-format
+msgid "upload a new version from source: %s"
+msgstr ""
+
+#: views.py:190
+#, python-format
+msgid "upload a local document from source: %s"
+msgstr "carica un documento in locale dalla sorgente: %s"
+
+#: views.py:236
+#, python-format
+msgid "Document version from staging file: %s, uploaded successfully."
+msgstr ""
+
+#: views.py:239
+#, python-format
+msgid "Staging file: %s, uploaded successfully."
+msgstr "File in allestimento:%s, caricato con successo."
+
+#: views.py:242
+#, python-format
+msgid ""
+"Staging file: %s, uncompressed successfully and uploaded as individual "
+"files."
+msgstr ""
+
+#: views.py:245
+#, python-format
+msgid "Staging file: %s, was not compressed, uploaded as a single file."
+msgstr ""
+
+#: views.py:250
+#, python-format
+msgid "Staging file: %s, deleted successfully."
+msgstr "File in allestimento:%s, cancellato con successo."
+
+#: views.py:273
+#, python-format
+msgid "upload a new version from staging source: %s"
+msgstr ""
+
+#: views.py:275
+#, python-format
+msgid "upload a document from staging source: %s"
+msgstr "carica documento dalla sorgente allestimento:%s"
+
+#: views.py:288
+msgid "files in staging path"
+msgstr "path dei file in allestimento"
+
+#: views.py:320
+msgid "Current document type"
+msgstr ""
+
+#: views.py:321
+msgid "None"
+msgstr ""
+
+#: views.py:328
+msgid "Current metadata"
+msgstr "Metadati correnti"
+
+#: views.py:366 views.py:385
+#, python-format
+msgid "Staging file transformation error: %(error)s"
+msgstr "Errore nella trasformazione del file: %(error)s"
+
+#: views.py:408
+msgid "Staging file delete successfully."
+msgstr "File in allestimento cancellato con successo."
+
+#: views.py:410
+#, python-format
+msgid "Staging file delete error; %s."
+msgstr "Errore nella cancellazione del file in allestimento;%s."
+
+#: views.py:470
+msgid "Source edited successfully"
+msgstr "Sorgente modificata con successo"
+
+#: views.py:473
+#, python-format
+msgid "Error editing source; %s"
+msgstr "Errore nella modifica del sorgente;%s"
+
+#: views.py:478
+#, python-format
+msgid "edit source: %s"
+msgstr "modifica sorgente:%s"
+
+#: views.py:483 views.py:523 views.py:585 views.py:626 views.py:656
+#: views.py:699
+msgid "source"
+msgstr "sorgente"
+
+#: views.py:512
+#, python-format
+msgid "Source \"%s\" deleted successfully."
+msgstr "Sorgente \"%s\" cancellata con successo."
+
+#: views.py:514
+#, python-format
+msgid "Error deleting source \"%(source)s\": %(error)s"
+msgstr "Errore nella cancellazione della sorgente \"%(source)s\": %(error)s"
+
+#: views.py:521
+#, python-format
+msgid "Are you sure you wish to delete the source: %s?"
+msgstr "Sei sicuro di voler cancellare la sorgente: %s?"
+
+#: views.py:553
+msgid "Source created successfully"
+msgstr "Sorgente creata con successo"
+
+#: views.py:556
+#, python-format
+msgid "Error creating source; %s"
+msgstr "Errore nella creazione della sorgente;%s"
+
+#: views.py:561
+#, python-format
+msgid "Create new source of type: %s"
+msgstr "Crea nuovo tipo di sorgente:%s"
+
+#: views.py:583
+#, python-format
+msgid "transformations for: %s"
+msgstr "trasformazione per: %s"
+
+#: views.py:613
+msgid "Source transformation edited successfully"
+msgstr "Sorgente per la trasformazione modificata con successo"
+
+#: views.py:616
+#, python-format
+msgid "Error editing source transformation; %s"
+msgstr "Errore nella modifica della sorgente per la trasformazione;%s"
+
+#: views.py:621
+#, python-format
+msgid "Edit transformation: %s"
+msgstr "Modifica trasformazione:%s"
+
+#: views.py:644
+msgid "Source transformation deleted successfully."
+msgstr "Sorgente per la trasformazione cancellata con successo."
+
+#: views.py:646
+#, python-format
+msgid "Error deleting source transformation; %(error)s"
+msgstr ""
+"Erroro nella cancellazione della sorgente per la trasformazione; %(error)s"
+
+#: views.py:659
+#, python-format
+msgid ""
+"Are you sure you wish to delete source transformation \"%(transformation)s\""
+msgstr ""
+"Sei sicuro di voler cancellare la sorgente di trasformazione "
+"\"%(transformation)s\""
+
+#: views.py:689
+msgid "Source transformation created successfully"
+msgstr "Sorgente di trasformazione creata con successo"
+
+#: views.py:692
+#, python-format
+msgid "Error creating source transformation; %s"
+msgstr "Errore nella creazione della sorgente di trasformazione; %s"
+
+#: views.py:701
+#, python-format
+msgid "Create new transformation for source: %s"
+msgstr "Crea una nuova sorgente per la trasformazione:%s"
+
+
diff --git a/apps/sources/locale/pl/LC_MESSAGES/django.mo b/apps/sources/locale/pl/LC_MESSAGES/django.mo
new file mode 100644
index 0000000000..77f71c4ef5
Binary files /dev/null and b/apps/sources/locale/pl/LC_MESSAGES/django.mo differ
diff --git a/apps/sources/locale/pl/LC_MESSAGES/django.po b/apps/sources/locale/pl/LC_MESSAGES/django.po
new file mode 100644
index 0000000000..e046cb780b
--- /dev/null
+++ b/apps/sources/locale/pl/LC_MESSAGES/django.po
@@ -0,0 +1,525 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# , 2012.
+msgid ""
+msgstr ""
+"Project-Id-Version: Mayan EDMS\n"
+"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
+"PO-Revision-Date: 2012-02-21 21:20+0000\n"
+"Last-Translator: mic \n"
+"Language-Team: Polish (http://www.transifex.net/projects/p/mayan-edms/language/pl/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: pl\n"
+"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
+
+#: __init__.py:19
+msgid "preview"
+msgstr "podgląd"
+
+#: __init__.py:20 __init__.py:28 __init__.py:34
+msgid "delete"
+msgstr "usunąć"
+
+#: __init__.py:22
+msgid "sources"
+msgstr "źródła"
+
+#: __init__.py:23 literals.py:53 models.py:203
+msgid "web forms"
+msgstr ""
+
+#: __init__.py:24 models.py:174
+msgid "staging folders"
+msgstr ""
+
+#: __init__.py:25 models.py:238
+msgid "watch folders"
+msgstr ""
+
+#: __init__.py:27 __init__.py:33
+msgid "edit"
+msgstr "edycja"
+
+#: __init__.py:29
+msgid "add new source"
+msgstr ""
+
+#: __init__.py:31
+msgid "transformations"
+msgstr ""
+
+#: __init__.py:32
+msgid "add transformation"
+msgstr ""
+
+#: __init__.py:36
+msgid "Document sources"
+msgstr ""
+
+#: __init__.py:38
+msgid "upload new version"
+msgstr "Prześlij nową wersję"
+
+#: __init__.py:68 widgets.py:39
+msgid "thumbnail"
+msgstr "miniatura"
+
+#: forms.py:34 forms.py:59
+msgid "Expand compressed files"
+msgstr ""
+
+#: forms.py:35 forms.py:60
+msgid "Upload a compressed file's contained files as individual documents"
+msgstr ""
+
+#: forms.py:43
+msgid "Staging file"
+msgstr ""
+
+#: forms.py:50
+msgid "File"
+msgstr "Plik"
+
+#: literals.py:8 literals.py:13
+msgid "Always"
+msgstr "Zawsze"
+
+#: literals.py:9 literals.py:14
+msgid "Never"
+msgstr "Nigdy"
+
+#: literals.py:15
+msgid "Ask user"
+msgstr "Pytaj użytkownika"
+
+#: literals.py:30
+msgid "Disk"
+msgstr "Dysk"
+
+#: literals.py:31
+msgid "Database"
+msgstr "Baza danych"
+
+#: literals.py:32
+msgid "Drive"
+msgstr ""
+
+#: literals.py:33
+msgid "Network drive"
+msgstr "Dysk sieciowy"
+
+#: literals.py:34
+msgid "User drive"
+msgstr ""
+
+#: literals.py:35
+msgid "Envelope"
+msgstr "Koperta"
+
+#: literals.py:36
+msgid "Folder"
+msgstr "Folder"
+
+#: literals.py:37
+msgid "World"
+msgstr "Świat"
+
+#: literals.py:38
+msgid "Printer"
+msgstr "Drukarka"
+
+#: literals.py:39
+msgid "Empty printer"
+msgstr "Pusta drukarka"
+
+#: literals.py:47 models.py:202
+msgid "web form"
+msgstr ""
+
+#: literals.py:48
+msgid "server staging folder"
+msgstr ""
+
+#: literals.py:49
+msgid "server watch folder"
+msgstr ""
+
+#: literals.py:54
+msgid "server staging folders"
+msgstr ""
+
+#: literals.py:55
+msgid "server watch folders"
+msgstr ""
+
+#: models.py:37
+msgid "title"
+msgstr "tytuł"
+
+#: models.py:38
+msgid "enabled"
+msgstr "włączony"
+
+#: models.py:39
+msgid "whitelist"
+msgstr "biała lista"
+
+#: models.py:40
+msgid "blacklist"
+msgstr "czarna lista"
+
+#: models.py:142
+msgid "icon"
+msgstr "ikona"
+
+#: models.py:142
+msgid "An icon to visually distinguish this source."
+msgstr ""
+
+#: models.py:158 models.py:210
+msgid "folder path"
+msgstr ""
+
+#: models.py:158 models.py:210
+msgid "Server side filesystem path."
+msgstr ""
+
+#: models.py:159
+msgid "preview width"
+msgstr ""
+
+#: models.py:159
+msgid "Width value to be passed to the converter backend."
+msgstr ""
+
+#: models.py:160
+msgid "preview height"
+msgstr ""
+
+#: models.py:160
+msgid "Height value to be passed to the converter backend."
+msgstr ""
+
+#: models.py:161 models.py:198 models.py:211
+msgid "uncompress"
+msgstr "rozpakuj"
+
+#: models.py:161 models.py:198 models.py:211
+msgid "Whether to expand or not compressed archives."
+msgstr ""
+
+#: models.py:162 models.py:212
+msgid "delete after upload"
+msgstr ""
+
+#: models.py:162 models.py:212
+msgid "Delete the file after is has been successfully uploaded."
+msgstr ""
+
+#: models.py:173
+msgid "staging folder"
+msgstr ""
+
+#: models.py:213
+msgid "interval"
+msgstr ""
+
+#: models.py:213
+msgid ""
+"Inverval in seconds where the watch folder path is checked for new "
+"documents."
+msgstr ""
+
+#: models.py:237
+msgid "watch folder"
+msgstr "sprawdzaj folder"
+
+#: models.py:242
+msgid "Enter a valid value."
+msgstr "Wprowadź poprawną wartość."
+
+#: models.py:270 views.py:589
+msgid "order"
+msgstr ""
+
+#: models.py:271 views.py:590 views.py:627 views.py:657
+msgid "transformation"
+msgstr ""
+
+#: models.py:272 views.py:591
+msgid "arguments"
+msgstr ""
+
+#: models.py:272
+#, python-format
+msgid "Use dictionaries to indentify arguments, example: %s"
+msgstr ""
+
+#: models.py:283
+msgid "document source transformation"
+msgstr ""
+
+#: models.py:284
+msgid "document source transformations"
+msgstr ""
+
+#: models.py:290 models.py:291
+msgid "out of process"
+msgstr ""
+
+#: permissions.py:7
+msgid "Sources setup"
+msgstr ""
+
+#: permissions.py:8
+msgid "View existing document sources"
+msgstr ""
+
+#: permissions.py:9
+msgid "Edit document sources"
+msgstr ""
+
+#: permissions.py:10
+msgid "Delete document sources"
+msgstr ""
+
+#: permissions.py:11
+msgid "Create new document sources"
+msgstr ""
+
+#: staging.py:44
+#, python-format
+msgid "Unable get list of staging files: %s"
+msgstr ""
+
+#: staging.py:129
+#, python-format
+msgid "Unable to upload staging file: %s"
+msgstr ""
+
+#: staging.py:139
+#, python-format
+msgid "Unable to delete staging file: %s"
+msgstr ""
+
+#: utils.py:40
+msgid "Whitelist Blacklist validation error."
+msgstr ""
+
+#: views.py:98
+msgid "here"
+msgstr ""
+
+#: views.py:103
+msgid "Upload sources"
+msgstr ""
+
+#: views.py:105
+msgid ""
+"No interactive document sources have been defined or none have been enabled."
+msgstr ""
+
+#: views.py:106
+#, python-format
+msgid "Click %(setup_link)s to add or enable some document sources."
+msgstr ""
+
+#: views.py:163
+msgid "New document version uploaded successfully."
+msgstr "Nowa wersja dokument została pomyślnie przesłana."
+
+#: views.py:167
+msgid "File uploaded successfully."
+msgstr "Plik został pomyślnie przesłany."
+
+#: views.py:170
+msgid "File uncompressed successfully and uploaded as individual files."
+msgstr "Plik rozpakowany pomyślnie i przesłany w osobnych plikach."
+
+#: views.py:173
+msgid "File was not a compressed file, uploaded as it was."
+msgstr "Plik nie był skompresowany , przesłane w oryginale"
+
+#: views.py:179 views.py:258
+#, python-format
+msgid "Unhandled exception: %s"
+msgstr ""
+
+#: views.py:188
+#, python-format
+msgid "upload a new version from source: %s"
+msgstr ""
+
+#: views.py:190
+#, python-format
+msgid "upload a local document from source: %s"
+msgstr ""
+
+#: views.py:236
+#, python-format
+msgid "Document version from staging file: %s, uploaded successfully."
+msgstr ""
+
+#: views.py:239
+#, python-format
+msgid "Staging file: %s, uploaded successfully."
+msgstr ""
+
+#: views.py:242
+#, python-format
+msgid ""
+"Staging file: %s, uncompressed successfully and uploaded as individual "
+"files."
+msgstr ""
+
+#: views.py:245
+#, python-format
+msgid "Staging file: %s, was not compressed, uploaded as a single file."
+msgstr ""
+
+#: views.py:250
+#, python-format
+msgid "Staging file: %s, deleted successfully."
+msgstr ""
+
+#: views.py:273
+#, python-format
+msgid "upload a new version from staging source: %s"
+msgstr ""
+
+#: views.py:275
+#, python-format
+msgid "upload a document from staging source: %s"
+msgstr ""
+
+#: views.py:288
+msgid "files in staging path"
+msgstr ""
+
+#: views.py:320
+msgid "Current document type"
+msgstr ""
+
+#: views.py:321
+msgid "None"
+msgstr ""
+
+#: views.py:328
+msgid "Current metadata"
+msgstr ""
+
+#: views.py:366 views.py:385
+#, python-format
+msgid "Staging file transformation error: %(error)s"
+msgstr ""
+
+#: views.py:408
+msgid "Staging file delete successfully."
+msgstr ""
+
+#: views.py:410
+#, python-format
+msgid "Staging file delete error; %s."
+msgstr ""
+
+#: views.py:470
+msgid "Source edited successfully"
+msgstr ""
+
+#: views.py:473
+#, python-format
+msgid "Error editing source; %s"
+msgstr ""
+
+#: views.py:478
+#, python-format
+msgid "edit source: %s"
+msgstr "edytować źródło:%s"
+
+#: views.py:483 views.py:523 views.py:585 views.py:626 views.py:656
+#: views.py:699
+msgid "source"
+msgstr "źródło"
+
+#: views.py:512
+#, python-format
+msgid "Source \"%s\" deleted successfully."
+msgstr "Źródło \"%s\" zostało usunięte."
+
+#: views.py:514
+#, python-format
+msgid "Error deleting source \"%(source)s\": %(error)s"
+msgstr ""
+
+#: views.py:521
+#, python-format
+msgid "Are you sure you wish to delete the source: %s?"
+msgstr "Czy na pewno chcesz usunąć źródło:%s?"
+
+#: views.py:553
+msgid "Source created successfully"
+msgstr "Źródło pomyślnie utworzone"
+
+#: views.py:556
+#, python-format
+msgid "Error creating source; %s"
+msgstr "Błąd podczas tworzenia źródła;%s"
+
+#: views.py:561
+#, python-format
+msgid "Create new source of type: %s"
+msgstr "Utwórz nowe typ źródło:%s"
+
+#: views.py:583
+#, python-format
+msgid "transformations for: %s"
+msgstr ""
+
+#: views.py:613
+msgid "Source transformation edited successfully"
+msgstr ""
+
+#: views.py:616
+#, python-format
+msgid "Error editing source transformation; %s"
+msgstr ""
+
+#: views.py:621
+#, python-format
+msgid "Edit transformation: %s"
+msgstr ""
+
+#: views.py:644
+msgid "Source transformation deleted successfully."
+msgstr ""
+
+#: views.py:646
+#, python-format
+msgid "Error deleting source transformation; %(error)s"
+msgstr ""
+
+#: views.py:659
+#, python-format
+msgid ""
+"Are you sure you wish to delete source transformation \"%(transformation)s\""
+msgstr ""
+
+#: views.py:689
+msgid "Source transformation created successfully"
+msgstr ""
+
+#: views.py:692
+#, python-format
+msgid "Error creating source transformation; %s"
+msgstr ""
+
+#: views.py:701
+#, python-format
+msgid "Create new transformation for source: %s"
+msgstr ""
diff --git a/apps/sources/locale/pt/LC_MESSAGES/django.mo b/apps/sources/locale/pt/LC_MESSAGES/django.mo
index 242213a5ba..6f2e4bc1cd 100644
Binary files a/apps/sources/locale/pt/LC_MESSAGES/django.mo and b/apps/sources/locale/pt/LC_MESSAGES/django.mo differ
diff --git a/apps/sources/locale/pt/LC_MESSAGES/django.po b/apps/sources/locale/pt/LC_MESSAGES/django.po
index 0e71ddee4e..2898677a7d 100644
--- a/apps/sources/locale/pt/LC_MESSAGES/django.po
+++ b/apps/sources/locale/pt/LC_MESSAGES/django.po
@@ -1,105 +1,93 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
-#
+#
# Translators:
# , 2011.
msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-11-22 11:26-0400\n"
-"PO-Revision-Date: 2011-11-02 01:21+0000\n"
-"Last-Translator: emersonsoares \n"
-"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/"
-"team/pt/)\n"
-"Language: pt\n"
+"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
+"PO-Revision-Date: 2012-02-12 19:23+0000\n"
+"Last-Translator: Roberto Rosario \n"
+"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/team/pt/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
+"Language: pt\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
-#: __init__.py:14
-msgid "View existing document sources"
-msgstr "Ver fontes de documentos existentes"
-
-#: __init__.py:15
-msgid "Edit document sources"
-msgstr "Editar fontes de documentos"
-
-#: __init__.py:16
-msgid "Delete document sources"
-msgstr "Excluir fontes de documentos"
-
-#: __init__.py:17
-msgid "Create new document sources"
-msgstr "Criar novas fontes de documentos"
-
#: __init__.py:19
-msgid "Sources setup"
-msgstr "Configuração de fontes"
-
-#: __init__.py:25
msgid "preview"
msgstr "visualização"
-#: __init__.py:26 __init__.py:34 __init__.py:40
+#: __init__.py:20 __init__.py:28 __init__.py:34
msgid "delete"
msgstr "excluir"
-#: __init__.py:28
+#: __init__.py:22
msgid "sources"
msgstr "fontes"
-#: __init__.py:29 literals.py:53 models.py:159
+#: __init__.py:23 literals.py:53 models.py:203
msgid "web forms"
msgstr "formulários web"
-#: __init__.py:30 models.py:130
+#: __init__.py:24 models.py:174
msgid "staging folders"
msgstr "staging folders"
-#: __init__.py:31 models.py:194
+#: __init__.py:25 models.py:238
msgid "watch folders"
msgstr "assistir pastas"
-#: __init__.py:33 __init__.py:39
+#: __init__.py:27 __init__.py:33
msgid "edit"
msgstr "editar"
-#: __init__.py:35
+#: __init__.py:29
msgid "add new source"
msgstr "adicionar nova fonte"
-#: __init__.py:37
+#: __init__.py:31
msgid "transformations"
msgstr "transformações"
-#: __init__.py:38
+#: __init__.py:32
msgid "add transformation"
msgstr "adicionar transformação"
-#: __init__.py:42
+#: __init__.py:36
msgid "Document sources"
msgstr "Fontes de documentos"
-#: __init__.py:69 widgets.py:39
+#: __init__.py:38
+msgid "upload new version"
+msgstr ""
+
+#: __init__.py:68 widgets.py:39
msgid "thumbnail"
msgstr "miniaturas"
-#: forms.py:32 forms.py:55
+#: forms.py:34 forms.py:59
msgid "Expand compressed files"
msgstr "Expandir arquivos compactados"
-#: forms.py:33 forms.py:56
+#: forms.py:35 forms.py:60
msgid "Upload a compressed file's contained files as individual documents"
msgstr ""
-"Upload de um arquivo compactado contendo arquivos como documentos individuais"
+"Upload de um arquivo compactado contendo arquivos como documentos "
+"individuais"
-#: forms.py:41
+#: forms.py:43
msgid "Staging file"
msgstr "Preparação de arquivo"
+#: forms.py:50
+msgid "File"
+msgstr ""
+
#: literals.py:8 literals.py:13
msgid "Always"
msgstr "Sempre"
@@ -152,7 +140,7 @@ msgstr "Impressora"
msgid "Empty printer"
msgstr "Impressora vazia"
-#: literals.py:47 models.py:158
+#: literals.py:47 models.py:202
msgid "web form"
msgstr "formulário web"
@@ -172,129 +160,154 @@ msgstr "server staging folders"
msgid "server watch folders"
msgstr "assistir pastas do servidor"
-#: models.py:29
+#: models.py:37
msgid "title"
msgstr "título"
-#: models.py:30
+#: models.py:38
msgid "enabled"
msgstr "habilitado"
-#: models.py:31
+#: models.py:39
msgid "whitelist"
msgstr "lista branca"
-#: models.py:32
+#: models.py:40
msgid "blacklist"
msgstr "lista negra"
-#: models.py:98
+#: models.py:142
msgid "icon"
msgstr "ícone"
-#: models.py:98
+#: models.py:142
msgid "An icon to visually distinguish this source."
msgstr "Um ícone para distinguir visualmente essa fonte."
-#: models.py:114 models.py:166
+#: models.py:158 models.py:210
msgid "folder path"
msgstr "caminho da pasta"
-#: models.py:114 models.py:166
+#: models.py:158 models.py:210
msgid "Server side filesystem path."
msgstr "Caminho do sistema do servidor"
-#: models.py:115
+#: models.py:159
msgid "preview width"
msgstr "largura de visualização"
-#: models.py:115
+#: models.py:159
msgid "Width value to be passed to the converter backend."
msgstr "Valor da largura a ser passado para o backend conversor."
-#: models.py:116
+#: models.py:160
msgid "preview height"
msgstr "altura de visualização"
-#: models.py:116
+#: models.py:160
msgid "Height value to be passed to the converter backend."
msgstr "Valor de altura para ser passado para o backend conversor."
-#: models.py:117 models.py:154 models.py:167
+#: models.py:161 models.py:198 models.py:211
msgid "uncompress"
msgstr "descompactar"
-#: models.py:117 models.py:154 models.py:167
+#: models.py:161 models.py:198 models.py:211
msgid "Whether to expand or not compressed archives."
msgstr "Se expandir ou não arquivos compactados."
-#: models.py:118 models.py:168
+#: models.py:162 models.py:212
msgid "delete after upload"
msgstr "excluir após o upload"
-#: models.py:118 models.py:168
+#: models.py:162 models.py:212
msgid "Delete the file after is has been successfully uploaded."
msgstr "Excluir o arquivo depois de ter sido carregado com sucesso."
-#: models.py:129
+#: models.py:173
msgid "staging folder"
msgstr "preparação de pasta"
-#: models.py:169
+#: models.py:213
msgid "interval"
msgstr "intervalo"
-#: models.py:169
+#: models.py:213
msgid ""
-"Inverval in seconds where the watch folder path is checked for new documents."
+"Inverval in seconds where the watch folder path is checked for new "
+"documents."
msgstr ""
"Invervalo em segundos, onde o caminho da pasta assistida está marcada para "
"novos documentos."
-#: models.py:193
+#: models.py:237
msgid "watch folder"
msgstr "assistir pasta"
-#: models.py:198
+#: models.py:242
msgid "Enter a valid value."
msgstr "Digite um valor válido."
-#: models.py:226 views.py:487
+#: models.py:270 views.py:589
msgid "order"
msgstr "ordem"
-#: models.py:227 views.py:488 views.py:525 views.py:555
+#: models.py:271 views.py:590 views.py:627 views.py:657
msgid "transformation"
msgstr "transformação"
-#: models.py:228 views.py:489
+#: models.py:272 views.py:591
msgid "arguments"
msgstr "argumentos"
-#: models.py:228
+#: models.py:272
#, python-format
msgid "Use dictionaries to indentify arguments, example: %s"
msgstr "Use dicionários para identificar os argumentos, exemplo: %s"
-#: models.py:239
+#: models.py:283
msgid "document source transformation"
msgstr "transformação do documento de origem"
-#: models.py:240
+#: models.py:284
msgid "document source transformations"
msgstr "fonte de transformações de documentos"
-#: staging.py:42
+#: models.py:290 models.py:291
+msgid "out of process"
+msgstr ""
+
+#: permissions.py:7
+msgid "Sources setup"
+msgstr "Configuração de fontes"
+
+#: permissions.py:8
+msgid "View existing document sources"
+msgstr "Ver fontes de documentos existentes"
+
+#: permissions.py:9
+msgid "Edit document sources"
+msgstr "Editar fontes de documentos"
+
+#: permissions.py:10
+msgid "Delete document sources"
+msgstr "Excluir fontes de documentos"
+
+#: permissions.py:11
+msgid "Create new document sources"
+msgstr "Criar novas fontes de documentos"
+
+#: staging.py:44
#, python-format
msgid "Unable get list of staging files: %s"
msgstr "Unable get list of staging files: %s"
-#: staging.py:127
+#: staging.py:129
#, python-format
msgid "Unable to upload staging file: %s"
msgstr "Unable to upload staging file: %s"
-#: staging.py:137
+#: staging.py:139
#, python-format
msgid "Unable to delete staging file: %s"
msgstr "Unable to delete staging file: %s"
@@ -303,151 +316,203 @@ msgstr "Unable to delete staging file: %s"
msgid "Whitelist Blacklist validation error."
msgstr "Erro de validação da Lista Negra e da Lista Branca"
-#: views.py:80
+#: views.py:98
msgid "here"
msgstr "aqui"
-#: views.py:85
+#: views.py:103
msgid "Upload sources"
msgstr "Carregar fontes"
-#: views.py:87
+#: views.py:105
msgid ""
"No interactive document sources have been defined or none have been enabled."
msgstr ""
"Nenhuma fonte de documento interativo foi definido ou nenhuma delas foi "
"ativada."
-#: views.py:88
+#: views.py:106
#, python-format
msgid "Click %(setup_link)s to add or enable some document sources."
msgstr ""
"Clique %(setup_link)s para adicionar ou permitir algumas fontes de "
"documentos."
-#: views.py:136
-msgid "Document uploaded successfully."
-msgstr "Documento enviado com sucesso."
+#: views.py:163
+msgid "New document version uploaded successfully."
+msgstr ""
-#: views.py:152
+#: views.py:167
+msgid "File uploaded successfully."
+msgstr ""
+
+#: views.py:170
+msgid "File uncompressed successfully and uploaded as individual files."
+msgstr ""
+
+#: views.py:173
+msgid "File was not a compressed file, uploaded as it was."
+msgstr ""
+
+#: views.py:179 views.py:258
+#, python-format
+msgid "Unhandled exception: %s"
+msgstr ""
+
+#: views.py:188
+#, python-format
+msgid "upload a new version from source: %s"
+msgstr ""
+
+#: views.py:190
#, python-format
msgid "upload a local document from source: %s"
msgstr "carregar um documento local da fonte: %s"
-#: views.py:182
+#: views.py:236
+#, python-format
+msgid "Document version from staging file: %s, uploaded successfully."
+msgstr ""
+
+#: views.py:239
#, python-format
msgid "Staging file: %s, uploaded successfully."
msgstr "Staging file: %s, uploaded successfully."
-#: views.py:187
+#: views.py:242
+#, python-format
+msgid ""
+"Staging file: %s, uncompressed successfully and uploaded as individual "
+"files."
+msgstr ""
+
+#: views.py:245
+#, python-format
+msgid "Staging file: %s, was not compressed, uploaded as a single file."
+msgstr ""
+
+#: views.py:250
#, python-format
msgid "Staging file: %s, deleted successfully."
msgstr "Staging file: %s, deleted successfully."
-#: views.py:209
+#: views.py:273
+#, python-format
+msgid "upload a new version from staging source: %s"
+msgstr ""
+
+#: views.py:275
#, python-format
msgid "upload a document from staging source: %s"
msgstr "upload a document from staging source: %s"
-#: views.py:215
+#: views.py:288
msgid "files in staging path"
msgstr "files in staging path"
-#: views.py:229
+#: views.py:320
+msgid "Current document type"
+msgstr ""
+
+#: views.py:321
+msgid "None"
+msgstr ""
+
+#: views.py:328
msgid "Current metadata"
msgstr "Metadados atuais"
-#: views.py:265 views.py:284
+#: views.py:366 views.py:385
#, python-format
msgid "Staging file transformation error: %(error)s"
msgstr "Staging file transformation error: %(error)s"
-#: views.py:307
+#: views.py:408
msgid "Staging file delete successfully."
msgstr "Staging file delete successfully."
-#: views.py:309
+#: views.py:410
#, python-format
msgid "Staging file delete error; %s."
msgstr "Staging file delete error; %s."
-#: views.py:368
+#: views.py:470
msgid "Source edited successfully"
msgstr "Fonte editada com sucesso"
-#: views.py:371
+#: views.py:473
#, python-format
msgid "Error editing source; %s"
msgstr "Erro ao editar fonte; %s"
-#: views.py:376
+#: views.py:478
#, python-format
msgid "edit source: %s"
msgstr "editar fonte: %s"
-#: views.py:381 views.py:421 views.py:483 views.py:524 views.py:554
-#: views.py:597
+#: views.py:483 views.py:523 views.py:585 views.py:626 views.py:656
+#: views.py:699
msgid "source"
msgstr "fonte"
-#: views.py:410
+#: views.py:512
#, python-format
msgid "Source \"%s\" deleted successfully."
msgstr "Fonte \"%s\" removida com sucesso."
-#: views.py:412
+#: views.py:514
#, python-format
msgid "Error deleting source \"%(source)s\": %(error)s"
msgstr "Erro ao excluir fonte \" %(source)s \": %(error)s "
-#: views.py:419
+#: views.py:521
#, python-format
msgid "Are you sure you wish to delete the source: %s?"
msgstr "Tem certeza de que deseja deletar a fonte: %s?"
-#: views.py:451
+#: views.py:553
msgid "Source created successfully"
msgstr "Fonte criada com sucesso"
-#: views.py:454
+#: views.py:556
#, python-format
msgid "Error creating source; %s"
msgstr "Erro ao criar fonte; %s"
-#: views.py:459
+#: views.py:561
#, python-format
msgid "Create new source of type: %s"
msgstr "Criar nova fonte do tipo: %s"
-#: views.py:481
+#: views.py:583
#, python-format
msgid "transformations for: %s"
msgstr "transformações para: %s"
-#: views.py:511
+#: views.py:613
msgid "Source transformation edited successfully"
msgstr "Transformação de fonte alterado com sucesso"
-#: views.py:514
+#: views.py:616
#, python-format
msgid "Error editing source transformation; %s"
msgstr "Erro ao editar transformação de fonte; %s"
-#: views.py:519
+#: views.py:621
#, python-format
msgid "Edit transformation: %s"
msgstr "Editar transformação: %s"
-#: views.py:542
+#: views.py:644
msgid "Source transformation deleted successfully."
msgstr "Transformação de fonte excluída com sucesso."
-#: views.py:544
+#: views.py:646
#, python-format
msgid "Error deleting source transformation; %(error)s"
msgstr "Erro ao deletar transformação de fonte; %(error)s "
-#: views.py:557
+#: views.py:659
#, python-format
msgid ""
"Are you sure you wish to delete source transformation \"%(transformation)s\""
@@ -455,16 +520,18 @@ msgstr ""
"Tem certeza de que deseja deletar a transformação de fonte \" "
"%(transformation)s \""
-#: views.py:587
+#: views.py:689
msgid "Source transformation created successfully"
msgstr "Transformação de fonte criada com sucesso"
-#: views.py:590
+#: views.py:692
#, python-format
msgid "Error creating source transformation; %s"
msgstr "Erro ao criar a transformação de fonte; %s"
-#: views.py:599
+#: views.py:701
#, python-format
msgid "Create new transformation for source: %s"
msgstr "Criar nova transformação de fonte: %s"
+
+
diff --git a/apps/sources/locale/ru/LC_MESSAGES/django.mo b/apps/sources/locale/ru/LC_MESSAGES/django.mo
index 90fbdf8a30..4a4717424c 100644
Binary files a/apps/sources/locale/ru/LC_MESSAGES/django.mo and b/apps/sources/locale/ru/LC_MESSAGES/django.mo differ
diff --git a/apps/sources/locale/ru/LC_MESSAGES/django.po b/apps/sources/locale/ru/LC_MESSAGES/django.po
index 86c34d5294..9683a35df2 100644
--- a/apps/sources/locale/ru/LC_MESSAGES/django.po
+++ b/apps/sources/locale/ru/LC_MESSAGES/django.po
@@ -1,105 +1,91 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
-#
+#
# Translators:
-# Sergey Glita , 2011.
+# Sergey Glita , 2011, 2012.
msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-11-22 11:26-0400\n"
-"PO-Revision-Date: 2011-11-04 15:25+0000\n"
-"Last-Translator: gsv70 \n"
-"Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/team/"
-"ru/)\n"
-"Language: ru\n"
+"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
+"PO-Revision-Date: 2012-02-27 04:24+0000\n"
+"Last-Translator: Sergey Glita \n"
+"Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/language/ru/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
-"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
-
-#: __init__.py:14
-msgid "View existing document sources"
-msgstr "Просмотр существующих источников документов"
-
-#: __init__.py:15
-msgid "Edit document sources"
-msgstr "Редактировать источник документов"
-
-#: __init__.py:16
-msgid "Delete document sources"
-msgstr "Удалить источник документов "
-
-#: __init__.py:17
-msgid "Create new document sources"
-msgstr "Создать новый источник документов"
+"Language: ru\n"
+"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
#: __init__.py:19
-msgid "Sources setup"
-msgstr "Настройки источников"
-
-#: __init__.py:25
msgid "preview"
msgstr "предварительный просмотр"
-#: __init__.py:26 __init__.py:34 __init__.py:40
+#: __init__.py:20 __init__.py:28 __init__.py:34
msgid "delete"
msgstr "удалить"
-#: __init__.py:28
+#: __init__.py:22
msgid "sources"
msgstr "источники"
-#: __init__.py:29 literals.py:53 models.py:159
+#: __init__.py:23 literals.py:53 models.py:203
msgid "web forms"
msgstr "web-формы"
-#: __init__.py:30 models.py:130
+#: __init__.py:24 models.py:174
msgid "staging folders"
msgstr "транспортные папки"
-#: __init__.py:31 models.py:194
+#: __init__.py:25 models.py:238
msgid "watch folders"
msgstr "наблюдаемые папки"
-#: __init__.py:33 __init__.py:39
+#: __init__.py:27 __init__.py:33
msgid "edit"
msgstr "редактировать"
-#: __init__.py:35
+#: __init__.py:29
msgid "add new source"
msgstr "добавить новый источник"
-#: __init__.py:37
+#: __init__.py:31
msgid "transformations"
msgstr "преобразования"
-#: __init__.py:38
+#: __init__.py:32
msgid "add transformation"
msgstr "добавить преобразование"
-#: __init__.py:42
+#: __init__.py:36
msgid "Document sources"
msgstr "Источники документов"
-#: __init__.py:69 widgets.py:39
+#: __init__.py:38
+msgid "upload new version"
+msgstr "загрузить новую версию"
+
+#: __init__.py:68 widgets.py:39
msgid "thumbnail"
msgstr "миниатюра"
-#: forms.py:32 forms.py:55
+#: forms.py:34 forms.py:59
msgid "Expand compressed files"
msgstr "Извлекать из архивов?"
-#: forms.py:33 forms.py:56
+#: forms.py:35 forms.py:60
msgid "Upload a compressed file's contained files as individual documents"
msgstr "Загрузить файлы, содержащиеся в архиве в качестве отдельных документов"
-#: forms.py:41
+#: forms.py:43
msgid "Staging file"
msgstr "Промежуточный файл"
+#: forms.py:50
+msgid "File"
+msgstr "Файл"
+
#: literals.py:8 literals.py:13
msgid "Always"
msgstr "Всегда"
@@ -152,7 +138,7 @@ msgstr "Принтер"
msgid "Empty printer"
msgstr "Пустой принтер"
-#: literals.py:47 models.py:158
+#: literals.py:47 models.py:202
msgid "web form"
msgstr "веб-формы"
@@ -172,128 +158,152 @@ msgstr "папки на промежуточном сервере"
msgid "server watch folders"
msgstr "наблюдаемые папки"
-#: models.py:29
+#: models.py:37
msgid "title"
msgstr "название"
-#: models.py:30
+#: models.py:38
msgid "enabled"
msgstr "разрешено"
-#: models.py:31
+#: models.py:39
msgid "whitelist"
msgstr "белый список"
-#: models.py:32
+#: models.py:40
msgid "blacklist"
msgstr "черный список"
-#: models.py:98
+#: models.py:142
msgid "icon"
msgstr "иконка"
-#: models.py:98
+#: models.py:142
msgid "An icon to visually distinguish this source."
msgstr "Значок, чтобы визуально отличать этот источник."
-#: models.py:114 models.py:166
+#: models.py:158 models.py:210
msgid "folder path"
msgstr "путь к папке"
-#: models.py:114 models.py:166
+#: models.py:158 models.py:210
msgid "Server side filesystem path."
msgstr "Путь на сервере"
-#: models.py:115
+#: models.py:159
msgid "preview width"
msgstr "ширина предпросмотра"
-#: models.py:115
+#: models.py:159
msgid "Width value to be passed to the converter backend."
msgstr "Ширина после обработки."
-#: models.py:116
+#: models.py:160
msgid "preview height"
msgstr "Предварительный просмотр высоты"
-#: models.py:116
+#: models.py:160
msgid "Height value to be passed to the converter backend."
msgstr "Высота после обработки."
-#: models.py:117 models.py:154 models.py:167
+#: models.py:161 models.py:198 models.py:211
msgid "uncompress"
msgstr "распаковать"
-#: models.py:117 models.py:154 models.py:167
+#: models.py:161 models.py:198 models.py:211
msgid "Whether to expand or not compressed archives."
msgstr "Независимо от того распакованы или нет архивы."
-#: models.py:118 models.py:168
+#: models.py:162 models.py:212
msgid "delete after upload"
msgstr "удалить после загрузки"
-#: models.py:118 models.py:168
+#: models.py:162 models.py:212
msgid "Delete the file after is has been successfully uploaded."
msgstr "Удалить файл после загрузки."
-#: models.py:129
+#: models.py:173
msgid "staging folder"
msgstr "промежуточная папка"
-#: models.py:169
+#: models.py:213
msgid "interval"
msgstr "интервал"
-#: models.py:169
+#: models.py:213
msgid ""
-"Inverval in seconds where the watch folder path is checked for new documents."
-msgstr ""
-"Интервал в секундах, между проверками папки на появление новых документов."
+"Inverval in seconds where the watch folder path is checked for new "
+"documents."
+msgstr "Интервал в секундах, между проверками папки на появление новых документов."
-#: models.py:193
+#: models.py:237
msgid "watch folder"
msgstr "просматривать папку"
-#: models.py:198
+#: models.py:242
msgid "Enter a valid value."
msgstr "Введите допустимое значение."
-#: models.py:226 views.py:487
+#: models.py:270 views.py:589
msgid "order"
msgstr "порядок"
-#: models.py:227 views.py:488 views.py:525 views.py:555
+#: models.py:271 views.py:590 views.py:627 views.py:657
msgid "transformation"
msgstr "преобразование"
-#: models.py:228 views.py:489
+#: models.py:272 views.py:591
msgid "arguments"
msgstr "аргументы"
-#: models.py:228
+#: models.py:272
#, python-format
msgid "Use dictionaries to indentify arguments, example: %s"
msgstr "Использование словарей для определения аргументов, например: %s"
-#: models.py:239
+#: models.py:283
msgid "document source transformation"
msgstr "преобразования источника документов"
-#: models.py:240
+#: models.py:284
msgid "document source transformations"
msgstr "преобразования источника документов"
-#: staging.py:42
+#: models.py:290 models.py:291
+msgid "out of process"
+msgstr "из процесса"
+
+#: permissions.py:7
+msgid "Sources setup"
+msgstr "Настройки источников"
+
+#: permissions.py:8
+msgid "View existing document sources"
+msgstr "Просмотр существующих источников документов"
+
+#: permissions.py:9
+msgid "Edit document sources"
+msgstr "Редактировать источник документов"
+
+#: permissions.py:10
+msgid "Delete document sources"
+msgstr "Удалить источник документов "
+
+#: permissions.py:11
+msgid "Create new document sources"
+msgstr "Создать новый источник документов"
+
+#: staging.py:44
#, python-format
msgid "Unable get list of staging files: %s"
msgstr "Не удалось получить список промежуточных файлов: %s"
-#: staging.py:127
+#: staging.py:129
#, python-format
msgid "Unable to upload staging file: %s"
msgstr "Невозможно загрузить промежуточный файл: %s"
-#: staging.py:137
+#: staging.py:139
#, python-format
msgid "Unable to delete staging file: %s"
msgstr "Не удается удалить промежуточный файл: %s"
@@ -302,165 +312,214 @@ msgstr "Не удается удалить промежуточный файл:
msgid "Whitelist Blacklist validation error."
msgstr "Ошибка проверки белого или черного списков."
-#: views.py:80
+#: views.py:98
msgid "here"
msgstr "здесь"
-#: views.py:85
+#: views.py:103
msgid "Upload sources"
msgstr "Загрузить источники"
-#: views.py:87
+#: views.py:105
msgid ""
"No interactive document sources have been defined or none have been enabled."
msgstr "Интерактивные источники документов не были определены разрешены."
-#: views.py:88
+#: views.py:106
#, python-format
msgid "Click %(setup_link)s to add or enable some document sources."
-msgstr ""
-"Нажмите %(setup_link)s, чтобы добавить или включить какой-нибудь документ "
-"источников."
+msgstr "Нажмите %(setup_link)s, чтобы добавить или включить какой-нибудь документ источников."
-#: views.py:136
-msgid "Document uploaded successfully."
-msgstr "Документ загружен успешно."
+#: views.py:163
+msgid "New document version uploaded successfully."
+msgstr "Новая версия документа загружена."
-#: views.py:152
+#: views.py:167
+msgid "File uploaded successfully."
+msgstr "Файл загружен."
+
+#: views.py:170
+msgid "File uncompressed successfully and uploaded as individual files."
+msgstr "Файл распакован и загружен в виде отдельных файлов."
+
+#: views.py:173
+msgid "File was not a compressed file, uploaded as it was."
+msgstr "Файл не сжат и загружен как есть."
+
+#: views.py:179 views.py:258
+#, python-format
+msgid "Unhandled exception: %s"
+msgstr "Необработанное исключение %s"
+
+#: views.py:188
+#, python-format
+msgid "upload a new version from source: %s"
+msgstr "загрузка новой версии из источника %s"
+
+#: views.py:190
#, python-format
msgid "upload a local document from source: %s"
msgstr "загрузить локальный документ из источника: %s"
-#: views.py:182
+#: views.py:236
+#, python-format
+msgid "Document version from staging file: %s, uploaded successfully."
+msgstr "Версия документа из транспортного файла %s загружена."
+
+#: views.py:239
#, python-format
msgid "Staging file: %s, uploaded successfully."
msgstr "Промежуточный файл %s загружен."
-#: views.py:187
+#: views.py:242
+#, python-format
+msgid ""
+"Staging file: %s, uncompressed successfully and uploaded as individual "
+"files."
+msgstr "Транспортный файл %s распакован и загружен в виде отдельных файлов."
+
+#: views.py:245
+#, python-format
+msgid "Staging file: %s, was not compressed, uploaded as a single file."
+msgstr "Транспортный файл %s не был сжат загруженные в исходном виде."
+
+#: views.py:250
#, python-format
msgid "Staging file: %s, deleted successfully."
msgstr "Постановка файл %s успешно удален."
-#: views.py:209
+#: views.py:273
+#, python-format
+msgid "upload a new version from staging source: %s"
+msgstr "загрузка новой версии из источника %s"
+
+#: views.py:275
#, python-format
msgid "upload a document from staging source: %s"
msgstr "загрузить документ из промежуточного источника %s"
-#: views.py:215
+#: views.py:288
msgid "files in staging path"
msgstr " файлы в транспортном пути"
-#: views.py:229
+#: views.py:320
+msgid "Current document type"
+msgstr "Текущий тип документа"
+
+#: views.py:321
+msgid "None"
+msgstr "Нет"
+
+#: views.py:328
msgid "Current metadata"
msgstr "Действующие метаданные"
-#: views.py:265 views.py:284
+#: views.py:366 views.py:385
#, python-format
msgid "Staging file transformation error: %(error)s"
msgstr "Ошибка преобразования транспортного файла: %(error)s"
-#: views.py:307
+#: views.py:408
msgid "Staging file delete successfully."
msgstr "Транспортный файл удалён."
-#: views.py:309
+#: views.py:410
#, python-format
msgid "Staging file delete error; %s."
msgstr "Ошибка удаления транспортного файла %s."
-#: views.py:368
+#: views.py:470
msgid "Source edited successfully"
msgstr "Источник успешно изменен"
-#: views.py:371
+#: views.py:473
#, python-format
msgid "Error editing source; %s"
msgstr "Ошибка редактирования источника; %s"
-#: views.py:376
+#: views.py:478
#, python-format
msgid "edit source: %s"
msgstr "редактировать источник: %s"
-#: views.py:381 views.py:421 views.py:483 views.py:524 views.py:554
-#: views.py:597
+#: views.py:483 views.py:523 views.py:585 views.py:626 views.py:656
+#: views.py:699
msgid "source"
msgstr "источник"
-#: views.py:410
+#: views.py:512
#, python-format
msgid "Source \"%s\" deleted successfully."
msgstr "Источник \"%s\"удален."
-#: views.py:412
+#: views.py:514
#, python-format
msgid "Error deleting source \"%(source)s\": %(error)s"
msgstr "Ошибка при удалении источника \"%(source)s\": %(error)s"
-#: views.py:419
+#: views.py:521
#, python-format
msgid "Are you sure you wish to delete the source: %s?"
msgstr "Вы действительно хотите удалить источник: %s?"
-#: views.py:451
+#: views.py:553
msgid "Source created successfully"
msgstr "Источник создан"
-#: views.py:454
+#: views.py:556
#, python-format
msgid "Error creating source; %s"
msgstr "Ошибка создания источника; %s"
-#: views.py:459
+#: views.py:561
#, python-format
msgid "Create new source of type: %s"
msgstr "Создать новый источник типа: %s"
-#: views.py:481
+#: views.py:583
#, python-format
msgid "transformations for: %s"
msgstr "преобразования для: %s"
-#: views.py:511
+#: views.py:613
msgid "Source transformation edited successfully"
msgstr "Преобразование источника изменено"
-#: views.py:514
+#: views.py:616
#, python-format
msgid "Error editing source transformation; %s"
msgstr "Ошибка редактирования преобразования источника; %s"
-#: views.py:519
+#: views.py:621
#, python-format
msgid "Edit transformation: %s"
msgstr "Изменить преобразование: %s"
-#: views.py:542
+#: views.py:644
msgid "Source transformation deleted successfully."
msgstr "Преобразование источника удалено."
-#: views.py:544
+#: views.py:646
#, python-format
msgid "Error deleting source transformation; %(error)s"
msgstr "Ошибка при удалении преобразования источника; %(error)s"
-#: views.py:557
+#: views.py:659
#, python-format
msgid ""
"Are you sure you wish to delete source transformation \"%(transformation)s\""
-msgstr ""
-"Вы действительно хотите удалить источник трансформации \"%(transformation)s\""
+msgstr "Вы действительно хотите удалить источник трансформации \"%(transformation)s\""
-#: views.py:587
+#: views.py:689
msgid "Source transformation created successfully"
msgstr "Преобразование источника создано"
-#: views.py:590
+#: views.py:692
#, python-format
msgid "Error creating source transformation; %s"
msgstr "Ошибка создания преобразования источника; %s"
-#: views.py:599
+#: views.py:701
#, python-format
msgid "Create new transformation for source: %s"
msgstr "Создать новое преобразование для источника: %s"
diff --git a/apps/sources/management/__init__.py b/apps/sources/management/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/apps/sources/management/commands/__init__.py b/apps/sources/management/commands/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/apps/sources/management/commands/bulk_upload.py b/apps/sources/management/commands/bulk_upload.py
new file mode 100644
index 0000000000..8fa11f652e
--- /dev/null
+++ b/apps/sources/management/commands/bulk_upload.py
@@ -0,0 +1,81 @@
+from __future__ import absolute_import
+
+import os
+import sys
+from optparse import make_option
+
+from django.core.management.base import BaseCommand, CommandError, LabelCommand
+from django.utils.simplejson import loads
+
+from metadata.api import convert_dict_to_dict_list
+from documents.models import DocumentType
+
+from ...models import OutOfProcess
+from ...compressed_file import CompressedFile, NotACompressedFile
+
+
+class Command(LabelCommand):
+ args = ''
+ help = 'Upload documents from a compressed file in to the database.'
+ option_list = LabelCommand.option_list + (
+ make_option('--noinput', action='store_false', dest='interactive',
+ default=True, help='Do not ask the user for confirmation before '
+ 'starting.'),
+ make_option('--metadata', action='store', dest='metadata',
+ help='A metadata dictionary list to apply to the documents.'),
+ make_option('--document_type', action='store', dest='document_type_name',
+ help='The document type to apply to the uploaded documents.'),
+ )
+
+ def handle_label(self, label, **options):
+ if not os.access(label, os.R_OK):
+ raise CommandError("File '%s' is not readable." % label)
+
+ if options['metadata']:
+ try:
+ metadata_dict = loads(options['metadata'])
+ metadata_dict_list = convert_dict_to_dict_list(metadata_dict)
+ except Exception, e:
+ sys.exit('Metadata error: %s' % e)
+ else:
+ metadata_dict_list = None
+
+ if options['document_type_name']:
+ try:
+ document_type = DocumentType.objects.get(name=options['document_type_name'])
+ except DocumentType.DoesNotExist:
+ sys.exit('Unknown document type')
+ else:
+ document_type = None
+
+ if _confirm(options['interactive']) == 'yes':
+ print 'Beginning upload...'
+ if metadata_dict_list:
+ print 'Using the metadata values:'
+ for key, value in metadata_dict.items():
+ print '%s: %s' % (key, value)
+
+ if document_type:
+ print 'Uploaded document will be of type: %s' % options['document_type_name']
+
+ source = OutOfProcess()
+ fd = open(label)
+ try:
+ result = source.upload_file(fd, filename=None, use_file_name=False, document_type=document_type, expand=True, metadata_dict_list=metadata_dict_list, user=None, document=None, new_version_data=None, command_line=True)
+ pass
+ except NotACompressedFile:
+ print '%s is not a compressed file.' % label
+ else:
+ print 'Finished.'
+
+ fd.close()
+ else:
+ print 'Cancelled.'
+
+
+def _confirm(interactive):
+ if not interactive:
+ return 'yes'
+ return raw_input('You have requested to bulk upload a number of documents from a compressed file.\n'
+ 'Are you sure you want to do this?\n'
+ 'Type \'yes\' to continue, or any other value to cancel: ')
diff --git a/apps/sources/managers.py b/apps/sources/managers.py
index 53aa143d5b..4e74ec7d4f 100644
--- a/apps/sources/managers.py
+++ b/apps/sources/managers.py
@@ -22,5 +22,5 @@ class SourceTransformationManager(models.Manager):
)
except (ValueError, SyntaxError), e:
warnings.append(e)
-
+
return transformations, warnings
diff --git a/apps/sources/migrations/0001_initial.py b/apps/sources/migrations/0001_initial.py
new file mode 100644
index 0000000000..e92afa7fcb
--- /dev/null
+++ b/apps/sources/migrations/0001_initial.py
@@ -0,0 +1,156 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Adding model 'StagingFolder'
+ db.create_table('sources_stagingfolder', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('title', self.gf('django.db.models.fields.CharField')(max_length=64)),
+ ('enabled', self.gf('django.db.models.fields.BooleanField')(default=True)),
+ ('whitelist', self.gf('django.db.models.fields.TextField')(blank=True)),
+ ('blacklist', self.gf('django.db.models.fields.TextField')(blank=True)),
+ ('icon', self.gf('django.db.models.fields.CharField')(max_length=24, null=True, blank=True)),
+ ('folder_path', self.gf('django.db.models.fields.CharField')(max_length=255)),
+ ('preview_width', self.gf('django.db.models.fields.IntegerField')(null=True, blank=True)),
+ ('preview_height', self.gf('django.db.models.fields.IntegerField')(null=True, blank=True)),
+ ('uncompress', self.gf('django.db.models.fields.CharField')(max_length=1)),
+ ('delete_after_upload', self.gf('django.db.models.fields.BooleanField')(default=True)),
+ ))
+ db.send_create_signal('sources', ['StagingFolder'])
+
+ # Adding model 'WebForm'
+ db.create_table('sources_webform', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('title', self.gf('django.db.models.fields.CharField')(max_length=64)),
+ ('enabled', self.gf('django.db.models.fields.BooleanField')(default=True)),
+ ('whitelist', self.gf('django.db.models.fields.TextField')(blank=True)),
+ ('blacklist', self.gf('django.db.models.fields.TextField')(blank=True)),
+ ('icon', self.gf('django.db.models.fields.CharField')(max_length=24, null=True, blank=True)),
+ ('uncompress', self.gf('django.db.models.fields.CharField')(max_length=1)),
+ ))
+ db.send_create_signal('sources', ['WebForm'])
+
+ # Adding model 'WatchFolder'
+ db.create_table('sources_watchfolder', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('title', self.gf('django.db.models.fields.CharField')(max_length=64)),
+ ('enabled', self.gf('django.db.models.fields.BooleanField')(default=True)),
+ ('whitelist', self.gf('django.db.models.fields.TextField')(blank=True)),
+ ('blacklist', self.gf('django.db.models.fields.TextField')(blank=True)),
+ ('folder_path', self.gf('django.db.models.fields.CharField')(max_length=255)),
+ ('uncompress', self.gf('django.db.models.fields.CharField')(max_length=1)),
+ ('delete_after_upload', self.gf('django.db.models.fields.BooleanField')(default=True)),
+ ('interval', self.gf('django.db.models.fields.PositiveIntegerField')()),
+ ))
+ db.send_create_signal('sources', ['WatchFolder'])
+
+ # Adding model 'SourceTransformation'
+ db.create_table('sources_sourcetransformation', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('content_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['contenttypes.ContentType'])),
+ ('object_id', self.gf('django.db.models.fields.PositiveIntegerField')()),
+ ('order', self.gf('django.db.models.fields.PositiveIntegerField')(default=0, null=True, db_index=True, blank=True)),
+ ('transformation', self.gf('django.db.models.fields.CharField')(max_length=128)),
+ ('arguments', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
+ ))
+ db.send_create_signal('sources', ['SourceTransformation'])
+
+ # Adding model 'OutOfProcess'
+ db.create_table('sources_outofprocess', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('title', self.gf('django.db.models.fields.CharField')(max_length=64)),
+ ('enabled', self.gf('django.db.models.fields.BooleanField')(default=True)),
+ ('whitelist', self.gf('django.db.models.fields.TextField')(blank=True)),
+ ('blacklist', self.gf('django.db.models.fields.TextField')(blank=True)),
+ ))
+ db.send_create_signal('sources', ['OutOfProcess'])
+
+
+ def backwards(self, orm):
+
+ # Deleting model 'StagingFolder'
+ db.delete_table('sources_stagingfolder')
+
+ # Deleting model 'WebForm'
+ db.delete_table('sources_webform')
+
+ # Deleting model 'WatchFolder'
+ db.delete_table('sources_watchfolder')
+
+ # Deleting model 'SourceTransformation'
+ db.delete_table('sources_sourcetransformation')
+
+ # Deleting model 'OutOfProcess'
+ db.delete_table('sources_outofprocess')
+
+
+ models = {
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'sources.outofprocess': {
+ 'Meta': {'ordering': "('title',)", 'object_name': 'OutOfProcess'},
+ 'blacklist': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'whitelist': ('django.db.models.fields.TextField', [], {'blank': 'True'})
+ },
+ 'sources.sourcetransformation': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'SourceTransformation'},
+ 'arguments': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'order': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0', 'null': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'transformation': ('django.db.models.fields.CharField', [], {'max_length': '128'})
+ },
+ 'sources.stagingfolder': {
+ 'Meta': {'ordering': "('title',)", 'object_name': 'StagingFolder'},
+ 'blacklist': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'delete_after_upload': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'folder_path': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'icon': ('django.db.models.fields.CharField', [], {'max_length': '24', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'preview_height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'preview_width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'uncompress': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'whitelist': ('django.db.models.fields.TextField', [], {'blank': 'True'})
+ },
+ 'sources.watchfolder': {
+ 'Meta': {'ordering': "('title',)", 'object_name': 'WatchFolder'},
+ 'blacklist': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'delete_after_upload': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'folder_path': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'interval': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'uncompress': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'whitelist': ('django.db.models.fields.TextField', [], {'blank': 'True'})
+ },
+ 'sources.webform': {
+ 'Meta': {'ordering': "('title',)", 'object_name': 'WebForm'},
+ 'blacklist': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'icon': ('django.db.models.fields.CharField', [], {'max_length': '24', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'uncompress': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'whitelist': ('django.db.models.fields.TextField', [], {'blank': 'True'})
+ }
+ }
+
+ complete_apps = ['sources']
diff --git a/apps/sources/migrations/0002_preview_width_required.py b/apps/sources/migrations/0002_preview_width_required.py
new file mode 100644
index 0000000000..3cb2587561
--- /dev/null
+++ b/apps/sources/migrations/0002_preview_width_required.py
@@ -0,0 +1,84 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Changing field 'StagingFolder.preview_width'
+ db.alter_column('sources_stagingfolder', 'preview_width', self.gf('django.db.models.fields.IntegerField')(default=640))
+
+
+ def backwards(self, orm):
+
+ # Changing field 'StagingFolder.preview_width'
+ db.alter_column('sources_stagingfolder', 'preview_width', self.gf('django.db.models.fields.IntegerField')(null=True))
+
+
+ models = {
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'sources.outofprocess': {
+ 'Meta': {'ordering': "('title',)", 'object_name': 'OutOfProcess'},
+ 'blacklist': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'whitelist': ('django.db.models.fields.TextField', [], {'blank': 'True'})
+ },
+ 'sources.sourcetransformation': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'SourceTransformation'},
+ 'arguments': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'order': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0', 'null': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'transformation': ('django.db.models.fields.CharField', [], {'max_length': '128'})
+ },
+ 'sources.stagingfolder': {
+ 'Meta': {'ordering': "('title',)", 'object_name': 'StagingFolder'},
+ 'blacklist': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'delete_after_upload': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'folder_path': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'icon': ('django.db.models.fields.CharField', [], {'max_length': '24', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'preview_height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'preview_width': ('django.db.models.fields.IntegerField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'uncompress': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'whitelist': ('django.db.models.fields.TextField', [], {'blank': 'True'})
+ },
+ 'sources.watchfolder': {
+ 'Meta': {'ordering': "('title',)", 'object_name': 'WatchFolder'},
+ 'blacklist': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'delete_after_upload': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'folder_path': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'interval': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'uncompress': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'whitelist': ('django.db.models.fields.TextField', [], {'blank': 'True'})
+ },
+ 'sources.webform': {
+ 'Meta': {'ordering': "('title',)", 'object_name': 'WebForm'},
+ 'blacklist': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'icon': ('django.db.models.fields.CharField', [], {'max_length': '24', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'uncompress': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'whitelist': ('django.db.models.fields.TextField', [], {'blank': 'True'})
+ }
+ }
+
+ complete_apps = ['sources']
diff --git a/apps/sources/migrations/__init__.py b/apps/sources/migrations/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/apps/sources/models.py b/apps/sources/models.py
index 3d09915617..0941abd00d 100644
--- a/apps/sources/models.py
+++ b/apps/sources/models.py
@@ -1,13 +1,17 @@
+from __future__ import absolute_import
+
from ast import literal_eval
+import logging
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
from django.core.exceptions import ValidationError
+from django.db import transaction
from converter.api import get_available_transformations_choices
-from converter.literals import DIMENSION_SEPARATOR
+from converter.literals import DIMENSION_SEPARATOR
from documents.models import DocumentType, Document
from documents.literals import HISTORY_DOCUMENT_CREATED
from document_indexing.api import update_indexes
@@ -15,14 +19,17 @@ from history.api import create_history
from metadata.models import MetadataType
from metadata.api import save_metadata_list
from scheduler.api import register_interval_job, remove_job
+from acls.utils import apply_default_acls
-from sources.managers import SourceTransformationManager
-from sources.literals import SOURCE_CHOICES, SOURCE_CHOICES_PLURAL, \
- SOURCE_INTERACTIVE_UNCOMPRESS_CHOICES, SOURCE_CHOICE_WEB_FORM, \
- SOURCE_CHOICE_STAGING, SOURCE_ICON_DISK, SOURCE_ICON_DRIVE, \
- SOURCE_ICON_CHOICES, SOURCE_CHOICE_WATCH, SOURCE_UNCOMPRESS_CHOICES, \
- SOURCE_UNCOMPRESS_CHOICE_Y
-from sources.compressed_file import CompressedFile, NotACompressedFile
+from .managers import SourceTransformationManager
+from .literals import (SOURCE_CHOICES, SOURCE_CHOICES_PLURAL,
+ SOURCE_INTERACTIVE_UNCOMPRESS_CHOICES, SOURCE_CHOICE_WEB_FORM,
+ SOURCE_CHOICE_STAGING, SOURCE_ICON_DISK, SOURCE_ICON_DRIVE,
+ SOURCE_ICON_CHOICES, SOURCE_CHOICE_WATCH, SOURCE_UNCOMPRESS_CHOICES,
+ SOURCE_UNCOMPRESS_CHOICE_Y)
+from .compressed_file import CompressedFile, NotACompressedFile
+
+logger = logging.getLogger(__name__)
class BaseModel(models.Model):
@@ -31,7 +38,7 @@ class BaseModel(models.Model):
whitelist = models.TextField(blank=True, verbose_name=_(u'whitelist'), editable=False)
blacklist = models.TextField(blank=True, verbose_name=_(u'blacklist'), editable=False)
#document_type = models.ForeignKey(DocumentType, blank=True, null=True, verbose_name=_(u'document type'), help_text=(u'Optional document type to be applied to documents uploaded from this source.'))
-
+
@classmethod
def class_fullname(cls):
return unicode(dict(SOURCE_CHOICES).get(cls.source_type))
@@ -42,41 +49,55 @@ class BaseModel(models.Model):
def __unicode__(self):
return u'%s' % self.title
-
+
def fullname(self):
return u' '.join([self.class_fullname(), '"%s"' % self.title])
-
+
def internal_name(self):
return u'%s_%d' % (self.source_type, self.pk)
def get_transformation_list(self):
return SourceTransformation.transformations.get_for_object_as_list(self)
- def upload_file(self, file_object, filename=None, use_file_name=False, document_type=None, expand=False, metadata_dict_list=None, user=None, document=None, new_version_data=None):
+ def upload_file(self, file_object, filename=None, use_file_name=False, document_type=None, expand=False, metadata_dict_list=None, user=None, document=None, new_version_data=None, command_line=False):
+ is_compressed = None
+
if expand:
try:
cf = CompressedFile(file_object)
+ count = 1
for fp in cf.children():
- self.upload_single_file(fp, None, document_type, metadata_dict_list, user)
+ if command_line:
+ print 'Uploading file #%d: %s' % (count, fp)
+ self.upload_single_file(file_object=fp, filename=None, document_type=document_type, metadata_dict_list=metadata_dict_list, user=user)
fp.close()
+ count += 1
except NotACompressedFile:
- self.upload_single_file(file_object, filename, document_type, metadata_dict_list, user)
+ is_compressed = False
+ logging.debug('Exception: NotACompressedFile')
+ if command_line:
+ raise
+ self.upload_single_file(file_object=file_object, filename=filename, document_type=document_type, metadata_dict_list=metadata_dict_list, user=user)
+ else:
+ is_compressed = True
else:
self.upload_single_file(file_object, filename, use_file_name, document_type, metadata_dict_list, user, document, new_version_data)
-
+
file_object.close()
-
+ return {'is_compressed': is_compressed}
+
+ @transaction.commit_on_success
def upload_single_file(self, file_object, filename=None, use_file_name=False, document_type=None, metadata_dict_list=None, user=None, document=None, new_version_data=None):
+ new_document = not document
+
if not document:
document = Document()
if document_type:
document.document_type = document_type
- document.save()
+ document.save()
- if metadata_dict_list:
- save_metadata_list(metadata_dict_list, document, create=True)
- warnings = update_indexes(document)
+ apply_default_acls(document, user)
if user:
document.add_as_recent_document_for_user(user)
@@ -91,17 +112,28 @@ class BaseModel(models.Model):
if not new_version_data:
new_version_data = {}
-
- new_version = document.new_version(file=file_object, **new_version_data)
+
+ try:
+ new_version = document.new_version(file=file_object, **new_version_data)
+ except Exception:
+ # Don't leave the database in a broken state
+ # document.delete()
+ transaction.rollback()
+ raise
+
if filename:
- new_version.filename = filename
- new_version.save()
+ document.rename(filename)
transformations, errors = self.get_transformation_list()
new_version.apply_default_transformations(transformations)
#TODO: new HISTORY for version updates
-
+
+ if metadata_dict_list and new_document:
+ # Only do for new documents
+ save_metadata_list(metadata_dict_list, document, create=True)
+ warnings = update_indexes(document)
+
class Meta:
ordering = ('title',)
abstract = True
@@ -118,14 +150,14 @@ class InteractiveBaseModel(BaseModel):
class Meta(BaseModel.Meta):
abstract = True
-
+
class StagingFolder(InteractiveBaseModel):
is_interactive = True
source_type = SOURCE_CHOICE_STAGING
default_icon = SOURCE_ICON_DRIVE
-
+
folder_path = models.CharField(max_length=255, verbose_name=_(u'folder path'), help_text=_(u'Server side filesystem path.'))
- preview_width = models.IntegerField(blank=True, null=True, verbose_name=_(u'preview width'), help_text=_(u'Width value to be passed to the converter backend.'))
+ preview_width = models.IntegerField(verbose_name=_(u'preview width'), help_text=_(u'Width value to be passed to the converter backend.'))
preview_height = models.IntegerField(blank=True, null=True, verbose_name=_(u'preview height'), help_text=_(u'Height value to be passed to the converter backend.'))
uncompress = models.CharField(max_length=1, choices=SOURCE_INTERACTIVE_UNCOMPRESS_CHOICES, verbose_name=_(u'uncompress'), help_text=_(u'Whether to expand or not compressed archives.'))
delete_after_upload = models.BooleanField(default=True, verbose_name=_(u'delete after upload'), help_text=_(u'Delete the file after is has been successfully uploaded.'))
@@ -142,7 +174,7 @@ class StagingFolder(InteractiveBaseModel):
verbose_name = _(u'staging folder')
verbose_name_plural = _(u'staging folders')
-'''
+"""
class SourceMetadata(models.Model):
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
@@ -156,7 +188,7 @@ class SourceMetadata(models.Model):
class Meta:
verbose_name = _(u'source metadata')
verbose_name_plural = _(u'sources metadata')
-'''
+"""
class WebForm(InteractiveBaseModel):
@@ -171,16 +203,16 @@ class WebForm(InteractiveBaseModel):
verbose_name = _(u'web form')
verbose_name_plural = _(u'web forms')
-
+
class WatchFolder(BaseModel):
is_interactive = False
source_type = SOURCE_CHOICE_WATCH
-
+
folder_path = models.CharField(max_length=255, verbose_name=_(u'folder path'), help_text=_(u'Server side filesystem path.'))
uncompress = models.CharField(max_length=1, choices=SOURCE_UNCOMPRESS_CHOICES, verbose_name=_(u'uncompress'), help_text=_(u'Whether to expand or not compressed archives.'))
delete_after_upload = models.BooleanField(default=True, verbose_name=_(u'delete after upload'), help_text=_(u'Delete the file after is has been successfully uploaded.'))
interval = models.PositiveIntegerField(verbose_name=_(u'interval'), help_text=_(u'Inverval in seconds where the watch folder path is checked for new documents.'))
-
+
def save(self, *args, **kwargs):
if self.pk:
remove_job(self.internal_name())
@@ -189,11 +221,11 @@ class WatchFolder(BaseModel):
def schedule(self):
if self.enabled:
- register_interval_job(self.internal_name(),
- title=self.fullname(), func=self.execute,
+ register_interval_job(self.internal_name(),
+ title=self.fullname(), func=self.execute,
kwargs={'source_id': self.pk}, seconds=self.interval
)
-
+
def execute(self, source_id):
source = WatchFolder.objects.get(pk=source_id)
if source.uncompress == SOURCE_UNCOMPRESS_CHOICE_Y:
@@ -201,11 +233,11 @@ class WatchFolder(BaseModel):
else:
expand = False
print 'execute: %s' % self.internal_name()
-
+
class Meta(BaseModel.Meta):
verbose_name = _(u'watch folder')
verbose_name_plural = _(u'watch folders')
-
+
class ArgumentsValidator(object):
message = _(u'Enter a valid value.')
@@ -251,3 +283,11 @@ class SourceTransformation(models.Model):
ordering = ('order',)
verbose_name = _(u'document source transformation')
verbose_name_plural = _(u'document source transformations')
+
+
+class OutOfProcess(BaseModel):
+ is_interactive = False
+
+ class Meta(BaseModel.Meta):
+ verbose_name = _(u'out of process')
+ verbose_name_plural = _(u'out of process')
diff --git a/apps/sources/permissions.py b/apps/sources/permissions.py
new file mode 100644
index 0000000000..e5911fe72c
--- /dev/null
+++ b/apps/sources/permissions.py
@@ -0,0 +1,11 @@
+from __future__ import absolute_import
+
+from django.utils.translation import ugettext_lazy as _
+
+from permissions.models import Permission, PermissionNamespace
+
+sources_setup_namespace = PermissionNamespace('sources_setup', _(u'Sources setup'))
+PERMISSION_SOURCES_SETUP_VIEW = Permission.objects.register(sources_setup_namespace, 'sources_setup_view', _(u'View existing document sources'))
+PERMISSION_SOURCES_SETUP_EDIT = Permission.objects.register(sources_setup_namespace, 'sources_setup_edit', _(u'Edit document sources'))
+PERMISSION_SOURCES_SETUP_DELETE = Permission.objects.register(sources_setup_namespace, 'sources_setup_delete', _(u'Delete document sources'))
+PERMISSION_SOURCES_SETUP_CREATE = Permission.objects.register(sources_setup_namespace, 'sources_setup_create', _(u'Create new document sources'))
diff --git a/apps/sources/staging.py b/apps/sources/staging.py
index 774bc01db8..c6a92a2bcb 100644
--- a/apps/sources/staging.py
+++ b/apps/sources/staging.py
@@ -1,3 +1,5 @@
+from __future__ import absolute_import
+
import errno
import os
import hashlib
@@ -39,7 +41,7 @@ def get_all_files(path):
try:
return sorted([os.path.normcase(f) for f in os.listdir(path) if os.path.isfile(os.path.join(path, f))])
except OSError, exc:
- raise OSError(ugettext(u'Unable get list of staging files: %s') % exc)
+ raise Exception(ugettext(u'Unable get list of staging files: %s') % exc)
def _return_new_class():
@@ -100,9 +102,7 @@ class StagingFile(object):
self.source = source
self.filepath = filepath
self.filename = os.path.basename(filepath)
- fd = open(filepath, 'rb')
- self._id = HASH_FUNCTION(fd.read())
- fd.close()
+ self._id = HASH_FUNCTION(filepath)
def __unicode__(self):
return self.filename
@@ -134,7 +134,7 @@ class StagingFile(object):
if exc.errno == errno.ENOENT:
pass
else:
- raise OSError(ugettext(u'Unable to delete staging file: %s') % exc)
+ raise Exception(ugettext(u'Unable to delete staging file: %s') % exc)
def get_valid_image(self, size=THUMBNAIL_SIZE, transformations=None):
return convert(self.filepath, size=size, cleanup_files=False, transformations=transformations)
diff --git a/apps/sources/tests.py b/apps/sources/tests.py
deleted file mode 100644
index 2247054b35..0000000000
--- a/apps/sources/tests.py
+++ /dev/null
@@ -1,23 +0,0 @@
-"""
-This file demonstrates two different styles of tests (one doctest and one
-unittest). These will both pass when you run "manage.py test".
-
-Replace these with more appropriate tests for your application.
-"""
-
-from django.test import TestCase
-
-class SimpleTest(TestCase):
- def test_basic_addition(self):
- """
- Tests that 1 + 1 always equals 2.
- """
- self.failUnlessEqual(1 + 1, 2)
-
-__test__ = {"doctest": """
-Another way to test that 1 + 1 is equal to 2.
-
->>> 1 + 1 == 2
-True
-"""}
-
diff --git a/apps/sources/urls.py b/apps/sources/urls.py
index 7baf07a1a9..9b8f6ad59f 100644
--- a/apps/sources/urls.py
+++ b/apps/sources/urls.py
@@ -1,7 +1,9 @@
+from __future__ import absolute_import
+
from django.conf.urls.defaults import patterns, url
-from sources.literals import SOURCE_CHOICE_WEB_FORM, SOURCE_CHOICE_STAGING, \
- SOURCE_CHOICE_WATCH
+from .literals import (SOURCE_CHOICE_WEB_FORM, SOURCE_CHOICE_STAGING,
+ SOURCE_CHOICE_WATCH)
urlpatterns = patterns('sources.views',
url(r'^staging_file/type/(?P\w+)/(?P\d+)/(?P\w+)/preview/$', 'staging_file_preview', (), 'staging_file_preview'),
diff --git a/apps/sources/utils.py b/apps/sources/utils.py
index 6d61ad9ebb..79a2c80fc4 100644
--- a/apps/sources/utils.py
+++ b/apps/sources/utils.py
@@ -9,28 +9,28 @@ def accept_item(value, whitelist, blacklist, default_accept=True):
"""
return true if this item is either whitelisted or
not blacklisted
- """
+ """
if not whitelist:
whitelist = []
-
+
if not blacklist:
blacklist = []
- # note the order
- for reject, item_list in ([False, whitelist], [True, blacklist]):
+ # note the order
+ for reject, item_list in ([False, whitelist], [True, blacklist]):
#print 'item_list: %s' % item_list
#print 'reject: %s' % reject
for okpattern in item_list:
#print 'okpattern: %s' % okpattern
- if re.findall(okpattern.replace('*', '\S+'), value, re.I):
- # match!
+ if re.findall(okpattern.replace('*', '\S+'), value, re.I):
+ # match!
#print 'MATCH'
- if reject:
- return False
- else:
+ if reject:
+ return False
+ else:
return True
- # default is to accept all
+ # default is to accept all
return default_accept
diff --git a/apps/sources/views.py b/apps/sources/views.py
index d3b8a628a1..ddbf4c71b0 100644
--- a/apps/sources/views.py
+++ b/apps/sources/views.py
@@ -1,3 +1,5 @@
+from __future__ import absolute_import
+
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response, get_object_or_404
from django.template import RequestContext
@@ -6,29 +8,33 @@ from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ugettext
from django.utils.safestring import mark_safe
+from django.conf import settings
+from django.core.exceptions import PermissionDenied
-from documents.literals import PERMISSION_DOCUMENT_CREATE
+from documents.permissions import (PERMISSION_DOCUMENT_CREATE,
+ PERMISSION_DOCUMENT_NEW_VERSION)
from documents.models import DocumentType, Document
from documents.conf.settings import THUMBNAIL_SIZE
from metadata.api import decode_metadata_from_url, metadata_repr_as_list
-from permissions.api import check_permissions
+from permissions.models import Permission
from common.utils import encapsulate
import sendfile
+from acls.models import AccessEntry
-from sources.models import WebForm, StagingFolder, SourceTransformation, \
- WatchFolder
-from sources.literals import SOURCE_CHOICE_WEB_FORM, SOURCE_CHOICE_STAGING, \
- SOURCE_CHOICE_WATCH
-from sources.literals import SOURCE_UNCOMPRESS_CHOICE_Y, \
- SOURCE_UNCOMPRESS_CHOICE_ASK
-from sources.staging import create_staging_file_class, StagingFile
-from sources.forms import StagingDocumentForm, WebFormForm, \
- WatchFolderSetupForm
+from sources.models import (WebForm, StagingFolder, SourceTransformation,
+ WatchFolder)
+from sources.literals import (SOURCE_CHOICE_WEB_FORM, SOURCE_CHOICE_STAGING,
+ SOURCE_CHOICE_WATCH)
+from sources.literals import (SOURCE_UNCOMPRESS_CHOICE_Y,
+ SOURCE_UNCOMPRESS_CHOICE_ASK)
+from sources.staging import create_staging_file_class
+from sources.forms import (StagingDocumentForm, WebFormForm,
+ WatchFolderSetupForm)
from sources.forms import WebFormSetupForm, StagingFolderSetupForm
from sources.forms import SourceTransformationForm, SourceTransformationForm_create
-from sources import PERMISSION_SOURCES_SETUP_VIEW, \
- PERMISSION_SOURCES_SETUP_EDIT, PERMISSION_SOURCES_SETUP_DELETE, \
- PERMISSION_SOURCES_SETUP_CREATE
+from .permissions import (PERMISSION_SOURCES_SETUP_VIEW,
+ PERMISSION_SOURCES_SETUP_EDIT, PERMISSION_SOURCES_SETUP_DELETE,
+ PERMISSION_SOURCES_SETUP_CREATE)
def return_function(obj):
@@ -42,7 +48,7 @@ def get_tab_link_for_source(source, document=None):
else:
view = u'upload_interactive'
args = [u'"%s"' % source.source_type, source.pk]
-
+
return {
'text': source.title,
'view': view,
@@ -50,19 +56,19 @@ def get_tab_link_for_source(source, document=None):
'famfam': source.icon,
'keep_query': True,
'conditional_highlight': return_function(source),
- }
+ }
def get_active_tab_links(document=None):
tab_links = []
-
+
web_forms = WebForm.objects.filter(enabled=True)
for web_form in web_forms:
tab_links.append(get_tab_link_for_source(web_form, document))
staging_folders = StagingFolder.objects.filter(enabled=True)
for staging_folder in staging_folders:
- tab_links.append(get_tab_link_for_source(staging_folder, document))
+ tab_links.append(get_tab_link_for_source(staging_folder, document))
return {
'tab_links': tab_links,
@@ -70,15 +76,20 @@ def get_active_tab_links(document=None):
SOURCE_CHOICE_STAGING: staging_folders
}
-def upload_interactive(request, source_type=None, source_id=None, document_pk=None):
- check_permissions(request.user, [PERMISSION_DOCUMENT_CREATE])
+def upload_interactive(request, source_type=None, source_id=None, document_pk=None):
subtemplates_list = []
if document_pk:
document = get_object_or_404(Document, pk=document_pk)
+ try:
+ Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_NEW_VERSION])
+ except PermissionDenied:
+ AccessEntry.objects.check_access(PERMISSION_DOCUMENT_NEW_VERSION, request.user, document)
+
results = get_active_tab_links(document)
else:
+ Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_CREATE])
document = None
results = get_active_tab_links()
@@ -139,23 +150,33 @@ def upload_interactive(request, source_type=None, source_id=None, document_pk=No
expand = False
new_filename = get_form_filename(form)
-
- web_form.upload_file(request.FILES['file'],
+
+ result = web_form.upload_file(request.FILES['file'],
new_filename, use_file_name=form.cleaned_data.get('use_file_name', False),
document_type=document_type,
expand=expand,
metadata_dict_list=decode_metadata_from_url(request.GET),
user=request.user,
document=document,
- new_version_data=form.cleaned_data.get('new_version_data')
+ new_version_data=form.cleaned_data.get('new_version_data')
)
if document:
- messages.success(request, _(u'Document version uploaded successfully.'))
+ messages.success(request, _(u'New document version uploaded successfully.'))
return HttpResponseRedirect(reverse('document_view_simple', args=[document.pk]))
else:
- messages.success(request, _(u'Document uploaded successfully.'))
+ if result['is_compressed'] == None:
+ messages.success(request, _(u'File uploaded successfully.'))
+
+ if result['is_compressed'] == True:
+ messages.success(request, _(u'File uncompressed successfully and uploaded as individual files.'))
+
+ if result['is_compressed'] == False:
+ messages.warning(request, _(u'File was not a compressed file, uploaded as it was.'))
+
return HttpResponseRedirect(request.get_full_path())
except Exception, e:
+ if settings.DEBUG:
+ raise
messages.error(request, _(u'Unhandled exception: %s') % e)
else:
form = WebFormForm(
@@ -168,7 +189,7 @@ def upload_interactive(request, source_type=None, source_id=None, document_pk=No
title = _(u'upload a new version from source: %s') % web_form.title
else:
title = _(u'upload a local document from source: %s') % web_form.title
-
+
subtemplates_list.append({
'name': 'generic_form_subtemplate.html',
'context': {
@@ -202,20 +223,27 @@ def upload_interactive(request, source_type=None, source_id=None, document_pk=No
expand = False
new_filename = get_form_filename(form)
-
- staging_folder.upload_file(staging_file.upload(),
+
+ result = staging_folder.upload_file(staging_file.upload(),
new_filename, use_file_name=form.cleaned_data.get('use_file_name', False),
document_type=document_type,
expand=expand,
metadata_dict_list=decode_metadata_from_url(request.GET),
user=request.user,
document=document,
- new_version_data=form.cleaned_data.get('new_version_data')
+ new_version_data=form.cleaned_data.get('new_version_data')
)
if document:
messages.success(request, _(u'Document version from staging file: %s, uploaded successfully.') % staging_file.filename)
else:
- messages.success(request, _(u'Staging file: %s, uploaded successfully.') % staging_file.filename)
+ if result['is_compressed'] == None:
+ messages.success(request, _(u'Staging file: %s, uploaded successfully.') % staging_file.filename)
+
+ if result['is_compressed'] == True:
+ messages.success(request, _(u'Staging file: %s, uncompressed successfully and uploaded as individual files.') % staging_file.filename)
+
+ if result['is_compressed'] == False:
+ messages.warning(request, _(u'Staging file: %s, was not compressed, uploaded as a single file.') % staging_file.filename)
if staging_folder.delete_after_upload:
transformations, errors = staging_folder.get_transformation_list()
@@ -226,6 +254,8 @@ def upload_interactive(request, source_type=None, source_id=None, document_pk=No
else:
return HttpResponseRedirect(request.get_full_path())
except Exception, e:
+ if settings.DEBUG:
+ raise
messages.error(request, _(u'Unhandled exception: %s') % e)
else:
form = StagingDocumentForm(cls=StagingFile,
@@ -244,7 +274,7 @@ def upload_interactive(request, source_type=None, source_id=None, document_pk=No
title = _(u'upload a new version from staging source: %s') % staging_folder.title
else:
title = _(u'upload a document from staging source: %s') % staging_folder.title
-
+
subtemplates_list = [
{
'name': 'generic_form_subtemplate.html',
@@ -261,7 +291,7 @@ def upload_interactive(request, source_type=None, source_id=None, document_pk=No
'hide_link': True,
}
},
- ]
+ ]
if document:
context['object'] = document
@@ -276,15 +306,23 @@ def upload_interactive(request, source_type=None, source_id=None, document_pk=No
},
'upload_interactive': {
'links': results['tab_links']
- }
+ }
}
},
})
-
+
if not document:
context.update(
{
'sidebar_subtemplates_list': [
+ {
+ 'name': 'generic_subtemplate.html',
+ 'context': {
+ 'title': _(u'Current document type'),
+ 'paragraphs': [document_type if document_type else _(u'None')],
+ 'side_bar': True,
+ }
+ },
{
'name': 'generic_subtemplate.html',
'context': {
@@ -296,7 +334,7 @@ def upload_interactive(request, source_type=None, source_id=None, document_pk=No
],
}
)
-
+
return render_to_response('generic_form.html', context,
context_instance=RequestContext(request))
@@ -315,7 +353,7 @@ def get_form_filename(form):
def staging_file_preview(request, source_type, source_id, staging_file_id):
- check_permissions(request.user, [PERMISSION_DOCUMENT_CREATE])
+ Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_CREATE])
staging_folder = get_object_or_404(StagingFolder, pk=source_id)
StagingFile = create_staging_file_class(request, staging_folder.folder_path)
transformations, errors = SourceTransformation.transformations.get_for_object_as_list(staging_folder)
@@ -334,7 +372,7 @@ def staging_file_preview(request, source_type, source_id, staging_file_id):
def staging_file_thumbnail(request, source_id, staging_file_id):
- check_permissions(request.user, [PERMISSION_DOCUMENT_CREATE])
+ Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_CREATE])
staging_folder = get_object_or_404(StagingFolder, pk=source_id)
StagingFile = create_staging_file_class(request, staging_folder.folder_path, source=staging_folder)
transformations, errors = SourceTransformation.transformations.get_for_object_as_list(staging_folder)
@@ -353,7 +391,7 @@ def staging_file_thumbnail(request, source_id, staging_file_id):
def staging_file_delete(request, source_type, source_id, staging_file_id):
- check_permissions(request.user, [PERMISSION_DOCUMENT_CREATE])
+ Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_CREATE])
staging_folder = get_object_or_404(StagingFolder, pk=source_id)
StagingFile = create_staging_file_class(request, staging_folder.folder_path)
@@ -386,8 +424,9 @@ def staging_file_delete(request, source_type, source_id, staging_file_id):
}, context_instance=RequestContext(request))
+# Setup views
def setup_source_list(request, source_type):
- check_permissions(request.user, [PERMISSION_SOURCES_SETUP_VIEW])
+ Permission.objects.check_permissions(request.user, [PERMISSION_SOURCES_SETUP_VIEW])
if source_type == SOURCE_CHOICE_WEB_FORM:
cls = WebForm
@@ -405,12 +444,12 @@ def setup_source_list(request, source_type):
}
return render_to_response('generic_list.html', context,
- context_instance=RequestContext(request))
+ context_instance=RequestContext(request))
def setup_source_edit(request, source_type, source_id):
- check_permissions(request.user, [PERMISSION_SOURCES_SETUP_EDIT])
-
+ Permission.objects.check_permissions(request.user, [PERMISSION_SOURCES_SETUP_EDIT])
+
if source_type == SOURCE_CHOICE_WEB_FORM:
cls = WebForm
form_class = WebFormSetupForm
@@ -420,7 +459,7 @@ def setup_source_edit(request, source_type, source_id):
elif source_type == SOURCE_CHOICE_WATCH:
cls = WatchFolder
form_class = WatchFolderSetupForm
-
+
source = get_object_or_404(cls, pk=source_id)
next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', '/')))
@@ -449,7 +488,7 @@ def setup_source_edit(request, source_type, source_id):
def setup_source_delete(request, source_type, source_id):
- check_permissions(request.user, [PERMISSION_SOURCES_SETUP_DELETE])
+ Permission.objects.check_permissions(request.user, [PERMISSION_SOURCES_SETUP_DELETE])
if source_type == SOURCE_CHOICE_WEB_FORM:
cls = WebForm
form_icon = u'application_form_delete.png'
@@ -462,12 +501,12 @@ def setup_source_delete(request, source_type, source_id):
cls = WatchFolder
form_icon = u'folder_delete.png'
redirect_view = 'setup_watch_folder_list'
-
+
redirect_view = reverse('setup_source_list', args=[source_type])
previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', redirect_view)))
source = get_object_or_404(cls, pk=source_id)
-
+
if request.method == 'POST':
try:
source.delete()
@@ -495,8 +534,8 @@ def setup_source_delete(request, source_type, source_id):
def setup_source_create(request, source_type):
- check_permissions(request.user, [PERMISSION_SOURCES_SETUP_CREATE])
-
+ Permission.objects.check_permissions(request.user, [PERMISSION_SOURCES_SETUP_CREATE])
+
if source_type == SOURCE_CHOICE_WEB_FORM:
cls = WebForm
form_class = WebFormSetupForm
@@ -506,7 +545,7 @@ def setup_source_create(request, source_type):
elif source_type == SOURCE_CHOICE_WATCH:
cls = WatchFolder
form_class = WatchFolderSetupForm
-
+
if request.method == 'POST':
form = form_class(data=request.POST)
if form.is_valid():
@@ -529,8 +568,8 @@ def setup_source_create(request, source_type):
def setup_source_transformation_list(request, source_type, source_id):
- check_permissions(request.user, [PERMISSION_SOURCES_SETUP_EDIT])
-
+ Permission.objects.check_permissions(request.user, [PERMISSION_SOURCES_SETUP_EDIT])
+
if source_type == SOURCE_CHOICE_WEB_FORM:
cls = WebForm
elif source_type == SOURCE_CHOICE_STAGING:
@@ -557,12 +596,12 @@ def setup_source_transformation_list(request, source_type, source_id):
}
return render_to_response('generic_list.html', context,
- context_instance=RequestContext(request))
+ context_instance=RequestContext(request))
def setup_source_transformation_edit(request, transformation_id):
- check_permissions(request.user, [PERMISSION_SOURCES_SETUP_EDIT])
-
+ Permission.objects.check_permissions(request.user, [PERMISSION_SOURCES_SETUP_EDIT])
+
source_transformation = get_object_or_404(SourceTransformation, pk=transformation_id)
redirect_view = reverse('setup_source_transformation_list', args=[source_transformation.content_object.source_type, source_transformation.content_object.pk])
next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', redirect_view)))
@@ -590,11 +629,11 @@ def setup_source_transformation_edit(request, transformation_id):
],
'next': next,
},
- context_instance=RequestContext(request))
+ context_instance=RequestContext(request))
def setup_source_transformation_delete(request, transformation_id):
- check_permissions(request.user, [PERMISSION_SOURCES_SETUP_EDIT])
+ Permission.objects.check_permissions(request.user, [PERMISSION_SOURCES_SETUP_EDIT])
source_transformation = get_object_or_404(SourceTransformation, pk=transformation_id)
redirect_view = reverse('setup_source_transformation_list', args=[source_transformation.content_object.source_type, source_transformation.content_object.pk])
@@ -617,18 +656,18 @@ def setup_source_transformation_delete(request, transformation_id):
'navigation_object_list': [
{'object': 'source', 'name': _(u'source')},
{'object': 'transformation', 'name': _(u'transformation')}
- ],
+ ],
'title': _(u'Are you sure you wish to delete source transformation "%(transformation)s"') % {
'transformation': source_transformation.get_transformation_display(),
},
'previous': previous,
'form_icon': u'shape_square_delete.png',
},
- context_instance=RequestContext(request))
+ context_instance=RequestContext(request))
def setup_source_transformation_create(request, source_type, source_id):
- check_permissions(request.user, [PERMISSION_SOURCES_SETUP_EDIT])
+ Permission.objects.check_permissions(request.user, [PERMISSION_SOURCES_SETUP_EDIT])
if source_type == SOURCE_CHOICE_WEB_FORM:
cls = WebForm
@@ -636,11 +675,11 @@ def setup_source_transformation_create(request, source_type, source_id):
cls = StagingFolder
elif source_type == SOURCE_CHOICE_WATCH:
cls = WatchFolder
-
+
source = get_object_or_404(cls, pk=source_id)
-
+
redirect_view = reverse('setup_source_transformation_list', args=[source.source_type, source.pk])
-
+
if request.method == 'POST':
form = SourceTransformationForm_create(request.POST)
if form.is_valid():
@@ -654,7 +693,7 @@ def setup_source_transformation_create(request, source_type, source_id):
messages.error(request, _(u'Error creating source transformation; %s') % e)
else:
form = SourceTransformationForm_create()
-
+
return render_to_response('generic_form.html', {
'form': form,
'source': source,
diff --git a/apps/sources/widgets.py b/apps/sources/widgets.py
index ae5bf8e1bc..f55223290a 100644
--- a/apps/sources/widgets.py
+++ b/apps/sources/widgets.py
@@ -28,7 +28,7 @@ class FamFamRadioSelect(forms.widgets.RadioSelect):
def staging_file_thumbnail(staging_file):
try:
staging_file.get_valid_image()
- template = u''
+ template = u''
except:
template = u''
@@ -36,5 +36,6 @@ def staging_file_thumbnail(staging_file):
'url': reverse('staging_file_preview', args=[staging_file.source.source_type, staging_file.source.pk, staging_file.id]),
'thumbnail': reverse('staging_file_thumbnail', args=[staging_file.source.pk, staging_file.id]),
'static_url': settings.STATIC_URL,
- 'string': _(u'thumbnail')
+ 'string': _(u'thumbnail'),
+ 'filename': staging_file.filename
})
diff --git a/apps/storage/conf/settings.py b/apps/storage/conf/settings.py
index edd332734a..a410692e9e 100644
--- a/apps/storage/conf/settings.py
+++ b/apps/storage/conf/settings.py
@@ -1,5 +1,8 @@
"""Configuration options for the storage app"""
+import os
+
from django.utils.translation import ugettext_lazy as _
+from django.conf import settings
from smart_settings.api import register_settings
@@ -10,6 +13,6 @@ register_settings(
{'name': u'GRIDFS_HOST', 'global_name': u'STORAGE_GRIDFS_HOST', 'default': u'localhost'},
{'name': u'GRIDFS_PORT', 'global_name': u'STORAGE_GRIDFS_PORT', 'default': 27017},
{'name': u'GRIDFS_DATABASE_NAME', 'global_name': u'STORAGE_GRIDFS_DATABASE_NAME', 'default': u'document_storage'},
- {'name': u'FILESTORAGE_LOCATION', 'global_name': u'STORAGE_FILESTORAGE_LOCATION', 'default': u'document_storage', 'exists': True},
+ {'name': u'FILESTORAGE_LOCATION', 'global_name': u'STORAGE_FILESTORAGE_LOCATION', 'default': os.path.join(settings.PROJECT_ROOT, u'document_storage'), 'exists': True},
]
)
diff --git a/apps/storage/tests.py b/apps/storage/tests.py
deleted file mode 100644
index 2247054b35..0000000000
--- a/apps/storage/tests.py
+++ /dev/null
@@ -1,23 +0,0 @@
-"""
-This file demonstrates two different styles of tests (one doctest and one
-unittest). These will both pass when you run "manage.py test".
-
-Replace these with more appropriate tests for your application.
-"""
-
-from django.test import TestCase
-
-class SimpleTest(TestCase):
- def test_basic_addition(self):
- """
- Tests that 1 + 1 always equals 2.
- """
- self.failUnlessEqual(1 + 1, 2)
-
-__test__ = {"doctest": """
-Another way to test that 1 + 1 is equal to 2.
-
->>> 1 + 1 == 2
-True
-"""}
-
diff --git a/apps/tags/__init__.py b/apps/tags/__init__.py
index 4b349e012e..2bfcb2f508 100644
--- a/apps/tags/__init__.py
+++ b/apps/tags/__init__.py
@@ -1,63 +1,69 @@
+from __future__ import absolute_import
+
from django.utils.translation import ugettext_lazy as _
-from navigation.api import register_links, register_top_menu, \
- register_model_list_columns, register_multi_item_links
-from permissions.api import register_permission, set_namespace_title
+from navigation.api import (register_links, register_top_menu,
+ register_model_list_columns, register_multi_item_links)
from common.utils import encapsulate
from documents.models import Document
+from acls.api import class_permissions
+from acls.permissions import ACLS_VIEW_ACL
from taggit.models import Tag
+from taggit.managers import TaggableManager
-from tags.widgets import tag_color_block
-
-PERMISSION_TAG_CREATE = {'namespace': 'tags', 'name': 'tag_create', 'label': _(u'Create new tags')}
-PERMISSION_TAG_ATTACH = {'namespace': 'tags', 'name': 'tag_attach', 'label': _(u'Attach exising tags')}
-PERMISSION_TAG_REMOVE = {'namespace': 'tags', 'name': 'tag_remove', 'label': _(u'Remove tags from documents')}
-PERMISSION_TAG_DELETE = {'namespace': 'tags', 'name': 'tag_delete', 'label': _(u'Delete global tags')}
-PERMISSION_TAG_EDIT = {'namespace': 'tags', 'name': 'tag_edit', 'label': _(u'Edit global tags')}
-PERMISSION_TAG_VIEW = {'namespace': 'tags', 'name': 'tag_view', 'label': _(u'View a document\'s tags')}
-
-set_namespace_title('tags', _(u'Tags'))
-register_permission(PERMISSION_TAG_CREATE)
-register_permission(PERMISSION_TAG_ATTACH)
-register_permission(PERMISSION_TAG_REMOVE)
-register_permission(PERMISSION_TAG_DELETE)
-register_permission(PERMISSION_TAG_EDIT)
-register_permission(PERMISSION_TAG_VIEW)
+from .widgets import (get_tags_inline_widget_simple, single_tag_widget)
+from .permissions import (PERMISSION_TAG_CREATE, PERMISSION_TAG_ATTACH,
+ PERMISSION_TAG_REMOVE, PERMISSION_TAG_DELETE, PERMISSION_TAG_EDIT,
+ PERMISSION_TAG_VIEW)
tag_list = {'text': _(u'tag list'), 'view': 'tag_list', 'famfam': 'tag_blue'}
-tag_create = {'text': _(u'create new tag'), 'view': 'tag_create', 'famfam': 'tag_blue_add'}
-tag_add_attach = {'text': _(u'attach tag'), 'view': 'tag_add_attach', 'args': 'object.pk', 'famfam': 'tag_blue_add', 'permission': [PERMISSION_TAG_CREATE, PERMISSION_TAG_ATTACH]}
+tag_create = {'text': _(u'create new tag'), 'view': 'tag_create', 'famfam': 'tag_blue_add', 'permissions': [PERMISSION_TAG_CREATE]}
+tag_attach = {'text': _(u'attach tag'), 'view': 'tag_attach', 'args': 'object.pk', 'famfam': 'tag_blue_add', 'permissions': [PERMISSION_TAG_ATTACH]}
tag_document_remove = {'text': _(u'remove'), 'view': 'tag_remove', 'args': ['object.id', 'document.id'], 'famfam': 'tag_blue_delete', 'permissions': [PERMISSION_TAG_REMOVE]}
tag_document_remove_multiple = {'text': _(u'remove'), 'view': 'tag_multiple_remove', 'args': 'document.id', 'famfam': 'tag_blue_delete', 'permissions': [PERMISSION_TAG_REMOVE]}
-tag_document_list = {'text': _(u'tags'), 'view': 'document_tags', 'args': 'object.pk', 'famfam': 'tag_blue', 'permissions': [PERMISSION_TAG_REMOVE], 'children_view_regex': ['tag']}
+tag_document_list = {'text': _(u'tags'), 'view': 'document_tags', 'args': 'object.pk', 'famfam': 'tag_blue', 'permissions': [PERMISSION_TAG_REMOVE, PERMISSION_TAG_ATTACH], 'children_view_regex': ['tag']}
tag_delete = {'text': _(u'delete'), 'view': 'tag_delete', 'args': 'object.id', 'famfam': 'tag_blue_delete', 'permissions': [PERMISSION_TAG_DELETE]}
tag_edit = {'text': _(u'edit'), 'view': 'tag_edit', 'args': 'object.id', 'famfam': 'tag_blue_edit', 'permissions': [PERMISSION_TAG_EDIT]}
tag_tagged_item_list = {'text': _(u'tagged documents'), 'view': 'tag_tagged_item_list', 'args': 'object.id', 'famfam': 'page'}
tag_multiple_delete = {'text': _(u'delete'), 'view': 'tag_multiple_delete', 'famfam': 'tag_blue_delete', 'permissions': [PERMISSION_TAG_DELETE]}
+tag_acl_list = {'text': _(u'ACLs'), 'view': 'tag_acl_list', 'args': 'object.pk', 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]}
register_model_list_columns(Tag, [
{
- 'name': _(u'color'),
- 'attribute': encapsulate(lambda x: tag_color_block(x))
+ 'name': _(u'preview'),
+ 'attribute': encapsulate(lambda x: single_tag_widget(x))
},
{
- 'name': _(u'color name'),
- 'attribute': encapsulate(lambda x: x.tagproperties_set.get().get_color_display()),
+ 'name': _(u'tagged items'),
+ 'attribute': encapsulate(lambda x: x.taggit_taggeditem_items.count())
}
])
-register_links(Tag, [tag_tagged_item_list, tag_edit, tag_delete])
+register_model_list_columns(Document, [
+ {'name':_(u'tags'), 'attribute':
+ encapsulate(lambda x: get_tags_inline_widget_simple(x))
+ },
+])
+register_links(Tag, [tag_tagged_item_list, tag_edit, tag_delete, tag_acl_list])
register_multi_item_links(['tag_list'], [tag_multiple_delete])
-
-register_links(['tag_list', 'tag_delete', 'tag_edit', 'tag_tagged_item_list', 'tag_multiple_delete', 'tag_create'], [tag_list, tag_create], menu_name='secondary_menu')
-
-#register_sidebar_template(['document_tags'], 'tags_sidebar_template.html')
-
-register_top_menu('tags', link={'text': _(u'tags'), 'view': 'tag_list', 'famfam': 'tag_blue'}, children_path_regex=[r'^tags/[^d]'])
+register_links([Tag, 'tag_list', 'tag_create'], [tag_list, tag_create], menu_name='secondary_menu')
+register_top_menu('tags', link={'text': _(u'tags'), 'view': 'tag_list', 'famfam': 'tag_blue'}, children_view_regex=[r'^tag_(list|create|delete|edit|tagged|acl)'])
register_links(Document, [tag_document_list], menu_name='form_header')
-register_links(['document_tags', 'tag_add_attach', 'tag_remove', 'tag_multiple_remove'], [tag_add_attach], menu_name='sidebar')
-
+register_links(['document_tags', 'tag_remove', 'tag_multiple_remove', 'tag_attach'], [tag_attach], menu_name='sidebar')
register_multi_item_links(['document_tags'], [tag_document_remove_multiple])
+
+class_permissions(Document, [
+ PERMISSION_TAG_ATTACH,
+ PERMISSION_TAG_REMOVE,
+])
+
+class_permissions(Tag, [
+ PERMISSION_TAG_DELETE,
+ PERMISSION_TAG_EDIT,
+ PERMISSION_TAG_VIEW,
+])
+
+Document.add_to_class('tags', TaggableManager())
diff --git a/apps/tags/admin.py b/apps/tags/admin.py
index 495fc03066..009033002f 100644
--- a/apps/tags/admin.py
+++ b/apps/tags/admin.py
@@ -1,6 +1,7 @@
+from __future__ import absolute_import
+
from django.contrib import admin
-from tags.models import TagProperties
-
+from .models import TagProperties
admin.site.register(TagProperties)
diff --git a/apps/tags/forms.py b/apps/tags/forms.py
index 046809c7c8..b10ac68679 100644
--- a/apps/tags/forms.py
+++ b/apps/tags/forms.py
@@ -1,19 +1,20 @@
+from __future__ import absolute_import
+
+import logging
+
from django import forms
from django.utils.translation import ugettext_lazy as _
+from django.core.exceptions import PermissionDenied
from taggit.models import Tag
-from models import COLOR_CHOICES
+from acls.models import AccessEntry
+from permissions.models import Permission
+from .models import COLOR_CHOICES
+from .permissions import PERMISSION_TAG_VIEW
-class AddTagForm(forms.Form):
- """
- Form to be displayed in the sidebar of a document and allow adding
- new or existing tags
- """
- new_tag = forms.CharField(required=False, label=_(u'New tag'))
- color = forms.ChoiceField(choices=COLOR_CHOICES, required=False, label=_(u'Color'))
- existing_tags = forms.ModelChoiceField(required=False, queryset=Tag.objects.all(), label=_(u'Existing tags'))
+logger = logging.getLogger(__name__)
class TagForm(forms.Form):
@@ -22,3 +23,20 @@ class TagForm(forms.Form):
"""
name = forms.CharField(label=_(u'Name'))
color = forms.ChoiceField(choices=COLOR_CHOICES, label=_(u'Color'))
+
+
+class TagListForm(forms.Form):
+ def __init__(self, *args, **kwargs):
+ user = kwargs.pop('user', None)
+ logger.debug('user: %s' % user)
+ super(TagListForm, self).__init__(*args, **kwargs)
+
+ queryset = Tag.objects.all()
+ try:
+ Permission.objects.check_permissions(user, [PERMISSION_TAG_VIEW])
+ except PermissionDenied:
+ queryset = AccessEntry.objects.filter_objects_by_access(PERMISSION_TAG_VIEW, user, queryset)
+
+ self.fields['tag'] = forms.ModelChoiceField(
+ queryset=queryset,
+ label=_(u'Tags'))
diff --git a/apps/tags/literals.py b/apps/tags/literals.py
new file mode 100644
index 0000000000..4053c3273a
--- /dev/null
+++ b/apps/tags/literals.py
@@ -0,0 +1,41 @@
+from __future__ import absolute_import
+
+from django.utils.translation import ugettext_lazy as _
+
+
+COLOR_RED = u'red'
+COLOR_BLUE = u'blu'
+COLOR_MAGENTA = u'mag'
+COLOR_CYAN = u'cya'
+COLOR_YELLOW = u'yel'
+COLOR_GREENYELLOW = u'gry'
+COLOR_CORAL = u'crl'
+COLOR_KHAKI = u'kki'
+COLOR_LIGHTGREY = u'lig'
+COLOR_ORANGE = u'org'
+
+COLOR_CHOICES = (
+ (COLOR_BLUE, _(u'Blue')),
+ (COLOR_CYAN, _(u'Cyan')),
+ (COLOR_CORAL, _(u'Coral')),
+ (COLOR_GREENYELLOW, _(u'Green-Yellow')),
+ (COLOR_KHAKI, _(u'Khaki')),
+ (COLOR_LIGHTGREY, _(u'LightGrey')),
+ (COLOR_MAGENTA, _(u'Magenta')),
+ (COLOR_RED, _(u'Red')),
+ (COLOR_ORANGE, _(u'Orange')),
+ (COLOR_YELLOW, _(u'Yellow'))
+)
+
+COLOR_CODES = (
+ (COLOR_RED, u'red'),
+ (COLOR_BLUE, u'blue'),
+ (COLOR_MAGENTA, u'magenta'),
+ (COLOR_CYAN, u'cyan'),
+ (COLOR_YELLOW, u'yellow'),
+ (COLOR_GREENYELLOW, u'greenyellow '),
+ (COLOR_CORAL, u'coral'),
+ (COLOR_KHAKI, u'khaki'),
+ (COLOR_ORANGE, u'orange'),
+ (COLOR_LIGHTGREY, u'lightgrey'),
+)
diff --git a/apps/tags/locale/en/LC_MESSAGES/django.po b/apps/tags/locale/en/LC_MESSAGES/django.po
index 3a71fb37af..c80ab3348f 100644
--- a/apps/tags/locale/en/LC_MESSAGES/django.po
+++ b/apps/tags/locale/en/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-11-22 11:26-0400\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -17,245 +17,227 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: __init__.py:13
-msgid "Create new tags"
-msgstr ""
-
-#: __init__.py:14
-msgid "Attach exising tags"
-msgstr ""
-
-#: __init__.py:15
-msgid "Remove tags from documents"
-msgstr ""
-
-#: __init__.py:16
-msgid "Delete global tags"
-msgstr ""
-
-#: __init__.py:17
-msgid "Edit global tags"
-msgstr ""
-
-#: __init__.py:18
-msgid "View a document's tags"
-msgstr ""
-
#: __init__.py:20
-msgid "Tags"
-msgstr ""
-
-#: __init__.py:28
msgid "tag list"
msgstr ""
-#: __init__.py:29
+#: __init__.py:21
msgid "create new tag"
msgstr ""
-#: __init__.py:30
+#: __init__.py:22
msgid "attach tag"
msgstr ""
-#: __init__.py:31 __init__.py:32
+#: __init__.py:23 __init__.py:24
msgid "remove"
msgstr ""
-#: __init__.py:33 __init__.py:58 utils.py:14 views.py:144
+#: __init__.py:25 __init__.py:44 __init__.py:52 views.py:98
msgid "tags"
msgstr ""
-#: __init__.py:34 __init__.py:37
+#: __init__.py:26 __init__.py:29
msgid "delete"
msgstr ""
-#: __init__.py:35
+#: __init__.py:27
msgid "edit"
msgstr ""
-#: __init__.py:36
+#: __init__.py:28
msgid "tagged documents"
msgstr ""
-#: __init__.py:41 models.py:46
-msgid "color"
+#: __init__.py:30
+msgid "ACLs"
msgstr ""
-#: __init__.py:45
-msgid "color name"
+#: __init__.py:34
+msgid "preview"
msgstr ""
-#: forms.py:14
-msgid "New tag"
+#: __init__.py:38
+msgid "tagged items"
msgstr ""
-#: forms.py:15 forms.py:24
-msgid "Color"
-msgstr ""
-
-#: forms.py:16
-msgid "Existing tags"
-msgstr ""
-
-#: forms.py:23
+#: forms.py:24
msgid "Name"
msgstr ""
-#: models.py:18
+#: forms.py:25
+msgid "Color"
+msgstr ""
+
+#: forms.py:42 permissions.py:7
+msgid "Tags"
+msgstr ""
+
+#: literals.py:18
msgid "Blue"
msgstr ""
-#: models.py:19
+#: literals.py:19
msgid "Cyan"
msgstr ""
-#: models.py:20
+#: literals.py:20
msgid "Coral"
msgstr ""
-#: models.py:21
+#: literals.py:21
msgid "Green-Yellow"
msgstr ""
-#: models.py:22
+#: literals.py:22
msgid "Khaki"
msgstr ""
-#: models.py:23
+#: literals.py:23
msgid "LightGrey"
msgstr ""
-#: models.py:24
+#: literals.py:24
msgid "Magenta"
msgstr ""
-#: models.py:25
+#: literals.py:25
msgid "Red"
msgstr ""
-#: models.py:26
+#: literals.py:26
msgid "Orange"
msgstr ""
-#: models.py:27
+#: literals.py:27
msgid "Yellow"
msgstr ""
-#: models.py:45 views.py:185 views.py:233 views.py:248
+#: models.py:12 views.py:154 views.py:206 views.py:220
msgid "tag"
msgstr ""
-#: models.py:49
+#: models.py:13
+msgid "color"
+msgstr ""
+
+#: models.py:16
msgid "tag properties"
msgstr ""
-#: models.py:50
+#: models.py:17
msgid "tags properties"
msgstr ""
-#: views.py:33
+#: permissions.py:9
+msgid "Create new tags"
+msgstr ""
+
+#: permissions.py:10
+msgid "Delete tags"
+msgstr ""
+
+#: permissions.py:11
+msgid "Edit tags"
+msgstr ""
+
+#: permissions.py:12
+msgid "View tags"
+msgstr ""
+
+#: permissions.py:13
+msgid "Attach tags to documents"
+msgstr ""
+
+#: permissions.py:14
+msgid "Remove tags from documents"
+msgstr ""
+
+#: views.py:42
msgid "Tag already exists."
msgstr ""
-#: views.py:40
+#: views.py:50
msgid "Tag created succesfully."
msgstr ""
-#: views.py:46
+#: views.py:56
msgid "create tag"
msgstr ""
-#: views.py:73 views.py:112
-msgid "Must choose either a new tag or an existing one."
-msgstr ""
-
-#: views.py:77 views.py:116
+#: views.py:77
#, python-format
msgid "Document is already tagged as \"%s\""
msgstr ""
-#: views.py:86
-#, python-format
-msgid "Tag \"%s\" added successfully."
-msgstr ""
-
-#: views.py:124
-#, python-format
-msgid "Tag \"%s\" added and attached successfully."
-msgstr ""
-
-#: views.py:126
+#: views.py:82
#, python-format
msgid "Tag \"%s\" attached successfully."
msgstr ""
-#: views.py:133
+#: views.py:88
#, python-format
msgid "attach tag to: %s"
msgstr ""
-#: views.py:149
-msgid "tagged items"
-msgstr ""
-
-#: views.py:166 views.py:280
+#: views.py:130 views.py:257
msgid "Must provide at least one tag."
msgstr ""
-#: views.py:176
+#: views.py:145
#, python-format
msgid "Tag \"%s\" deleted successfully."
msgstr ""
-#: views.py:178 views.py:294
+#: views.py:147 views.py:269
#, python-format
msgid "Error deleting tag \"%(tag)s\": %(error)s"
msgstr ""
-#: views.py:193
+#: views.py:162
#, python-format
msgid "Are you sure you wish to delete the tag: %s?"
msgstr ""
-#: views.py:194 views.py:197
+#: views.py:163 views.py:166
msgid "Will be removed from all documents."
msgstr ""
-#: views.py:196
+#: views.py:165
#, python-format
msgid "Are you sure you wish to delete the tags: %s?"
msgstr ""
-#: views.py:221
+#: views.py:194
msgid "Tag updated succesfully."
msgstr ""
-#: views.py:230
+#: views.py:203
#, python-format
msgid "edit tag: %s"
msgstr ""
-#: views.py:245
+#: views.py:217
#, python-format
msgid "documents with the tag \"%s\""
msgstr ""
-#: views.py:258
+#: views.py:236
#, python-format
msgid "tags for: %s"
msgstr ""
-#: views.py:292
+#: views.py:267
#, python-format
msgid "Tag \"%s\" removed successfully."
msgstr ""
-#: views.py:308
+#: views.py:283
#, python-format
msgid "Are you sure you wish to remove the tag: %s?"
msgstr ""
-#: views.py:310
+#: views.py:285
#, python-format
msgid "Are you sure you wish to remove the tags: %s?"
msgstr ""
diff --git a/apps/tags/locale/es/LC_MESSAGES/django.mo b/apps/tags/locale/es/LC_MESSAGES/django.mo
index 36248389b6..23f977dc77 100644
Binary files a/apps/tags/locale/es/LC_MESSAGES/django.mo and b/apps/tags/locale/es/LC_MESSAGES/django.mo differ
diff --git a/apps/tags/locale/es/LC_MESSAGES/django.po b/apps/tags/locale/es/LC_MESSAGES/django.po
index 1bd56cabd7..2a28bd8cd7 100644
--- a/apps/tags/locale/es/LC_MESSAGES/django.po
+++ b/apps/tags/locale/es/LC_MESSAGES/django.po
@@ -1,263 +1,244 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
-#
+#
# Translators:
-# Roberto Rosario , 2011.
+# Roberto Rosario , 2011, 2012.
msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-11-22 11:26-0400\n"
-"PO-Revision-Date: 2011-11-04 01:05+0000\n"
-"Last-Translator: rosarior \n"
-"Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/"
-"mayan-edms/team/es/)\n"
-"Language: es\n"
+"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
+"PO-Revision-Date: 2012-02-12 19:27+0000\n"
+"Last-Translator: Roberto Rosario \n"
+"Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/mayan-edms/team/es/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
+"Language: es\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
-#: __init__.py:13
-msgid "Create new tags"
-msgstr "Crear nuevas etiquetas"
-
-#: __init__.py:14
-msgid "Attach exising tags"
-msgstr "Anejar etiquetas existentes"
-
-#: __init__.py:15
-msgid "Remove tags from documents"
-msgstr "Remover etiquetas de los documentos"
-
-#: __init__.py:16
-msgid "Delete global tags"
-msgstr "Eliminar las etiquetas globales"
-
-#: __init__.py:17
-msgid "Edit global tags"
-msgstr "Editar etiquetas globales"
-
-#: __init__.py:18
-msgid "View a document's tags"
-msgstr "Ver etiquetas de un documento"
-
#: __init__.py:20
-msgid "Tags"
-msgstr "Etiquetas"
-
-#: __init__.py:28
msgid "tag list"
msgstr "lista de etiquetas"
-#: __init__.py:29
+#: __init__.py:21
msgid "create new tag"
msgstr "crear nueva etiqueta"
-#: __init__.py:30
+#: __init__.py:22
msgid "attach tag"
msgstr "adjuntar etiqueta"
-#: __init__.py:31 __init__.py:32
+#: __init__.py:23 __init__.py:24
msgid "remove"
msgstr "remover"
-#: __init__.py:33 __init__.py:58 utils.py:14 views.py:144
+#: __init__.py:25 __init__.py:44 __init__.py:52 views.py:98
msgid "tags"
msgstr "etiquetas"
-#: __init__.py:34 __init__.py:37
+#: __init__.py:26 __init__.py:29
msgid "delete"
msgstr "eliminar"
-#: __init__.py:35
+#: __init__.py:27
msgid "edit"
msgstr "editar"
-#: __init__.py:36
+#: __init__.py:28
msgid "tagged documents"
msgstr "documentos etiquetados"
-#: __init__.py:41 models.py:46
-msgid "color"
-msgstr "color"
+#: __init__.py:30
+msgid "ACLs"
+msgstr "LCAs"
-#: __init__.py:45
-msgid "color name"
-msgstr "nombre del color"
+#: __init__.py:34
+msgid "preview"
+msgstr "muestra"
-#: forms.py:14
-msgid "New tag"
-msgstr "Nueva etiqueta"
+#: __init__.py:38
+msgid "tagged items"
+msgstr "artículos etiquetados"
-#: forms.py:15 forms.py:24
-msgid "Color"
-msgstr "Color"
-
-#: forms.py:16
-msgid "Existing tags"
-msgstr "Etiquetas existentes"
-
-#: forms.py:23
+#: forms.py:24
msgid "Name"
msgstr "Nombre"
-#: models.py:18
+#: forms.py:25
+msgid "Color"
+msgstr "Color"
+
+#: forms.py:42 permissions.py:7
+msgid "Tags"
+msgstr "Etiquetas"
+
+#: literals.py:18
msgid "Blue"
msgstr "Azul"
-#: models.py:19
+#: literals.py:19
msgid "Cyan"
msgstr "Cian"
-#: models.py:20
+#: literals.py:20
msgid "Coral"
msgstr "Coral"
-#: models.py:21
+#: literals.py:21
msgid "Green-Yellow"
msgstr "Verde-Amarillo"
-#: models.py:22
+#: literals.py:22
msgid "Khaki"
msgstr "Caqui"
-#: models.py:23
+#: literals.py:23
msgid "LightGrey"
msgstr "Gris claro"
-#: models.py:24
+#: literals.py:24
msgid "Magenta"
msgstr "Magenta"
-#: models.py:25
+#: literals.py:25
msgid "Red"
msgstr "Rojo"
-#: models.py:26
+#: literals.py:26
msgid "Orange"
msgstr "Naranja"
-#: models.py:27
+#: literals.py:27
msgid "Yellow"
msgstr "Amarillo"
-#: models.py:45 views.py:185 views.py:233 views.py:248
+#: models.py:12 views.py:154 views.py:206 views.py:220
msgid "tag"
msgstr "etiqueta"
-#: models.py:49
+#: models.py:13
+msgid "color"
+msgstr "color"
+
+#: models.py:16
msgid "tag properties"
msgstr "propiedades de etiqueta"
-#: models.py:50
+#: models.py:17
msgid "tags properties"
msgstr "propiedades de etiquetas"
-#: views.py:33
+#: permissions.py:9
+msgid "Create new tags"
+msgstr "Crear nuevas etiquetas"
+
+#: permissions.py:10
+msgid "Delete tags"
+msgstr "Borrar etiquetas"
+
+#: permissions.py:11
+msgid "Edit tags"
+msgstr "Editar etiquetas"
+
+#: permissions.py:12
+msgid "View tags"
+msgstr "Ver etiquetas"
+
+#: permissions.py:13
+msgid "Attach tags to documents"
+msgstr "Anejar etiquetas a documentos"
+
+#: permissions.py:14
+msgid "Remove tags from documents"
+msgstr "Remover etiquetas de los documentos"
+
+#: views.py:42
msgid "Tag already exists."
msgstr "Etiqueta ya existe."
-#: views.py:40
+#: views.py:50
msgid "Tag created succesfully."
msgstr "Etiqueta creada exitosamente."
-#: views.py:46
+#: views.py:56
msgid "create tag"
msgstr "crear etiquetas"
-#: views.py:73 views.py:112
-msgid "Must choose either a new tag or an existing one."
-msgstr "Debe elegir una etiqueta nueva o una ya existente."
-
-#: views.py:77 views.py:116
+#: views.py:77
#, python-format
msgid "Document is already tagged as \"%s\""
msgstr "Documento ya está etiquetado como \"%s\""
-#: views.py:86
-#, python-format
-msgid "Tag \"%s\" added successfully."
-msgstr "Etiqueta \"%s\", agregada exitosamente."
-
-#: views.py:124
-#, python-format
-msgid "Tag \"%s\" added and attached successfully."
-msgstr "Etiqueta \"%s\" agregada y se adjuntada exitosamente."
-
-#: views.py:126
+#: views.py:82
#, python-format
msgid "Tag \"%s\" attached successfully."
msgstr "Etiqueta \"%s\" adjuntada exitosamente."
-#: views.py:133
+#: views.py:88
#, python-format
msgid "attach tag to: %s"
msgstr "adjuntar etiqueta a: %s"
-#: views.py:149
-msgid "tagged items"
-msgstr "artículos etiquetados"
-
-#: views.py:166 views.py:280
+#: views.py:130 views.py:257
msgid "Must provide at least one tag."
msgstr "Debe proveer al menos una etiqueta."
-#: views.py:176
+#: views.py:145
#, python-format
msgid "Tag \"%s\" deleted successfully."
msgstr "Etiqueta \"%s\" borrada exitosamente."
-#: views.py:178 views.py:294
+#: views.py:147 views.py:269
#, python-format
msgid "Error deleting tag \"%(tag)s\": %(error)s"
msgstr "Error al eliminar la etiqueta \"%(tag)s\": %(error)s"
-#: views.py:193
+#: views.py:162
#, python-format
msgid "Are you sure you wish to delete the tag: %s?"
msgstr "¿Está seguro que desea eliminar la etiqueta: %s?"
-#: views.py:194 views.py:197
+#: views.py:163 views.py:166
msgid "Will be removed from all documents."
msgstr "Se removerá de todos los documentos."
-#: views.py:196
+#: views.py:165
#, python-format
msgid "Are you sure you wish to delete the tags: %s?"
msgstr "¿Está seguro que desea eliminar de las etiquetas: %s?"
-#: views.py:221
+#: views.py:194
msgid "Tag updated succesfully."
msgstr "Etiqueta actualizada exitosamente."
-#: views.py:230
+#: views.py:203
#, python-format
msgid "edit tag: %s"
msgstr "editar la etiqueta: %s"
-#: views.py:245
+#: views.py:217
#, python-format
msgid "documents with the tag \"%s\""
msgstr "documentos con la etiqueta \"%s\""
-#: views.py:258
+#: views.py:236
#, python-format
msgid "tags for: %s"
msgstr "etiquetas para: %s"
-#: views.py:292
+#: views.py:267
#, python-format
msgid "Tag \"%s\" removed successfully."
msgstr "Etiqueta \"%s\" removida exitosamente."
-#: views.py:308
+#: views.py:283
#, python-format
msgid "Are you sure you wish to remove the tag: %s?"
msgstr "¿Está seguro que desea eliminar la etiqueta: %s?"
-#: views.py:310
+#: views.py:285
#, python-format
msgid "Are you sure you wish to remove the tags: %s?"
msgstr "¿Está seguro que desea eliminar de las etiquetas: %s?"
@@ -265,3 +246,5 @@ msgstr "¿Está seguro que desea eliminar de las etiquetas: %s?"
#: templatetags/tags_tags.py:17
msgid "Add tag to document"
msgstr "Agregar etiqueta al documento"
+
+
diff --git a/apps/tags/locale/it/LC_MESSAGES/django.mo b/apps/tags/locale/it/LC_MESSAGES/django.mo
new file mode 100644
index 0000000000..053f74c273
Binary files /dev/null and b/apps/tags/locale/it/LC_MESSAGES/django.mo differ
diff --git a/apps/tags/locale/it/LC_MESSAGES/django.po b/apps/tags/locale/it/LC_MESSAGES/django.po
new file mode 100644
index 0000000000..34e4aceea0
--- /dev/null
+++ b/apps/tags/locale/it/LC_MESSAGES/django.po
@@ -0,0 +1,251 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# , 2011.
+# Roberto Rosario , 2011.
+msgid ""
+msgstr ""
+"Project-Id-Version: Mayan EDMS\n"
+"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
+"PO-Revision-Date: 2012-02-12 19:23+0000\n"
+"Last-Translator: Roberto Rosario \n"
+"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/it/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: it\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+
+#: __init__.py:20
+msgid "tag list"
+msgstr "lista delle etichette"
+
+#: __init__.py:21
+msgid "create new tag"
+msgstr "crea una nuova etichetta"
+
+#: __init__.py:22
+msgid "attach tag"
+msgstr "allega un'etichetta"
+
+#: __init__.py:23 __init__.py:24
+msgid "remove"
+msgstr "rimuovi"
+
+#: __init__.py:25 __init__.py:44 __init__.py:52 views.py:98
+msgid "tags"
+msgstr "etichette"
+
+#: __init__.py:26 __init__.py:29
+msgid "delete"
+msgstr "cancella"
+
+#: __init__.py:27
+msgid "edit"
+msgstr "modifica"
+
+#: __init__.py:28
+msgid "tagged documents"
+msgstr "documenti etichettati"
+
+#: __init__.py:30
+msgid "ACLs"
+msgstr ""
+
+#: __init__.py:34
+msgid "preview"
+msgstr ""
+
+#: __init__.py:38
+msgid "tagged items"
+msgstr "articoli etichettati."
+
+#: forms.py:24
+msgid "Name"
+msgstr "Nome"
+
+#: forms.py:25
+msgid "Color"
+msgstr "Colori"
+
+#: forms.py:42 permissions.py:7
+msgid "Tags"
+msgstr "Etichette"
+
+#: literals.py:18
+msgid "Blue"
+msgstr "Blue"
+
+#: literals.py:19
+msgid "Cyan"
+msgstr "Ciaono"
+
+#: literals.py:20
+msgid "Coral"
+msgstr "Corallo"
+
+#: literals.py:21
+msgid "Green-Yellow"
+msgstr "Verdognolo"
+
+#: literals.py:22
+msgid "Khaki"
+msgstr "Khaki"
+
+#: literals.py:23
+msgid "LightGrey"
+msgstr "Grigio chiaro"
+
+#: literals.py:24
+msgid "Magenta"
+msgstr "Magenta"
+
+#: literals.py:25
+msgid "Red"
+msgstr "Rosso"
+
+#: literals.py:26
+msgid "Orange"
+msgstr "Arancione"
+
+#: literals.py:27
+msgid "Yellow"
+msgstr "Giallo"
+
+#: models.py:12 views.py:154 views.py:206 views.py:220
+msgid "tag"
+msgstr "etichetta"
+
+#: models.py:13
+msgid "color"
+msgstr "colore"
+
+#: models.py:16
+msgid "tag properties"
+msgstr "proprità dell'etichetta"
+
+#: models.py:17
+msgid "tags properties"
+msgstr "proprietà delle etichette"
+
+#: permissions.py:9
+msgid "Create new tags"
+msgstr "Crea un nuova etichetta"
+
+#: permissions.py:10
+msgid "Delete tags"
+msgstr ""
+
+#: permissions.py:11
+msgid "Edit tags"
+msgstr ""
+
+#: permissions.py:12
+msgid "View tags"
+msgstr ""
+
+#: permissions.py:13
+msgid "Attach tags to documents"
+msgstr ""
+
+#: permissions.py:14
+msgid "Remove tags from documents"
+msgstr "Rimuovi etichetta dal documento"
+
+#: views.py:42
+msgid "Tag already exists."
+msgstr "L'etichetta già esiste"
+
+#: views.py:50
+msgid "Tag created succesfully."
+msgstr "Etichetta creata con successo"
+
+#: views.py:56
+msgid "create tag"
+msgstr "crea etichetta"
+
+#: views.py:77
+#, python-format
+msgid "Document is already tagged as \"%s\""
+msgstr "Il documento è giià stato etichettato come \"%s\"."
+
+#: views.py:82
+#, python-format
+msgid "Tag \"%s\" attached successfully."
+msgstr "Eticetta \"%s\" allegata con successo."
+
+#: views.py:88
+#, python-format
+msgid "attach tag to: %s"
+msgstr "allega etichetta a:%s"
+
+#: views.py:130 views.py:257
+msgid "Must provide at least one tag."
+msgstr "Devi fornire almeno un'etichetta"
+
+#: views.py:145
+#, python-format
+msgid "Tag \"%s\" deleted successfully."
+msgstr "Etichetta \"%s\" cancellata con successo."
+
+#: views.py:147 views.py:269
+#, python-format
+msgid "Error deleting tag \"%(tag)s\": %(error)s"
+msgstr "Errore nel cancellare l'etichetta \"%(tag)s\": %(error)s"
+
+#: views.py:162
+#, python-format
+msgid "Are you sure you wish to delete the tag: %s?"
+msgstr "Sei sicuro di voler cancellare questa etichetta: %s?"
+
+#: views.py:163 views.py:166
+msgid "Will be removed from all documents."
+msgstr "Sarà rimossa da tutti i documenti"
+
+#: views.py:165
+#, python-format
+msgid "Are you sure you wish to delete the tags: %s?"
+msgstr "Sei sicuro di voler cancellare tutte queste etichette: %s?"
+
+#: views.py:194
+msgid "Tag updated succesfully."
+msgstr "Etichetta aggiornata con successo"
+
+#: views.py:203
+#, python-format
+msgid "edit tag: %s"
+msgstr "modifica l'etichetta:%s"
+
+#: views.py:217
+#, python-format
+msgid "documents with the tag \"%s\""
+msgstr "documenti con l'etichetta \"%s\""
+
+#: views.py:236
+#, python-format
+msgid "tags for: %s"
+msgstr "etichette per: %s"
+
+#: views.py:267
+#, python-format
+msgid "Tag \"%s\" removed successfully."
+msgstr "Etichetta \"%s\" rimossa con successo."
+
+#: views.py:283
+#, python-format
+msgid "Are you sure you wish to remove the tag: %s?"
+msgstr "Sei sicuro di voler rimuovere le etichetta: %s ?"
+
+#: views.py:285
+#, python-format
+msgid "Are you sure you wish to remove the tags: %s?"
+msgstr "Sei sicuro di voler rimuovere le etichette: %s ?"
+
+#: templatetags/tags_tags.py:17
+msgid "Add tag to document"
+msgstr "Aggiungi l'etichetta al documento"
+
+
diff --git a/apps/tags/locale/pl/LC_MESSAGES/django.mo b/apps/tags/locale/pl/LC_MESSAGES/django.mo
new file mode 100644
index 0000000000..1d19aee01f
Binary files /dev/null and b/apps/tags/locale/pl/LC_MESSAGES/django.mo differ
diff --git a/apps/tags/locale/pl/LC_MESSAGES/django.po b/apps/tags/locale/pl/LC_MESSAGES/django.po
new file mode 100644
index 0000000000..0934ee350b
--- /dev/null
+++ b/apps/tags/locale/pl/LC_MESSAGES/django.po
@@ -0,0 +1,248 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# , 2012.
+msgid ""
+msgstr ""
+"Project-Id-Version: Mayan EDMS\n"
+"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
+"PO-Revision-Date: 2012-02-20 16:03+0000\n"
+"Last-Translator: mic \n"
+"Language-Team: Polish (http://www.transifex.net/projects/p/mayan-edms/language/pl/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: pl\n"
+"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
+
+#: __init__.py:20
+msgid "tag list"
+msgstr "lista tagów"
+
+#: __init__.py:21
+msgid "create new tag"
+msgstr "utworzyć nowy tag"
+
+#: __init__.py:22
+msgid "attach tag"
+msgstr ""
+
+#: __init__.py:23 __init__.py:24
+msgid "remove"
+msgstr "usuń"
+
+#: __init__.py:25 __init__.py:44 __init__.py:52 views.py:98
+msgid "tags"
+msgstr "tagi"
+
+#: __init__.py:26 __init__.py:29
+msgid "delete"
+msgstr "usunąć"
+
+#: __init__.py:27
+msgid "edit"
+msgstr "edytuj"
+
+#: __init__.py:28
+msgid "tagged documents"
+msgstr ""
+
+#: __init__.py:30
+msgid "ACLs"
+msgstr ""
+
+#: __init__.py:34
+msgid "preview"
+msgstr ""
+
+#: __init__.py:38
+msgid "tagged items"
+msgstr ""
+
+#: forms.py:24
+msgid "Name"
+msgstr "Nazwa"
+
+#: forms.py:25
+msgid "Color"
+msgstr ""
+
+#: forms.py:42 permissions.py:7
+msgid "Tags"
+msgstr "Tagi"
+
+#: literals.py:18
+msgid "Blue"
+msgstr "Niebieski"
+
+#: literals.py:19
+msgid "Cyan"
+msgstr "Cyan"
+
+#: literals.py:20
+msgid "Coral"
+msgstr "Koral"
+
+#: literals.py:21
+msgid "Green-Yellow"
+msgstr "Zielono-żółty"
+
+#: literals.py:22
+msgid "Khaki"
+msgstr "Khaki"
+
+#: literals.py:23
+msgid "LightGrey"
+msgstr "Jasnoszary"
+
+#: literals.py:24
+msgid "Magenta"
+msgstr "Magenta"
+
+#: literals.py:25
+msgid "Red"
+msgstr "Czerwony"
+
+#: literals.py:26
+msgid "Orange"
+msgstr "Pomarańczowy"
+
+#: literals.py:27
+msgid "Yellow"
+msgstr "Żółty"
+
+#: models.py:12 views.py:154 views.py:206 views.py:220
+msgid "tag"
+msgstr "tag"
+
+#: models.py:13
+msgid "color"
+msgstr ""
+
+#: models.py:16
+msgid "tag properties"
+msgstr ""
+
+#: models.py:17
+msgid "tags properties"
+msgstr ""
+
+#: permissions.py:9
+msgid "Create new tags"
+msgstr "Utwórz nowe tagi"
+
+#: permissions.py:10
+msgid "Delete tags"
+msgstr ""
+
+#: permissions.py:11
+msgid "Edit tags"
+msgstr ""
+
+#: permissions.py:12
+msgid "View tags"
+msgstr ""
+
+#: permissions.py:13
+msgid "Attach tags to documents"
+msgstr ""
+
+#: permissions.py:14
+msgid "Remove tags from documents"
+msgstr "Usuń tagi z dokumentów"
+
+#: views.py:42
+msgid "Tag already exists."
+msgstr ""
+
+#: views.py:50
+msgid "Tag created succesfully."
+msgstr ""
+
+#: views.py:56
+msgid "create tag"
+msgstr ""
+
+#: views.py:77
+#, python-format
+msgid "Document is already tagged as \"%s\""
+msgstr ""
+
+#: views.py:82
+#, python-format
+msgid "Tag \"%s\" attached successfully."
+msgstr ""
+
+#: views.py:88
+#, python-format
+msgid "attach tag to: %s"
+msgstr ""
+
+#: views.py:130 views.py:257
+msgid "Must provide at least one tag."
+msgstr ""
+
+#: views.py:145
+#, python-format
+msgid "Tag \"%s\" deleted successfully."
+msgstr ""
+
+#: views.py:147 views.py:269
+#, python-format
+msgid "Error deleting tag \"%(tag)s\": %(error)s"
+msgstr ""
+
+#: views.py:162
+#, python-format
+msgid "Are you sure you wish to delete the tag: %s?"
+msgstr ""
+
+#: views.py:163 views.py:166
+msgid "Will be removed from all documents."
+msgstr ""
+
+#: views.py:165
+#, python-format
+msgid "Are you sure you wish to delete the tags: %s?"
+msgstr ""
+
+#: views.py:194
+msgid "Tag updated succesfully."
+msgstr ""
+
+#: views.py:203
+#, python-format
+msgid "edit tag: %s"
+msgstr ""
+
+#: views.py:217
+#, python-format
+msgid "documents with the tag \"%s\""
+msgstr ""
+
+#: views.py:236
+#, python-format
+msgid "tags for: %s"
+msgstr ""
+
+#: views.py:267
+#, python-format
+msgid "Tag \"%s\" removed successfully."
+msgstr ""
+
+#: views.py:283
+#, python-format
+msgid "Are you sure you wish to remove the tag: %s?"
+msgstr ""
+
+#: views.py:285
+#, python-format
+msgid "Are you sure you wish to remove the tags: %s?"
+msgstr ""
+
+#: templatetags/tags_tags.py:17
+msgid "Add tag to document"
+msgstr ""
diff --git a/apps/tags/locale/pt/LC_MESSAGES/django.mo b/apps/tags/locale/pt/LC_MESSAGES/django.mo
index db86c8cc36..cbec8673bc 100644
Binary files a/apps/tags/locale/pt/LC_MESSAGES/django.mo and b/apps/tags/locale/pt/LC_MESSAGES/django.mo differ
diff --git a/apps/tags/locale/pt/LC_MESSAGES/django.po b/apps/tags/locale/pt/LC_MESSAGES/django.po
index bbc0936a4d..72632ba281 100644
--- a/apps/tags/locale/pt/LC_MESSAGES/django.po
+++ b/apps/tags/locale/pt/LC_MESSAGES/django.po
@@ -1,263 +1,245 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
-#
+#
# Translators:
# , 2011.
+# Roberto Rosario , 2012.
msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-11-22 11:26-0400\n"
-"PO-Revision-Date: 2011-11-02 01:45+0000\n"
-"Last-Translator: emersonsoares \n"
-"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/"
-"team/pt/)\n"
-"Language: pt\n"
+"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
+"PO-Revision-Date: 2012-02-21 16:45+0000\n"
+"Last-Translator: Roberto Rosario \n"
+"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/language/pt/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
+"Language: pt\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
-#: __init__.py:13
-msgid "Create new tags"
-msgstr "Criar novas etiquetas"
-
-#: __init__.py:14
-msgid "Attach exising tags"
-msgstr "Anexar etiquetas existentes"
-
-#: __init__.py:15
-msgid "Remove tags from documents"
-msgstr "Remover etiquetas de documentos"
-
-#: __init__.py:16
-msgid "Delete global tags"
-msgstr "Excluir etiquetas globais"
-
-#: __init__.py:17
-msgid "Edit global tags"
-msgstr "Editar etiquetas globais"
-
-#: __init__.py:18
-msgid "View a document's tags"
-msgstr "Ver etiquetas de um documento"
-
#: __init__.py:20
-msgid "Tags"
-msgstr "Etiquetas"
-
-#: __init__.py:28
msgid "tag list"
msgstr "lista de etiquetas"
-#: __init__.py:29
+#: __init__.py:21
msgid "create new tag"
msgstr "criar nova etiqueta"
-#: __init__.py:30
+#: __init__.py:22
msgid "attach tag"
msgstr "anexar etiqueta"
-#: __init__.py:31 __init__.py:32
+#: __init__.py:23 __init__.py:24
msgid "remove"
msgstr "remover"
-#: __init__.py:33 __init__.py:58 utils.py:14 views.py:144
+#: __init__.py:25 __init__.py:44 __init__.py:52 views.py:98
msgid "tags"
msgstr "Etiquetas"
-#: __init__.py:34 __init__.py:37
+#: __init__.py:26 __init__.py:29
msgid "delete"
msgstr "excluir"
-#: __init__.py:35
+#: __init__.py:27
msgid "edit"
msgstr "editar"
-#: __init__.py:36
+#: __init__.py:28
msgid "tagged documents"
msgstr "documentos etiquetados"
-#: __init__.py:41 models.py:46
-msgid "color"
-msgstr "cor"
+#: __init__.py:30
+msgid "ACLs"
+msgstr ""
-#: __init__.py:45
-msgid "color name"
-msgstr "nome da cor"
+#: __init__.py:34
+msgid "preview"
+msgstr ""
-#: forms.py:14
-msgid "New tag"
-msgstr "Nova etiqueta"
+#: __init__.py:38
+msgid "tagged items"
+msgstr "itens marcados"
-#: forms.py:15 forms.py:24
-msgid "Color"
-msgstr "Cor"
-
-#: forms.py:16
-msgid "Existing tags"
-msgstr "Etiquetas existentes"
-
-#: forms.py:23
+#: forms.py:24
msgid "Name"
msgstr "Nome"
-#: models.py:18
+#: forms.py:25
+msgid "Color"
+msgstr "Cor"
+
+#: forms.py:42 permissions.py:7
+msgid "Tags"
+msgstr "Etiquetas"
+
+#: literals.py:18
msgid "Blue"
msgstr "Azul"
-#: models.py:19
+#: literals.py:19
msgid "Cyan"
msgstr "Ciano"
-#: models.py:20
+#: literals.py:20
msgid "Coral"
msgstr "Coral"
-#: models.py:21
+#: literals.py:21
msgid "Green-Yellow"
msgstr "Verde-Amarelo"
-#: models.py:22
+#: literals.py:22
msgid "Khaki"
msgstr "Caqui"
-#: models.py:23
+#: literals.py:23
msgid "LightGrey"
msgstr "Cinza Claro"
-#: models.py:24
+#: literals.py:24
msgid "Magenta"
msgstr "Magenta"
-#: models.py:25
+#: literals.py:25
msgid "Red"
msgstr "Vermelho"
-#: models.py:26
+#: literals.py:26
msgid "Orange"
msgstr "Laranja"
-#: models.py:27
+#: literals.py:27
msgid "Yellow"
msgstr "Amarelo"
-#: models.py:45 views.py:185 views.py:233 views.py:248
+#: models.py:12 views.py:154 views.py:206 views.py:220
msgid "tag"
msgstr "etiqueta"
-#: models.py:49
+#: models.py:13
+msgid "color"
+msgstr "cor"
+
+#: models.py:16
msgid "tag properties"
msgstr "propriedades de etiqueta"
-#: models.py:50
+#: models.py:17
msgid "tags properties"
msgstr "propriedades de etiquetas"
-#: views.py:33
+#: permissions.py:9
+msgid "Create new tags"
+msgstr "Criar novas etiquetas"
+
+#: permissions.py:10
+msgid "Delete tags"
+msgstr "Excluir etiquetas"
+
+#: permissions.py:11
+msgid "Edit tags"
+msgstr "Editar as etiquetas"
+
+#: permissions.py:12
+msgid "View tags"
+msgstr "Ver etiquetas"
+
+#: permissions.py:13
+msgid "Attach tags to documents"
+msgstr "Anexar etiquetas para documentos"
+
+#: permissions.py:14
+msgid "Remove tags from documents"
+msgstr "Remover etiquetas de documentos"
+
+#: views.py:42
msgid "Tag already exists."
msgstr "Etiqueta já existe."
-#: views.py:40
+#: views.py:50
msgid "Tag created succesfully."
msgstr "Etiqueta criada com sucesso."
-#: views.py:46
+#: views.py:56
msgid "create tag"
msgstr "criar etiqueta"
-#: views.py:73 views.py:112
-msgid "Must choose either a new tag or an existing one."
-msgstr "Deve optar por uma nova etiqueta ou uma já existente."
-
-#: views.py:77 views.py:116
+#: views.py:77
#, python-format
msgid "Document is already tagged as \"%s\""
msgstr "Documento já está marcado como \"%s\""
-#: views.py:86
-#, python-format
-msgid "Tag \"%s\" added successfully."
-msgstr "Etiqueta \"%s\" adicionada com sucesso."
-
-#: views.py:124
-#, python-format
-msgid "Tag \"%s\" added and attached successfully."
-msgstr "Etiqueta \"%s\", acrescentada e anexada com sucesso."
-
-#: views.py:126
+#: views.py:82
#, python-format
msgid "Tag \"%s\" attached successfully."
msgstr "Etiqueta \"%s\" anexada com sucesso."
-#: views.py:133
+#: views.py:88
#, python-format
msgid "attach tag to: %s"
msgstr "anexar etiqueta a: %s"
-#: views.py:149
-msgid "tagged items"
-msgstr "itens marcados"
-
-#: views.py:166 views.py:280
+#: views.py:130 views.py:257
msgid "Must provide at least one tag."
msgstr "Deve fornecer pelo menos uma etiqueta."
-#: views.py:176
+#: views.py:145
#, python-format
msgid "Tag \"%s\" deleted successfully."
msgstr "Etiqueta \"%s\" removida com sucesso."
-#: views.py:178 views.py:294
+#: views.py:147 views.py:269
#, python-format
msgid "Error deleting tag \"%(tag)s\": %(error)s"
msgstr "Erro ao excluir etiqueta \" %(tag)s \": %(error)s "
-#: views.py:193
+#: views.py:162
#, python-format
msgid "Are you sure you wish to delete the tag: %s?"
msgstr "Tem certeza de que deseja excluir a etiqueta: %s?"
-#: views.py:194 views.py:197
+#: views.py:163 views.py:166
msgid "Will be removed from all documents."
msgstr "Será removido de todos os documentos."
-#: views.py:196
+#: views.py:165
#, python-format
msgid "Are you sure you wish to delete the tags: %s?"
msgstr "Você tem certeza que deseja deletar as etiquetas: %s?"
-#: views.py:221
+#: views.py:194
msgid "Tag updated succesfully."
msgstr "Etiqueta atualizada com sucesso."
-#: views.py:230
+#: views.py:203
#, python-format
msgid "edit tag: %s"
msgstr "editar etiqueta: %s"
-#: views.py:245
+#: views.py:217
#, python-format
msgid "documents with the tag \"%s\""
msgstr "documentos com a etiqueta \"%s\""
-#: views.py:258
+#: views.py:236
#, python-format
msgid "tags for: %s"
msgstr "etiquetas para: %s"
-#: views.py:292
+#: views.py:267
#, python-format
msgid "Tag \"%s\" removed successfully."
msgstr "Etiqueta \"%s\" removida com sucesso."
-#: views.py:308
+#: views.py:283
#, python-format
msgid "Are you sure you wish to remove the tag: %s?"
msgstr "Tem certeza de que deseja remover a etiqueta: %s?"
-#: views.py:310
+#: views.py:285
#, python-format
msgid "Are you sure you wish to remove the tags: %s?"
msgstr "Tem certeza de que deseja remover as etiquetas: %s?"
diff --git a/apps/tags/locale/ru/LC_MESSAGES/django.mo b/apps/tags/locale/ru/LC_MESSAGES/django.mo
index 9caaeae59d..52c652c98d 100644
Binary files a/apps/tags/locale/ru/LC_MESSAGES/django.mo and b/apps/tags/locale/ru/LC_MESSAGES/django.mo differ
diff --git a/apps/tags/locale/ru/LC_MESSAGES/django.po b/apps/tags/locale/ru/LC_MESSAGES/django.po
index 1e057efbd3..4ac1a23f22 100644
--- a/apps/tags/locale/ru/LC_MESSAGES/django.po
+++ b/apps/tags/locale/ru/LC_MESSAGES/django.po
@@ -1,263 +1,244 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
-#
+#
# Translators:
+# Sergey Glita , 2012.
msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-11-22 11:26-0400\n"
-"PO-Revision-Date: 2011-11-04 15:20+0000\n"
-"Last-Translator: gsv70 \n"
-"Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/team/"
-"ru/)\n"
-"Language: ru\n"
+"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
+"POT-Creation-Date: 2012-02-12 15:20-0400\n"
+"PO-Revision-Date: 2012-02-27 04:24+0000\n"
+"Last-Translator: Sergey Glita \n"
+"Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/language/ru/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
-"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
-
-#: __init__.py:13
-msgid "Create new tags"
-msgstr "Создание новых меток"
-
-#: __init__.py:14
-msgid "Attach exising tags"
-msgstr "Прикрепить существующие метки"
-
-#: __init__.py:15
-msgid "Remove tags from documents"
-msgstr "Удаление тегов из документов"
-
-#: __init__.py:16
-msgid "Delete global tags"
-msgstr "Удалить общие метки"
-
-#: __init__.py:17
-msgid "Edit global tags"
-msgstr "Изменить общие метки"
-
-#: __init__.py:18
-msgid "View a document's tags"
-msgstr "Просмотр тегов документа"
+"Language: ru\n"
+"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
#: __init__.py:20
-msgid "Tags"
-msgstr "Метки"
-
-#: __init__.py:28
msgid "tag list"
msgstr "список меток"
-#: __init__.py:29
+#: __init__.py:21
msgid "create new tag"
msgstr "создать новую метку"
-#: __init__.py:30
+#: __init__.py:22
msgid "attach tag"
msgstr "пометить"
-#: __init__.py:31 __init__.py:32
+#: __init__.py:23 __init__.py:24
msgid "remove"
msgstr "удаление"
-#: __init__.py:33 __init__.py:58 utils.py:14 views.py:144
+#: __init__.py:25 __init__.py:44 __init__.py:52 views.py:98
msgid "tags"
msgstr "метки"
-#: __init__.py:34 __init__.py:37
+#: __init__.py:26 __init__.py:29
msgid "delete"
msgstr "удалить"
-#: __init__.py:35
+#: __init__.py:27
msgid "edit"
msgstr "редактировать"
-#: __init__.py:36
+#: __init__.py:28
msgid "tagged documents"
msgstr "помеченные документы"
-#: __init__.py:41 models.py:46
-msgid "color"
-msgstr "цвет"
+#: __init__.py:30
+msgid "ACLs"
+msgstr "ACLs"
-#: __init__.py:45
-msgid "color name"
-msgstr "название цвета"
+#: __init__.py:34
+msgid "preview"
+msgstr "предварительный просмотр"
-#: forms.py:14
-msgid "New tag"
-msgstr "Новая метка"
+#: __init__.py:38
+msgid "tagged items"
+msgstr "помеченные элементы"
-#: forms.py:15 forms.py:24
-msgid "Color"
-msgstr "Цвет"
-
-#: forms.py:16
-msgid "Existing tags"
-msgstr "Существующие метки"
-
-#: forms.py:23
+#: forms.py:24
msgid "Name"
msgstr "Имя"
-#: models.py:18
+#: forms.py:25
+msgid "Color"
+msgstr "Цвет"
+
+#: forms.py:42 permissions.py:7
+msgid "Tags"
+msgstr "Метки"
+
+#: literals.py:18
msgid "Blue"
msgstr "Синий"
-#: models.py:19
+#: literals.py:19
msgid "Cyan"
msgstr "Голубой"
-#: models.py:20
+#: literals.py:20
msgid "Coral"
msgstr "Коралловый"
-#: models.py:21
+#: literals.py:21
msgid "Green-Yellow"
msgstr "Зелено-желтый"
-#: models.py:22
+#: literals.py:22
msgid "Khaki"
msgstr "Хаки"
-#: models.py:23
+#: literals.py:23
msgid "LightGrey"
msgstr "Светло-серый"
-#: models.py:24
+#: literals.py:24
msgid "Magenta"
msgstr "Пурпурный"
-#: models.py:25
+#: literals.py:25
msgid "Red"
msgstr "Красный"
-#: models.py:26
+#: literals.py:26
msgid "Orange"
msgstr "Оранжевый"
-#: models.py:27
+#: literals.py:27
msgid "Yellow"
msgstr "Желтый"
-#: models.py:45 views.py:185 views.py:233 views.py:248
+#: models.py:12 views.py:154 views.py:206 views.py:220
msgid "tag"
msgstr "метка"
-#: models.py:49
+#: models.py:13
+msgid "color"
+msgstr "цвет"
+
+#: models.py:16
msgid "tag properties"
msgstr "свойства метки"
-#: models.py:50
+#: models.py:17
msgid "tags properties"
msgstr "свойства метки"
-#: views.py:33
+#: permissions.py:9
+msgid "Create new tags"
+msgstr "Создание новых меток"
+
+#: permissions.py:10
+msgid "Delete tags"
+msgstr "Удалить метки"
+
+#: permissions.py:11
+msgid "Edit tags"
+msgstr "Редактировать метки"
+
+#: permissions.py:12
+msgid "View tags"
+msgstr "Посмотреть метки"
+
+#: permissions.py:13
+msgid "Attach tags to documents"
+msgstr "Прикрепить метки к документам"
+
+#: permissions.py:14
+msgid "Remove tags from documents"
+msgstr "Удаление тегов из документов"
+
+#: views.py:42
msgid "Tag already exists."
msgstr "Метка уже существует."
-#: views.py:40
+#: views.py:50
msgid "Tag created succesfully."
msgstr "Метка создана."
-#: views.py:46
+#: views.py:56
msgid "create tag"
msgstr "создать метку"
-#: views.py:73 views.py:112
-msgid "Must choose either a new tag or an existing one."
-msgstr "Необходимо выбрать новые метки или существующие."
-
-#: views.py:77 views.py:116
+#: views.py:77
#, python-format
msgid "Document is already tagged as \"%s\""
msgstr "Документ уже помечены как \"%s\""
-#: views.py:86
-#, python-format
-msgid "Tag \"%s\" added successfully."
-msgstr "Метка \"%s\" добавлена"
-
-#: views.py:124
-#, python-format
-msgid "Tag \"%s\" added and attached successfully."
-msgstr "Метка\"%s\" добавлена и прикреплена."
-
-#: views.py:126
+#: views.py:82
#, python-format
msgid "Tag \"%s\" attached successfully."
msgstr "Помечено как \"%s\""
-#: views.py:133
+#: views.py:88
#, python-format
msgid "attach tag to: %s"
msgstr "пометить как %s"
-#: views.py:149
-msgid "tagged items"
-msgstr "помеченные элементы"
-
-#: views.py:166 views.py:280
+#: views.py:130 views.py:257
msgid "Must provide at least one tag."
msgstr "Должна быть хотя бы одна метка."
-#: views.py:176
+#: views.py:145
#, python-format
msgid "Tag \"%s\" deleted successfully."
msgstr "Метка \"%s\"удалён."
-#: views.py:178 views.py:294
+#: views.py:147 views.py:269
#, python-format
msgid "Error deleting tag \"%(tag)s\": %(error)s"
msgstr "Ошибка при удалении метки \"%(tag)s\": %(error)s"
-#: views.py:193
+#: views.py:162
#, python-format
msgid "Are you sure you wish to delete the tag: %s?"
msgstr "Вы действительно хотите удалить метку: %s?"
-#: views.py:194 views.py:197
+#: views.py:163 views.py:166
msgid "Will be removed from all documents."
msgstr "Будет удален из всех документов."
-#: views.py:196
+#: views.py:165
#, python-format
msgid "Are you sure you wish to delete the tags: %s?"
msgstr "Вы действительно хотите удалить метки: %s?"
-#: views.py:221
+#: views.py:194
msgid "Tag updated succesfully."
msgstr "Метка обновлена."
-#: views.py:230
+#: views.py:203
#, python-format
msgid "edit tag: %s"
msgstr "редактировать метку %s"
-#: views.py:245
+#: views.py:217
#, python-format
msgid "documents with the tag \"%s\""
msgstr "документы с тегом \"%s\""
-#: views.py:258
+#: views.py:236
#, python-format
msgid "tags for: %s"
msgstr "теги для:%s"
-#: views.py:292
+#: views.py:267
#, python-format
msgid "Tag \"%s\" removed successfully."
msgstr "Метка \"%s\" удалена."
-#: views.py:308
+#: views.py:283
#, python-format
msgid "Are you sure you wish to remove the tag: %s?"
msgstr "Вы действительно хотите снять метку: %s?"
-#: views.py:310
+#: views.py:285
#, python-format
msgid "Are you sure you wish to remove the tags: %s?"
msgstr "Вы действительно хотите снять метку: %s?"
diff --git a/apps/tags/models.py b/apps/tags/models.py
index 8c36a2cb7c..98bd405f3b 100644
--- a/apps/tags/models.py
+++ b/apps/tags/models.py
@@ -1,44 +1,11 @@
+from __future__ import absolute_import
+
from django.db import models
from django.utils.translation import ugettext_lazy as _
from taggit.models import Tag
-COLOR_RED = u'red'
-COLOR_BLUE = u'blu'
-COLOR_MAGENTA = u'mag'
-COLOR_CYAN = u'cya'
-COLOR_YELLOW = u'yel'
-COLOR_GREENYELLOW = u'gry'
-COLOR_CORAL = u'crl'
-COLOR_KHAKI = u'kki'
-COLOR_LIGHTGREY = u'lig'
-COLOR_ORANGE = u'org'
-
-COLOR_CHOICES = (
- (COLOR_BLUE, _(u'Blue')),
- (COLOR_CYAN, _(u'Cyan')),
- (COLOR_CORAL, _(u'Coral')),
- (COLOR_GREENYELLOW, _(u'Green-Yellow')),
- (COLOR_KHAKI, _(u'Khaki')),
- (COLOR_LIGHTGREY, _(u'LightGrey')),
- (COLOR_MAGENTA, _(u'Magenta')),
- (COLOR_RED, _(u'Red')),
- (COLOR_ORANGE, _(u'Orange')),
- (COLOR_YELLOW, _(u'Yellow'))
-)
-
-COLOR_CODES = (
- (COLOR_RED, u'red'),
- (COLOR_BLUE, u'blue'),
- (COLOR_MAGENTA, u'magenta'),
- (COLOR_CYAN, u'cyan'),
- (COLOR_YELLOW, u'yellow'),
- (COLOR_GREENYELLOW, u'greenyellow '),
- (COLOR_CORAL, u'coral'),
- (COLOR_KHAKI, u'khaki'),
- (COLOR_ORANGE, u'orange'),
- (COLOR_LIGHTGREY, u'lightgrey'),
-)
+from .literals import COLOR_CHOICES, COLOR_CODES
class TagProperties(models.Model):
diff --git a/apps/tags/permissions.py b/apps/tags/permissions.py
new file mode 100644
index 0000000000..cb4c7f9ae7
--- /dev/null
+++ b/apps/tags/permissions.py
@@ -0,0 +1,14 @@
+from __future__ import absolute_import
+
+from django.utils.translation import ugettext_lazy as _
+
+from permissions.models import PermissionNamespace, Permission
+
+tags_namespace = PermissionNamespace('tags', _(u'Tags'))
+
+PERMISSION_TAG_CREATE = Permission.objects.register(tags_namespace, 'tag_create', _(u'Create new tags'))
+PERMISSION_TAG_DELETE = Permission.objects.register(tags_namespace, 'tag_delete', _(u'Delete tags'))
+PERMISSION_TAG_EDIT = Permission.objects.register(tags_namespace, 'tag_edit', _(u'Edit tags'))
+PERMISSION_TAG_VIEW = Permission.objects.register(tags_namespace, 'tag_view', _(u'View tags'))
+PERMISSION_TAG_ATTACH = Permission.objects.register(tags_namespace, 'tag_attach', _(u'Attach tags to documents'))
+PERMISSION_TAG_REMOVE = Permission.objects.register(tags_namespace, 'tag_remove', _(u'Remove tags from documents'))
diff --git a/apps/tags/tests.py b/apps/tags/tests.py
index 2247054b35..094293d35c 100644
--- a/apps/tags/tests.py
+++ b/apps/tags/tests.py
@@ -1,23 +1,16 @@
-"""
-This file demonstrates two different styles of tests (one doctest and one
-unittest). These will both pass when you run "manage.py test".
+from django.utils import unittest
-Replace these with more appropriate tests for your application.
-"""
+from .models import Tag, TagProperties
+from .literals import COLOR_RED
-from django.test import TestCase
-class SimpleTest(TestCase):
- def test_basic_addition(self):
- """
- Tests that 1 + 1 always equals 2.
- """
- self.failUnlessEqual(1 + 1, 2)
-
-__test__ = {"doctest": """
-Another way to test that 1 + 1 is equal to 2.
-
->>> 1 + 1 == 2
-True
-"""}
+class TagTestCase(unittest.TestCase):
+ def setUp(self):
+ self.tag = Tag(name='test')
+ self.tag.save()
+ self.tp = TagProperties(tag=self.tag, color=COLOR_RED)
+ self.tp.save()
+ def runTest(self):
+ self.failUnlessEqual(self.tag.name, 'test')
+ self.failUnlessEqual(self.tp.get_color_code(), 'red')
diff --git a/apps/tags/urls.py b/apps/tags/urls.py
index d649819642..14c9902303 100644
--- a/apps/tags/urls.py
+++ b/apps/tags/urls.py
@@ -10,7 +10,8 @@ urlpatterns = patterns('tags.views',
url(r'^(?P\d+)/remove_from_document/(?P\d+)/$', 'tag_remove', (), 'tag_remove'),
url(r'^multiple/remove_from_document/(?P\d+)/$', 'tag_multiple_remove', (), 'tag_multiple_remove'),
- url(r'^document/(?P\d+)/add/$', 'tag_add_attach', (), 'tag_add_attach'),
- url(r'^document/(?P\d+)/add/from_sidebar/$', 'tag_add_sidebar', (), 'tag_add_sidebar'),
+ url(r'^document/(?P\d+)/add/$', 'tag_attach', (), 'tag_attach'),
url(r'^document/(?P\d+)/list/$', 'document_tags', (), 'document_tags'),
+
+ url(r'^(?P\d+)/acl/list/$', 'tag_acl_list', (), 'tag_acl_list'),
)
diff --git a/apps/tags/utils.py b/apps/tags/utils.py
deleted file mode 100644
index 9496d9e88e..0000000000
--- a/apps/tags/utils.py
+++ /dev/null
@@ -1,19 +0,0 @@
-from django.utils.translation import ugettext_lazy as _
-
-from tags import tag_document_remove, tag_tagged_item_list
-
-
-def get_tags_subtemplate(obj):
- """
- Return all the settings to render a subtemplate containing an
- object's tags
- """
- return {
- 'name': 'generic_list_subtemplate.html',
- 'context': {
- 'title': _(u'tags'),
- 'object_list': obj.tags.all(),
- 'hide_link': True,
- 'navigation_object_links': [tag_tagged_item_list, tag_document_remove],
- }
- }
diff --git a/apps/tags/views.py b/apps/tags/views.py
index 45d91c1921..a153506e02 100644
--- a/apps/tags/views.py
+++ b/apps/tags/views.py
@@ -1,26 +1,35 @@
+from __future__ import absolute_import
+
+import logging
+
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response, get_object_or_404
from django.template import RequestContext
from django.contrib import messages
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _
+from django.core.exceptions import PermissionDenied
-from permissions.api import check_permissions
+from permissions import Permission
from taggit.models import Tag
from documents.models import Document
from documents.views import document_list
-from common.utils import encapsulate
+from documents.permissions import PERMISSION_DOCUMENT_VIEW
+from acls.models import AccessEntry
+from acls.views import acl_list_for
+from acls.utils import apply_default_acls
-from tags.forms import AddTagForm, TagForm
-from tags.models import TagProperties
-from tags import PERMISSION_TAG_CREATE, PERMISSION_TAG_ATTACH, \
- PERMISSION_TAG_REMOVE, PERMISSION_TAG_DELETE, PERMISSION_TAG_EDIT, \
- PERMISSION_TAG_VIEW
-from tags import tag_tagged_item_list as tag_tagged_item_list_link
+from .forms import TagListForm, TagForm
+from .models import TagProperties
+from .permissions import (PERMISSION_TAG_CREATE, PERMISSION_TAG_ATTACH,
+ PERMISSION_TAG_REMOVE, PERMISSION_TAG_DELETE, PERMISSION_TAG_EDIT,
+ PERMISSION_TAG_VIEW)
+
+logger = logging.getLogger(__name__)
def tag_create(request):
- #check_permissions(request.user, [PERMISSION_TAG_EDIT])
+ Permission.objects.check_permissions(request.user, [PERMISSION_TAG_CREATE])
redirect_url = reverse('tag_list')
previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', redirect_url)))
@@ -32,11 +41,12 @@ def tag_create(request):
if tag_name in Tag.objects.values_list('name', flat=True):
messages.error(request, _(u'Tag already exists.'))
return HttpResponseRedirect(previous)
-
+
tag = Tag(name=tag_name)
tag.save()
TagProperties(tag=tag, color=form.cleaned_data['color']).save()
-
+ apply_default_acls(tag, request.user)
+
messages.success(request, _(u'Tag created succesfully.'))
return HttpResponseRedirect(redirect_url)
else:
@@ -46,88 +56,33 @@ def tag_create(request):
'title': _(u'create tag'),
'form': form,
},
- context_instance=RequestContext(request))
+ context_instance=RequestContext(request))
-def tag_add_sidebar(request, document_id):
+def tag_attach(request, document_id):
document = get_object_or_404(Document, pk=document_id)
- previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', reverse('tag_list'))))
-
- if request.method == 'POST':
- previous = request.META.get('HTTP_REFERER', '/')
- form = AddTagForm(request.POST)
- if form.is_valid():
- if form.cleaned_data['new_tag']:
- check_permissions(request.user, [PERMISSION_TAG_CREATE])
- tag_name = form.cleaned_data['new_tag']
- if Tag.objects.filter(name=tag_name):
- is_new = False
- else:
- is_new = True
- elif form.cleaned_data['existing_tags']:
- check_permissions(request.user, [PERMISSION_TAG_ATTACH])
- tag_name = form.cleaned_data['existing_tags']
- is_new = False
- else:
- messages.error(request, _(u'Must choose either a new tag or an existing one.'))
- return HttpResponseRedirect(previous)
-
- if tag_name in document.tags.values_list('name', flat=True):
- messages.warning(request, _(u'Document is already tagged as "%s"') % tag_name)
- return HttpResponseRedirect(previous)
-
- document.tags.add(tag_name)
-
- if is_new:
- tag = Tag.objects.get(name=tag_name)
- TagProperties(tag=tag, color=form.cleaned_data['color']).save()
-
- messages.success(request, _(u'Tag "%s" added successfully.') % tag_name)
-
- return HttpResponseRedirect(previous)
-
-
-def tag_add_attach(request, document_id):
- # TODO: merge with tag_add_sidebar
- document = get_object_or_404(Document, pk=document_id)
+ try:
+ Permission.objects.check_permissions(request.user, [PERMISSION_TAG_ATTACH])
+ except PermissionDenied:
+ AccessEntry.objects.check_access(PERMISSION_TAG_ATTACH, request.user, document)
next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', reverse('document_tags', args=[document.pk]))))
if request.method == 'POST':
- form = AddTagForm(request.POST)
+ form = TagListForm(request.POST, user=request.user)
if form.is_valid():
- if form.cleaned_data['new_tag']:
- check_permissions(request.user, [PERMISSION_TAG_CREATE])
- tag_name = form.cleaned_data['new_tag']
- if Tag.objects.filter(name=tag_name):
- is_new = False
- else:
- is_new = True
- elif form.cleaned_data['existing_tags']:
- check_permissions(request.user, [PERMISSION_TAG_ATTACH])
- tag_name = form.cleaned_data['existing_tags']
- is_new = False
- else:
- messages.error(request, _(u'Must choose either a new tag or an existing one.'))
+ tag = form.cleaned_data['tag']
+ if tag in document.tags.all():
+ messages.warning(request, _(u'Document is already tagged as "%s"') % tag)
return HttpResponseRedirect(next)
- if tag_name in document.tags.values_list('name', flat=True):
- messages.warning(request, _(u'Document is already tagged as "%s"') % tag_name)
- return HttpResponseRedirect(next)
-
- document.tags.add(tag_name)
-
- if is_new:
- tag = Tag.objects.get(name=tag_name)
- TagProperties(tag=tag, color=form.cleaned_data['color']).save()
- messages.success(request, _(u'Tag "%s" added and attached successfully.') % tag_name)
- else:
- messages.success(request, _(u'Tag "%s" attached successfully.') % tag_name)
+ document.tags.add(tag)
+ messages.success(request, _(u'Tag "%s" attached successfully.') % tag)
return HttpResponseRedirect(next)
else:
- form = AddTagForm()
+ form = TagListForm(user=request.user)
return render_to_response('generic_form.html', {
'title': _(u'attach tag to: %s') % document,
@@ -138,23 +93,32 @@ def tag_add_attach(request, document_id):
context_instance=RequestContext(request))
-def tag_list(request):
- return render_to_response('generic_list.html', {
- 'object_list': Tag.objects.all(),
+def tag_list(request, queryset=None, extra_context=None):
+ context = {
'title': _(u'tags'),
'hide_link': True,
'multi_select_as_buttons': True,
- 'extra_columns': [
- {
- 'name': _(u'tagged items'),
- 'attribute': encapsulate(lambda x: x.taggit_taggeditem_items.count())
- }
- ]
- }, context_instance=RequestContext(request))
+ 'hide_object': True,
+ }
+ if extra_context:
+ context.update(extra_context)
+
+ queryset = queryset if not (queryset is None) else Tag.objects.all()
+
+ try:
+ Permission.objects.check_permissions(request.user, [PERMISSION_TAG_VIEW])
+ except PermissionDenied:
+ queryset = AccessEntry.objects.filter_objects_by_access(PERMISSION_TAG_VIEW, request.user, queryset)
+
+ context['object_list'] = queryset
+
+ return render_to_response('generic_list.html',
+ context,
+ context_instance=RequestContext(request)
+ )
def tag_delete(request, tag_id=None, tag_id_list=None):
- check_permissions(request.user, [PERMISSION_TAG_DELETE])
post_action_redirect = None
if tag_id:
@@ -166,6 +130,11 @@ def tag_delete(request, tag_id=None, tag_id_list=None):
messages.error(request, _(u'Must provide at least one tag.'))
return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))
+ try:
+ Permission.objects.check_permissions(request.user, [PERMISSION_TAG_DELETE])
+ except PermissionDenied:
+ tags = AccessEntry.objects.filter_objects_by_access(PERMISSION_TAG_DELETE, request.user, tags)
+
previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', '/')))
next = request.POST.get('next', request.GET.get('next', post_action_redirect if post_action_redirect else request.META.get('HTTP_REFERER', '/')))
@@ -207,9 +176,13 @@ def tag_multiple_delete(request):
def tag_edit(request, tag_id):
- check_permissions(request.user, [PERMISSION_TAG_EDIT])
tag = get_object_or_404(Tag, pk=tag_id)
+ try:
+ Permission.objects.check_permissions(request.user, [PERMISSION_TAG_EDIT])
+ except PermissionDenied:
+ AccessEntry.objects.check_access(PERMISSION_TAG_EDIT, request.user, tag)
+
if request.method == 'POST':
form = TagForm(request.POST)
if form.is_valid():
@@ -237,11 +210,10 @@ def tag_edit(request, tag_id):
def tag_tagged_item_list(request, tag_id):
tag = get_object_or_404(Tag, pk=tag_id)
- object_list = [tagged_item.content_object for tagged_item in tag.taggit_taggeditem_items.all()]
return document_list(
request,
- object_list=object_list,
+ object_list=Document.objects.filter(tags__in=[tag]),
title=_('documents with the tag "%s"') % tag,
extra_context={
'object': tag,
@@ -251,24 +223,29 @@ def tag_tagged_item_list(request, tag_id):
def document_tags(request, document_id):
- check_permissions(request.user, [PERMISSION_TAG_VIEW])
document = get_object_or_404(Document, pk=document_id)
- return render_to_response('generic_list.html', {
- 'title': _(u'tags for: %s') % document,
- 'object_list': document.tags.all(),
- 'hide_link': True,
- 'navigation_object_links': [tag_tagged_item_list_link],
+ try:
+ Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW])
+ except PermissionDenied:
+ AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document)
+
+ context = {
'object': document,
'document': document,
- 'disable_auto_focus': True,
- 'multi_select_as_buttons': True,
- },
- context_instance=RequestContext(request))
+ 'title': _(u'tags for: %s') % document,
+ }
+
+ return tag_list(request, queryset=document.tags.all(), extra_context=context)
def tag_remove(request, document_id, tag_id=None, tag_id_list=None):
- check_permissions(request.user, [PERMISSION_TAG_REMOVE])
+ document = get_object_or_404(Document, pk=document_id)
+
+ try:
+ Permission.objects.check_permissions(request.user, [PERMISSION_TAG_REMOVE])
+ except PermissionDenied:
+ AccessEntry.objects.check_access(PERMISSION_TAG_REMOVE, request.user, document)
post_action_redirect = None
@@ -280,8 +257,6 @@ def tag_remove(request, document_id, tag_id=None, tag_id_list=None):
messages.error(request, _(u'Must provide at least one tag.'))
return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))
- document = get_object_or_404(Document, pk=document_id)
-
previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', '/')))
next = request.POST.get('next', request.GET.get('next', post_action_redirect if post_action_redirect else request.META.get('HTTP_REFERER', '/')))
@@ -315,3 +290,16 @@ def tag_remove(request, document_id, tag_id=None, tag_id_list=None):
def tag_multiple_remove(request, document_id):
return tag_remove(request, document_id=document_id, tag_id_list=request.GET.get('id_list', []))
+
+
+def tag_acl_list(request, tag_pk):
+ tag = get_object_or_404(Tag, pk=tag_pk)
+ logger.debug('tag: %s' % tag)
+
+ return acl_list_for(
+ request,
+ tag,
+ extra_context={
+ 'object': tag,
+ }
+ )
diff --git a/apps/tags/widgets.py b/apps/tags/widgets.py
index ab1b6762b1..ecf966612e 100644
--- a/apps/tags/widgets.py
+++ b/apps/tags/widgets.py
@@ -1,4 +1,3 @@
-from django.utils.translation import ugettext_lazy as _
from django.utils.safestring import mark_safe
@@ -6,6 +5,7 @@ def get_tags_inline_widget(document):
"""
A tag widget that includes the total tag count for a given document
"""
+ # TODO: merge widgets
tags_template = []
tag_count = document.tags.count()
if tag_count:
@@ -13,7 +13,7 @@ def get_tags_inline_widget(document):
for tag in document.tags.all():
tags_template.append(u'
%s
' % (tag.tagproperties_set.get().get_color_code(), tag.name))
-
+
tags_template.append(u'')
tags_template.append(u'')
return mark_safe(u''.join(tags_template))
@@ -21,8 +21,7 @@ def get_tags_inline_widget(document):
def get_tags_inline_widget_simple(document):
"""
- A tag widget that only displayes the rectangular colored boxes for a
- given document
+ A tag widget that displays the tags for the given document
"""
tags_template = []
@@ -30,12 +29,20 @@ def get_tags_inline_widget_simple(document):
if tag_count:
tags_template.append('
')
for tag in document.tags.all():
- tags_template.append('
+ {% get_web_theme_setting "VERBOSE_LOGIN" as verbose_login %}
+ {% if verbose_login %}
+ {% include "verbose_login.html" %}
+ {% endif %}
+ {% endblock %}
+ {% endif %}
diff --git a/apps/web_theme/tests.py b/apps/web_theme/tests.py
deleted file mode 100644
index 2247054b35..0000000000
--- a/apps/web_theme/tests.py
+++ /dev/null
@@ -1,23 +0,0 @@
-"""
-This file demonstrates two different styles of tests (one doctest and one
-unittest). These will both pass when you run "manage.py test".
-
-Replace these with more appropriate tests for your application.
-"""
-
-from django.test import TestCase
-
-class SimpleTest(TestCase):
- def test_basic_addition(self):
- """
- Tests that 1 + 1 always equals 2.
- """
- self.failUnlessEqual(1 + 1, 2)
-
-__test__ = {"doctest": """
-Another way to test that 1 + 1 is equal to 2.
-
->>> 1 + 1 == 2
-True
-"""}
-
diff --git a/contrib/mayan_11_1.pdf b/contrib/mayan_11_1.pdf
new file mode 100644
index 0000000000..5fba2c87c3
Binary files /dev/null and b/contrib/mayan_11_1.pdf differ
diff --git a/contrib/mayan_11_1.pdf.gpg b/contrib/mayan_11_1.pdf.gpg
new file mode 100644
index 0000000000..e271fe8df3
Binary files /dev/null and b/contrib/mayan_11_1.pdf.gpg differ
diff --git a/contrib/mayan_11_1.pdf.sig b/contrib/mayan_11_1.pdf.sig
new file mode 100644
index 0000000000..de11aa6db1
Binary files /dev/null and b/contrib/mayan_11_1.pdf.sig differ
diff --git a/contrib/supervisor/mayan-celery.conf b/contrib/supervisor/mayan-celery.conf
deleted file mode 100644
index efcfd35927..0000000000
--- a/contrib/supervisor/mayan-celery.conf
+++ /dev/null
@@ -1,23 +0,0 @@
-; =======================================
-; celeryd supervisor example for Django
-; =======================================
-
-[program:celery]
-command=/usr/share/mayan/bin/python /usr/share/mayan/mayan/manage.py celeryd --loglevel=INFO
-directory=/usr/share/mayan/mayan
-user=nobody
-numprocs=1
-stdout_logfile=/var/log/mayan-celeryd.log
-stderr_logfile=/var/log/mayan-celeryd.log
-autostart=true
-autorestart=true
-startsecs=10
-
-; Need to wait for currently executing tasks to finish at shutdown.
-; Increase this if you have very long running tasks.
-stopwaitsecs = 600
-
-; if rabbitmq is supervised, set its priority higher
-; so it starts first
-priority=998
-
diff --git a/contrib/supervisor/mayan-celerybeat.conf b/contrib/supervisor/mayan-celerybeat.conf
deleted file mode 100644
index 7a37e9437f..0000000000
--- a/contrib/supervisor/mayan-celerybeat.conf
+++ /dev/null
@@ -1,19 +0,0 @@
-; ==========================================
-; celerybeat supervisor example for Django
-; ==========================================
-
-[program:celerybeat]
-command=/usr/share/mayan/bin/python /usr/share/mayan/mayan/manage.py celerybeat --schedule=/var/lib/celery/celerybeat-schedule --loglevel=INFO
-directory=/usr/share/mayan/mayan
-user=nobody
-numprocs=1
-stdout_logfile=/var/log/mayan-celerybeat.log
-stderr_logfile=/var/log/mayan-celerybeat.log
-autostart=true
-autorestart=true
-startsecs=10
-
-; if rabbitmq is supervised, set its priority higher
-; so it starts first
-priority=999
-
diff --git a/docs/_ext/djangodocs.py b/docs/_ext/djangodocs.py
new file mode 100644
index 0000000000..3cf00a38e1
--- /dev/null
+++ b/docs/_ext/djangodocs.py
@@ -0,0 +1,229 @@
+"""
+Sphinx plugins for Django documentation.
+"""
+import os
+import re
+
+from docutils import nodes, transforms
+try:
+ import json
+except ImportError:
+ try:
+ import simplejson as json
+ except ImportError:
+ try:
+ from django.utils import simplejson as json
+ except ImportError:
+ json = None
+
+from sphinx import addnodes, roles, __version__ as sphinx_ver
+from sphinx.builders.html import StandaloneHTMLBuilder
+from sphinx.writers.html import SmartyPantsHTMLTranslator
+from sphinx.util.console import bold
+from sphinx.util.compat import Directive
+
+# RE for option descriptions without a '--' prefix
+simple_option_desc_re = re.compile(
+ r'([-_a-zA-Z0-9]+)(\s*.*?)(?=,\s+(?:/|-|--)|$)')
+
+def setup(app):
+ app.add_crossref_type(
+ directivename = "setting",
+ rolename = "setting",
+ indextemplate = "pair: %s; setting",
+ )
+ app.add_crossref_type(
+ directivename = "templatetag",
+ rolename = "ttag",
+ indextemplate = "pair: %s; template tag"
+ )
+ app.add_crossref_type(
+ directivename = "templatefilter",
+ rolename = "tfilter",
+ indextemplate = "pair: %s; template filter"
+ )
+ app.add_crossref_type(
+ directivename = "fieldlookup",
+ rolename = "lookup",
+ indextemplate = "pair: %s; field lookup type",
+ )
+ app.add_description_unit(
+ directivename = "django-admin",
+ rolename = "djadmin",
+ indextemplate = "pair: %s; django-admin command",
+ parse_node = parse_django_admin_node,
+ )
+ app.add_description_unit(
+ directivename = "django-admin-option",
+ rolename = "djadminopt",
+ indextemplate = "pair: %s; django-admin command-line option",
+ parse_node = parse_django_adminopt_node,
+ )
+ app.add_config_value('django_next_version', '0.0', True)
+ app.add_directive('versionadded', VersionDirective)
+ app.add_directive('versionchanged', VersionDirective)
+ app.add_builder(DjangoStandaloneHTMLBuilder)
+
+
+class VersionDirective(Directive):
+ has_content = True
+ required_arguments = 1
+ optional_arguments = 1
+ final_argument_whitespace = True
+ option_spec = {}
+
+ def run(self):
+ env = self.state.document.settings.env
+ arg0 = self.arguments[0]
+ is_nextversion = env.config.django_next_version == arg0
+ ret = []
+ node = addnodes.versionmodified()
+ ret.append(node)
+ if not is_nextversion:
+ if len(self.arguments) == 1:
+ linktext = 'Please see the release notes ' % (arg0)
+ xrefs = roles.XRefRole()('doc', linktext, linktext, self.lineno, self.state)
+ node.extend(xrefs[0])
+ node['version'] = arg0
+ else:
+ node['version'] = "Development version"
+ node['type'] = self.name
+ if len(self.arguments) == 2:
+ inodes, messages = self.state.inline_text(self.arguments[1], self.lineno+1)
+ node.extend(inodes)
+ if self.content:
+ self.state.nested_parse(self.content, self.content_offset, node)
+ ret = ret + messages
+ env.note_versionchange(node['type'], node['version'], node, self.lineno)
+ return ret
+
+
+class DjangoHTMLTranslator(SmartyPantsHTMLTranslator):
+ """
+ Django-specific reST to HTML tweaks.
+ """
+
+ # Don't use border=1, which docutils does by default.
+ def visit_table(self, node):
+ self._table_row_index = 0 # Needed by Sphinx
+ self.body.append(self.starttag(node, 'table', CLASS='docutils'))
+
+ # ? Really?
+ def visit_desc_parameterlist(self, node):
+ self.body.append('(')
+ self.first_param = 1
+ self.param_separator = node.child_text_separator
+
+ def depart_desc_parameterlist(self, node):
+ self.body.append(')')
+
+ if sphinx_ver < '1.0.8':
+ #
+ # Don't apply smartypants to literal blocks
+ #
+ def visit_literal_block(self, node):
+ self.no_smarty += 1
+ SmartyPantsHTMLTranslator.visit_literal_block(self, node)
+
+ def depart_literal_block(self, node):
+ SmartyPantsHTMLTranslator.depart_literal_block(self, node)
+ self.no_smarty -= 1
+
+ #
+ # Turn the "new in version" stuff (versionadded/versionchanged) into a
+ # better callout -- the Sphinx default is just a little span,
+ # which is a bit less obvious that I'd like.
+ #
+ # FIXME: these messages are all hardcoded in English. We need to change
+ # that to accomodate other language docs, but I can't work out how to make
+ # that work.
+ #
+ version_text = {
+ 'deprecated': 'Deprecated in Django %s',
+ 'versionchanged': 'Changed in Django %s',
+ 'versionadded': 'New in Django %s',
+ }
+
+ def visit_versionmodified(self, node):
+ self.body.append(
+ self.starttag(node, 'div', CLASS=node['type'])
+ )
+ title = "%s%s" % (
+ self.version_text[node['type']] % node['version'],
+ len(node) and ":" or "."
+ )
+ self.body.append('%s ' % title)
+
+ def depart_versionmodified(self, node):
+ self.body.append("
\n")
+
+ # Give each section a unique ID -- nice for custom CSS hooks
+ def visit_section(self, node):
+ old_ids = node.get('ids', [])
+ node['ids'] = ['s-' + i for i in old_ids]
+ node['ids'].extend(old_ids)
+ SmartyPantsHTMLTranslator.visit_section(self, node)
+ node['ids'] = old_ids
+
+def parse_django_admin_node(env, sig, signode):
+ command = sig.split(' ')[0]
+ env._django_curr_admin_command = command
+ title = "django-admin.py %s" % sig
+ signode += addnodes.desc_name(title, title)
+ return sig
+
+def parse_django_adminopt_node(env, sig, signode):
+ """A copy of sphinx.directives.CmdoptionDesc.parse_signature()"""
+ from sphinx.domains.std import option_desc_re
+ count = 0
+ firstname = ''
+ for m in option_desc_re.finditer(sig):
+ optname, args = m.groups()
+ if count:
+ signode += addnodes.desc_addname(', ', ', ')
+ signode += addnodes.desc_name(optname, optname)
+ signode += addnodes.desc_addname(args, args)
+ if not count:
+ firstname = optname
+ count += 1
+ if not count:
+ for m in simple_option_desc_re.finditer(sig):
+ optname, args = m.groups()
+ if count:
+ signode += addnodes.desc_addname(', ', ', ')
+ signode += addnodes.desc_name(optname, optname)
+ signode += addnodes.desc_addname(args, args)
+ if not count:
+ firstname = optname
+ count += 1
+ if not firstname:
+ raise ValueError
+ return firstname
+
+
+class DjangoStandaloneHTMLBuilder(StandaloneHTMLBuilder):
+ """
+ Subclass to add some extra things we need.
+ """
+
+ name = 'djangohtml'
+
+ def finish(self):
+ super(DjangoStandaloneHTMLBuilder, self).finish()
+ if json is None:
+ self.warn("cannot create templatebuiltins.js due to missing simplejson dependency")
+ return
+ self.info(bold("writing templatebuiltins.js..."))
+ xrefs = self.env.domaindata["std"]["objects"]
+ templatebuiltins = {
+ "ttags": [n for ((t, n), (l, a)) in xrefs.items()
+ if t == "templatetag" and l == "ref/templates/builtins"],
+ "tfilters": [n for ((t, n), (l, a)) in xrefs.items()
+ if t == "templatefilter" and l == "ref/templates/builtins"],
+ }
+ outfilename = os.path.join(self.outdir, "templatebuiltins.js")
+ f = open(outfilename, 'wb')
+ f.write('var django_template_builtins = ')
+ json.dump(templatebuiltins, f)
+ f.write(';\n')
+ f.close();
diff --git a/docs/changelog.rst b/docs/changelog.rst
deleted file mode 100644
index 3396407b17..0000000000
--- a/docs/changelog.rst
+++ /dev/null
@@ -1,716 +0,0 @@
-Version 0.11.2
---------------
-* Fix issue #17, thanks to Сергей Глита (https://github.com/gsv70) for
- finding this one.
-
-Version 0.11
-------------
-* Support for signed documents verification added, embedded and detached
- signatures are supported. When verifying a document Mayan EDMS will
- try to fetch the public key from the list of keyservers provided in the
- configuration option SIGNATURES_KEYSERVERS (which defaults to
- 'pool.sks-keyservers.net'). A public key management view has been added
- to the setup menu as well as a key query and fetching view to manually
- import keys from a keyserver.
-* Added support for document versions. Users can upload unlimited amount
- of versions for a document using a very flexible document version numbering
- system, users can also revert to a previous document version.
-* OCR queue processing improvements.
-* Office documents handling improvements.
-* Text extraction support for office documents.
-* RTF text documents are now handled as office documents.
-* Added a view to delete the document image cache, useful when switching
- converter backends or doing diagnostics.
-* Added South to the requirements.
-* Merged documents' filename and extension database fiels into a single
- filename field, filename are store as uploaded not manipulation is done
- Users with existing data must install South and run the appropiate
- migrate commands::
- $ pip install -r requirements/production.txt
- $ ./manager syncdb
- $ ./manage.py migrate documents 0001 --fake
- $ ./manage.py migrate documents
-* Added new office document mimetype
- * application/vnd.ms-office
-* Fixed documents not saving the file encoding
-* Removed extra slash in ajax-loader.gif URL fixes #15, thanks to
- IHLeanne for finding this one
-
-
-Version 0.10.1
---------------
-* Upgraded django-compressor to version 1.1.1, run::
-
- $ pip install --upgrade -r requirements/production.txt
-
- to upgrade
-
-* django-compressor is now disabled by default, users must explicitly
- enable it adding COMPRESS_ENABLED=True to their settings_local.py file
-
-
-Version 0.10
-------------
-* Added a proper setup views for the document grouping functionality.
-* Document grouping is now called smart linking as it relates better to
- how it actually works. The data base schema was changed and users must
- do the required::
-
- $ ./manager syncdb
-
- for the new tables to be created.
-* Grappelli is no longer required as can be uninstalled.
-* New smarter document preview widget that doesn't allow zooming or viewing
- unknown or invalid documents.
-* New office document converter, requires:
-
- * LibreOffice (https://www.libreoffice.org/)
- * unoconv [version 0.5] (https://github.com/dagwieers/unoconv)
-
-* The new office documents converter won't convert files with the extension
- .docx because these files are recognized as zip files instead. This
- is an issue of the libmagic library.
-
-* New configuration option added ``CONVERTER_UNOCONV_USE_PIPE`` that controls
- how unoconv handles the communication with LibreOffice. The default of
- ``True`` causes unoconv to use **pipes**, this approach is slower than using
- **TCP/IP** ports but it is more stable.
-
-* Initial `REST` `API` that exposes documents properties and one method, this
- new `API` is used by the new smart document widget and requires the
- package ``djangorestframework``, users must issue a::
-
- $ pip install -r requirements/production.txt
-
- to install this new requirement.
-
-* MIME type detection and caching performance updates.
-* Updated the included version of ``jQuery`` to 1.7
-* Updated the included version of ``JqueryAsynchImageLoader`` to 0.9.7
-* Document image serving response now specifies a MIME type for increased
- browser compatibility.
-* Small change in the scheduler that increases stability.
-* Russian translation updates (Сергей Глита [Sergey Glita])
-* Improved and generalized the OCR queue locking mechanism, this should
- eliminate any posibility of race conditions between Mayan EDMS OCR nodes.
-* Added support for signals to the OCR queue, this results in instant OCR
- processing upon submittal of a document to the OCR queue, this works in
- addition to the current polling processing which eliminates the
- posibility of stale documents in the OCR queue.
-* Added multiple document OCR submit link
-* Re enabled tesseract language specific OCR processing and added a one
- (1) time language neutral retry for failed language specific OCR
-
-Version 0.9.1
--------------
-* Added handling percent encoded unicode query strings in search URL,
- thanks to (Сергей Глита [Sergei Glita]) for reporting.
-* Added a FAQ explaing how to fix MySQL collation related error when
- doing searches also thanks to (Сергей Глита [Sergei Glita]) for
- reporting this one.
-
-Version 0.9.0
--------------
-* Simplified getting mimetypes from files by merging 2 implementations
- (document based and file based)
-* Updated python converter backend, document model and staging module
- to use the new get_mimetype API
-* Only allow clickable thumbnails for document and staging files with a
- valid image
-* Removed tag count from the group document list widget to conserve
- vertical space
-* Updated required Django version to 1.3.1
-* Removed the included 3rd party module django-sendfile, now added to
- the requirement files.
-
- * User should do a pip install -r requirements/production.txt to update
-
-* Changed to Semantic Versioning (http://semver.org/), with
- recommendations 7, 8 and 9 causing the most effect in the versioning number.
-* Added Russian locale post OCR cleanup backend (Сергей Глита [Sergei Glita])
-* Reduced severity of the messages displayed when no OCR cleanup backend
- is found for a language
-* Complete Portuguese translation (Emerson Soares and Renata Oliveira)
-* Complete Russian translation (Сергей Глита [Sergei Glita])
-* Added animate.css to use CSS to animate flash messages with better
- fallback on non JS browsers
-* The admin and sentry links are no longer hard-coded (Meurig Freeman)
-* Improved appearance of the document tag widget
- (https://p.twimg.com/Ac0Q0b-CAAE1lfA.png:large)
-* Added django_compress and cssmin to the requirements files and enabled
- django_compress for CSS and JS files
-* Added granting and revoking permission methods to the permission model
-* Correctly calculate the mimetype icons paths when on development mode
-* Added a new more comprehensive method of passing multiple variables
- per item in multi item selection views
-* Used new multi parameter passing method to improve the usability of
- the grant/revoke permission view, thanks to Cezar Jenkins
- (https://twitter.com/#!/emperorcezar) for the suggestion
-* Added step to the documentation explaining how to install Mayan EDMS
- on Webfaction
-* Added an entry in the documentation to the screencast explaining how
- to install Mayan EDMS on DjangoZoom
-* Added required changes to add Mayan EDMS to Transifex.com
-* Fixed the apache contrib file static file directory name
-* Added improved documentation
-
-Version 0.8.3
--------------
-* Added a Contributors file under the docs directory
-* Moved the document grouping subtemplate windows into a document
- information tab
-* Change the mode the setup options are shown, opting to use a more of a
- dashboard style now
-* Changed the tool menu to use the same button layout of the setup menu
-* Moved OCR related handling to the tools main menu
-* Improved the metadata type and metadata set selection widget during
- the document upload wizard
-* Added a view to the about menu to read the LICENSE file included with
- Mayan
-* Added converter backend agnostic image file format descriptions
-* Disable whitelist and blacklist temporarily, removed document_type
- field from interactive sources
-* Fully disabled watch folders until they are working correctly
-* Updated the project title to 'Mayan EDMS'
-* If ghostscript is installed add PDF and PS to the list of file formats
- by the python converter backend
-* Use Pillow (http://pypi.python.org/pypi/Pillow) instead of PIL
-
- - Pillow is a fork of PIL with several updated including better jpeg and png library detection
- - Users must uninstall PIL before installing Pillow
-
-* Updated the static media url in the login excempt url list
-* Added remediatory code to sidestep issue #10 caused by DjangoZoom's deployment script executing the collectstatic command before creating the database structure with syncdb. Thanks to Joost Cassee (https://github.com/jcassee) for reporting this one.
-* Perform extra validation of the image cache directory and fallback to creating a temporary directory on validation failure
-* Fixed a source creation bug, that caused invalid links to a non existing source transformation to appear on the sidebar
-
-
-Version 0.8.2
--------------
-* Moved code to Django 1.3
-
- - Users have to use the ``collectstatic`` management command::
-
- $ ./manage.py collectstatic
-
- - The ``site_media`` directory is no more, users must update the media
- serving directives in current deployments and point them to the
- ``static`` directory instead
-
-* The changelog is now available under the ``about`` main menu
-* ``Grappelli`` no longer bundled with Mayan
-
- - Users must install Grappelli or execute::
-
- $ pip install --upgrade -r requirements/production.txt
-
-* Even easier UI language switching
-* Added email login method, to enable it, set::
-
- AUTHENTICATION_BACKENDS = ('common.auth.email_auth_backend.EmailAuthBackend',)
- COMMON_LOGIN_METHOD = 'email'
-
-
-Version 0.8.1
--------------
-* Tags can now also be created from the main menu
-* Added item count column to index instance list view
-* Updated document indexing widget to show different icon for indexes or
- indexes that contain documents
-* Replaced the Textarea widget with the TextAreaDiv widget on document
- and document page detail views
-
- - This change will allow highlighting search terms in the future
-
-* Unknown document file format page count now defaults to 1
-
- - When uploading documents which the selected converted backend doesn't
- understand, the total page count will fallback to 1 page to at least
- show some data, and a comment will be automatically added to the
- document description
-
-* Added new MAIN_DISABLE_ICONS to turn off all icons
-
- - This options works very well when using the ``default`` theme
-
-* The default theme is now ``activo``
-* Improved document page views and document page transformation views
- navigation
-* Added OCR queue document transformations
-
- - Use this for doing resizing or rotation fixes to improve OCR results
-
-* Added reset view link to the document page view to reset the zoom
- level and page rotation
-* Staging files now show a thumbnail preview instead of preview link
-
-
-Version 0.8.0
--------------
-* Distributed OCR queue processing via celery is disabled for the time
- being
-* Added support for local scheduling of jobs
-
- - This addition removes celery beat requirement, and make is optional
-
-* Improve link highlighting
-* Navigation improvements
-* Documents with an unknown file format now display a mime type place
- holder icon instead of a error icon
-* Mayan now does pre caching of document visual representation improving
- overall thumbnail, preview and display speed
-
- - Page image rotation and zooming is faster too with this update
-
-* Removed all QUALITY related settings
-* ``COMMON_TEMPORARY_DIRECTORY`` is now validated when Mayan starts and if
- not valid falls back to creating it's own temporary folder
-* Added PDF file support to the python converter backend via ghostscript
-
- - This requires the installation of:
-
- + ghostscript python package
- + ghostscript system binaries and libraries
-
-* Added PDF text parsing support to the python converter backend
-
- - This requires the installation of:
-
- + pdfminer python package
-
-* Added PDF page count support to the python converter backend
-* Added python only converter backend supporting resizing, zooming and rotation
-
- - This backend required the installation of the python image library (PIL)
- - This backend is useful when Graphicsmagick or Imagemagick can not be installed for some reason
- - If understand fewer file format than the other 2 backends
-
-* Added default tranformation support to document sources
-* Removed ``DOCUMENT_DEFAULT_TRANSFORMATIONS`` setup options
-* Document sources are now defined via a series of view under the setup main menu
-* This removes all the ``DOCUMENT_STAGING`` related setup options
-
- - Two document source types are supported local (via a web form),
- and staging
- - However multiple document sources can be defined each with their own
- set of transformations and default metadata selection
-
-* Use ``python-magic`` to determine a document's mimetype otherwise
- fallback to use python's mimetypes library
-* Remove the included sources for ``python-magic`` instead it is now fetched
- from github by pip
-* Removed the document subtemplates and changed to a tabbed style
-* Added link to document index content view to navigate the tree upwards
-* Added new option ``MAIN_DISABLE_HOME_VIEW`` to disable the home main menu
- tab and save some space
-* Added new option to the web theme app, ``WEB_THEME_VERBOSE_LOGIN``
- that display a more information on the login screen
- (version, copyright, logos)
-* Added a confirmation dialog to the document tag removal view
-
-Version 0.7.6
--------------
-* Added recent searches per user support
-
- - The ammount of searches stored is controlled by the setup option
- ``SEARCH_RECENT_COUNT``
-
-* The document page zoom button are now disabled when reaching the minimum
- or maximum zoom level
-* The document page navigation links are now disabled when view the first
- and last page of a document
-* Document page title now displays the current page vs the total page
- count
-* Document page title now displays the current zoom level and rotation
- degrees
-* Added means set the expansion compressed files during document creation,
- via web interface removing the need for the configuration options:
- ``UNCOMPRESS_COMPRESSED_LOCAL_FILES`` and ``UNCOMPRESS_COMPRESSED_STAGING_FILES``
-* Added 'search again' button to the advances search results view
-* Implementes an advanced search feature, which allows for individual field terms
-
- - Search fields supported: document type, MIME type, filename,
- extension, metadata values, content, description, tags, comments
-
-Version 0.7.5
--------------
-* Added a help messages to the sidebar of some views
-* Renamed some forms submit button to more intuitive one
-
- - 'Search' on the submit button of the search form
- - 'Next step' on the document creation wizard
-
-* Added view to list supported file formats and reported by the
- converter backend
-* Added redirection support to multi object action views
-* Renamed 'document list' link to 'all documents' and
- 'recent document list' to 'recent documents'
-* Removed 'change password' link next to the current user's name and
- added a few views to handle the current user's password, details and
- details editing
-
-Version 0.7.4
--------------
-* Renamed 'secondary actions' to 'secondary menu'
-* Added document type setup views to the setup menu
-* Added document type file name editing views to the setup menu
-* Fixed document queue properties sidebar template not showing
-
-Version 0.7.3
--------------
-* Refactored main menu navigation and converted all apps to this new
- system
-* Multi item links are now displayed on top of generic lists as well as
- on the bottom
-* Spanish translation updates
-* Updated requirements to use the latest development version of
- django-mptt
-* Improved user folder document removal views
-* Added ability to specify default metadata or metadataset per
- document type
-* Converted filename handling to use os.path library for improved
- portability
-* Added edit source object attribute difference detection and logging
- to history app
-* Missing metadata type in a document during a multi document editing doesn't raise errors anymore.
-
- - This allows for multi document heterogeneous metadata editing in a single step.
-
-* Added document multi item links in search results
-
- - Direct editing can be done from the search result list
-
-* Permissions are now grouped and assigned a group name
-* Improved role management views
-* Document type is now an optional document property
-
- - Documents can be created without an explicit document type
-
-* Added support for per user staging directories
-* Updated logos
-
-Version 0.7
------------
-* Added confirmation dialogs icons
-* Added comment app with support for adding and deleting comments to
- and from documents
-* Updated requirements files as per issue #9
-* Show tagged item count in the tag list view
-* Show tagget document link in the tags subtemplate of documents
-* Made comment sorted by oldest first, made comment subtemplate
- scrollable
-* Rename comments app to document_comment to avoid conflict with
- Django's comment app
-* Made document comments searchable
-
-Version 0.5.1
--------------
-* Applied initial merge of the new subtemplate renderer
-* Fixed tag removal logic
-* Initial commit to support document comments
-* Updated so that loading spinner is displayed always
-* Exclude tags from the local document upload form
-* Added document tagging support
-
- - Requires installing ``django-taggit`` and doing a ``sync-db``
-
-Version 0.5
------------
-* Added tag list view and global tag delete support
-* Added tag editing view and listing documents with an specific tag
-* Changed the previewing and deleting staging files views to required
- ``DOCUMENT_CREATE`` permission
-* Added no-parent-history class to document page links so that iframe clicking doesn't affect the parent window history
-
- - Fixes back button issue on Chrome 9 & 10
-
-* Added per app version display tag
-* Added loading spinner animation
-* Messages tweaks and translation updates
-* Converter app cleanups, document pre-cache, magic number removal
-* Added OCR view displaying all active OCR tasks from all cluster nodes
-* Disabled ``CELERY_DISABLE_RATE_LIMITS`` by default
-* Implement local task locking using Django locmem cache backend
-* Added doc extension to office document format list
-* Removed redundant transformation calculation
-* Make sure OCR in processing documents cannot be deleted
-* PEP8, pylint cleanups and removal of relative imports
-* Removed the obsolete ``DOCUMENTS_GROUP_MAX_RESULTS`` setting option
-* Improved visual appearance of messages by displaying them outside the
- main form
-* Added link to close all notifications with one click
-* Made the queue processing interval configurable by means of a new
- setting: ``OCR_QUEUE_PROCESSING_INTERVAL``
-* Added detection and reset of orphaned ocr documents being left as
- 'processing' when celery dies
-* Improved unknown format detection in the graphicsmagick backend
-* Improved document convertion API
-* Added initial support for converting office documents (only ods and
- docx tested)
-* Added sample configuration files for supervisor and apache under
- contrib/
-* Avoid duplicates in recent document list
-* Added the configuration option CONVERTER_GM_SETTINGS to pass
- GraphicsMagicks specific commands the the GM backend
-* Lower image convertion quality if the format is jpg
-* Inverted the rotation button, more intuitive this way
-* Merged and reduced the document page zoom and rotation views
-* Increased permissions app permission's label field size
-
- - DB Update required
-
-* Added support for metadata group actions
-* Reduced the document pages widget size
-* Display the metadata group numeric total in the metadata group form
- title
-* Reorganized page detail icons
-* Added first & last page navigation links to document page view
-* Added interactive zoom support to document page detail view
-* Spanish translation updates
-* Added ``DOCUMENTS_ZOOM_PERCENT_STEP``, ``DOCUMENTS_ZOOM_MAX_LEVEL``,
- ``DOCUMENTS_ZOOM_MIN_LEVEL`` configuration options to allow detailed
- zoom control
-* Added interactive document page view rotation support
-* Changed the side bar document grouping with carousel style document
- grouping form widget
-* Removed the obsolete ``DOCUMENTS_TRANFORMATION_PREVIEW_SIZE`` and
- ``DOCUMENTS_GROUP_SHOW_THUMBNAIL`` setting options
-* Improved double submit prevention
-* Added a direct rename field to the local update and staging upload
- forms
-* Separated document page detail view into document text and document
- image views
-* Added grab-scroll to document page view
-* Disabled submit buttons and any buttons when during a form submit
-* Updated the page preview widget to display a infinite-style horizontal
- carousel of page previews
-* Added support user document folders
-
- - Must do a ``syncdb`` to add the new tables
-
-* Added support for listing the most recent accessed documents per user
-* Added document page navigation
-* Fixed diagnostics url resolution
-* Added confirmation dialog to document's find missing document file
- diagnostic
-* Added a document page edit view
-* Added support for the command line program pdftotext from the
- poppler-utils packages to extract text from PDF documents without
- doing OCR
-* Fixed document description editing
-* Replaced page break text with page number when displaying document
- content
-* Implemented detail form readonly fields the correct way, this fixes
- copy & paste issues with Firefox
-* New document page view
-* Added view to add or remove user to a specific role
-* Updated the jQuery packages with the web_theme app to version 1.5.2
-* Made ``AVAILABLE_INDEXING_FUNCTION`` setting a setting of the documents
- app instead of the filesystem_serving app
-* Fixed document download in FireFox for documents containing spaces in
- the filename
-* If mime detection fails set mime type to '' instead of 'unknown'
-* Use document MIME type when downloading otherwise use
- 'application/octet-stream' if none
-* Changed the way document page count is parsed from the graphics
- backend, fixing issue #7
-* Optimized document metadata query and display
-* Implemented OCR output cleanups for English and Spanish
-* Redirect user to the website entry point if already logged and lands
- in the login template
-* Changed from using SimpleUploadedFile class to stream file to the
- simpler File class wrapper
-* Updated staging files previews to use sendfile instead of serve_file
-* Moved staging file preview creation logic from documents.views to
- staging.py
-* When deleting staging file, it's cached preview is also deleted
-* Added a new setup option:
-
- - ``FILESYSTEM_INDEXING_AVAILABLE_FUNCTIONS`` - a dictionary to allow users
- to add custom functions
-
-* Made automatic OCR a function of the OCR app and not of Documents app (via signals)
-
- - Renamed setup option ``DOCUMENT_AUTOMATIC_OCR`` to ``OCR_AUTOMATIC_OCR``
-
-* Clear node name when requeueing a document for OCR
-* Added support for editing the metadata of multiple documents at the
- same time
-* Added Graphics magick support by means of user selectable graphic convertion backends
-
- - Some settings renamed to support this change:
-
- + ``CONVERTER_CONVERT_PATH`` is now ``CONVERTER_IM_CONVERT_PATH``
- + ``CONVERTER_IDENTIFY_PATH`` is now ``CONVERTER_IM_IDENTIFY_PATH``
-
- - Added options:
-
- + ``CONVERTER_GM_PATH`` - File path to graphicsmagick's program.
- + ``CONVERTER_GRAPHICS_BACKEND`` - Backend to use: ``ImageMagick`` or
- ``GraphicMagick``
-
-* Raise ImportError and notify user when specifying a non existant
- converter graphics backend
-* Fixed issue #4, avoid circular import in permissions/__init__.py
-* Add a user to a default role only when the user is created
-* Added total page count to statistics view
-* Added support to disable the default scrolling JS code included in
- web_theme app, saving some KBs in transfer
-* Clear last ocr results when requeueing a document
-* Removed the 'exists' column in document list view, diagnostics
- superceded this
-* Added 3rd party sendfile app (support apache's X-sendfile)
-* Updated the get_document_image view to use the new sendfile app
-* Fixed the issue of the strip spaces middleware conflicting with
- downloads
-* Removed custom IE9 tags
-* Closed Issue #6
-* Allow deletion of non existing documents from OCR queue
-* Allow OCR requeue of pending documents
-* Invalid page numbers now raise Http404, not found instead of error
-* Added an additional check to lower the chance of OCR race conditions
- between nodes
-* Introduce a random delay to each node to further reduce the chance of
- a race condition, until row locking can be implemented or is
- implemented by Django
-* Moved navigation code to its own app
-* Reimplemented OCR delay code, only delay new document
- Added a new field: delay, update your database schema accordingly
-* Made the concurrent ocr code more granular, per node, every node can
- handle different amounts of concurrent ocr tasks
- Added a new field: node_name, update your database schema acordinging
-* Reduced default ocr delay time
-* Added a new diagnostics tab under the tools menu
-* Added a new option ``OCR_REPLICATION_DELAY`` to allow the storage some
- time for replication before attempting to do OCR to a document
-* Added OCR multi document re-queue and delete support
-* Added simple statistics page (total used storage, total docs, etc)
-* Implemented form based and button based multi item actions (button
- based by default)
-* Added multi document delete
-* Fixed a few HTML validation errors
-* Issues are now tracked using github
-* Added indexing flags to ocr model
-* Small optimization in document list view
-* Small search optimization
-* Display "DEBUG mode" string in title if ``DEBUG`` variable is set to True
-* Added the fix-permissions bash script under misc/ folder
-* Plugged another file descriptor leak
-* Show class name in config settings view
-* Added missing config option from the setup menu
-* Close file descriptor to avoid leaks
-* Don't allow duplicate documents in queues
-* Don't raise ``PermissionDenied`` exception in ``PermissionDenied middleware``,
- even while debugging
-* Fixed page number detection
-* Created 'simple document' for non technical users with all of a
- document pages content
-* Use document preview code for staging file also
-* Error picture literal name removal
-* Spanish translation updates
-* Show document file path in regards of its storage
-* Added new setting: side bar search box
-* Implemented new ``PermissioDenied`` exception middleware handler
-* Permissions app api now returns a ``PermissionDenied`` exception instead
- of a custom one
-* Added new 403 error template
-* Updated the 404 template to display only a not found message
-* Moved the login required middleware to the common app
-* Fixed search app's model.objects.filter indentation, improved result
- count calculation
-* Added dynamic comparison types to search app
-* Separated search code from view code
-* Correctly calculate show result count for multi model searches
-* Fixed OCR queue list showing wrong thumbnail
-* Fixed staging file preview
-* Show current metadata in document upload view sidebar
-* Show sentry login for admin users
-* Do not reinitialize document queue and/or queued document on reentry
-* Try extra hard not to assign same uuid to two documents
-* Added new transformation preview size setting
-* Renamed document queue state links
-* Changed ocr status display sidebar from form based to text based
-* Added document action to clear all the document's page transformations
-* Allow search across related fields
-* Optimzed search for speed and memory footprint
-* Added ``LIMIT`` setting to search
-* Show search elapsed time on result page
-* Converter now differentiates between unknown file format and convert
- errors
-* Close file descriptors when executing external programs to
- prevent/reduce file descriptior leaks
-* Improved exception handling of external programs
-* Show document thumbnail in document ocr queue list
-* Make ocr document date submitted column non breakable
-* Fix permissions, directories set to mode 755 and files to mode 644
-* Try to fix issue #2, "random ORM field error on search while doing OCR"
-* Added configurable location setting for file based storage
-* Prepend storage name to differentiate config options
-* Fixed duplicated document search
-* Optimized document duplicate search
-* Added locale middleware, menu bar language switching works now
-* Only show language selection list if localemiddleware is active
-* Spanish translation updates
-* Added links, views and permissions to disable or enable an OCR queue
-* Enabled Django's template caching
-* Added document queue property side bar window to the document queue
- list view
-* Added HTML spaceless middleware to remove whitespace in HTML code
-* If current user is superuser or staff show thumbnail & preview
- generation error messages
-* Added a setting to show document thumbnail in metadata group list
-* Started adding configurations setting descriptions
-* Initial GridFS storage support
-* Implemented size and delete methods for GridFS
-* Implement GridFS storage user settings
-* Added document link in the OCR document queue list
-* Link to manually re queue failed OCR
-* Don't separate links (encose object list links with white-space:
- nowrap;)
-* Added document description to the field search list
-* Sort OCR queued documents according to submitted date & time
-* Document filesystem serving is now a separate app
-
- - Steps to update (Some warnings may be returned, but these are not
- fatal as they might be related to missing metadata in some documents):
-
- + rename the following settings:
-
- + ``DOCUMENTS_FILESYSTEM_FILESERVING_ENABLE`` to ``FILESYSTEM_FILESERVING_ENABLE``
- + ``DOCUMENTS_FILESYSTEM_FILESERVING_PATH`` to ``FILESYSTEM_FILESERVING_PATH``
- + ``DOCUMENTS_FILESYSTEM_SLUGIFY_PATHS`` to ``FILESYSTEM_SLUGIFY_PATHS``
- + ``DOCUMENTS_FILESYSTEM_MAX_RENAME_COUNT`` to ``FILESYSTEM_MAX_RENAME_COUNT``
-
- + Do a ./manage.py syncdb
- + Execute 'Recreate index links' locate in the tools menu
- + Wait a few minutes
-
-* Added per document duplicate search and a tools menu option to seach
- all duplicated documents
-* Added document tool that deletes and re-creates all documents
- filesystem links
-* Increased document's and document metadata index filename field's size
- to 255 characters
-* Added sentry to monitor and store error for later debugging
-* Zip files can now be uncompressed in memory and their content uploaded
- individually in one step
-* Added support for concurrent, queued OCR processing using celery
-* Apply default transformations to document before OCR
-* Added unpaper to the OCR convertion pipe
-* Added views to create, edit and grant/revoke permissions to roles
-* Added multipage documents support (only tested on pdfs)
-
- - To update a previous database do: [d.update_page_count() for d in Document.objects.all()]
-
-* Added support for document page transformation (no GUI yet)
-* Added permissions and roles support
-* Added python-magic for smarter MIME type detection
- (https://github.com/ahupp/python-magic).
-* Added a new Document model field: file_mime_encoding.
-* Show only document metadata in document list view.
-* If one document type exists, the create document wizard skips the
- first step.
-* Changed to a liquid css grid
-* Added the ability to group documents by their metadata
-* New abstracted options to adjust document conversion quality (default,
- low, high)
diff --git a/docs/conf.py b/docs/conf.py
index 48200208da..ded1ddc7f8 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -17,6 +17,7 @@ import sys, os
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
+sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "_ext")))
# -- General configuration -----------------------------------------------------
@@ -25,7 +26,9 @@ import sys, os
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode']
+#extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode']
+#extensions = ["djangodocs", "sphinx.ext.intersphinx"]
+extensions = ['djangodocs']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
@@ -37,7 +40,8 @@ source_suffix = '.rst'
#source_encoding = 'utf-8-sig'
# The master toctree document.
-master_doc = 'index'
+#master_doc = 'index'
+master_doc = 'contents'
# General information about the project.
project = u'Mayan EDMS'
@@ -48,10 +52,10 @@ copyright = u'2011, Roberto Rosario'
# built documents.
#
# The short X.Y version.
-version = '0.11.1'
+version = '0.12'
# The full version, including alpha/beta/rc tags.
-release = '0.11.1'
+release = '0.12'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@@ -71,15 +75,15 @@ exclude_patterns = ['_build']
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
-#add_function_parentheses = True
+add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
-#add_module_names = True
+add_module_names = False
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
-#show_authors = False
+show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
@@ -179,7 +183,7 @@ htmlhelp_basename = 'MayanEDMSdoc'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
- ('index', 'MayanEDMS.tex', u'Mayan EDMS Documentation',
+ ('contents', 'MayanEDMS.tex', u'Mayan EDMS Documentation',
u'Roberto Rosario', 'manual'),
]
@@ -212,6 +216,6 @@ latex_documents = [
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
- ('index', 'mayanedms', u'Mayan EDMS Documentation',
+ ('contents', 'mayanedms', u'Mayan EDMS Documentation',
[u'Roberto Rosario'], 1)
]
diff --git a/docs/contents.rst b/docs/contents.rst
new file mode 100644
index 0000000000..d97a668d11
--- /dev/null
+++ b/docs/contents.rst
@@ -0,0 +1,20 @@
+.. _contents:
+
+=================================
+Mayan EDMS documentation contents
+=================================
+
+.. toctree::
+ :hidden:
+
+ index
+
+.. toctree::
+ :maxdepth: 3
+
+ intro/index
+ topics/index
+ releases/index
+ credits/index
+ faq/index
+
diff --git a/docs/credits.rst b/docs/credits.rst
deleted file mode 100644
index e0b3e815d6..0000000000
--- a/docs/credits.rst
+++ /dev/null
@@ -1,124 +0,0 @@
-=======
-Credits
-=======
-
-* Python
- * Copyright (c) 2001-2010 Python Software Foundation.
- * Copyright (c) 2000 BeOpen.com.
- * Copyright (c) 1995-2001 Corporation for National Research Initiatives.
- * Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam.
-
-* Django - A high-level Python Web framework that encourages rapid development and clean, pragmatic design.
- * Copyright Django Software Foundation
- * http://www.djangoproject.com/
-
-* django-pagination
- * Copyright Eric Florenzano (floguy@gmail.com)
- * http://django-pagination.googlecode.com/
-
-* Web App Theme
- * Copyright Andrea Franz (http://gravityblast.com)
- * git://github.com/pilu/web-app-theme.git
-
-* Imagemagick - Convert, Edit, Or Compose Bitmap Images
- * Copyright 1999-2011 ImageMagick Studio LLC
- * http://www.imagemagick.org/script/index.php
-
-* FAMFAMFAM Silk icons
- * Copyright Mark James (http://www.twitter.com/markjames)
- * http://www.famfamfam.com/lab/icons/silk/
-
-* 3 state FAMFAMFAM Silk icon sets: discrete images and CSS sprite palette
- * Copyright Sky Sanders
- * skysanders.net/subtext
-
-* django-extensions - Extensions for Django
- * Copyright Bas van Oostveen (v.oostveen@gmail.com)
- * http://code.google.com/p/django-command-extensions/
-
-* django-rosetta - A Django application that eases the translation of Django projects
- * Copyright Marco Bonetti (mbonetti@gmail.com)
- * http://code.google.com/p/django-rosetta/
-
-* Werkzeug - The Swiss Army knife of Python web development
- * Copyright Armin Ronacher (armin.ronacher@active-4.com)
- * http://werkzeug.pocoo.org/
-
-* BoundFormWizard - A subclass of Django's FormWizard that handled FormSets.
- * Matthew Flanagan (http://www.blogger.com/profile/15093905875465763876)
- * http://code.google.com/p/wadofstuff/
-
-* django-filetransfers - File upload/download abstraction
- * Waldemar Kornewald
- * http://www.allbuttonspressed.com/projects/django-filetransfers
-
-* tesseract - An OCR Engine that was developed at HP Labs between 1985 and 1995... and now at Google.
- * http://code.google.com/p/tesseract-ocr/
-
-* Image file 1068504_92921456 "Mayan piramid" (Stock Exchange)
- * Andres Ojeda (http://www.sxc.hu/profile/andres_ol)
-
-* Image 1297211435_error
- * http://kde-look.org/usermanager/search.php?username=InFeRnODeMoN
-
-* Fat cow icon set
- * http://www.fatcow.com/free-icons
-
-* Python-magic - python-magic is a simple wrapper for libmagic
- * Adam Hupp
- * https://github.com/ahupp/python-magic
-
-* Fancybox - FancyBox is a tool for displaying images, html content and multi-media in a Mac-style "lightbox" that floats overtop of web page.
- * http://fancybox.net
-
-* unpaper - post-processing scanned and photocopied book pages
- * Jens Gulden 2005-2007 - unpaper@jensgulden.de.
- * http://unpaper.berlios.de/
-
-* celery - Celery is an open source asynchronous task queue/job queue based on distributed message passing. It is focused on real-time operation, but supports scheduling as well.
- * Copyright 2009-2011, Ask Solem & contributors
- * http://ask.github.com/celery/getting-started/introduction.html
-
-* django-celery - django-celery provides Celery integration for Django
- * Copyright Ask Solem & contributors
- * http://github.com/ask/django-celery/
-
-* favicon
- * http://www.iconfinder.com/icondetails/21581/24/draw_pyramid_icon
- * Gnome Project
-
-* MongoDB - (from "humongous") is a scalable, high-performance, open source, document-oriented database.
- * Copyright 10gen
- * http://www.mongodb.org/
-
-* PyMongo - is a Python distribution containing tools for working with MongoDB, and is the recommended way to work with MongoDB from Python.
- * Copyright 2009, Michael Dirolf
- * http://api.mongodb.org/python/
-
-* GridFS - is a storage specification for large objects in MongoDB
- * Copyright 10gen
- * http://www.mongodb.org/display/DOCS/GridFS+Specification
-
-* django-sendfile - This is a wrapper around web-server specific methods for sending files to web clients.
- * johnsensible (John Montgomery)
- * https://github.com/johnsensible/django-sendfile
-
-* jQuery-Jail - Jquery Asynchronous Image Loader (JAIL)
- * Sebastiano Armeli-Battana (contact@sebarmeli.com)
- * http://www.sebastianoarmelibattana.com/projects/jail
-
-* django-taggit - is a reusable Django application for simple tagging
- * Alex Gaynor (alex.gaynor@gmail.com)
- * http://pypi.python.org/pypi/django-taggit
-
-* Image 392336_7079 (stock exchange)
-
-* djangorestframework
-
-* South
-
-* python-gnupg
-
-* python-hkp
-
-
diff --git a/docs/LICENSE b/docs/credits/LICENSE
similarity index 100%
rename from docs/LICENSE
rename to docs/credits/LICENSE
diff --git a/docs/contributors.rst b/docs/credits/contributors.rst
similarity index 55%
rename from docs/contributors.rst
rename to docs/credits/contributors.rst
index cae85f3c13..7d015e8d78 100644
--- a/docs/contributors.rst
+++ b/docs/credits/contributors.rst
@@ -4,17 +4,21 @@
Contributors
============
+
How to contribute?
------------------
You can help further the development of **Mayan EDMS** by reporting bugs, submitting documentation, patches, with monetary or hardware donations.
+
Bug fixes
---------
* Aziz M. Bookwala (https://github.com/azizmb)
* IHLeanne (https://github.com/IHLeanne)
* Сергей Глита [Sergey Glita] (s.v.glita@gmail.com)
* Meurig Freeman (https://github.com/meurig)
+* David Herring (https://github.com/abadger1406)
+
Bug reports
-----------
@@ -25,19 +29,53 @@ Bug reports
* dAnjou (https://github.com/dAnjou)
* Сергей Глита [Sergey Glita] (s.v.glita@gmail.com)
* IHLeanne (https://github.com/IHLeanne)
+* valterwill (https://github.com/valterwill)
+* David Herring (https://github.com/abadger1406)
+
Patches
-------
* Meurig Freeman (https://github.com/meurig)
* Сергей Глита [Sergey Glita] (s.v.glita@gmail.com)
+
Suggestions
-----------
* Cezar Jenkins (https://twitter.com/#!/emperorcezar)
* Сергей Глита [Sergey Glita] (s.v.glita@gmail.com)
+* Barry Rowlingson (http://geospaced.blogspot.com)
+* Gour (https://github.com/gour)
+
Translations
------------
-* Emerson Soares (http://emersonsoares.com)
-* Renata Oliveira (https://twitter.com/#!/rnataoliveira)
+* Portuguese
+
+ - Emerson Soares (http://emersonsoares.com)
+ - Renata Oliveira (https://twitter.com/#!/rnataoliveira)
+
+* Russian
+
+ - Сергей Глита [Sergey Glita] (s.v.glita@gmail.com)
+
+* Italian
+
+ - SeeOpen.IT (Numero Verde: 800.910.125, E-mail: sales@seeopen.it)
+
+* Polish
+
+ - mic (https://www.transifex.net/accounts/profile/mic/)
+
+
+Remote access for debugging
+---------------------------
* Сергей Глита [Sergey Glita] (s.v.glita@gmail.com)
+* David Herring (https://github.com/abadger1406)
+* Michael Terretta (terretta@gmail.com)
+
+
+Monetary donations
+------------------
+* David Herring (https://github.com/abadger1406) - $100
+* David Herring (https://github.com/abadger1406) - $250
+* Michael Terretta (terretta@gmail.com) - $100
diff --git a/docs/credits/index.rst b/docs/credits/index.rst
new file mode 100644
index 0000000000..0280222168
--- /dev/null
+++ b/docs/credits/index.rst
@@ -0,0 +1,12 @@
+Credits
+=======
+
+Here we list everything and everybody that has made his/her/its part in improving
+**Mayan EDMS**
+
+.. toctree::
+ :maxdepth: 1
+
+ contributors
+ software_used
+ license
diff --git a/docs/license.rst b/docs/credits/license.rst
similarity index 100%
rename from docs/license.rst
rename to docs/credits/license.rst
diff --git a/docs/credits/software_used.rst b/docs/credits/software_used.rst
new file mode 100644
index 0000000000..0725bd6d66
--- /dev/null
+++ b/docs/credits/software_used.rst
@@ -0,0 +1,156 @@
+=============
+Software used
+=============
+
+* Python
+
+ * Copyright (c) 2001-2010 Python Software Foundation.
+ * Copyright (c) 2000 BeOpen.com.
+ * Copyright (c) 1995-2001 Corporation for National Research Initiatives.
+ * Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam.
+
+* Django - A high-level Python Web framework that encourages rapid development and clean, pragmatic design.
+
+ * Copyright Django Software Foundation
+ * http://www.djangoproject.com/
+
+* django-pagination
+
+ * Copyright Eric Florenzano (floguy@gmail.com)
+ * http://django-pagination.googlecode.com/
+
+* Web App Theme
+
+ * Copyright Andrea Franz (http://gravityblast.com)
+ * git://github.com/pilu/web-app-theme.git
+
+* Imagemagick - Convert, Edit, Or Compose Bitmap Images
+
+ * Copyright 1999-2011 ImageMagick Studio LLC
+ * http://www.imagemagick.org/script/index.php
+
+* FAMFAMFAM Silk icons
+
+ * Copyright Mark James (http://www.twitter.com/markjames)
+ * http://www.famfamfam.com/lab/icons/silk/
+
+* 3 state FAMFAMFAM Silk icon sets: discrete images and CSS sprite palette
+
+ * Copyright Sky Sanders
+ * skysanders.net/subtext
+
+* django-extensions - Extensions for Django
+
+ * Copyright Bas van Oostveen (v.oostveen@gmail.com)
+ * http://code.google.com/p/django-command-extensions/
+
+* django-rosetta - A Django application that eases the translation of Django projects
+
+ * Copyright Marco Bonetti (mbonetti@gmail.com)
+ * http://code.google.com/p/django-rosetta/
+
+* Werkzeug - The Swiss Army knife of Python web development
+
+ * Copyright Armin Ronacher (armin.ronacher@active-4.com)
+ * http://werkzeug.pocoo.org/
+
+* BoundFormWizard - A subclass of Django's FormWizard that handled FormSets.
+
+ * Matthew Flanagan (http://www.blogger.com/profile/15093905875465763876)
+ * http://code.google.com/p/wadofstuff/
+
+* django-filetransfers - File upload/download abstraction
+
+ * Waldemar Kornewald
+ * http://www.allbuttonspressed.com/projects/django-filetransfers
+
+* tesseract - An OCR Engine that was developed at HP Labs between 1985 and 1995... and now at Google.
+
+ * http://code.google.com/p/tesseract-ocr/
+
+* Image file 1068504_92921456 "Mayan piramid" (Stock Exchange)
+
+ * Andres Ojeda (http://www.sxc.hu/profile/andres_ol)
+ * http://www.sxc.hu/browse.phtml?f=view&id=1068504
+
+* Image 1297211435_error
+
+ * http://kde-look.org/usermanager/search.php?username=InFeRnODeMoN
+
+* Fat cow icon set
+
+ * http://www.fatcow.com/free-icons
+
+* Python-magic - python-magic is a simple wrapper for libmagic
+
+ * Adam Hupp
+ * https://github.com/ahupp/python-magic
+
+* Fancybox - FancyBox is a tool for displaying images, html content and multi-media in a Mac-style "lightbox" that floats overtop of web page.
+
+ * http://fancybox.net
+
+* unpaper - post-processing scanned and photocopied book pages
+
+ * Jens Gulden 2005-2007 - unpaper@jensgulden.de.
+ * http://unpaper.berlios.de/
+
+* favicon
+
+ * http://www.iconfinder.com/icondetails/21581/24/draw_pyramid_icon
+ * Gnome Project
+
+* MongoDB - (from "humongous") is a scalable, high-performance, open source, document-oriented database.
+
+ * Copyright 10gen
+ * http://www.mongodb.org/
+
+* PyMongo - is a Python distribution containing tools for working with MongoDB, and is the recommended way to work with MongoDB from Python.
+
+ * Copyright 2009, Michael Dirolf
+ * http://api.mongodb.org/python/
+
+* GridFS - is a storage specification for large objects in MongoDB
+
+ * Copyright 10gen
+ * http://www.mongodb.org/display/DOCS/GridFS+Specification
+
+* django-sendfile - This is a wrapper around web-server specific methods for sending files to web clients.
+
+ * johnsensible (John Montgomery)
+ * https://github.com/johnsensible/django-sendfile
+
+* jQuery-Jail - Jquery Asynchronous Image Loader (JAIL)
+
+ * Sebastiano Armeli-Battana (contact@sebarmeli.com)
+ * http://www.sebastianoarmelibattana.com/projects/jail
+
+* django-taggit - is a reusable Django application for simple tagging
+
+ * Alex Gaynor (alex.gaynor@gmail.com)
+ * http://pypi.python.org/pypi/django-taggit
+
+* Image 392336_7079 (stock exchange) "Chichen Itza" (Stock Exchange)
+
+ * Joerg Witthoeft "Beamer29" (http://www.sxc.hu/profile/Beamer29)
+ * http://www.sxc.hu/browse.phtml?f=view&id=392336
+
+* Django REST framework - lightweight REST framework for Django, that aims to make it easy to build well-connected, self-describing RESTful Web APIs.
+
+ * http://django-rest-framework.org/
+
+* South - intelligent schema and data migrations for Django projects.
+
+ * http://south.aeracode.org/
+
+* python-gnupg - a Python library which takes care of the internal details and allows its users to generate and manage keys, encrypt and decrypt data, and sign and verify messages.
+
+ * http://code.google.com/p/python-gnupg/
+
+* python-hkp - Python HKP client
+
+ * Copyright Dmitry Gladkov
+ * https://github.com/dgladkov/python-hkp
+
+
+
diff --git a/docs/faq.rst b/docs/faq.rst
deleted file mode 100644
index 241e76b4a2..0000000000
--- a/docs/faq.rst
+++ /dev/null
@@ -1,131 +0,0 @@
-===
-FAQ
-===
-
-Frequently asked questions and solutions
-
-
-
-_mysql_exceptions.OperationalError: (1267, "Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and (utf8_general_ci,COERCIBLE) for operation '='")
-------------------------------------------------------------------------------------------------------------------------------------------------------
-
- * Solution::
-
- $ manage.py shell
- >>> from django.db import connection
- >>> cursor = connection.cursor()
- >>> cursor.execute('SHOW TABLES')
- >>> results=[]
- >>> for row in cursor.fetchall(): results.append(row)
- >>> for row in results: cursor.execute('ALTER TABLE %s CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;' % (row[0]))
-
-
- * References:
-
- - http://www.djangoshmango.com/?p=99
- - http://stackoverflow.com/questions/1073295/django-character-set-with-mysql-weirdness
-
-
-
-Incorrect string value: ``'\xE2\x80\x95rs6...'`` for column ``'content'`` at row 1
-----------------------------------------------------------------------------------
-
-When using ``MySQL`` and doing OCR on languages other than English
-
- * Solution:
-
- - Use utf-8 collation on MySQL server, or at least in table 'documents_documentpage', 'content' field
- - Ref: 1- http://groups.google.com/group/django-users/browse_thread/thread/429447086fca6412
- - Ref: 2- http://markmail.org/message/bqajx2utvmtriixi
-
-File system links not showing when serving content with ``Samba``
------------------------------------------------------------------
-
- * Solution:
-
- - Disable unix extensions in the [global] section and enable wide links for the file serving share
-
- - Example::
-
- [global]
- unix extensions = no
-
- ...
-
- [digitalizacion]
- path = /var/local/mayan
- guest ok = yes
- read only = yes
- wide links = yes
- follow symlinks = yes
-
-
- - Ref: 1- http://www.samba.org/samba/docs/man/manpages-3/smb.conf.5.html
-
-
-How to store documents outside of **Mayan EDMS's** path
--------------------------------------------------------
-
- * Sub class Django's ``FileSystemStorage`` class:
-
- - Create a file called ``customstorage.py``::
-
- from django.core.files.storage import FileSystemStorage
-
- class CustomStorage(FileSystemStorage):
- def __init__(self, *args, **kwargs):
- super(CustomStorage, self).__init__(*args, **kwargs)
- self.location='/new/path/to/documents/'
- self.base_url='document_storage'
-
- - In the ``settings.py`` add::
-
- from customstorage import CustomStorage
- DOCUMENTS_STORAGE_BACKEND = CustomStorage
-
-
-How to enable the ``GridFS`` storage backend
---------------------------------------------
-
- * Solution:
-
- - Add the following lines to ``settings.py``::
-
- from storage.backends.gridfsstorage import GridFSStorage
- DOCUMENTS_STORAGE_BACKEND = GridFSStorage
-
- - Filesystem metadata indexing will not work with this storage backend as
- the files are inside a ``MongoDB`` database and can't be linked (at least for now)
-
-
-Site search is slow
--------------------
-
- * Add indexes to the following fields:
-
- - ``documents_document`` - description, recommended size: 160
- - ``documents_documentmetadata`` - value, recommended size: 80
- - ``documents_documentpage`` - content, recommended size: 3000
-
-
-How to enable x-sendile support for ``Apache``
-----------------------------------------------
-
- * Add the following line to your ``settings.py`` file::
-
- SENDFILE_BACKEND = 'sendfile.backends.xsendfile'
-
- * On your apache configuration file add::
-
- XSendFile on
- XSendFileAllowAbove on
-
-
-The included version of ``unoconv`` in my distribution is too old
--------------------------------------------------------------
-
- * Only the file 'unoconv' file from https://github.com/dagwieers/unoconv is needed.
- Put it in a user designated directory for binaries such as /usr/local/bin and
- setup Mayan's configuration option in your settings_local.py file like this::
-
- CONVERTER_UNOCONV_PATH = '/usr/local/bin/unoconv'
diff --git a/docs/faq/index.rst b/docs/faq/index.rst
new file mode 100644
index 0000000000..f24adbae02
--- /dev/null
+++ b/docs/faq/index.rst
@@ -0,0 +1,253 @@
+===
+FAQ
+===
+
+Frequently asked questions and solutions
+
+Database related
+----------------
+
+**Q: PostgreSQL vs. MySQL**
+
+Since Django abstracts database operations from a functional point of view
+**Mayan EDMS** will behave exactly the same either way. The only concern
+would be that MySQL doesn't support transactions for schema modifying
+commands. The only moment this could cause problems is when running
+South migrations during upgrades, if a migration fails the database
+structure is left in a transitory state and has to be reverted manually
+before trying again.
+
+
+**Q: _mysql_exceptions. OperationalError: (1267, "Illegal mix of collations (latin1_swedish_ci, IMPLICIT) and (utf8_general_ci, COERCIBLE) for operation '='")**
+
+* Solution::
+
+ $ manage.py shell
+ >>> from django.db import connection
+ >>> cursor = connection.cursor()
+ >>> cursor.execute('SHOW TABLES')
+ >>> results=[]
+ >>> for row in cursor.fetchall(): results.append(row)
+ >>> for row in results: cursor.execute('ALTER TABLE %s CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;' % (row[0]))
+
+
+* References:
+
+ - http://www.djangoshmango.com/?p=99
+ - http://stackoverflow.com/questions/1073295/django-character-set-with-mysql-weirdness
+
+
+**Q: Incorrect string value: ``'\xE2\x80\x95rs6...'`` for column ``'content'`` at row 1**
+
+When using ``MySQL`` and doing OCR on languages other than English
+
+* Solution:
+
+ - Use utf-8 collation on MySQL server, or at least in table 'documents_documentpage', 'content' field
+ - Ref: 1- http://groups.google.com/group/django-users/browse_thread/thread/429447086fca6412
+ - Ref: 2- http://markmail.org/message/bqajx2utvmtriixi
+
+
+Document sharing
+----------------
+
+**Q: File system links not showing when serving content with ``Samba``**
+
+* Solution:
+
+ - Disable unix extensions in the [global] section and enable wide links for the file serving share
+ - Example::
+
+ [global]
+ unix extensions = no
+
+ ...
+
+ [digitalizacion]
+ path = /var/local/mayan
+ guest ok = yes
+ read only = yes
+ wide links = yes
+ follow symlinks = yes
+
+
+ - Ref: 1- http://www.samba.org/samba/docs/man/manpages-3/smb.conf.5.html
+
+
+Document handling
+-----------------
+
+**How to store documents outside of **Mayan EDMS's** path**
+
+* Sub class Django's ``FileSystemStorage`` class:
+
+ - Create a file called ``customstorage.py``::
+
+ from django.core.files.storage import FileSystemStorage
+
+ class CustomStorage(FileSystemStorage):
+ def __init__(self, *args, **kwargs):
+ super(CustomStorage, self).__init__(*args, **kwargs)
+ self.location='/new/path/to/documents/'
+ self.base_url='document_storage'
+
+ - In the ``settings.py`` add::
+
+ from customstorage import CustomStorage
+ DOCUMENTS_STORAGE_BACKEND = CustomStorage
+
+
+**Q: How to enable the ``GridFS`` storage backend**
+
+* Solution:
+
+ - Add the following lines to ``settings.py``::
+
+ from storage.backends.gridfsstorage import GridFSStorage
+ DOCUMENTS_STORAGE_BACKEND = GridFSStorage
+ - Filesystem metadata indexing will not work with this storage backend as
+ the files are inside a ``MongoDB`` database and can't be linked (at least for now)
+
+**Q: How do you upload a new version of an existing file?**
+
+* Solution:
+
+ - Choose a document, and go to the versions tab, on the right menu at
+ the bottom under ``Other available action`` there is
+ ``Upload new version``. Clicking it will take you to a very similar
+ view as the ``Upload new document`` but you will be able to specify
+ version number and comments for the new version being uploaded.
+
+**Q: Site search is slow**
+
+* Add indexes to the following fields:
+
+ - ``documents_document`` - description, recommended size: 160
+ - ``documents_documentpage`` - content, recommended size: 3000
+
+This is a temporary solution as **Mayan EDMS** will soon be moving to a
+specialized full text search solution.
+
+
+Webserver
+---------
+
+**Q: How to enable x-sendile support for ``Apache``**
+
+* If using Ubuntu execute the following::
+
+ $ sudo apt-get install libapache2-mod-xsendfile
+
+* Add the following line to your ``settings.py`` file::
+
+ SENDFILE_BACKEND = 'sendfile.backends.xsendfile'
+
+* On your apache configuration file add::
+
+ XSendFile on
+ XSendFileAllowAbove on
+
+
+OCR
+---
+
+**Q: The included version of ``unoconv`` in my distribution is too old**
+
+* Only the file 'unoconv' file from https://github.com/dagwieers/unoconv is needed.
+ Put it in a user designated directory for binaries such as /usr/local/bin and
+ setup Mayan's configuration option in your settings_local.py file like this::
+
+ CONVERTER_UNOCONV_PATH = '/usr/local/bin/unoconv'
+
+If you already have office or text documents uploaded into **Mayan EDMS**,
+after setting up and testing ``unoconv`` by hand, go to 'Tools',
+'Maintenance', 'Update office documents' page count', this will force a
+re-detection and re-processing of any document found to be of office format.
+
+
+Deployments
+-----------
+
+**Q: Is virtualenv required as specified in the documentation?**
+
+* It is not necessary, it's just a strong recommendation mainly to reduce
+ dependency conflicts by isolation from the main Python system install.
+ If not using a virtualenv, pip would install Mayan's dependencies
+ globally coming in conflict with the distribution's prepackaged Python
+ libraries messing other Django projects or Python programs, or another
+ later Python/Django project dependencies coming into conflict causing
+ Mayan to stop working for no apparent reason.
+
+
+**Q: Mayan EDMS installed correctly and works, but static files are not served**
+
+Django's development server doesn't serve static files unless the ``DEBUG``
+option is set to ``True``, this mode of operation should only be used for
+development or testing. For production deployments the management command::
+
+ $ ./manage.py collectstatic
+
+should be used and the resulting ``static`` folder served from a webserver.
+For more information, read https://docs.djangoproject.com/en/dev/howto/static-files/
+and https://docs.djangoproject.com/en/1.2/howto/static-files/ or
+http://mayan-edms-ru.blogspot.com/2011/11/blog-post_09.html
+
+
+Other
+-----
+
+
+**Q: How to connect Mayan EDMS to an Active Directory tree**
+
+I used these two libraries as they seemed the most maintained from the quick search I did.
+
+* http://www.python-ldap.org/
+* http://packages.python.org/django-auth-ldap/
+
+After figuring out the corresponding OU, CN and such (which took quite a while since I'm not well versed in LDAP). For configuration options, Mayan EDMS imports settings_local.py after importing settings.py to allow users to override the defaults without modifying any file tracked by Git, this makes upgrading by using Git's pull command extremely easy. My settings_local.py file is as follows:
+
+::
+
+ import ldap
+ from django_auth_ldap.config import LDAPSearch
+
+ # makes sure this works in Active Directory
+ ldap.set_option(ldap.OPT_REFERRALS, 0)
+
+ AUTH_LDAP_SERVER_URI = "ldap://172.16.XX.XX:389"
+ AUTH_LDAP_BIND_DN = 'cn=Roberto Rosario Gonzalez,ou=Aguadilla,ou=XX,ou=XX,dc=XX,dc=XX,dc=XX'
+ AUTH_LDAP_BIND_PASSWORD = 'XXXXXXXXXXXXXX'
+ AUTH_LDAP_USER_SEARCH = LDAPSearch('dc=XX,dc=XX,dc=XX', ldap.SCOPE_SUBTREE, '(SAMAccountName=%(user)s)')
+
+ # Populate the Django user from the LDAP directory.
+ AUTH_LDAP_USER_ATTR_MAP = {
+ "first_name": "givenName",
+ "last_name": "sn",
+ "email": "mail"
+ }
+
+ # This is the default, but I like to be explicit.
+ AUTH_LDAP_ALWAYS_UPDATE_USER = True
+
+ AUTHENTICATION_BACKENDS = (
+ 'django_auth_ldap.backend.LDAPBackend',
+ 'django.contrib.auth.backends.ModelBackend',
+ )
+
+
+
+if your organization policies don't allow anonymous directory queries,
+create a dummy account and set the ``AUTH_LDAP_BIND_DN`` and
+``AUTH_LDAP_BIND_PASSWORD`` options to match the account.
+
+For a more advanced example check this StackOverflow question:
+http://stackoverflow.com/questions/6493985/django-auth-ldap
+
+
+**Q: Can you change the display order of documents...i.e can they be in alphabetical order?**
+
+A the moment no, but it is something being considered.
+
+
+
+
diff --git a/docs/features.rst b/docs/features.rst
deleted file mode 100644
index e272d75e40..0000000000
--- a/docs/features.rst
+++ /dev/null
@@ -1,100 +0,0 @@
-========
-Features
-========
-
-
-* Document versioning.
-
- * Store many versions of the same document, download or revert to a previous version.
-
-* Electronic signature verification.
-
- * Check the authenticity of documents by verifying their embedded cryptographic signatures or upload detached signatures for document signed after they were stored.
-
-* Collaboration tools.
-
- * Discuss documents, comment on new version of a document.
-
-* Office document format support.
-
- * Word processing files? Spreadsheets? Sresentations? They are supported too.
-
-* User defined metadata fields and meta data sets.
-
- * Metadata fields can be grouped into sets per technical, legal or structural requirements such as the `Dublin core`_
-
-.. _`Dublin core`: http://dublincore.org/metadata-basics/
-
-* Dynamic default values for metadata.
-
- * Metadata fields can have an initial value which can be static or determined by an user provided Python code snipped.
-
-* Filesystem integration.
-
- * If enabled, the document database index can be mirrored in the filesystem of the hosting computers and shared via Samba_ or any other method to clients computers on a network.
-
-.. _Samba: http://www.samba.org/
-
-* User defined document unique identifier and checksum algorithms.
-
- * Users can alter the default method used to uniquely indentify documents.
-
-* Documents can be uploaded from different sources.
-
- * Local file or server side file uploads.
-
-* Batch upload many documents with the same metadata.
-
- * Clone a document's metadata for speedier uploads and eliminate repetitive data entry.
-
-* Previews for a great deal of image formats, including PDF.
-
- * **Mayan EDMS** provides different file conversion backends with different levels of functionality and requirements to adapt to different deployment environments.
-
-* Full text searching.
-
- * Document can be searched by their text content, their metadata or any other file attribute such as name, extension, etc.
-
-* Configurable document grouping.
-
- * Automatic linking of documents based on metadata values or document properties.
-
-* Roles support.
-
- * Users can created an unlimited amount of different roles and are not restricted to the traditional admin, operator, guest paradigm.
-
-* Fine grained permissions system.
-
- * There is a permission for every atomic operation performed by users.
-
-* Multi page document support.
-
- * Multiple page PDFs and TIFFs files supported.
-
-* Distributed OCR processing.
-
- * The task of transcribing text from documents via OCR can be distributed among several physical or virtual computers to decrease load and increase availability.
-
-* Multilingual user interface (English, Spanish, Portuguese, Russian).
-
- * **Mayan EDMS** is written using the Django_ framework which natively support Unicode, this coupled with the use of text templates allows **Mayan EDMS** to be translated to practically any language spoken in the world, by default four translations are provided: English, Spanish, Portuguese and Russian.
-
-.. _Django: https://www.djangoproject.com/
-
-* Multilingual OCR support.
-
- * *As supported by the OCR engine tesseract.
-
-* Duplicated document search.
-
-* Plugable storage backends (File based and GridFS included).
-
- * Very easy to convert other 3rd party such as the ones available for Amazon EC2.
-
-* Color coded tagging.
-
- * Labeled and color coded tags that are intituitive.
-
-* Staging folders to receive scanned documents directly from network attached scanners.
-
- * Preview scanned files even before uploading them.
diff --git a/docs/figure_src/ACL.svg b/docs/figure_src/ACL.svg
new file mode 100644
index 0000000000..f0d4c66162
--- /dev/null
+++ b/docs/figure_src/ACL.svg
@@ -0,0 +1,594 @@
+
+
+
+
diff --git a/docs/figure_src/index_instance.svg b/docs/figure_src/index_instance.svg
new file mode 100644
index 0000000000..938d7edccf
--- /dev/null
+++ b/docs/figure_src/index_instance.svg
@@ -0,0 +1,724 @@
+
+
+
+
diff --git a/docs/figure_src/index_template.svg b/docs/figure_src/index_template.svg
new file mode 100644
index 0000000000..9a586b74db
--- /dev/null
+++ b/docs/figure_src/index_template.svg
@@ -0,0 +1,204 @@
+
+
+
+
diff --git a/docs/figure_src/indexes.svg b/docs/figure_src/indexes.svg
new file mode 100644
index 0000000000..f08d8ab0fd
--- /dev/null
+++ b/docs/figure_src/indexes.svg
@@ -0,0 +1,513 @@
+
+
+
+
diff --git a/docs/figure_src/permissions.svg b/docs/figure_src/permissions.svg
new file mode 100644
index 0000000000..3588418dfd
--- /dev/null
+++ b/docs/figure_src/permissions.svg
@@ -0,0 +1,392 @@
+
+
+
+
diff --git a/docs/figure_src/versioning.svg b/docs/figure_src/versioning.svg
new file mode 100644
index 0000000000..e1f16f0618
--- /dev/null
+++ b/docs/figure_src/versioning.svg
@@ -0,0 +1,214 @@
+
+
+
+
diff --git a/docs/index.rst b/docs/index.rst
index 5c115df121..0079a21776 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -1,49 +1,96 @@
-========
-Overview
-========
-Open source, Django_ based document manager with custom metadata indexing, file serving integration and OCR_ capabilities.
+.. _index:
-.. _Django: http://www.djangoproject.com/
+========================
+Mayan EDMS documentation
+========================
+.. rubric:: `Open source`_, Django_ based document manager with custom
+ metadata_ indexing_, file serving integration, OCR_ capabilities,
+ document versioning_ and `digital signature verification`_.
-:Website: http://bit.ly/mayan-edms
-:Source: http://github.com/rosarior/mayan
-:Video: http://bit.ly/pADNXv
-:Issue tracker: http://github.com/rosarior/mayan/issues
-
-
-**Mayan EDMS** started as a simple project whose only requirement was the storage of PDF files, from there it has grown into a complete electronic document management solution.
-**Mayan EDMS** can optimize an organization's bulk upload, storage and retrieval or documents.
-Documents are organized using document classes, user defined metadata fields as well as automatic document grouping and indexing. Documents can be retrieved from the document index or by means of full
-text searching. Users can search for terms in the document's metadata, properties or contents extracted from PDFs or transcribed by OCR_. **Mayan EDMS** is written in Python_ using the Django_ framework, which makes it very agile and fast, specially when compared with existing Java based solutions.
-Being based on patent free, `Open source`_ technologies, **Mayan EDMS** provides legal safety to users and organizations, as well as peace of mind as documents and all related information is stored in open source and transparent formats allowing portability and avoiding `vendor lock-in`_.
-Being written using Python_, **Mayan EDMS** runs on many POSIX compliant operating systems, this coupled with many configuration parameters, allows **Mayan EDMS** to be deployed on many hardware and software configurations such as single server based, clusters, virtualized and cloud based hosting giving adopters the choice of using the infrastructure of their choice.
-On hosting providers that support Django_ such as DjangoZoom_, **Mayan EDMS** can be deployed in under 2 minutes with just a few clicks of the mouse [#]_.
-
-.. [#] "Deploying Mayan EDMS on DjangoZoom.com" @ Youtube (http://bit.ly/mayan-djangozoom)
-.. _`vendor lock-in`: https://secure.wikimedia.org/wikipedia/en/wiki/Vendor_lock-in
-.. _Python: http://www.python.org/
.. _Django: http://www.djangoproject.com/
.. _OCR: https://secure.wikimedia.org/wikipedia/en/wiki/Optical_character_recognition
-.. _`Open source`: https://secure.wikimedia.org/wikipedia/en/wiki/Open_source
-.. _DjangoZoom: http://djangozoom.com/
+.. _digital signature verification: http://en.wikipedia.org/wiki/Digital_signature
+.. _versioning: http://en.wikipedia.org/wiki/Versioning
+.. _metadata: http://en.wikipedia.org/wiki/Metadata
+.. _indexing: http://en.wikipedia.org/wiki/Index_card
+.. _Open source: http://en.wikipedia.org/wiki/Open_source
+
+On the Web
+=====================
+
+* Website: http://www.mayan-edms.com
+* Source: http://github.com/rosarior/mayan
+* Video: http://bit.ly/Mayan-Intro
+
+Looking for specific information? Try the :doc:`detailed table of contents ` otherwise below are the different part of the documentation.
+
+First steps
+===========
+
+ :doc:`Overview ` |
+ :doc:`Features ` |
+ :doc:`Requirements ` |
+ :doc:`Installation `
-========
-Contents
-========
+Understanding Mayan EDMS
+========================
+ :doc:`File storage ` |
+ :doc:`Initial data loading ` |
+ :doc:`Permission system ` |
+ :doc:`Transformations ` |
+ :doc:`Document visualization ` |
+ :doc:`Document versioning ` |
+ :doc:`Document signatures ` |
+ :doc:`Indexes ` |
+ :doc:`Smart links ` |
+ :doc:`OCR `
+
+
+Between versions
+================
.. toctree::
:maxdepth: 2
- features
- requirements
- installation
- settings
- updates
- development
- contributors
- credits
- faq
- license
+ releases/index
+
+
+Customization and fine tunning
+==============================
+
+ :doc:`Settings ` | :doc:`Customization `
+
+
+For developers
+==============
+
+ :doc:`Development ` | :doc:`Documentation ` | :doc:`Translations `
+
+
+Credits
+=======
+
+ :doc:`Contributors ` |
+ :doc:`Software used ` |
+ :doc:`Licensing `
+
+
+Getting help
+============
+
+Having trouble? We'd like to help!
+
+* Try the :doc:`FAQ ` -- it's got answers to many common questions.
+
+* Search for information in the `archives of the mayan-edms mailing list`_, or
+ `post a question`_. If you prefer news servers, use the gateway provided by Gname_.
+
+* Report bugs with **Mayan EDMS** using Github's `ticket tracker`_.
+
+.. _archives of the mayan-edms mailing list: http://groups.google.com/group/mayan-edms/
+.. _Gname: http://news.gmane.org/gmane.comp.python.django.mayan-edms
+.. _post a question: http://groups.google.com/group/mayan-edms
+.. _ticket tracker: http://github.com/rosarior/mayan/issues
diff --git a/docs/intro/features.rst b/docs/intro/features.rst
new file mode 100644
index 0000000000..fc8a34139e
--- /dev/null
+++ b/docs/intro/features.rst
@@ -0,0 +1,100 @@
+========
+Features
+========
+
+* :doc:`Document versioning <../topics/versioning>`.
+
+ * Store many versions of the same document, download or revert to a previous version.
+
+* :doc:`Electronic signature verification <../topics/signatures>`.
+
+ * Check the authenticity of documents by verifying their embedded
+ cryptographic signatures or upload detached signatures for document
+ signed after they were stored.
+
+* Collaboration tools.
+
+ * Discuss documents, comment on new version of a document.
+
+* Office document format support.
+
+ * Word processing files? Spreadsheets? Presentations? They are supported too.
+
+* User defined metadata fields and meta data sets.
+
+ * Metadata fields can be grouped into sets per technical, legal or structural requirements such as the `Dublin core`_
+
+* Dynamic default values for metadata.
+
+ * Metadata fields can have an initial value which can be static or determined by an user provided Python code snipped.
+
+* Filesystem integration.
+
+ * If enabled, the document database index can be mirrored in the filesystem of the hosting computers and shared via Samba_ or any other method to clients computers on a network.
+
+* User defined document unique identifier and checksum algorithms.
+
+ * Users can alter the default method used to uniquely indentify documents.
+
+* Documents can be uploaded from different sources.
+
+ * Local file or server side file uploads.
+
+* Batch upload many documents with the same metadata.
+
+ * Clone a document's metadata for speedier uploads and eliminate repetitive data entry.
+
+* Previews for a great deal of image formats, including PDF.
+
+ * **Mayan EDMS** provides different file conversion backends with different levels of functionality and requirements to adapt to different deployment environments.
+
+* Full text searching.
+
+ * Document can be searched by their text content, their metadata or any other file attribute such as name, extension, etc.
+
+* Configurable document grouping.
+
+ * Automatic linking of documents based on metadata values or document properties.
+
+* :doc:`Roles support <../topics/permissions>`.
+
+ * Users can created an unlimited amount of different roles and are not restricted to the traditional admin, operator, guest paradigm.
+
+* :doc:`Fine grained permissions system <../topics/permissions>`.
+
+ * There is a permission for every atomic operation performed by users.
+
+* Multi page document support.
+
+ * Multiple page PDFs and TIFFs files supported.
+
+* :doc:`Distributed OCR processing <../topics/ocr>`.
+
+ * The task of transcribing text from documents via OCR can be distributed among several physical or virtual computers to decrease load and increase availability.
+
+* Multilingual user interface (English, Spanish, Portuguese, Russian, Polish).
+
+ * **Mayan EDMS** is written using the Django_ framework which natively support Unicode, this coupled with the use of text templates allows **Mayan EDMS** to be translated to practically any language spoken in the world, by default four translations are provided: English, Spanish, Portuguese and Russian.
+
+* :doc:`Multilingual OCR support <../topics/ocr>`.
+
+ * As supported by the OCR engine tesseract.
+
+* Duplicated document search.
+
+* :doc:`Plugable storage backends <../topics/file_storage>` (File based and GridFS included).
+
+ * Very easy to use 3rd party plugins such as the ones available for Amazon EC2.
+
+* Color coded tagging.
+
+ * Labeled and color coded tags that are intituitive.
+
+* Staging folders to receive scanned documents directly from network attached scanners.
+
+ * Preview scanned files even before uploading them.
+
+
+.. _`Dublin core`: http://dublincore.org/metadata-basics/
+.. _Samba: http://www.samba.org/
+.. _Django: https://www.djangoproject.com/
diff --git a/docs/intro/index.rst b/docs/intro/index.rst
new file mode 100644
index 0000000000..de2ea70513
--- /dev/null
+++ b/docs/intro/index.rst
@@ -0,0 +1,33 @@
+Getting started
+===============
+
+New to Mayan EDMS? Read this material to quickly get up and running.
+
+.. toctree::
+ :maxdepth: 1
+
+ overview
+ features
+ requirements
+ installation
+
+
+.. seealso::
+
+ If you're new to Python_, you might want to start by getting an idea of what
+ the language is like. Mayan EDMS is 100% Python, so if you've got minimal
+ comfort with Python you'll probably get a lot more out of Mayan EDMS.
+
+ If you're new to programming entirely, you might want to start with this
+ `list of Python resources for non-programmers`_
+
+ If you already know a few other languages and want to get up to speed with
+ Python quickly, we recommend `Dive Into Python`_ (also available in a
+ `dead-tree version`_). If that's not quite your style, there are quite
+ a few other `books about Python`_.
+
+ .. _python: http://python.org/
+ .. _list of Python resources for non-programmers: http://wiki.python.org/moin/BeginnersGuide/NonProgrammers
+ .. _dive into python: http://diveintopython.net/
+ .. _dead-tree version: http://www.amazon.com/exec/obidos/ASIN/1590593561/ref=nosim/jacobian20
+ .. _books about Python: http://wiki.python.org/moin/PythonBooks
diff --git a/docs/installation.rst b/docs/intro/installation.rst
similarity index 53%
rename from docs/installation.rst
rename to docs/intro/installation.rst
index 98e96a283b..3d9056fab7 100644
--- a/docs/installation.rst
+++ b/docs/intro/installation.rst
@@ -36,10 +36,15 @@ If using the ``MySQL`` database manager, use the following commands::
$ apt-get install python-dev libmysqlclient-dev gcc -y
$ pip install MySQL-python
+
+If using PostgreSQL, enter the following::
+
+ $ apt-get install python-dev libpq-dev gcc-y
+ $ pip install pip install psycopg2
Populate the database with the project's schema doing::
- $ ./manage.py syncdb
+ $ ./manage.py syncdb --migrate
Collect the static files of the project into the ``static`` folder for serving via a webserver::
@@ -52,25 +57,25 @@ Webfaction
To install **Mayan EDMS** on Webfaction_, follow these steps:
-#. Create a new database:
+1. Create a new database:
- * Enter the following selections:
+ * Enter the following selections:
- * Type:* ``Mysql``
- * Name:* ``_mayan``
- * Encoding:* ``utf-8``
+ * Type:* ``Mysql``
+ * Name:* ``_mayan``
+ * Encoding:* ``utf-8``
- * Anotate the provided password.
+ * Anotate the provided password.
-#. Create a new app:
+2. Create a new app:
- * Enter the following in the textbox:
+ * Enter the following in the textbox:
- * Name:* ``mayan``
- * App category:* ``mod_wsgi``
- * App type:* ``mod_wsgi 3.3/Python 2.7``
+ * Name:* ``mayan_app``
+ * App category:* ``mod_wsgi``
+ * App type:* ``mod_wsgi 3.3/Python 2.7``
-#. Login via ssh, and execute::
+3. Login via ssh, and execute::
$ easy_install-2.7 virtualenv
$ cd ~/webapps/mayan_app
@@ -81,63 +86,81 @@ To install **Mayan EDMS** on Webfaction_, follow these steps:
$ source ../bin/activate
$ pip install -r requirements/production.txt
-#. Install the Python MySQL database driver::
+4. Install the Python MySQL database driver::
$ pip install MySQL-python
-#. Create a settings_local.py file, and paste into it the following::
+5. Create a settings_local.py file, and paste into it the following::
- $ DATABASES = {
- $ 'default': {
- $ 'ENGINE': 'django.db.backends.mysql',
- $ 'NAME': '_mayan',
- $ 'USER': '_mayan',
- $ 'PASSWORD': '',
- $ 'HOST': '',
- $ 'PORT': '',
- $ }
- $ }
+ DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.mysql',
+ 'NAME': '_mayan',
+ 'USER': '_mayan',
+ 'PASSWORD': '',
+ 'HOST': '',
+ 'PORT': '',
+ }
+ }
-#. Create the database schema (during this step two errors will appears about failling to install indexes on ``documents.Document`` and ``documents.DocumentPage`` models, ignore them for now)::
+6. Create the database schema::
- $ ./manage.py syncdb
+ $ ./manage.py syncdb --migrate
-#. Collect the static files of the apps::
+7. Collect the static files of the apps::
$ ./manage.py collectstatic -l --noinput
-#. Create a new app:
+8. Create a new app:
- * Enter the following:
+ * Enter the following:
- * Name:* ``mayan_static``
- * App category:* ``Symbolic link``
- * App type:* ``Symbolic link to static-only app``
- * Extra info: ``/home//webapps/mayan_app/mayan/mayan/static``
+ * Name:* ``mayan_static``
+ * App category:* ``Symbolic link``
+ * App type:* ``Symbolic link to static-only app``
+ * Extra info: ``/home//webapps/mayan_app/mayan/mayan/static``
-#. Create the website:
+9. Create the website:
- * Name: ``mayan_edms``
- * Choose a subdomain
- * Under ``Site apps:`` enter the following selections:
+ * Name: ``mayan_edms``
+ * Choose a subdomain
+ * Under ``Site apps:`` enter the following selections:
- * App #1
+ * App #1
- * App:* ``mayan_app``
- * URL path (ex: '/' or '/blog'):* ``/``
+ * App:* ``mayan_app``
+ * URL path (ex: '/' or '/blog'):* ``/``
- * App #2
+ * App #2
- * App:* ``mayan_static``
- * URL path (ex: '/' or '/blog'):* ``/mayan-static``
+ * App:* ``mayan_static``
+ * URL path (ex: '/' or '/blog'):* ``/mayan-static``
-#. Edit the file ``~/webapps/mayan_app/apache2/conf/httpd.conf``:
+10. Edit the file ``~/webapps/mayan_app/apache2/conf/httpd.conf``:
- * Disable the ``DirectoryIndex`` line and the ``DocumentRoot`` line
- * Add the following line::
+ * Disable the ``DirectoryIndex`` line and the ``DocumentRoot`` line.
+ * Add the following line::
- WSGIScriptAlias / /home//webapps/mayan_app/mayan/mayan/wsgi/dispatch.wsgi
+ WSGIScriptAlias / /home//webapps/mayan_app/mayan/mayan/wsgi/dispatch.wsgi
+
+ * Tune your WSGI process to only use 2 workers (as explained here: `Reducing mod_wsgi Memory Consumption`_)
+ to keep the memory usage under the basic 256MB of RAM provided or upgrade your plan to 512MB,
+ the line that controls the amount of workers launched is::
+
+ WSGIDaemonProcess mayan_app processes=5 python-path=/home//webapps/mayan_app/lib/python2.7 threads=1
+
+ change it to::
+
+ WSGIDaemonProcess mayan_app processes=2 python-path=/home//webapps/mayan_app/lib/python2.7 threads=1
+
+11. Restart your apache instance:
+
+ * Execute::
+
+ apache2/bin/restart
+
+
DjangoZoom
----------
For instructions on how to deploy **Mayan EDMS** on DjangoZoom, watch the screencast:
@@ -152,6 +175,7 @@ For instructions on how to deploy **Mayan EDMS** on DjangoZoom, watch the screen
.. _`Open source`: https://secure.wikimedia.org/wikipedia/en/wiki/Open_source
.. _DjangoZoom: http://djangozoom.com/
.. _Youtube: http://bit.ly/mayan-djangozoom
+.. _Django: http://www.djangoproject.com/
.. _Apache: https://www.apache.org/
@@ -160,5 +184,5 @@ For instructions on how to deploy **Mayan EDMS** on DjangoZoom, watch the screen
.. _Download: https://github.com/rosarior/mayan/archives/master
.. _Webfaction: http://www.webfaction.com
.. _deployed: https://docs.djangoproject.com/en/1.3/howto/deployment/
-.. _Django: https://www.djangoproject.com
.. _virtualenv: http://www.virtualenv.org/en/latest/index.html
+.. _`Reducing mod_wsgi Memory Consumption`: http://docs.webfaction.com/software/mod-wsgi.html#mod-wsgi-reducing-memory-consumption
diff --git a/docs/intro/overview.rst b/docs/intro/overview.rst
new file mode 100644
index 0000000000..f79fa55471
--- /dev/null
+++ b/docs/intro/overview.rst
@@ -0,0 +1,19 @@
+====================
+History and overview
+====================
+
+**Mayan EDMS** started as a simple project whose only requirement was the storage of PDF files, from there it has grown into a complete electronic document management solution.
+**Mayan EDMS** can optimize an organization's bulk upload, storage and retrieval or documents.
+Documents are organized using document classes, user defined metadata fields as well as automatic document grouping and indexing. Documents can be retrieved from the document index or by means of full
+text searching. Users can search for terms in the document's metadata, properties or contents extracted from PDFs or transcribed by OCR_. **Mayan EDMS** is written in Python_ using the Django_ framework, which makes it very agile and fast, specially when compared with existing Java based solutions.
+Being based on patent free, `Open source`_ technologies, **Mayan EDMS** provides legal safety to users and organizations, as well as peace of mind as documents and all related information is stored in open source and transparent formats allowing portability and avoiding `vendor lock-in`_.
+Being written using Python_, **Mayan EDMS** runs on many POSIX compliant operating systems, this coupled with many configuration parameters, allows **Mayan EDMS** to be deployed on many hardware and software configurations such as single server based, clusters, virtualized and cloud based hosting giving adopters the choice of using the infrastructure of their choice.
+On hosting providers that support Django_ such as DjangoZoom_, **Mayan EDMS** can be deployed in under 2 minutes with just a few clicks of the mouse [#]_.
+
+.. [#] "Deploying Mayan EDMS on DjangoZoom.com" @ Youtube (http://bit.ly/mayan-djangozoom)
+.. _`vendor lock-in`: https://secure.wikimedia.org/wikipedia/en/wiki/Vendor_lock-in
+.. _Python: http://www.python.org/
+.. _Django: http://www.djangoproject.com/
+.. _OCR: https://secure.wikimedia.org/wikipedia/en/wiki/Optical_character_recognition
+.. _`Open source`: https://secure.wikimedia.org/wikipedia/en/wiki/Open_source
+.. _DjangoZoom: http://djangozoom.com/
diff --git a/docs/requirements.rst b/docs/intro/requirements.rst
similarity index 90%
rename from docs/requirements.rst
rename to docs/intro/requirements.rst
index 665b9ba641..4b4cf9b00d 100644
--- a/docs/requirements.rst
+++ b/docs/intro/requirements.rst
@@ -28,12 +28,6 @@ Executables:
Optional requirements
=====================
-To enable distributed OCR support
----------------------------------
-
-* ``celery`` - asynchronous task queue/job queue based on distributed message passing
-* ``django-celery`` - celery integration for Django
-
To store documents in a GridFS database
---------------------------------------
diff --git a/docs/releases/0.10.1.rst b/docs/releases/0.10.1.rst
new file mode 100644
index 0000000000..d038b853f7
--- /dev/null
+++ b/docs/releases/0.10.1.rst
@@ -0,0 +1,10 @@
+Version 0.10.1
+--------------
+* Upgraded django-compressor to version 1.1.1, run::
+
+ $ pip install --upgrade -r requirements/production.txt
+
+ to upgrade
+
+* django-compressor is now disabled by default, users must explicitly
+ enable it adding COMPRESS_ENABLED=True to their settings_local.py file
diff --git a/docs/releases/0.10.rst b/docs/releases/0.10.rst
new file mode 100644
index 0000000000..cbe2f65ff5
--- /dev/null
+++ b/docs/releases/0.10.rst
@@ -0,0 +1,51 @@
+Version 0.10
+------------
+* Added a proper setup views for the document grouping functionality.
+* Document grouping is now called smart linking as it relates better to
+ how it actually works. The data base schema was changed and users must
+ do the required::
+
+ $ ./manager syncdb
+
+ for the new tables to be created.
+* Grappelli is no longer required as can be uninstalled.
+* New smarter document preview widget that doesn't allow zooming or viewing
+ unknown or invalid documents.
+* New office document converter, requires:
+
+ * LibreOffice (https://www.libreoffice.org/)
+ * unoconv [version 0.5] (https://github.com/dagwieers/unoconv)
+
+* The new office documents converter won't convert files with the extension
+ .docx because these files are recognized as zip files instead. This
+ is an issue of the libmagic library.
+
+* New configuration option added ``CONVERTER_UNOCONV_USE_PIPE`` that controls
+ how unoconv handles the communication with LibreOffice. The default of
+ ``True`` causes unoconv to use **pipes**, this approach is slower than using
+ **TCP/IP** ports but it is more stable.
+
+* Initial `REST` `API` that exposes documents properties and one method, this
+ new `API` is used by the new smart document widget and requires the
+ package ``djangorestframework``, users must issue a::
+
+ $ pip install -r requirements/production.txt
+
+ to install this new requirement.
+
+* MIME type detection and caching performance updates.
+* Updated the included version of ``jQuery`` to 1.7
+* Updated the included version of ``JqueryAsynchImageLoader`` to 0.9.7
+* Document image serving response now specifies a MIME type for increased
+ browser compatibility.
+* Small change in the scheduler that increases stability.
+* Russian translation updates (Сергей Глита [Sergey Glita])
+* Improved and generalized the OCR queue locking mechanism, this should
+ eliminate any posibility of race conditions between Mayan EDMS OCR nodes.
+* Added support for signals to the OCR queue, this results in instant OCR
+ processing upon submittal of a document to the OCR queue, this works in
+ addition to the current polling processing which eliminates the
+ posibility of stale documents in the OCR queue.
+* Added multiple document OCR submit link
+* Re enabled tesseract language specific OCR processing and added a one
+ (1) time language neutral retry for failed language specific OCR
diff --git a/docs/releases/0.11.1.rst b/docs/releases/0.11.1.rst
new file mode 100644
index 0000000000..f618bcf604
--- /dev/null
+++ b/docs/releases/0.11.1.rst
@@ -0,0 +1,8 @@
+Version 0.11.1
+--------------
+* Fixed a document deletion regression
+* Improves error detection when importing keys from a keyserver, catching
+ the exception KeyImportError and not KeyFetchingError
+* Fixes a wrong method call when verifying signatures for the first time upon document uploading
+* django-compress is now disabled by default to avoid problems when deploying with DjangoZoom
+* Improve post metadata set delete redirection
diff --git a/docs/releases/0.11.rst b/docs/releases/0.11.rst
new file mode 100644
index 0000000000..df691977e4
--- /dev/null
+++ b/docs/releases/0.11.rst
@@ -0,0 +1,34 @@
+Version 0.11
+------------
+* Support for signed documents verification added, embedded and detached
+ signatures are supported. When verifying a document Mayan EDMS will
+ try to fetch the public key from the list of keyservers provided in the
+ configuration option SIGNATURES_KEYSERVERS (which defaults to
+ 'pool.sks-keyservers.net'). A public key management view has been added
+ to the setup menu as well as a key query and fetching view to manually
+ import keys from a keyserver.
+* Added support for document versions. Users can upload unlimited amount
+ of versions for a document using a very flexible document version numbering
+ system, users can also revert to a previous document version.
+* OCR queue processing improvements.
+* Office documents handling improvements.
+* Text extraction support for office documents.
+* RTF text documents are now handled as office documents.
+* Added a view to delete the document image cache, useful when switching
+ converter backends or doing diagnostics.
+* Added South to the requirements.
+* Merged documents' filename and extension database fiels into a single
+ filename field, filename are store as uploaded not manipulation is done
+ Users with existing data must install South and run the appropiate
+ migrate commands::
+
+ $ pip install -r requirements/production.txt
+ $ ./manager syncdb
+ $ ./manage.py migrate documents 0001 --fake
+ $ ./manage.py migrate documents
+
+* Added new office document mimetype
+ * application/vnd.ms-office
+* Fixed documents not saving the file encoding
+* Removed extra slash in ajax-loader.gif URL fixes #15, thanks to
+ IHLeanne for finding this one
diff --git a/docs/releases/0.12.rst b/docs/releases/0.12.rst
new file mode 100644
index 0000000000..d382caf9cb
--- /dev/null
+++ b/docs/releases/0.12.rst
@@ -0,0 +1,232 @@
+==============================
+Mayan EDMS v0.12 release notes
+==============================
+
+*February 2012*
+
+Welcome to Mayan EDMS v0.12!
+
+This release commemorates **Mayan EDMS** first aniversary!
+
+Overview
+========
+
+Aside from new features, the focus of this release of **Mayan EDMS** also
+been about improving the code and documentation quality standard
+even further. The permission system has been completely overhauled to make
+it entire class based. The other big change is the addition of object
+level permissions, with this new system being applied to documents,
+folder, tags and smart links. There is also a small batch of navigation
+improvements. Big code cleanup and lots of changes 'under the hood',
+most of these are not visible to the end user, but make the code cleaner
+and more manageable so that more and better features can be added in future
+releases:
+
+* Absolute imports used throught the code
+* All app permissions have been move to a separate permissions.py file
+ per app
+* Complete permission system refactor.
+* Document signining code move to it's own app
+* Initial unit tests
+* A lot of logging used throught the entire project.
+* Much functionality moved to model managers.
+* A lot of code converted into classes.
+* Coding style improvements.
+* Template user authentication state logic improvements, for stonger
+ prevention against intrusion or unintentional display or access
+ of restricted data.
+* Removal of remarked code.
+
+
+What's new in Mayan EDMS v0.12
+==============================
+
+ACL support
+~~~~~~~~~~~
+* Object level access control is now in place for documents, folders,
+ tags and smart links. What this means is that administrators can now
+ grant permissions to users, groups or roles on for specific objects.
+ A more in-depth explanation of how this new ACL system can be found in
+ the :doc:`3 tier access control <../topics/permissions>` section of the
+ permissions chapter.
+
+* Default class ACL support. Administrators can setup the access control
+ lists that new documents, folders and tags will automatically inheric
+ when created. Aside from asigning permission to users, groups and roles
+ to specific objects, there is a special user called `Creator`, use to
+ allow the access control list that the actual creator of an object will
+ inherit.
+
+Anonymous user support
+~~~~~~~~~~~~~~~~~~~~~~
+Anonymous user support is a two tier function, first is the addition of
+the :setting:`COMMON_ALLOW_ANONYMOUS_ACCESS` configuration option that
+allows non authenticated user to browse all the pages of a **Mayan EDMS** installation.
+The second part of this support is the ability to assign permissions
+or individual access to objects to anonymous users.
+
+Translations
+~~~~~~~~~~~~~~~~~~~
+A new Italian translation is available, provided by SeeOpen.IT
+(www.seeopen.it, info@seeopen.it) as well as complete Russian translation
+update by Сергей Глита. Included in this release also the initial translation
+to Polish by mic.
+
+Usability improvements
+~~~~~~~~~~~~~~~~~~~~~~
+* Detached signature behavior improved, uploading a new detached signature
+ erases the previous one.
+* Usability improvement in the role member's add/removal form, by using
+ HTML's option groups tag property
+
+2 Step download process
+~~~~~~~~~~~~~~~~~~~~~~~
+The code for downloading single and multiple document and document versions
+has been merged with compression support also added. This allows for the
+download of documents in their original format or compressed and well as
+the download of several documents in a single compressed file.
+
+Customizable GPG home directory
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Addition of the :setting:`SIGNATURES_GPG_HOME` configuration option to let
+administrators set **Mayan EDMS**'s GPG instance home directory, used to
+store keyrings and other GPG configuration files.
+
+Out of process bulk uploading
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+A management command has been added to help upload a large number of documents
+from a compressed file. For information about this new feature check the
+:doc:`Initial data loading <../topics/initial_import>` chapter.
+
+
+Out of process user import
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+A management command has been added to import a large number users
+from a CSV file. More information about this new feature can also be found
+in the :doc:`Initial data loading <../topics/initial_import>` chapter.
+
+
+Refactored document indexing
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+:doc:`The document indexing <../topics/indexes>` functionality has been
+improved and moved from experimental
+stage to beta stage. Index configuration menus are now available on the
+``Setup`` menu and allows administrators to create skeleton trees that will
+be populated with document links depending on their metadata and properties.
+These populated trees can also be mirrored on the physical filesystem and shared
+using Samba or another filesharing server giving users a structured view
+of the documents contained within **Mayan EDMS** from the ``Indexes`` tab
+or from a mirrored index shared via the network. A new configuration option
+has been added, :setting:`DOCUMENT_INDEXING_FILESYSTEM_SERVING`, which maps
+the index internal name with the physical directory where such index will be
+mirrored on disk.
+
+Help shape Mayan EDMS's future
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Included in this version is a small feedback application, found under the
+``About`` main menu, where users by just answering some questions can
+help determine the priority of the next planned features on the pipeline,
+or even help add new features if enough requests are received. All questions
+are optional but answering as many as possible will help greatly understand
+the need of the **Mayan EDMS** user base.
+
+Staging file previews
+~~~~~~~~~~~~~~~~~~~~~
+The staging file previews now show the filename for easier
+identification and speedier upload selection. The staging files previews
+are now treated as a gallery which means that users can preview an entire
+page of staging files without having to click and close each one
+individually.
+
+
+Upgrading from a previous version
+=================================
+
+Start off by adding the new requirements::
+
+ $ pip install -r requirements/production.txt
+
+Then create the new database structures with::
+
+ $ ./manage.py syncdb
+
+Afterwards migrate existing database schema with::
+
+ $ ./manage.py migrate permissions 0001 --fake
+ $ ./manage.py migrate permissions
+
+
+When the following message appears
+
+::
+
+ The following content types are stale and need to be deleted:
+
+ permissions | permission
+
+ Any objects related to these content types by a foreign key will also
+ be deleted. Are you sure you want to delete these content types?
+ If you're unsure, answer 'no'.
+
+ Type 'yes' to continue, or 'no' to cancel:
+
+Type ``yes`` and press **Enter**
+
+And continue migrating database schema with::
+
+ $ ./manage.py migrate documents
+ $ ./manage.py migrate document_signatures
+ $ ./manage.py migrate folders 0001 --fake
+ $ ./manage.py migrate folders
+ $ ./manage.py migrate document_indexing 0001 --fake
+ $ ./manage.py migrate document_indexing
+ $ ./manage.py migrate sources 0001 --fake
+ $ ./manage.py migrate sources
+
+Again when a similar messages appears
+::
+
+ The following content types are stale and need to be deleted:
+
+ document_indexing | indexinstance
+
+ Any objects related to these content types by a foreign key will also
+ be deleted. Are you sure you want to delete these content types?
+ If you're unsure, answer 'no'.
+
+ Type 'yes' to continue, or 'no' to cancel:
+
+Type ``yes`` and press **Enter**
+
+The upgrade procedure is now complete.
+
+
+Backward incompatible changes
+=============================
+The permission system has been completely reworked so sadly this is a
+place where even data migration can't help and the permissions assigned
+to roles will be lost during the upgrade to version 0.12. Users, groups
+and roles will be preserved only permissions need to be assigned again,
+so write down your role permission setup before upgrading.
+
+Bugs fixed
+==========
+* Issue #17, special thanks to Dave Herring for all the help including
+ access to a machine suffering with the issue, and to Сергей Глита for
+ his research and eventual find of the core cause.
+* Statistics fixes.
+* Fixed get_image_cache_name regression in the OCR app.
+
+Stuff removed
+=============
+* Support for Celery and Sentry has been drop
+ for now.
+* Removed the 'db_index' argument from Text fields definition and
+ migrations as it was causing error messages for MySQL users, thanks to
+ Сергей Глита for reporting this one.
+* Configuration options removed:
+
+ * OCR_CACHE_URI
+ * DOCUMENT_INDEXING_FILESYSTEM_FILESERVING_PATH - Use the newest :setting:`DOCUMENT_INDEXING_FILESYSTEM_SERVING`
+ * DOCUMENT_INDEXING_FILESYSTEM_FILESERVING_ENABLE - Use the newest :setting:`DOCUMENT_INDEXING_FILESYSTEM_SERVING`
+
diff --git a/docs/releases/0.5.1.rst b/docs/releases/0.5.1.rst
new file mode 100644
index 0000000000..e003f04ca3
--- /dev/null
+++ b/docs/releases/0.5.1.rst
@@ -0,0 +1,10 @@
+Version 0.5.1
+-------------
+* Applied initial merge of the new subtemplate renderer
+* Fixed tag removal logic
+* Initial commit to support document comments
+* Updated so that loading spinner is displayed always
+* Exclude tags from the local document upload form
+* Added document tagging support
+
+ - Requires installing ``django-taggit`` and doing a ``sync-db``
diff --git a/docs/releases/0.5.rst b/docs/releases/0.5.rst
new file mode 100644
index 0000000000..3081395e65
--- /dev/null
+++ b/docs/releases/0.5.rst
@@ -0,0 +1,300 @@
+Version 0.5
+-----------
+* Added tag list view and global tag delete support
+* Added tag editing view and listing documents with an specific tag
+* Changed the previewing and deleting staging files views to required
+ ``DOCUMENT_CREATE`` permission
+* Added no-parent-history class to document page links so that iframe clicking doesn't affect the parent window history
+
+ - Fixes back button issue on Chrome 9 & 10
+
+* Added per app version display tag
+* Added loading spinner animation
+* Messages tweaks and translation updates
+* Converter app cleanups, document pre-cache, magic number removal
+* Added OCR view displaying all active OCR tasks from all cluster nodes
+* Disabled ``CELERY_DISABLE_RATE_LIMITS`` by default
+* Implement local task locking using Django locmem cache backend
+* Added doc extension to office document format list
+* Removed redundant transformation calculation
+* Make sure OCR in processing documents cannot be deleted
+* PEP8, pylint cleanups and removal of relative imports
+* Removed the obsolete ``DOCUMENTS_GROUP_MAX_RESULTS`` setting option
+* Improved visual appearance of messages by displaying them outside the
+ main form
+* Added link to close all notifications with one click
+* Made the queue processing interval configurable by means of a new
+ setting: ``OCR_QUEUE_PROCESSING_INTERVAL``
+* Added detection and reset of orphaned ocr documents being left as
+ 'processing' when celery dies
+* Improved unknown format detection in the graphicsmagick backend
+* Improved document convertion API
+* Added initial support for converting office documents (only ods and
+ docx tested)
+* Added sample configuration files for supervisor and apache under
+ contrib/
+* Avoid duplicates in recent document list
+* Added the configuration option CONVERTER_GM_SETTINGS to pass
+ GraphicsMagicks specific commands the the GM backend
+* Lower image convertion quality if the format is jpg
+* Inverted the rotation button, more intuitive this way
+* Merged and reduced the document page zoom and rotation views
+* Increased permissions app permission's label field size
+
+ - DB Update required
+
+* Added support for metadata group actions
+* Reduced the document pages widget size
+* Display the metadata group numeric total in the metadata group form
+ title
+* Reorganized page detail icons
+* Added first & last page navigation links to document page view
+* Added interactive zoom support to document page detail view
+* Spanish translation updates
+* Added ``DOCUMENTS_ZOOM_PERCENT_STEP``, ``DOCUMENTS_ZOOM_MAX_LEVEL``,
+ ``DOCUMENTS_ZOOM_MIN_LEVEL`` configuration options to allow detailed
+ zoom control
+* Added interactive document page view rotation support
+* Changed the side bar document grouping with carousel style document
+ grouping form widget
+* Removed the obsolete ``DOCUMENTS_TRANFORMATION_PREVIEW_SIZE`` and
+ ``DOCUMENTS_GROUP_SHOW_THUMBNAIL`` setting options
+* Improved double submit prevention
+* Added a direct rename field to the local update and staging upload
+ forms
+* Separated document page detail view into document text and document
+ image views
+* Added grab-scroll to document page view
+* Disabled submit buttons and any buttons when during a form submit
+* Updated the page preview widget to display a infinite-style horizontal
+ carousel of page previews
+* Added support user document folders
+
+ - Must do a ``syncdb`` to add the new tables
+
+* Added support for listing the most recent accessed documents per user
+* Added document page navigation
+* Fixed diagnostics url resolution
+* Added confirmation dialog to document's find missing document file
+ diagnostic
+* Added a document page edit view
+* Added support for the command line program pdftotext from the
+ poppler-utils packages to extract text from PDF documents without
+ doing OCR
+* Fixed document description editing
+* Replaced page break text with page number when displaying document
+ content
+* Implemented detail form readonly fields the correct way, this fixes
+ copy & paste issues with Firefox
+* New document page view
+* Added view to add or remove user to a specific role
+* Updated the jQuery packages with the web_theme app to version 1.5.2
+* Made ``AVAILABLE_INDEXING_FUNCTION`` setting a setting of the documents
+ app instead of the filesystem_serving app
+* Fixed document download in FireFox for documents containing spaces in
+ the filename
+* If mime detection fails set mime type to '' instead of 'unknown'
+* Use document MIME type when downloading otherwise use
+ 'application/octet-stream' if none
+* Changed the way document page count is parsed from the graphics
+ backend, fixing issue #7
+* Optimized document metadata query and display
+* Implemented OCR output cleanups for English and Spanish
+* Redirect user to the website entry point if already logged and lands
+ in the login template
+* Changed from using SimpleUploadedFile class to stream file to the
+ simpler File class wrapper
+* Updated staging files previews to use sendfile instead of serve_file
+* Moved staging file preview creation logic from documents.views to
+ staging.py
+* When deleting staging file, it's cached preview is also deleted
+* Added a new setup option:
+
+ - ``FILESYSTEM_INDEXING_AVAILABLE_FUNCTIONS`` - a dictionary to allow users
+ to add custom functions
+
+* Made automatic OCR a function of the OCR app and not of Documents app (via signals)
+
+ - Renamed setup option ``DOCUMENT_AUTOMATIC_OCR`` to ``OCR_AUTOMATIC_OCR``
+
+* Clear node name when requeueing a document for OCR
+* Added support for editing the metadata of multiple documents at the
+ same time
+* Added Graphics magick support by means of user selectable graphic convertion backends
+
+ - Some settings renamed to support this change:
+
+ + ``CONVERTER_CONVERT_PATH`` is now ``CONVERTER_IM_CONVERT_PATH``
+ + ``CONVERTER_IDENTIFY_PATH`` is now ``CONVERTER_IM_IDENTIFY_PATH``
+
+ - Added options:
+
+ + ``CONVERTER_GM_PATH`` - File path to graphicsmagick's program.
+ + ``CONVERTER_GRAPHICS_BACKEND`` - Backend to use: ``ImageMagick`` or
+ ``GraphicMagick``
+
+* Raise ImportError and notify user when specifying a non existant
+ converter graphics backend
+* Fixed issue #4, avoid circular import in permissions/__init__.py
+* Add a user to a default role only when the user is created
+* Added total page count to statistics view
+* Added support to disable the default scrolling JS code included in
+ web_theme app, saving some KBs in transfer
+* Clear last ocr results when requeueing a document
+* Removed the 'exists' column in document list view, diagnostics
+ superceded this
+* Added 3rd party sendfile app (support apache's X-sendfile)
+* Updated the get_document_image view to use the new sendfile app
+* Fixed the issue of the strip spaces middleware conflicting with
+ downloads
+* Removed custom IE9 tags
+* Closed Issue #6
+* Allow deletion of non existing documents from OCR queue
+* Allow OCR requeue of pending documents
+* Invalid page numbers now raise Http404, not found instead of error
+* Added an additional check to lower the chance of OCR race conditions
+ between nodes
+* Introduce a random delay to each node to further reduce the chance of
+ a race condition, until row locking can be implemented or is
+ implemented by Django
+* Moved navigation code to its own app
+* Reimplemented OCR delay code, only delay new document
+ Added a new field: delay, update your database schema accordingly
+* Made the concurrent ocr code more granular, per node, every node can
+ handle different amounts of concurrent ocr tasks
+ Added a new field: node_name, update your database schema acordinging
+* Reduced default ocr delay time
+* Added a new diagnostics tab under the tools menu
+* Added a new option ``OCR_REPLICATION_DELAY`` to allow the storage some
+ time for replication before attempting to do OCR to a document
+* Added OCR multi document re-queue and delete support
+* Added simple statistics page (total used storage, total docs, etc)
+* Implemented form based and button based multi item actions (button
+ based by default)
+* Added multi document delete
+* Fixed a few HTML validation errors
+* Issues are now tracked using github
+* Added indexing flags to ocr model
+* Small optimization in document list view
+* Small search optimization
+* Display "DEBUG mode" string in title if ``DEBUG`` variable is set to True
+* Added the fix-permissions bash script under misc/ folder
+* Plugged another file descriptor leak
+* Show class name in config settings view
+* Added missing config option from the setup menu
+* Close file descriptor to avoid leaks
+* Don't allow duplicate documents in queues
+* Don't raise ``PermissionDenied`` exception in ``PermissionDenied middleware``,
+ even while debugging
+* Fixed page number detection
+* Created 'simple document' for non technical users with all of a
+ document pages content
+* Use document preview code for staging file also
+* Error picture literal name removal
+* Spanish translation updates
+* Show document file path in regards of its storage
+* Added new setting: side bar search box
+* Implemented new ``PermissioDenied`` exception middleware handler
+* Permissions app api now returns a ``PermissionDenied`` exception instead
+ of a custom one
+* Added new 403 error template
+* Updated the 404 template to display only a not found message
+* Moved the login required middleware to the common app
+* Fixed search app's model.objects.filter indentation, improved result
+ count calculation
+* Added dynamic comparison types to search app
+* Separated search code from view code
+* Correctly calculate show result count for multi model searches
+* Fixed OCR queue list showing wrong thumbnail
+* Fixed staging file preview
+* Show current metadata in document upload view sidebar
+* Show sentry login for admin users
+* Do not reinitialize document queue and/or queued document on reentry
+* Try extra hard not to assign same uuid to two documents
+* Added new transformation preview size setting
+* Renamed document queue state links
+* Changed ocr status display sidebar from form based to text based
+* Added document action to clear all the document's page transformations
+* Allow search across related fields
+* Optimzed search for speed and memory footprint
+* Added ``LIMIT`` setting to search
+* Show search elapsed time on result page
+* Converter now differentiates between unknown file format and convert
+ errors
+* Close file descriptors when executing external programs to
+ prevent/reduce file descriptior leaks
+* Improved exception handling of external programs
+* Show document thumbnail in document ocr queue list
+* Make ocr document date submitted column non breakable
+* Fix permissions, directories set to mode 755 and files to mode 644
+* Try to fix issue #2, "random ORM field error on search while doing OCR"
+* Added configurable location setting for file based storage
+* Prepend storage name to differentiate config options
+* Fixed duplicated document search
+* Optimized document duplicate search
+* Added locale middleware, menu bar language switching works now
+* Only show language selection list if localemiddleware is active
+* Spanish translation updates
+* Added links, views and permissions to disable or enable an OCR queue
+* Enabled Django's template caching
+* Added document queue property side bar window to the document queue
+ list view
+* Added HTML spaceless middleware to remove whitespace in HTML code
+* If current user is superuser or staff show thumbnail & preview
+ generation error messages
+* Added a setting to show document thumbnail in metadata group list
+* Started adding configurations setting descriptions
+* Initial GridFS storage support
+* Implemented size and delete methods for GridFS
+* Implement GridFS storage user settings
+* Added document link in the OCR document queue list
+* Link to manually re queue failed OCR
+* Don't separate links (encose object list links with white-space:
+ nowrap;)
+* Added document description to the field search list
+* Sort OCR queued documents according to submitted date & time
+* Document filesystem serving is now a separate app
+
+ - Steps to update (Some warnings may be returned, but these are not
+ fatal as they might be related to missing metadata in some documents):
+
+ + rename the following settings:
+
+ + ``DOCUMENTS_FILESYSTEM_FILESERVING_ENABLE`` to ``FILESYSTEM_FILESERVING_ENABLE``
+ + ``DOCUMENTS_FILESYSTEM_FILESERVING_PATH`` to ``FILESYSTEM_FILESERVING_PATH``
+ + ``DOCUMENTS_FILESYSTEM_SLUGIFY_PATHS`` to ``FILESYSTEM_SLUGIFY_PATHS``
+ + ``DOCUMENTS_FILESYSTEM_MAX_RENAME_COUNT`` to ``FILESYSTEM_MAX_RENAME_COUNT``
+
+ + Do a ./manage.py syncdb
+ + Execute 'Recreate index links' locate in the tools menu
+ + Wait a few minutes
+
+* Added per document duplicate search and a tools menu option to seach
+ all duplicated documents
+* Added document tool that deletes and re-creates all documents
+ filesystem links
+* Increased document's and document metadata index filename field's size
+ to 255 characters
+* Added sentry to monitor and store error for later debugging
+* Zip files can now be uncompressed in memory and their content uploaded
+ individually in one step
+* Added support for concurrent, queued OCR processing using celery
+* Apply default transformations to document before OCR
+* Added unpaper to the OCR convertion pipe
+* Added views to create, edit and grant/revoke permissions to roles
+* Added multipage documents support (only tested on pdfs)
+
+ - To update a previous database do: [d.update_page_count() for d in Document.objects.all()]
+
+* Added support for document page transformation (no GUI yet)
+* Added permissions and roles support
+* Added python-magic for smarter MIME type detection
+ (https://github.com/ahupp/python-magic).
+* Added a new Document model field: file_mime_encoding.
+* Show only document metadata in document list view.
+* If one document type exists, the create document wizard skips the
+ first step.
+* Changed to a liquid css grid
+* Added the ability to group documents by their metadata
+* New abstracted options to adjust document conversion quality (default,
+ low, high)
diff --git a/docs/releases/0.7.3.rst b/docs/releases/0.7.3.rst
new file mode 100644
index 0000000000..5e02a70106
--- /dev/null
+++ b/docs/releases/0.7.3.rst
@@ -0,0 +1,32 @@
+Version 0.7.3
+-------------
+* Refactored main menu navigation and converted all apps to this new
+ system
+* Multi item links are now displayed on top of generic lists as well as
+ on the bottom
+* Spanish translation updates
+* Updated requirements to use the latest development version of
+ django-mptt
+* Improved user folder document removal views
+* Added ability to specify default metadata or metadataset per
+ document type
+* Converted filename handling to use os.path library for improved
+ portability
+* Added edit source object attribute difference detection and logging
+ to history app
+* Missing metadata type in a document during a multi document editing doesn't raise errors anymore.
+
+ - This allows for multi document heterogeneous metadata editing in a single step.
+
+* Added document multi item links in search results
+
+ - Direct editing can be done from the search result list
+
+* Permissions are now grouped and assigned a group name
+* Improved role management views
+* Document type is now an optional document property
+
+ - Documents can be created without an explicit document type
+
+* Added support for per user staging directories
+* Updated logos
diff --git a/docs/releases/0.7.4.rst b/docs/releases/0.7.4.rst
new file mode 100644
index 0000000000..0005fd5358
--- /dev/null
+++ b/docs/releases/0.7.4.rst
@@ -0,0 +1,6 @@
+Version 0.7.4
+-------------
+* Renamed 'secondary actions' to 'secondary menu'
+* Added document type setup views to the setup menu
+* Added document type file name editing views to the setup menu
+* Fixed document queue properties sidebar template not showing
diff --git a/docs/releases/0.7.5.rst b/docs/releases/0.7.5.rst
new file mode 100644
index 0000000000..9a065aa6d3
--- /dev/null
+++ b/docs/releases/0.7.5.rst
@@ -0,0 +1,16 @@
+Version 0.7.5
+-------------
+* Added a help messages to the sidebar of some views
+* Renamed some forms submit button to more intuitive one
+
+ - 'Search' on the submit button of the search form
+ - 'Next step' on the document creation wizard
+
+* Added view to list supported file formats and reported by the
+ converter backend
+* Added redirection support to multi object action views
+* Renamed 'document list' link to 'all documents' and
+ 'recent document list' to 'recent documents'
+* Removed 'change password' link next to the current user's name and
+ added a few views to handle the current user's password, details and
+ details editing
diff --git a/docs/releases/0.7.6.rst b/docs/releases/0.7.6.rst
new file mode 100644
index 0000000000..4f0607045d
--- /dev/null
+++ b/docs/releases/0.7.6.rst
@@ -0,0 +1,23 @@
+Version 0.7.6
+-------------
+* Added recent searches per user support
+
+ - The ammount of searches stored is controlled by the setup option
+ ``SEARCH_RECENT_COUNT``
+
+* The document page zoom button are now disabled when reaching the minimum
+ or maximum zoom level
+* The document page navigation links are now disabled when view the first
+ and last page of a document
+* Document page title now displays the current page vs the total page
+ count
+* Document page title now displays the current zoom level and rotation
+ degrees
+* Added means set the expansion compressed files during document creation,
+ via web interface removing the need for the configuration options:
+ ``UNCOMPRESS_COMPRESSED_LOCAL_FILES`` and ``UNCOMPRESS_COMPRESSED_STAGING_FILES``
+* Added 'search again' button to the advances search results view
+* Implementes an advanced search feature, which allows for individual field terms
+
+ - Search fields supported: document type, MIME type, filename,
+ extension, metadata values, content, description, tags, comments
diff --git a/docs/releases/0.7.rst b/docs/releases/0.7.rst
new file mode 100644
index 0000000000..4fd683c3a1
--- /dev/null
+++ b/docs/releases/0.7.rst
@@ -0,0 +1,13 @@
+Version 0.7
+-----------
+* Added confirmation dialogs icons
+* Added comment app with support for adding and deleting comments to
+ and from documents
+* Updated requirements files as per issue #9
+* Show tagged item count in the tag list view
+* Show tagget document link in the tags subtemplate of documents
+* Made comment sorted by oldest first, made comment subtemplate
+ scrollable
+* Rename comments app to document_comment to avoid conflict with
+ Django's comment app
+* Made document comments searchable
diff --git a/docs/releases/0.8.1.rst b/docs/releases/0.8.1.rst
new file mode 100644
index 0000000000..e001c9115b
--- /dev/null
+++ b/docs/releases/0.8.1.rst
@@ -0,0 +1,32 @@
+Version 0.8.1
+-------------
+* Tags can now also be created from the main menu
+* Added item count column to index instance list view
+* Updated document indexing widget to show different icon for indexes or
+ indexes that contain documents
+* Replaced the Textarea widget with the TextAreaDiv widget on document
+ and document page detail views
+
+ - This change will allow highlighting search terms in the future
+
+* Unknown document file format page count now defaults to 1
+
+ - When uploading documents which the selected converted backend doesn't
+ understand, the total page count will fallback to 1 page to at least
+ show some data, and a comment will be automatically added to the
+ document description
+
+* Added new MAIN_DISABLE_ICONS to turn off all icons
+
+ - This options works very well when using the ``default`` theme
+
+* The default theme is now ``activo``
+* Improved document page views and document page transformation views
+ navigation
+* Added OCR queue document transformations
+
+ - Use this for doing resizing or rotation fixes to improve OCR results
+
+* Added reset view link to the document page view to reset the zoom
+ level and page rotation
+* Staging files now show a thumbnail preview instead of preview link
diff --git a/docs/releases/0.8.2.rst b/docs/releases/0.8.2.rst
new file mode 100644
index 0000000000..c4fd0dee5f
--- /dev/null
+++ b/docs/releases/0.8.2.rst
@@ -0,0 +1,24 @@
+Version 0.8.2
+-------------
+* Moved code to Django 1.3
+
+ - Users have to use the ``collectstatic`` management command::
+
+ $ ./manage.py collectstatic
+
+ - The ``site_media`` directory is no more, users must update the media
+ serving directives in current deployments and point them to the
+ ``static`` directory instead
+
+* The changelog is now available under the ``about`` main menu
+* ``Grappelli`` no longer bundled with Mayan
+
+ - Users must install Grappelli or execute::
+
+ $ pip install --upgrade -r requirements/production.txt
+
+* Even easier UI language switching
+* Added email login method, to enable it, set::
+
+ AUTHENTICATION_BACKENDS = ('common.auth.email_auth_backend.EmailAuthBackend',)
+ COMMON_LOGIN_METHOD = 'email'
diff --git a/docs/releases/0.8.3.rst b/docs/releases/0.8.3.rst
new file mode 100644
index 0000000000..4e9f907a58
--- /dev/null
+++ b/docs/releases/0.8.3.rst
@@ -0,0 +1,29 @@
+Version 0.8.3
+-------------
+* Added a Contributors file under the docs directory
+* Moved the document grouping subtemplate windows into a document
+ information tab
+* Change the mode the setup options are shown, opting to use a more of a
+ dashboard style now
+* Changed the tool menu to use the same button layout of the setup menu
+* Moved OCR related handling to the tools main menu
+* Improved the metadata type and metadata set selection widget during
+ the document upload wizard
+* Added a view to the about menu to read the LICENSE file included with
+ Mayan
+* Added converter backend agnostic image file format descriptions
+* Disable whitelist and blacklist temporarily, removed document_type
+ field from interactive sources
+* Fully disabled watch folders until they are working correctly
+* Updated the project title to 'Mayan EDMS'
+* If ghostscript is installed add PDF and PS to the list of file formats
+ by the python converter backend
+* Use Pillow (http://pypi.python.org/pypi/Pillow) instead of PIL
+
+ - Pillow is a fork of PIL with several updated including better jpeg and png library detection
+ - Users must uninstall PIL before installing Pillow
+
+* Updated the static media url in the login excempt url list
+* Added remediatory code to sidestep issue #10 caused by DjangoZoom's deployment script executing the collectstatic command before creating the database structure with syncdb. Thanks to Joost Cassee (https://github.com/jcassee) for reporting this one.
+* Perform extra validation of the image cache directory and fallback to creating a temporary directory on validation failure
+* Fixed a source creation bug, that caused invalid links to a non existing source transformation to appear on the sidebar
diff --git a/docs/releases/0.8.rst b/docs/releases/0.8.rst
new file mode 100644
index 0000000000..bb70049bfb
--- /dev/null
+++ b/docs/releases/0.8.rst
@@ -0,0 +1,62 @@
+Version 0.8
+-----------
+* Distributed OCR queue processing via celery is disabled for the time
+ being
+* Added support for local scheduling of jobs
+
+ - This addition removes celery beat requirement, and make is optional
+
+* Improve link highlighting
+* Navigation improvements
+* Documents with an unknown file format now display a mime type place
+ holder icon instead of a error icon
+* Mayan now does pre caching of document visual representation improving
+ overall thumbnail, preview and display speed
+
+ - Page image rotation and zooming is faster too with this update
+
+* Removed all QUALITY related settings
+* ``COMMON_TEMPORARY_DIRECTORY`` is now validated when Mayan starts and if
+ not valid falls back to creating it's own temporary folder
+* Added PDF file support to the python converter backend via ghostscript
+
+ - This requires the installation of:
+
+ + ghostscript python package
+ + ghostscript system binaries and libraries
+
+* Added PDF text parsing support to the python converter backend
+
+ - This requires the installation of:
+
+ + pdfminer python package
+
+* Added PDF page count support to the python converter backend
+* Added python only converter backend supporting resizing, zooming and rotation
+
+ - This backend required the installation of the python image library (PIL)
+ - This backend is useful when Graphicsmagick or Imagemagick can not be installed for some reason
+ - If understand fewer file format than the other 2 backends
+
+* Added default tranformation support to document sources
+* Removed ``DOCUMENT_DEFAULT_TRANSFORMATIONS`` setup options
+* Document sources are now defined via a series of view under the setup main menu
+* This removes all the ``DOCUMENT_STAGING`` related setup options
+
+ - Two document source types are supported local (via a web form),
+ and staging
+ - However multiple document sources can be defined each with their own
+ set of transformations and default metadata selection
+
+* Use ``python-magic`` to determine a document's mimetype otherwise
+ fallback to use python's mimetypes library
+* Remove the included sources for ``python-magic`` instead it is now fetched
+ from github by pip
+* Removed the document subtemplates and changed to a tabbed style
+* Added link to document index content view to navigate the tree upwards
+* Added new option ``MAIN_DISABLE_HOME_VIEW`` to disable the home main menu
+ tab and save some space
+* Added new option to the web theme app, ``WEB_THEME_VERBOSE_LOGIN``
+ that display a more information on the login screen
+ (version, copyright, logos)
+* Added a confirmation dialog to the document tag removal view
diff --git a/docs/releases/0.9.1.rst b/docs/releases/0.9.1.rst
new file mode 100644
index 0000000000..2dc29b1a65
--- /dev/null
+++ b/docs/releases/0.9.1.rst
@@ -0,0 +1,7 @@
+Version 0.9.1
+-------------
+* Added handling percent encoded unicode query strings in search URL,
+ thanks to (Сергей Глита [Sergei Glita]) for reporting.
+* Added a FAQ explaing how to fix MySQL collation related error when
+ doing searches also thanks to (Сергей Глита [Sergei Glita]) for
+ reporting this one.
diff --git a/docs/releases/0.9.rst b/docs/releases/0.9.rst
new file mode 100644
index 0000000000..c3709ffe2f
--- /dev/null
+++ b/docs/releases/0.9.rst
@@ -0,0 +1,44 @@
+Version 0.9
+-----------
+* Simplified getting mimetypes from files by merging 2 implementations
+ (document based and file based)
+* Updated python converter backend, document model and staging module
+ to use the new get_mimetype API
+* Only allow clickable thumbnails for document and staging files with a
+ valid image
+* Removed tag count from the group document list widget to conserve
+ vertical space
+* Updated required Django version to 1.3.1
+* Removed the included 3rd party module django-sendfile, now added to
+ the requirement files.
+
+ * User should do a pip install -r requirements/production.txt to update
+
+* Changed to Semantic Versioning (http://semver.org/), with
+ recommendations 7, 8 and 9 causing the most effect in the versioning number.
+* Added Russian locale post OCR cleanup backend (Сергей Глита [Sergei Glita])
+* Reduced severity of the messages displayed when no OCR cleanup backend
+ is found for a language
+* Complete Portuguese translation (Emerson Soares and Renata Oliveira)
+* Complete Russian translation (Сергей Глита [Sergei Glita])
+* Added animate.css to use CSS to animate flash messages with better
+ fallback on non JS browsers
+* The admin and sentry links are no longer hard-coded (Meurig Freeman)
+* Improved appearance of the document tag widget
+ (https://p.twimg.com/Ac0Q0b-CAAE1lfA.png:large)
+* Added django_compress and cssmin to the requirements files and enabled
+ django_compress for CSS and JS files
+* Added granting and revoking permission methods to the permission model
+* Correctly calculate the mimetype icons paths when on development mode
+* Added a new more comprehensive method of passing multiple variables
+ per item in multi item selection views
+* Used new multi parameter passing method to improve the usability of
+ the grant/revoke permission view, thanks to Cezar Jenkins
+ (https://twitter.com/#!/emperorcezar) for the suggestion
+* Added step to the documentation explaining how to install Mayan EDMS
+ on Webfaction
+* Added an entry in the documentation to the screencast explaining how
+ to install Mayan EDMS on DjangoZoom
+* Added required changes to add Mayan EDMS to Transifex.com
+* Fixed the apache contrib file static file directory name
+* Added improved documentation
diff --git a/docs/releases/index.rst b/docs/releases/index.rst
new file mode 100644
index 0000000000..3bbee2aa57
--- /dev/null
+++ b/docs/releases/index.rst
@@ -0,0 +1,42 @@
+=============
+Release notes
+=============
+
+Release notes for the official **Mayan EDMS** releases. Each release note will tell you
+what's new in each version, and will also describe any backwards-incompatible
+changes made in that version.
+
+For those upgrading to a new version of **Mayan EDMS**, you will need to check
+all the backwards-incompatible changes and deprecated features for
+each 'final' release from the one after your current **Mayan EDMS** version,
+up to and including the new version.
+
+Latest version (0.12)
+---------------------
+.. toctree::
+ :maxdepth: 1
+
+ 0.12
+
+Historic changelogs
+-------------------
+.. toctree::
+ :maxdepth: 1
+
+ 0.11.1
+ 0.11
+ 0.10.1
+ 0.10
+ 0.9.1
+ 0.9
+ 0.8.3
+ 0.8.2
+ 0.8.1
+ 0.8
+ 0.7.6
+ 0.7.5
+ 0.7.4
+ 0.7.3
+ 0.7
+ 0.5.1
+ 0.5
diff --git a/docs/settings.rst b/docs/settings.rst
deleted file mode 100644
index 323bf84405..0000000000
--- a/docs/settings.rst
+++ /dev/null
@@ -1,411 +0,0 @@
-========
-Settings
-========
-
-**Mayan EDMS** has many configuration options that make it very adaptable to
-different server configurations.
-
-Documents
----------
-
-.. data:: DOCUMENTS_CHECKSUM_FUNCTION
-
- Default: ``hashlib.sha256(x).hexdigest()``
-
-
-.. data:: DOCUMENTS_UUID_FUNCTION
-
- Default: ``unicode(uuid.uuid4())``
-
-
-.. data:: DOCUMENTS_STORAGE_BACKEND
-
- Default: ``FileBasedStorage`` class
-
-
-.. data:: DOCUMENTS_PREVIEW_SIZE
-
- Default: ``640x480``
-
-
-.. data:: DOCUMENTS_PRINT_SIZE
-
- Default: ``1400``
-
-
-.. data:: DOCUMENTS_MULTIPAGE_PREVIEW_SIZE
-
- Default: ``160x120``
-
-
-.. data:: DOCUMENTS_THUMBNAIL_SIZE
-
- Default: ``50x50``
-
-
-.. data:: DOCUMENTS_DISPLAY_SIZE
-
- Default: ``1200``
-
-
-.. data:: DOCUMENTS_RECENT_COUNT
-
- Default: ``40``
-
- Maximum number of recent (created, edited, viewed) documents to
- remember per user.
-
-
-.. data:: DOCUMENTS_ZOOM_PERCENT_STEP
-
- Default: ``50``
-
- Amount in percent zoom in or out a document page per user interaction.
-
-
-.. data:: DOCUMENTS_ZOOM_MAX_LEVEL
-
- Default: ``200``
-
- Maximum amount in percent (%) to allow user to zoom in a document page interactively.
-
-
-.. data:: DOCUMENTS_ZOOM_MIN_LEVEL
-
- Default: ``50``
-
- Minimum amount in percent (%) to allow user to zoom out a document page interactively.
-
-
-.. data:: DOCUMENTS_ROTATION_STEP
-
- Default: ``90``
-
- Amount in degrees to rotate a document page per user interaction.
-
-
-.. data:: DOCUMENTS_CACHE_PATH
-
- Default: ``image_cache`` (relative to the installation path)
-
- The path where the visual representations of the documents are stored for fast display.
-
-
-Converter
----------
-
-.. data:: CONVERTER_IM_CONVERT_PATH
-
- Default: ``/usr/bin/convert``
-
-
- File path to imagemagick's convert program.
-
-
-.. data:: CONVERTER_IM_IDENTIFY_PATH
-
- Default: ``/usr/bin/identify``
-
-
- File path to imagemagick's identify program.
-
-
-.. data:: CONVERTER_GM_PATH
-
- Default: ``/usr/bin/gm``
-
-
- File path to graphicsmagick's program.
-
-
-.. data:: CONVERTER_GM_SETTINGS
-
- Default: None
-
-
-.. data:: CONVERTER_GRAPHICS_BACKEND
-
- Default: ``converter.backends.python``
-
- Graphics conversion backend to use. Options are: ``converter.backends.imagemagick``,
- ``converter.backends.graphicsmagick`` and ``converter.backends.python``.
-
- Suggested options: ``-limit files 1 -limit memory 1GB -limit map 2GB -density 200``
-
-
-.. data:: CONVERTER_UNOCONV_PATH
-
- Default: ``/usr/bin/unoconv``
-
- Path to the unoconv program.
-
-
-.. data:: CONVERTER_UNOCONV_USE_PIPE
-
- Default: ``True``
-
- Use alternate method of connection to LibreOffice using a pipe, it is slower but less prone to segmentation faults.
-
-
-Linking
--------
-
-.. data:: LINKING_SHOW_EMPTY_SMART_LINKS
-
- Default: ``True``
-
- Show smart links even when they don't return any documents.
-
-
-Storage
--------
-
-.. data:: STORAGE_GRIDFS_HOST
-
- Default: ``localhost``
-
-
-.. data:: STORAGE_GRIDFS_PORT
-
- Default: ``27017``
-
-
-.. data:: STORAGE_GRIDFS_DATABASE_NAME
-
- Default: ``document_storage``
-
-
-.. data:: STORAGE_FILESTORAGE_LOCATION
-
- Default: ``document_storage``
-
-
-Job processor
--------------
-
-.. data:: JOB_PROCESSING_BACKEND
-
- Default: ``None``
-
-
- Specified which job processing library to use, option are: None and celery.
-
-
-Document indexing
------------------
-
-.. data:: DOCUMENT_INDEXING_AVAILABLE_INDEXING_FUNCTIONS
-
- Default: ``proper_name``
-
-
-.. data:: DOCUMENT_INDEXING_SUFFIX_SEPARATOR
-
- Default: ``_`` (underscore)
-
-
-.. data:: DOCUMENT_INDEXING_FILESYSTEM_SLUGIFY_PATHS
-
- Default: ``False``
-
-
-.. data:: DOCUMENT_INDEXING_FILESYSTEM_MAX_SUFFIX_COUNT
-
- Default: ``1000``
-
-
-.. data:: DOCUMENT_INDEXING_FILESYSTEM_FILESERVING_PATH
-
- Default: ``/tmp/mayan/documents``
-
-
-.. data:: DOCUMENT_INDEXING_FILESYSTEM_FILESERVING_ENABLE
-
- Default: ``True``
-
-
-OCR
----
-
-.. data:: OCR_TESSERACT_PATH
-
- Default: ``/bin/tesseract``
-
-
-.. data:: OCR_TESSERACT_LANGUAGE
-
- Default: ``eng``
-
-
-.. data:: OCR_REPLICATION_DELAY
-
- Default: ``0``
-
- Amount of seconds to delay OCR of documents to allow for the node's
- storage replication overhead.
-
-
-.. data:: OCR_NODE_CONCURRENT_EXECUTION
-
- Default: ``1``
-
- Maximum amount of concurrent document OCRs a node can perform.
-
-
-.. data:: OCR_AUTOMATIC_OCR
-
- Default: ``False``
-
- Automatically queue newly created documents for OCR.
-
-
-.. data:: OCR_QUEUE_PROCESSING_INTERVAL
-
- Default: ``10``
-
-
-.. data:: OCR_CACHE_URI
-
- Default: ``None``
-
- URI in the form: ``"memcached://127.0.0.1:11211/"`` to specify a cache
- backend to use for locking. Multiple hosts can be specified separated
- by a semicolon.
-
-
-.. data:: OCR_UNPAPER_PATH
-
- Default: ``/usr/bin/unpaper``
-
- File path to unpaper program.
-
-
-Metadata
---------
-
-.. data:: METADATA_AVAILABLE_FUNCTIONS
-
- Default: ``current_date``
-
-
-.. data:: METADATA_AVAILABLE_MODELS
-
- Default: ``User``
-
-
-Common
-------
-
-.. data:: COMMON_TEMPORARY_DIRECTORY
-
- Default: ``/tmp``
-
- Temporary directory used site wide to store thumbnails, previews
- and temporary files. If none is specified, one will be created
- using tempfile.mkdtemp()
-
-
-.. data:: COMMON_DEFAULT_PAPER_SIZE
-
- Default: ``Letter``
-
-
-.. data:: COMMON_DEFAULT_PAGE_ORIENTATION
-
- Default: ``Portrait``
-
-
-.. data:: COMMON_AUTO_CREATE_ADMIN
-
- Default: ``True``
-
-
-.. data:: COMMON_AUTO_ADMIN_USERNAME
-
- Default: ``admin``
-
-
-.. data:: COMMON_AUTO_ADMIN_PASSWORD
-
- Default: ``admin``
-
-
-.. data:: COMMON_LOGIN_METHOD
-
- Default: ``username``
-
- Controls the mechanism used to authenticated user. Options are: ``username``, ``email``
-
-
-Search
-------
-
-.. data:: SEARCH_LIMIT
-
- Default: ``100``
-
- Maximum amount search hits to fetch and display.
-
-
-.. data:: SEARCH_RECENT_COUNT
-
- Default: ``5``
-
- Maximum number of search queries to remember per user.
-
-
-Web theme
----------
-
-.. data:: WEB_THEME_THEME
-
- Default: ``activo``
-
- CSS theme to apply, options are: ``amro``, ``bec``, ``bec-green``, ``blue``, ``default``, ``djime-cerulean``, ``drastic-dark``, ``kathleene``, ``olive``, ``orange``, ``red``, ``reidb-greenish`` and ``warehouse``.
-
-
-.. data:: WEB_THEME_VERBOSE_LOGIN
-
- Default: ``True``
-
- Display extra information in the login screen.
-
-
-Main
-----
-
-.. data:: MAIN_SIDE_BAR_SEARCH
-
- Default: ``False``
-
- Controls whether the search functionality is provided by a sidebar widget or by a menu entry.
-
-
-.. data:: MAIN_DISABLE_HOME_VIEW
-
- Default: ``False``
-
-
-.. data:: MAIN_DISABLE_ICONS
-
- Default: ``False``
-
-
-User management
----------------
-
-.. data:: ROLES_DEFAULT_ROLES
-
- Default: ``[]``
-
- A list of existing roles that are automatically assigned to newly created users
-
-
-Signatures
-----------
-
-.. data:: SIGNATURES_KEYSERVERS
-
- Default: ``['pool.sks-keyservers.net']``
-
- List of keyservers to be queried for unknown keys.
diff --git a/docs/topics/ACL.png b/docs/topics/ACL.png
new file mode 100644
index 0000000000..acd3458113
Binary files /dev/null and b/docs/topics/ACL.png differ
diff --git a/docs/topics/customization.rst b/docs/topics/customization.rst
new file mode 100644
index 0000000000..927bced0d3
--- /dev/null
+++ b/docs/topics/customization.rst
@@ -0,0 +1,49 @@
+=============
+Customization
+=============
+
+The general appearance of **Mayan EDMS** can be customized entirely just
+by changing a few settings.
+
+------
+Themes
+------
+**Mayan EDMS** uses `Andrea Franz's excellent web app template`_ which includes
+several themes that could be used to adapt **Mayan EDMS**'s appearance to match
+an organtization existing applications' look and feel.
+
+The theme can be changed very easily by settings the :setting:`WEB_THEME_THEME`
+configuration option to one of its valid values.
+
+.. image:: themes.png
+ :alt: themes
+
+------------
+Login screen
+------------
+The amount of information presented at the login screen can also be restricted
+if for security or desgin reasons using :setting:`WEB_THEME_VERBOSE_LOGIN`
+configuration option.
+
+.. image:: mayan-login.png
+ :alt: mayan login screen
+
+-----------
+Home screen
+-----------
+Sometimes users just want to go directly to work and not just be greeted with
+a home screen, for these kind of situations **Mayan EDMS** has the
+:setting:`MAIN_DISABLE_HOME_VIEW` configuration option which will cause
+users to land on their ``recent document list`` as soon as they log in.
+
+-----
+Icons
+-----
+Some themes such as ``default`` might be more visually appealing to some
+people without the menu icons, for this **Mayan EDMS** provides the
+:setting:`MAIN_DISABLE_ICONS` configuration option.
+
+.. image:: no-icons.png
+ :alt: mayan screens with out icons
+
+.. _`Andrea Franz's excellent web app template`: https://github.com/pilu/web-app-theme
diff --git a/docs/development.rst b/docs/topics/development.rst
similarity index 54%
rename from docs/development.rst
rename to docs/topics/development.rst
index b55371ac69..5ef1e680d6 100644
--- a/docs/development.rst
+++ b/docs/topics/development.rst
@@ -51,31 +51,54 @@ To familiarize yourself with the technical details of the project read the :ref:
.. _docs:
------------------
-Documentation
------------------
-The documentation is written in `reStructured Text`_ format.
+---------
+Debugging
+---------
-The documentation lives in the ``docs`` directory. In order to build it, you will first need to install Sphinx_. ::
+**Mayan EDMS** makes extensive use of Django's new `logging capabilities`_.
+To enable debug logging for the ``documents`` app for example add the following
+lines to your ``settings_local.py`` file::
- $ pip install sphinx
+ LOGGING = {
+ 'version': 1,
+ 'disable_existing_loggers': True,
+ 'formatters': {
+ 'verbose': {
+ 'format': '%(levelname)s %(asctime)s %(name)s %(process)d %(thread)d %(message)s'
+ },
+ 'intermediate': {
+ 'format': '%(name)s <%(process)d> [%(levelname)s] "%(funcName)s() %(message)s"'
+ },
+ 'simple': {
+ 'format': '%(levelname)s %(message)s'
+ },
+ },
+ 'handlers': {
+ 'console':{
+ 'level':'DEBUG',
+ 'class':'logging.StreamHandler',
+ 'formatter': 'intermediate'
+ }
+ },
+ 'loggers': {
+ 'documents': {
+ 'handlers':['console'],
+ 'propagate': True,
+ 'level':'DEBUG',
+ },
+ }
+ }
-Then, to build an HTML version of the documentation, simply run the following from the **docs** directory::
-
- $ make html
-
-Your ``docs/_build/html`` directory will then contain an HTML version of the documentation, ready for publication on most web servers.
-
-You can also generate the documentation in format other than HTML.
-
-.. _`reStructured Text`: http://docutils.sourceforge.net/rst.html
-.. _Sphinx: http://sphinx.pocoo.org
+Likewise, to see the debug output of the ``tags`` app, just add the following inside the ``loggers`` block::
----------------
-Translations
----------------
+ 'tags': {
+ 'handlers':['console'],
+ 'propagate': True,
+ 'level':'DEBUG',
+ },
-Translations are now being handled online via the **Transifex** website: https://www.transifex.net/projects/p/mayan-edms/
+
+.. _`logging capabilities`: https://docs.djangoproject.com/en/dev/topics/logging
diff --git a/docs/topics/document_visualization.rst b/docs/topics/document_visualization.rst
new file mode 100644
index 0000000000..cfedc23ad3
--- /dev/null
+++ b/docs/topics/document_visualization.rst
@@ -0,0 +1,37 @@
+======================
+Document visualization
+======================
+
+
+The philosophy in place is to try to avoid having users download a documents and leave
+**Mayan EDMS** to be able to see them, so in essence making **Mayan EDMS** a
+visualization tool too. The conversion backend is a stack of functions,
+first the mimetype is evaluated, if it is an office document it is passed
+to LibreOffice_ working in headless mode (and managed by supervisor_)
+via unoconv_ (more information about ``unoconv`` can be found in the :doc:`FAQ section <../faq/index>`)
+for conversion to PDF_. The PDF_ is stored in a temporary
+cache along side all the other files that were not office documents,
+from here they are inspected to determine the page count and the
+corresponding blank database entires are created. After the database
+update they all go to the conversion driver specified by the configuration
+option :setting:`CONVERTER_GRAPHICS_BACKEND` and a high resolution
+master preview of each file is generated and stored in the persistent
+cache. From the master previews in the persistent cache, volatile
+previews are then created on demand for the different sizes requested
+(thumbnail, page preview, full preview) and rotated interactively
+in the details view.
+
+
+Office document conversion however won't always work as expected because
+LibreOffice_ do not provide proper API's, so subprocess calling,
+temporary files and other black magic needs to be invoked to get it
+properly integrated. **Mayan EDMS** treats documents as collections of pages
+or frames, and text extraction and OCR is done per page not per document,
+thats why even text documents need to be rendered by LibreOffice_
+before they can be previewed and text can be extracted.
+
+
+.. _PDF: http://en.wikipedia.org/wiki/Portable_Document_Format
+.. _LibreOffice: http://www.libreoffice.org/
+.. _unoconv: https://github.com/dagwieers/unoconv/
+.. _supervisor: http://supervisord.org/introduction.html
diff --git a/docs/topics/documentation.rst b/docs/topics/documentation.rst
new file mode 100644
index 0000000000..9c6af6e058
--- /dev/null
+++ b/docs/topics/documentation.rst
@@ -0,0 +1,21 @@
+=============
+Documentation
+=============
+
+**Mayan EDMS**'s documentation is written in `reStructured Text`_ format.
+
+The documentation lives in the ``docs`` directory. In order to build it, you will first need to install Sphinx_. ::
+
+ $ pip install sphinx
+
+
+Then, to build an HTML version of the documentation, simply run the following from the **docs** directory::
+
+ $ make html
+
+Your ``docs/_build/html`` directory will then contain an HTML version of the documentation, ready for publication on most web servers.
+
+You can also generate the documentation in formats other than HTML.
+
+.. _`reStructured Text`: http://docutils.sourceforge.net/rst.html
+.. _Sphinx: http://sphinx.pocoo.org
diff --git a/docs/topics/file_storage.rst b/docs/topics/file_storage.rst
new file mode 100644
index 0000000000..8d980a15cf
--- /dev/null
+++ b/docs/topics/file_storage.rst
@@ -0,0 +1,26 @@
+============
+File storage
+============
+
+The files are stored and placed under **Mayan EDMS** "control" to avoid
+filename clashes (each file gets renamed to its UUID and with an extension)
+and stored in a simple flat arrangement in a directory. This doesn't
+stop access to the files but it is not recommended because moving,
+renaming or updating the files directly would throw the database out
+of sync. For direct access to the files the recommended way is to create an
+:doc:`index `, use the indexing mirroring feature and share the result via
+file serving software [#f1]_.
+
+**Mayan EDMS** components are as decoupled from each other as possible,
+storage in this case is very decoupled and its behavior is controlled
+not by the project but by the Storage progamming class. Why this design?
+All the other part don't make any assumptions about the actual file
+storage, so that **Mayan EDMS** can work saving files locally, over the
+network or even across the internet and still operate exactly the same.
+
+The file storage behavior is controlled by the :setting:`DOCUMENTS_STORAGE_BACKEND`
+and should be set to a class or subclass of Django's ``django.core.files.storage.FileSystemStorage`` class.
+
+.. rubric:: Footnotes
+
+.. [#f1] http://en.wikipedia.org/wiki/File_server
diff --git a/docs/topics/index.rst b/docs/topics/index.rst
new file mode 100644
index 0000000000..b5ca990d6b
--- /dev/null
+++ b/docs/topics/index.rst
@@ -0,0 +1,23 @@
+Using Mayan EDMS
+================
+
+Introductions to all the key parts of Mayan EDMS you'll need to know:
+
+.. toctree::
+ :maxdepth: 1
+
+ file_storage
+ initial_import
+ permissions
+ transformations
+ document_visualization
+ versioning
+ signatures
+ indexes
+ smart_links
+ ocr
+ settings
+ customization
+ development
+ documentation
+ translations
diff --git a/docs/topics/index_instance.png b/docs/topics/index_instance.png
new file mode 100644
index 0000000000..9310c1c013
Binary files /dev/null and b/docs/topics/index_instance.png differ
diff --git a/docs/topics/index_template.png b/docs/topics/index_template.png
new file mode 100644
index 0000000000..6d5596dd89
Binary files /dev/null and b/docs/topics/index_template.png differ
diff --git a/docs/topics/indexes.png b/docs/topics/indexes.png
new file mode 100644
index 0000000000..a1a5c776e6
Binary files /dev/null and b/docs/topics/indexes.png differ
diff --git a/docs/topics/indexes.rst b/docs/topics/indexes.rst
new file mode 100644
index 0000000000..9f818e5876
--- /dev/null
+++ b/docs/topics/indexes.rst
@@ -0,0 +1,59 @@
+=======
+Indexes
+=======
+
+Indexes are an automatic method to hierarchically organize documents in relation to their metadata and to each other.
+
+Index templates
+===============
+
+Since multiple indexes can be defined, the first step is to create an empty index.
+Administrators then define the tree template showing how the index will be structured.
+Each branch can be a pseudo folder, which can hold other child 'folders' or
+a document container which will have all the links to the documents that
+matched the path to reach the document container.
+
+.. image:: index_template.png
+ :alt: index template
+
+Index instances
+===============
+
+The template is the skeleton from which an instance of the index is then
+auto-populated with links to the documents depending on the rules of each
+branch of the index evaluated against the metadata and properties of the documents.
+
+.. image:: index_instance.png
+ :alt: index instance
+
+Index serving
+=============
+
+Indexes can be mirrored to the operating system filesystem
+using the configuration option
+:setting:`DOCUMENT_INDEXING_FILESYSTEM_SERVING`.
+
+``settings_local.py``::
+
+ # Supposing the 'Sample index' internal name is 'sample_index'
+ DOCUMENT_INDEXING_FILESYSTEM_SERVING = {
+ 'sample_index': '/var/local/document/sharing/invoices/',
+ }
+
+This creates an actual directory tree and links to the actual stored files but using
+the filename of the documents as stored in the database.
+
+.. image:: indexes.png
+ :alt: indexes diagram
+
+This filesystem mirror of the index can them be served with Samba_ across the
+network. This access would be read-only, with new versions of the files
+being uploaded from the web GUI using the document versioning support.
+
+The index cannot be edited manually to protect it's integrity, only changing
+the rules or the metadata of the documents would cause the index to be
+regenerated. For manual organization of documents there are the folders,
+their structure is however flat, and they have to be manually updated and
+curated.
+
+.. _Samba: http://www.samba.org/
diff --git a/docs/topics/initial_import.rst b/docs/topics/initial_import.rst
new file mode 100644
index 0000000000..72859f49bf
--- /dev/null
+++ b/docs/topics/initial_import.rst
@@ -0,0 +1,48 @@
+====================
+Initial data loading
+====================
+
+Bulk document import
+--------------------
+
+**Mayan EDMS** has the ability to individually upload the contents of compressed
+files, however by nature of being a web based application it is bounded by the
+limitations of the HTTP protocol, this imposes a limit on the file size and
+the amount of time **Mayan EDMS** may keep a connection open while it processes
+compressed files. When the desired amount of documents is bigger than what
+these limitations allow, **Mayan EDMS** provides a command line tool for out of
+process document importation.
+
+The command line options for this feature are as follows::
+
+ $ ./manage.py bulk_upload --noinput --metadata '{"project": "bulk"}' --document_type "Accounting documents" compressed.zip
+
+**Optional arguments**
+
+* The ``--noinput`` argument skips confirmation and starts the upload immediately.
+* The ``--metadata`` argument allows specifing what metadata will be assigned
+ to the documents when uploaded.
+* And the ``--document_type`` applies a previously defined
+ document type to the uploaded documents.
+
+
+Bulk user import
+----------------
+
+As well as providing bulk document import functionality **Mayan EDMS** also
+includes a management command to import a large number users
+from a CSV file. The command line options for this feature are as
+follow::
+
+ $ ./manage.py import_users --noinput --password=welcome123 --skip-repeated user_list.csv
+
+The CSV field order must be: username, first name, last name and email, any other
+column after those is ignored.
+
+**Optional arguments**
+
+* The ``--noinput`` argument skips confirmation and starts the import immediately.
+* The ``--password`` argument allows specifing what default password will be assigned
+ to all the new users that are imported.
+* The ``--skip-repeated`` tells the importedr to not stop when finding
+ that a user already exists in the database.
diff --git a/docs/topics/mayan-login.png b/docs/topics/mayan-login.png
new file mode 100644
index 0000000000..65673aa303
Binary files /dev/null and b/docs/topics/mayan-login.png differ
diff --git a/docs/topics/no-icons.png b/docs/topics/no-icons.png
new file mode 100644
index 0000000000..d00eec2d62
Binary files /dev/null and b/docs/topics/no-icons.png differ
diff --git a/docs/topics/ocr.rst b/docs/topics/ocr.rst
new file mode 100644
index 0000000000..52c57282ef
--- /dev/null
+++ b/docs/topics/ocr.rst
@@ -0,0 +1,18 @@
+===
+OCR
+===
+
+Because OCR is an intensive operation, documents are queued for OCR for
+later handling, the amount of documents processed in parallel is
+controlled by the :setting:`OCR_NODE_CONCURRENT_EXECUTION` configuration
+option. Ideally the machine serving **Mayan EDMS** should disable OCR
+processing by settings this options to 0, with other machines or cloud
+instances then connected to the same database doing the OCR processing.
+The document is checked to see if there are text parsers available, is
+no parser is available for that file type then the document is passed
+to tesseract page by page and the results stored per page, this is to
+keep the page image in sync with the transcribed text. However when
+viewing the document in the details tab all the pages text are
+concatenated and shown to the user. Setting the :setting:`OCR_AUTOMATIC_OCR`
+option to ``True`` would cause all newly uploaded documents to be
+queued automatically for OCR.
diff --git a/docs/topics/permissions.png b/docs/topics/permissions.png
new file mode 100644
index 0000000000..3c3809f405
Binary files /dev/null and b/docs/topics/permissions.png differ
diff --git a/docs/topics/permissions.rst b/docs/topics/permissions.rst
new file mode 100644
index 0000000000..4948654e85
--- /dev/null
+++ b/docs/topics/permissions.rst
@@ -0,0 +1,46 @@
+===========
+Permissions
+===========
+
+**Mayan EDMS** provides very exact control over what activies users can
+perform. This control is divided into two levels of operation:
+
+2 tier permissions assignement
+==============================
+
+This level of activity control works
+by allowing roles that are composed of users and group, to be granted
+a permission such that the holder of that permission can exercise it
+throught the entire collection of objects (document, folders, tags, etc),
+this method could be thought out as a global permission granting level.
+Example: Roles being granted the ``Document view`` permission will be able to view
+**all** documents in existance.
+
+.. image:: permissions.png
+ :alt: 2-tier permission diagram
+
+
+3 tier access control
+=====================
+
+When more control is desired over which objects
+actors(user, groups and roles) can exercise an action this method should be
+used. Under this level, actors are granted a
+permission but only in relation to a selected object. Example: Granting user
+``Joe`` the ``Document view`` access control for document ``Payroll``,
+would allow him to view this document only.
+
+.. image:: ACL.png
+ :alt: 3-tier access control diagram
+
+The permission system enforces inheritance by first checking if the user
+has a global permission, is a member of a group or a role that has a global
+permission and if not then checks to see if that user, a group or role to
+which he belongs, has been granted access to the specific object to which
+he is desiring to perform a given action that requires a permission.
+Only when these checks fails the user
+is forbidden to perform the action and a generic message indicating this is
+displayed to avoid providing any information that could be used to sidetrack
+the permission system or obtain any kind of information about the object
+from which the user was not allowed access.
+
diff --git a/docs/topics/settings.rst b/docs/topics/settings.rst
new file mode 100644
index 0000000000..ae395a435e
--- /dev/null
+++ b/docs/topics/settings.rst
@@ -0,0 +1,565 @@
+========
+Settings
+========
+
+**Mayan EDMS** has many configuration options that make it very adaptable to
+different server configurations.
+
+Documents
+=========
+
+.. setting:: DOCUMENTS_CHECKSUM_FUNCTION
+
+**DOCUMENTS_CHECKSUM_FUNCTION**
+
+Default: ``hashlib.sha256(x).hexdigest()``
+
+The function that will be used to calculate the hash value of each uploaded document.
+
+
+.. setting:: DOCUMENTS_UUID_FUNCTION
+
+**DOCUMENTS_UUID_FUNCTION**
+
+Default: ``unicode(uuid.uuid4())``
+
+The function that will be used to internally identify each uploaded document.
+
+
+.. setting:: DOCUMENTS_STORAGE_BACKEND
+
+**DOCUMENTS_STORAGE_BACKEND**
+
+Default: ``FileBasedStorage`` class
+
+The storage backend that will be used to store every document.
+
+
+.. setting:: DOCUMENTS_PREVIEW_SIZE
+
+**DOCUMENTS_PREVIEW_SIZE**
+
+Default: ``640x480``
+
+Size of the document list and recent document list previews.
+
+
+.. setting:: DOCUMENTS_PRINT_SIZE
+
+**DOCUMENTS_PRINT_SIZE**
+
+Default: ``1400``
+
+
+.. setting:: DOCUMENTS_MULTIPAGE_PREVIEW_SIZE
+
+**DOCUMENTS_MULTIPAGE_PREVIEW_SIZE**
+
+Default: ``160x120``
+
+
+.. setting:: DOCUMENTS_THUMBNAIL_SIZE
+
+**DOCUMENTS_THUMBNAIL_SIZE**
+
+Default: ``50x50``
+
+
+.. setting:: DOCUMENTS_DISPLAY_SIZE
+
+**DOCUMENTS_DISPLAY_SIZE**
+
+Default: ``1200``
+
+
+.. setting:: DOCUMENTS_RECENT_COUNT
+
+**DOCUMENTS_RECENT_COUNT**
+
+Default: ``40``
+
+Maximum number of recent (created, edited, viewed) documents to
+remember per user.
+
+
+.. setting:: DOCUMENTS_ZOOM_PERCENT_STEP
+
+**DOCUMENTS_ZOOM_PERCENT_STEP**
+
+Default: ``50``
+
+Amount in percent zoom in or out a document page per user interaction.
+
+
+.. setting:: DOCUMENTS_ZOOM_MAX_LEVEL
+
+**DOCUMENTS_ZOOM_MAX_LEVEL**
+
+Default: ``200``
+
+Maximum amount in percent (%) to allow user to zoom in a document page interactively.
+
+
+.. setting:: DOCUMENTS_ZOOM_MIN_LEVEL
+
+**DOCUMENTS_ZOOM_MIN_LEVEL**
+
+Default: ``50``
+
+Minimum amount in percent (%) to allow user to zoom out a document page interactively.
+
+
+.. setting:: DOCUMENTS_ROTATION_STEP
+
+**DOCUMENTS_ROTATION_STEP**
+
+Default: ``90``
+
+Amount in degrees to rotate a document page per user interaction.
+
+
+.. setting:: DOCUMENTS_CACHE_PATH
+
+**DOCUMENTS_CACHE_PATH**
+
+Default: ``image_cache`` (relative to the installation path)
+
+The path where the visual representations of the documents are stored for fast display.
+
+
+Converter
+=========
+.. setting:: CONVERTER_GRAPHICS_BACKEND
+
+**CONVERTER_GRAPHICS_BACKEND**
+
+Default: ``converter.backends.python``
+
+Graphics conversion backend to use. Options are:
+
+* ``converter.backends.imagemagick`` - Wrapper for ImageMagick
+
+ * Use the :setting:`CONVERTER_IM_CONVERT_PATH` and :setting:`CONVERTER_IM_IDENTIFY_PATH` to specify the binary files locations.
+
+* ``converter.backends.graphicsmagick`` - Wrapper for GraphicsMagick
+
+ * Use the :setting:`CONVERTER_GM_PATH` and :setting:`CONVERTER_GM_SETTINGS` to specify the binary file location and customized settings.
+
+* ``converter.backends.python`` - Wrapper for Pillow_ and Ghostscript_
+
+
+.. _Pillow: http://pypi.python.org/pypi/Pillow
+.. _Ghostscript: http://www.ghostscript.com/
+
+
+.. setting:: CONVERTER_IM_CONVERT_PATH
+
+**CONVERTER_IM_CONVERT_PATH**
+
+Default: ``/usr/bin/convert``
+
+File path to imagemagick's convert program.
+
+
+.. setting:: CONVERTER_IM_IDENTIFY_PATH
+
+**CONVERTER_IM_IDENTIFY_PATH**
+
+Default: ``/usr/bin/identify``
+
+File path to imagemagick's identify program.
+
+
+.. setting:: CONVERTER_GM_PATH
+
+**CONVERTER_GM_PATH**
+
+Default: ``/usr/bin/gm``
+
+File path to graphicsmagick's program.
+
+
+.. setting:: CONVERTER_GM_SETTINGS
+
+**CONVERTER_GM_SETTINGS**
+
+Default: None
+
+Suggested options: ``-limit files 1 -limit memory 1GB -limit map 2GB -density 200``
+
+Set of configuration options to pass to the GraphicsMagick executable to
+fine tune it's functionality as explained in the `GraphicsMagick documentation`_
+
+.. _GraphicsMagick documentation: http://www.graphicsmagick.org/convert.html#conv-opti
+
+
+.. setting:: CONVERTER_UNOCONV_PATH
+
+
+**CONVERTER_UNOCONV_PATH**
+
+Default: ``/usr/bin/unoconv``
+
+Path to the unoconv program used to call LibreOffice for office document convertion.
+
+
+.. setting:: CONVERTER_UNOCONV_USE_PIPE
+
+
+**CONVERTER_UNOCONV_USE_PIPE**
+
+Default: ``True``
+
+Use alternate method of connection to LibreOffice using a pipe, it is slower but less prone to segmentation faults.
+
+
+Linking
+=======
+
+.. setting:: LINKING_SHOW_EMPTY_SMART_LINKS
+
+**LINKING_SHOW_EMPTY_SMART_LINKS**
+
+Default: ``True``
+
+Show smart links even when they don't return any documents.
+
+
+Storage
+=======
+
+.. setting:: STORAGE_GRIDFS_HOST
+
+**STORAGE_GRIDFS_HOST**
+
+Default: ``localhost``
+
+
+.. setting:: STORAGE_GRIDFS_PORT
+
+**STORAGE_GRIDFS_PORT**
+
+Default: ``27017``
+
+
+.. setting:: STORAGE_GRIDFS_DATABASE_NAME
+
+**STORAGE_GRIDFS_DATABASE_NAME**
+
+Default: ``document_storage``
+
+
+.. setting:: STORAGE_FILESTORAGE_LOCATION
+
+**STORAGE_FILESTORAGE_LOCATION**
+
+Default: ``document_storage``
+
+
+Document indexing
+=================
+
+.. setting:: DOCUMENT_INDEXING_AVAILABLE_INDEXING_FUNCTIONS
+
+**DOCUMENT_INDEXING_AVAILABLE_INDEXING_FUNCTIONS**
+
+Default: ``proper_name``
+
+
+.. setting:: DOCUMENT_INDEXING_SUFFIX_SEPARATOR
+
+**DOCUMENT_INDEXING_SUFFIX_SEPARATOR**
+
+Default: ``_`` (underscore)
+
+
+.. setting:: DOCUMENT_INDEXING_FILESYSTEM_SLUGIFY_PATHS
+
+**DOCUMENT_INDEXING_FILESYSTEM_SLUGIFY_PATHS**
+
+Default: ``False``
+
+
+.. setting:: DOCUMENT_INDEXING_FILESYSTEM_MAX_SUFFIX_COUNT
+
+**DOCUMENT_INDEXING_FILESYSTEM_MAX_SUFFIX_COUNT**
+
+Default: ``1000``
+
+
+.. setting:: DOCUMENT_INDEXING_FILESYSTEM_SERVING
+
+**DOCUMENT_INDEXING_FILESYSTEM_SERVING**
+
+Default: ``{}``
+
+A dictionary that maps the index name and where on the filesystem that index will be mirrored.
+
+
+OCR
+===
+
+.. setting:: OCR_TESSERACT_PATH
+
+**OCR_TESSERACT_PATH**
+
+Default: ``/bin/tesseract``
+
+File path to the ``tesseract`` executable, used to perform OCR on document
+page's images.
+
+
+.. setting:: OCR_TESSERACT_LANGUAGE
+
+**OCR_TESSERACT_LANGUAGE**
+
+Default: ``eng``
+
+Language code passed to the ``tesseract`` executable.
+
+
+.. setting:: OCR_REPLICATION_DELAY
+
+**OCR_REPLICATION_DELAY**
+
+Default: ``0``
+
+Amount of seconds to delay OCR of documents to allow for the node's
+storage replication overhead.
+
+
+.. setting:: OCR_NODE_CONCURRENT_EXECUTION
+
+**OCR_NODE_CONCURRENT_EXECUTION**
+
+Default: ``1``
+
+Maximum amount of concurrent document OCRs a node can perform.
+
+
+.. setting:: OCR_AUTOMATIC_OCR
+
+**OCR_AUTOMATIC_OCR**
+
+Default: ``False``
+
+Automatically queue newly created documents or newly uploaded versions
+of existing documents for OCR.
+
+
+.. setting:: OCR_QUEUE_PROCESSING_INTERVAL
+
+**OCR_QUEUE_PROCESSING_INTERVAL**
+
+Default: ``10``
+
+
+.. setting:: OCR_UNPAPER_PATH
+
+**OCR_UNPAPER_PATH**
+
+Default: ``/usr/bin/unpaper``
+
+File path to the ``unpaper`` executable, used to clean up images before
+doing OCR.
+
+
+Metadata
+========
+
+.. setting:: METADATA_AVAILABLE_FUNCTIONS
+
+**METADATA_AVAILABLE_FUNCTIONS**
+
+Default: ``current_date``
+
+
+.. setting:: METADATA_AVAILABLE_MODELS
+
+**METADATA_AVAILABLE_MODELS**
+
+Default: ``User``
+
+
+Common
+======
+
+.. setting:: COMMON_TEMPORARY_DIRECTORY
+
+**COMMON_TEMPORARY_DIRECTORY**
+
+Default: ``/tmp``
+
+Temporary directory used site wide to store thumbnails, previews
+and temporary files. If none is specified, one will be created
+using tempfile.mkdtemp()
+
+
+.. setting:: COMMON_DEFAULT_PAPER_SIZE
+
+**COMMON_DEFAULT_PAPER_SIZE**
+
+Default: ``Letter``
+
+
+.. setting:: COMMON_DEFAULT_PAGE_ORIENTATION
+
+**COMMON_DEFAULT_PAGE_ORIENTATION**
+
+Default: ``Portrait``
+
+
+.. setting:: COMMON_AUTO_CREATE_ADMIN
+
+**COMMON_AUTO_CREATE_ADMIN**
+
+Default: ``True``
+
+Automatically creates an administrator superuser with the username
+specified by COMMON_AUTO_ADMIN_USERNAME and with the default password
+specified by COMMON_AUTO_ADMIN_PASSWORD
+
+
+.. setting:: COMMON_AUTO_ADMIN_USERNAME
+
+**COMMON_AUTO_ADMIN_USERNAME**
+
+Default: ``admin``
+
+Username of the automatically created superuser
+
+
+.. setting:: COMMON_AUTO_ADMIN_PASSWORD
+
+**COMMON_AUTO_ADMIN_PASSWORD**
+
+Default: ``admin``
+
+Default password of the automatically created superuser
+
+
+.. setting:: COMMON_LOGIN_METHOD
+
+**COMMON_LOGIN_METHOD**
+
+Default: ``username``
+
+Controls the mechanism used to authenticated user. Options are: ``username``, ``email``
+If using the ``email`` login method a proper email authentication backend must used
+such as AUTHENTICATION_BACKENDS = ('common.auth.email_auth_backend.EmailAuthBackend',)
+
+
+.. setting:: COMMON_ALLOW_ANONYMOUS_ACCESS
+
+**COMMON_ALLOW_ANONYMOUS_ACCESS**
+
+Default: ``False``
+
+Allow non authenticated users, access to all views.
+
+
+Search
+======
+
+.. setting:: SEARCH_LIMIT
+
+**SEARCH_LIMIT**
+
+Default: ``100``
+
+Maximum amount search hits to fetch and display.
+
+
+.. setting:: SEARCH_RECENT_COUNT
+
+**SEARCH_RECENT_COUNT**
+
+Default: ``5``
+
+Maximum number of search queries to remember per user.
+
+
+Web theme
+=========
+
+.. setting:: WEB_THEME_THEME
+
+**WEB_THEME_THEME**
+
+Default: ``activo``
+
+CSS theme to apply, options are: ``amro``, ``bec``, ``bec-green``, ``blue``,
+``default``, ``djime-cerulean``, ``drastic-dark``, ``kathleene``, ``olive``,
+``orange``, ``red``, ``reidb-greenish`` and ``warehouse``.
+
+
+.. setting:: WEB_THEME_VERBOSE_LOGIN
+
+**WEB_THEME_VERBOSE_LOGIN**
+
+Default: ``True``
+
+Display extra information in the login screen.
+
+
+Main
+====
+
+.. setting:: MAIN_SIDE_BAR_SEARCH
+
+**MAIN_SIDE_BAR_SEARCH**
+
+Default: ``False``
+
+Controls whether the search functionality is provided by a sidebar widget or by a menu entry.
+
+
+.. setting:: MAIN_DISABLE_HOME_VIEW
+
+**MAIN_DISABLE_HOME_VIEW**
+
+Default: ``False``
+
+Disable the home view and redirect users straight to the recent document list as soon as they log in.
+
+
+.. setting:: MAIN_DISABLE_ICONS
+
+**MAIN_DISABLE_ICONS**
+
+Default: ``False``
+
+Turns off navigation links' icons.
+
+
+User management
+===============
+
+.. setting:: ROLES_DEFAULT_ROLES
+
+**ROLES_DEFAULT_ROLES**
+
+Default: ``[]``
+
+A list of existing roles that are automatically assigned to newly created users
+
+
+Signatures
+==========
+
+.. setting:: SIGNATURES_KEYSERVERS
+
+**SIGNATURES_KEYSERVERS**
+
+Default: ``['pool.sks-keyservers.net']``
+
+List of keyservers to be queried for unknown keys.
+
+
+.. setting:: SIGNATURES_GPG_HOME
+
+**SIGNATURES_GPG_HOME**
+
+Default: ``gpg_home``
+
+Home directory used to store keys as well as configuration files.
diff --git a/docs/topics/signatures.rst b/docs/topics/signatures.rst
new file mode 100644
index 0000000000..f2cad89fc2
--- /dev/null
+++ b/docs/topics/signatures.rst
@@ -0,0 +1,24 @@
+===================
+Document signatures
+===================
+
+**Mayan EDMS** supports two types of document signatures, these are embedded and
+detached signatures. When a document with an embedded signature is
+uploaded, this signature is readily detected as part of the document
+inspection step. If the public key corresponding to the signee of the
+document is not found, **Mayan EDMS** will try to obtain it from the list of
+keyserver specified in the config option :setting:`SIGNATURES_KEYSERVERS`.
+Failing that, **Mayan EDMS** will indicate that the document is signed
+but that it has no way to verify such signature.
+Existing non signed documents can be signed in one of two way:
+by downloading the document, signing it, and uploading the signed document
+as a new version of the existing one using **Mayan EDMS** :doc:`versioning support `
+or by creating a detached signature for the non signed document and uploading
+such detached signature file using the option likewise named menu option.
+
+Maintenance of the public keyring can be done using the ``Key management``
+functionality in the ``Setup menu``
+
+From this menu, key servers can be queried
+and the results imported. Public keys no longer needed can also be deleted
+from this menu.
diff --git a/docs/topics/smart_links.rst b/docs/topics/smart_links.rst
new file mode 100644
index 0000000000..07db50a9d0
--- /dev/null
+++ b/docs/topics/smart_links.rst
@@ -0,0 +1,9 @@
+===========
+Smart links
+===========
+
+Smart links are usefull for navigation between documents. They are rule
+based but don't created any organizational structure just show the documents
+that match the rules as evaluated against the metadata of the currently
+displayed document. The index is global, the smart links are dependant
+on the current document the user is viewing.
diff --git a/docs/technical.rst b/docs/topics/technical.rst
similarity index 100%
rename from docs/technical.rst
rename to docs/topics/technical.rst
diff --git a/docs/topics/themes.png b/docs/topics/themes.png
new file mode 100644
index 0000000000..47ef20d00d
Binary files /dev/null and b/docs/topics/themes.png differ
diff --git a/docs/topics/transformations.rst b/docs/topics/transformations.rst
new file mode 100644
index 0000000000..7584b69698
--- /dev/null
+++ b/docs/topics/transformations.rst
@@ -0,0 +1,12 @@
+=========================
+What are transformations?
+=========================
+
+Transformation are useful to manipulate the preview of the stored documents
+in a persistent manner, for example some scanning equipment only produce
+landscape PDFs, in this case a default transformation for that document
+source would be "rotation: 270 degress", this way whenever a document is
+uploaded from that scanner it appears in portrait orientation.
+The transformation remains attached to the document, this way the file
+is preserved in it's original state (a requirement in legal environments)
+but only the representation is transformed to make it look right to the user.
diff --git a/docs/topics/translations.rst b/docs/topics/translations.rst
new file mode 100644
index 0000000000..65910f7025
--- /dev/null
+++ b/docs/topics/translations.rst
@@ -0,0 +1,8 @@
+============
+Translations
+============
+
+Translations are now being handled online via the **Transifex** website: https://www.transifex.net/projects/p/mayan-edms/.
+To create a translation team for a new language or contribute to an already
+existing language translation, create a **Transifex** account and contact
+the team coordinator of the respective language in which you are interested.
diff --git a/docs/topics/versioning.png b/docs/topics/versioning.png
new file mode 100644
index 0000000000..6ec2f24d86
Binary files /dev/null and b/docs/topics/versioning.png differ
diff --git a/docs/topics/versioning.rst b/docs/topics/versioning.rst
new file mode 100644
index 0000000000..5aa6dedee9
--- /dev/null
+++ b/docs/topics/versioning.rst
@@ -0,0 +1,25 @@
+===================
+Document versioning
+===================
+
+**Mayan EDMS** has the ability to store different versions of the same
+document. Users are provided with a very comprehensive but easy to use
+version numbering system that allows specifying a major, minor or micro
+version number increase.
+
+.. image:: versioning.png
+ :alt: versioning diagram
+
+A comment field is also provided to allow users
+to summarize the new verdion changes in comparison with the previous
+one. If a new version was uploded by mistake or such new version is no
+longer necessary **Mayan EDMS** provides the option to revert to a previous
+version of the document.
+
+To upload a new document version, select an existing document, click on the
+version tab of the document, and click on the 'upload new version' on the
+side bar. A new view very similar to the new document upload view will
+appear show the same interactive document sources that have been defined,
+but with new options to specify the new version number and an optional
+comment.
+
diff --git a/docs/updates.rst b/docs/updates.rst
deleted file mode 100644
index 09112c0c52..0000000000
--- a/docs/updates.rst
+++ /dev/null
@@ -1,5 +0,0 @@
-=========
-Changelog
-=========
-
-.. include:: changelog.rst
diff --git a/locale/es/LC_MESSAGES/django.mo b/locale/es/LC_MESSAGES/django.mo
deleted file mode 100644
index f3e6b3187d..0000000000
Binary files a/locale/es/LC_MESSAGES/django.mo and /dev/null differ
diff --git a/locale/es/LC_MESSAGES/django.po b/locale/es/LC_MESSAGES/django.po
deleted file mode 100644
index f10a098074..0000000000
--- a/locale/es/LC_MESSAGES/django.po
+++ /dev/null
@@ -1,28 +0,0 @@
-# SOME DESCRIPTIVE TITLE.
-# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
-# This file is distributed under the same license as the PACKAGE package.
-# FIRST AUTHOR , YEAR.
-#
-#, fuzzy
-msgid ""
-msgstr ""
-"Project-Id-Version: PACKAGE VERSION\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-03-05 20:26-0400\n"
-"PO-Revision-Date: 2011-03-05 20:46\n"
-"Last-Translator: Roberto Rosario \n"
-"Language-Team: LANGUAGE \n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Language: \n"
-"X-Translated-Using: django-rosetta 0.5.6\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-
-#: settings.py:52
-msgid "Spanish"
-msgstr "Español"
-
-#: settings.py:53
-msgid "English"
-msgstr "Inglés"
diff --git a/misc/compilemessages_all.sh b/misc/compilemessages_all.sh
index 5e3c5cf2a7..2b446850d5 100755
--- a/misc/compilemessages_all.sh
+++ b/misc/compilemessages_all.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-COMPILEMESSAGES="django-admin compilemessages"
+COMPILEMESSAGES="django-admin.py compilemessages"
PWD=`pwd`
BASE=$PWD
@@ -7,108 +7,173 @@ cd $BASE/apps/common
$COMPILEMESSAGES -l pt
$COMPILEMESSAGES -l ru
$COMPILEMESSAGES -l es
+$COMPILEMESSAGES -l it
+$COMPILEMESSAGES -l pl
cd $BASE/apps/converter
$COMPILEMESSAGES -l pt
$COMPILEMESSAGES -l ru
$COMPILEMESSAGES -l es
+$COMPILEMESSAGES -l it
+$COMPILEMESSAGES -l pl
cd $BASE/apps/documents
$COMPILEMESSAGES -l pt
$COMPILEMESSAGES -l ru
$COMPILEMESSAGES -l es
+$COMPILEMESSAGES -l it
+$COMPILEMESSAGES -l pl
cd $BASE/apps/document_comments
$COMPILEMESSAGES -l pt
$COMPILEMESSAGES -l ru
$COMPILEMESSAGES -l es
+$COMPILEMESSAGES -l it
+$COMPILEMESSAGES -l pl
cd $BASE/apps/document_indexing
$COMPILEMESSAGES -l pt
$COMPILEMESSAGES -l ru
$COMPILEMESSAGES -l es
+$COMPILEMESSAGES -l it
+$COMPILEMESSAGES -l pl
cd $BASE/apps/dynamic_search
$COMPILEMESSAGES -l pt
$COMPILEMESSAGES -l ru
$COMPILEMESSAGES -l es
+$COMPILEMESSAGES -l it
+$COMPILEMESSAGES -l pl
cd $BASE/apps/folders
$COMPILEMESSAGES -l pt
$COMPILEMESSAGES -l ru
$COMPILEMESSAGES -l es
+$COMPILEMESSAGES -l it
+$COMPILEMESSAGES -l pl
cd $BASE/apps/history
$COMPILEMESSAGES -l pt
$COMPILEMESSAGES -l ru
$COMPILEMESSAGES -l es
+$COMPILEMESSAGES -l it
+$COMPILEMESSAGES -l pl
cd $BASE/apps/linking
$COMPILEMESSAGES -l pt
$COMPILEMESSAGES -l ru
$COMPILEMESSAGES -l es
+$COMPILEMESSAGES -l it
+$COMPILEMESSAGES -l pl
cd $BASE/apps/main
$COMPILEMESSAGES -l pt
$COMPILEMESSAGES -l ru
$COMPILEMESSAGES -l es
+$COMPILEMESSAGES -l it
+$COMPILEMESSAGES -l pl
cd $BASE/apps/metadata
$COMPILEMESSAGES -l pt
$COMPILEMESSAGES -l ru
$COMPILEMESSAGES -l es
+$COMPILEMESSAGES -l it
+$COMPILEMESSAGES -l pl
cd $BASE/apps/navigation
$COMPILEMESSAGES -l pt
$COMPILEMESSAGES -l ru
$COMPILEMESSAGES -l es
+$COMPILEMESSAGES -l it
+$COMPILEMESSAGES -l pl
cd $BASE/apps/ocr
$COMPILEMESSAGES -l pt
$COMPILEMESSAGES -l ru
$COMPILEMESSAGES -l es
+$COMPILEMESSAGES -l it
+$COMPILEMESSAGES -l pl
cd $BASE/apps/permissions
$COMPILEMESSAGES -l pt
$COMPILEMESSAGES -l ru
$COMPILEMESSAGES -l es
+$COMPILEMESSAGES -l it
+$COMPILEMESSAGES -l pl
cd $BASE/apps/project_setup
$COMPILEMESSAGES -l pt
$COMPILEMESSAGES -l ru
$COMPILEMESSAGES -l es
+$COMPILEMESSAGES -l it
+$COMPILEMESSAGES -l pl
cd $BASE/apps/project_tools
$COMPILEMESSAGES -l pt
$COMPILEMESSAGES -l ru
$COMPILEMESSAGES -l es
+$COMPILEMESSAGES -l it
+$COMPILEMESSAGES -l pl
cd $BASE/apps/smart_settings
$COMPILEMESSAGES -l pt
$COMPILEMESSAGES -l ru
$COMPILEMESSAGES -l es
+$COMPILEMESSAGES -l it
+$COMPILEMESSAGES -l pl
cd $BASE/apps/sources
$COMPILEMESSAGES -l pt
$COMPILEMESSAGES -l ru
$COMPILEMESSAGES -l es
+$COMPILEMESSAGES -l it
+$COMPILEMESSAGES -l pl
cd $BASE/apps/tags
$COMPILEMESSAGES -l pt
$COMPILEMESSAGES -l ru
$COMPILEMESSAGES -l es
+$COMPILEMESSAGES -l it
+$COMPILEMESSAGES -l pl
cd $BASE/apps/user_management
$COMPILEMESSAGES -l pt
$COMPILEMESSAGES -l ru
$COMPILEMESSAGES -l es
+$COMPILEMESSAGES -l it
+$COMPILEMESSAGES -l pl
cd $BASE/apps/web_theme
$COMPILEMESSAGES -l pt
$COMPILEMESSAGES -l ru
$COMPILEMESSAGES -l es
+$COMPILEMESSAGES -l it
+$COMPILEMESSAGES -l pl
cd $BASE/apps/django_gpg
$COMPILEMESSAGES -l pt
$COMPILEMESSAGES -l ru
$COMPILEMESSAGES -l es
+$COMPILEMESSAGES -l it
+$COMPILEMESSAGES -l pl
+
+cd $BASE/apps/document_signatures
+$COMPILEMESSAGES -l pt
+$COMPILEMESSAGES -l ru
+$COMPILEMESSAGES -l es
+$COMPILEMESSAGES -l it
+$COMPILEMESSAGES -l pl
+
+cd $BASE/apps/acls
+$COMPILEMESSAGES -l pt
+$COMPILEMESSAGES -l ru
+$COMPILEMESSAGES -l es
+$COMPILEMESSAGES -l it
+$COMPILEMESSAGES -l pl
+
+cd $BASE/apps/feedback
+$COMPILEMESSAGES -l pt
+$COMPILEMESSAGES -l ru
+$COMPILEMESSAGES -l es
+$COMPILEMESSAGES -l it
+$COMPILEMESSAGES -l pl
diff --git a/misc/makemessages_all.sh b/misc/makemessages_all.sh
index d1e0fcd79e..96e45e6064 100755
--- a/misc/makemessages_all.sh
+++ b/misc/makemessages_all.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-MAKEMESSAGES="django-admin makemessages"
+MAKEMESSAGES="django-admin.py makemessages"
PWD=`pwd`
BASE=$PWD
@@ -8,129 +8,197 @@ $MAKEMESSAGES -l en
$MAKEMESSAGES -l pt
$MAKEMESSAGES -l ru
$MAKEMESSAGES -l es
+$MAKEMESSAGES -l it
+$MAKEMESSAGES -l pl
cd $BASE/apps/converter
$MAKEMESSAGES -l en
$MAKEMESSAGES -l pt
$MAKEMESSAGES -l ru
$MAKEMESSAGES -l es
+$MAKEMESSAGES -l it
+$MAKEMESSAGES -l pl
cd $BASE/apps/documents
$MAKEMESSAGES -l en
$MAKEMESSAGES -l pt
$MAKEMESSAGES -l ru
$MAKEMESSAGES -l es
+$MAKEMESSAGES -l it
+$MAKEMESSAGES -l pl
cd $BASE/apps/document_comments
$MAKEMESSAGES -l en
$MAKEMESSAGES -l pt
$MAKEMESSAGES -l ru
$MAKEMESSAGES -l es
+$MAKEMESSAGES -l it
+$MAKEMESSAGES -l pl
cd $BASE/apps/document_indexing
$MAKEMESSAGES -l en
$MAKEMESSAGES -l pt
$MAKEMESSAGES -l ru
$MAKEMESSAGES -l es
+$MAKEMESSAGES -l it
+$MAKEMESSAGES -l pl
cd $BASE/apps/dynamic_search
$MAKEMESSAGES -l en
$MAKEMESSAGES -l pt
$MAKEMESSAGES -l ru
$MAKEMESSAGES -l es
+$MAKEMESSAGES -l it
+$MAKEMESSAGES -l pl
cd $BASE/apps/folders
$MAKEMESSAGES -l en
$MAKEMESSAGES -l pt
$MAKEMESSAGES -l ru
$MAKEMESSAGES -l es
+$MAKEMESSAGES -l it
+$MAKEMESSAGES -l pl
cd $BASE/apps/history
$MAKEMESSAGES -l en
$MAKEMESSAGES -l pt
$MAKEMESSAGES -l ru
$MAKEMESSAGES -l es
+$MAKEMESSAGES -l it
+$MAKEMESSAGES -l pl
cd $BASE/apps/linking
$MAKEMESSAGES -l en
$MAKEMESSAGES -l pt
$MAKEMESSAGES -l ru
$MAKEMESSAGES -l es
+$MAKEMESSAGES -l it
+$MAKEMESSAGES -l pl
cd $BASE/apps/main
$MAKEMESSAGES -l en
$MAKEMESSAGES -l pt
$MAKEMESSAGES -l ru
$MAKEMESSAGES -l es
+$MAKEMESSAGES -l it
+$MAKEMESSAGES -l pl
cd $BASE/apps/metadata
$MAKEMESSAGES -l en
$MAKEMESSAGES -l pt
$MAKEMESSAGES -l ru
$MAKEMESSAGES -l es
+$MAKEMESSAGES -l it
+$MAKEMESSAGES -l pl
cd $BASE/apps/navigation
$MAKEMESSAGES -l en
$MAKEMESSAGES -l pt
$MAKEMESSAGES -l ru
$MAKEMESSAGES -l es
+$MAKEMESSAGES -l it
+$MAKEMESSAGES -l pl
cd $BASE/apps/ocr
$MAKEMESSAGES -l en
$MAKEMESSAGES -l pt
$MAKEMESSAGES -l ru
$MAKEMESSAGES -l es
+$MAKEMESSAGES -l it
+$MAKEMESSAGES -l pl
cd $BASE/apps/permissions
$MAKEMESSAGES -l en
$MAKEMESSAGES -l pt
$MAKEMESSAGES -l ru
$MAKEMESSAGES -l es
+$MAKEMESSAGES -l it
+$MAKEMESSAGES -l pl
cd $BASE/apps/project_setup
$MAKEMESSAGES -l en
$MAKEMESSAGES -l pt
$MAKEMESSAGES -l ru
$MAKEMESSAGES -l es
+$MAKEMESSAGES -l it
+$MAKEMESSAGES -l pl
cd $BASE/apps/project_tools
$MAKEMESSAGES -l en
$MAKEMESSAGES -l pt
$MAKEMESSAGES -l ru
$MAKEMESSAGES -l es
+$MAKEMESSAGES -l it
+$MAKEMESSAGES -l pl
cd $BASE/apps/smart_settings
$MAKEMESSAGES -l en
$MAKEMESSAGES -l pt
$MAKEMESSAGES -l ru
$MAKEMESSAGES -l es
+$MAKEMESSAGES -l it
+$MAKEMESSAGES -l pl
cd $BASE/apps/sources
$MAKEMESSAGES -l en
$MAKEMESSAGES -l pt
$MAKEMESSAGES -l ru
$MAKEMESSAGES -l es
+$MAKEMESSAGES -l it
+$MAKEMESSAGES -l pl
cd $BASE/apps/tags
$MAKEMESSAGES -l en
$MAKEMESSAGES -l pt
$MAKEMESSAGES -l ru
$MAKEMESSAGES -l es
+$MAKEMESSAGES -l it
+$MAKEMESSAGES -l pl
cd $BASE/apps/user_management
$MAKEMESSAGES -l en
$MAKEMESSAGES -l pt
$MAKEMESSAGES -l ru
$MAKEMESSAGES -l es
+$MAKEMESSAGES -l it
+$MAKEMESSAGES -l pl
cd $BASE/apps/web_theme
$MAKEMESSAGES -l en
$MAKEMESSAGES -l pt
$MAKEMESSAGES -l ru
$MAKEMESSAGES -l es
+$MAKEMESSAGES -l it
+$MAKEMESSAGES -l pl
cd $BASE/apps/django_gpg
$MAKEMESSAGES -l en
$MAKEMESSAGES -l pt
$MAKEMESSAGES -l ru
$MAKEMESSAGES -l es
+$MAKEMESSAGES -l it
+$MAKEMESSAGES -l pl
+
+cd $BASE/apps/document_signatures
+$MAKEMESSAGES -l en
+$MAKEMESSAGES -l pt
+$MAKEMESSAGES -l ru
+$MAKEMESSAGES -l es
+$MAKEMESSAGES -l it
+$MAKEMESSAGES -l pl
+
+cd $BASE/apps/acls
+$MAKEMESSAGES -l en
+$MAKEMESSAGES -l pt
+$MAKEMESSAGES -l ru
+$MAKEMESSAGES -l es
+$MAKEMESSAGES -l it
+$MAKEMESSAGES -l pl
+
+cd $BASE/apps/feedback
+$MAKEMESSAGES -l en
+$MAKEMESSAGES -l pt
+$MAKEMESSAGES -l ru
+$MAKEMESSAGES -l es
+$MAKEMESSAGES -l it
+$MAKEMESSAGES -l pl
diff --git a/misc/mayan.geany b/misc/mayan.geany
deleted file mode 100644
index fa2d7fac31..0000000000
--- a/misc/mayan.geany
+++ /dev/null
@@ -1,41 +0,0 @@
-
-[indentation]
-indent_width=4
-indent_type=0
-indent_hard_tab_width=8
-detect_indent=false
-indent_mode=2
-
-[project]
-name=mayan
-base_path=/home/rosarior/development/mayan/mayan/misc
-description=
-
-[long line marker]
-long_line_behaviour=1
-long_line_column=72
-
-[files]
-current_page=21
-FILE_NAME_0=275;Python;0;16;0;1;0;/home/rosarior/development/mayan/mayan/apps/main/__init__.py;0
-FILE_NAME_1=3931;Python;0;16;0;1;0;/home/rosarior/development/mayan/mayan/apps/documents/__init__.py;0
-FILE_NAME_2=1132;Python;0;16;0;1;0;/home/rosarior/development/mayan/mayan/apps/documents/urls.py;0
-FILE_NAME_3=0;Python;0;16;0;1;0;/home/rosarior/development/mayan/mayan/apps/documents/staging.py;0
-FILE_NAME_4=9731;Python;0;16;0;1;0;/home/rosarior/development/mayan/mayan/apps/documents/views.py;0
-FILE_NAME_5=4010;Python;0;16;0;1;0;/home/rosarior/development/mayan/mayan/apps/converter/api.py;0
-FILE_NAME_6=2005;Python;0;16;0;1;0;/home/rosarior/development/mayan/mayan/apps/documents/conf/settings.py;0
-FILE_NAME_7=541;Python;0;16;0;1;0;/home/rosarior/development/mayan/mayan/apps/converter/conf/settings.py;0
-FILE_NAME_8=1428;Python;0;16;0;1;0;/home/rosarior/development/mayan/mayan/apps/ocr/tasks.py;0
-FILE_NAME_9=3262;Python;0;16;0;1;0;/home/rosarior/development/mayan/mayan/apps/documents/models.py;0
-FILE_NAME_10=2574;Python;0;16;0;1;0;/home/rosarior/development/mayan/mayan/apps/dynamic_search/views.py;0
-FILE_NAME_11=5970;None;0;16;0;1;0;/home/rosarior/development/mayan/mayan/docs/TODO;0
-FILE_NAME_12=679;Markdown;0;16;0;1;0;/home/rosarior/development/mayan/mayan/README.md;0
-FILE_NAME_13=3347;Python;0;16;0;1;0;/home/rosarior/development/mayan/mayan/settings.py;0
-FILE_NAME_14=0;Python;0;16;0;1;0;/home/rosarior/development/mayan/mayan/apps/filesystem_serving/models.py;0
-FILE_NAME_15=2206;Python;0;16;0;1;0;/home/rosarior/development/mayan/mayan/apps/filesystem_serving/api.py;0
-FILE_NAME_16=0;Python;0;16;0;1;0;/home/rosarior/development/mayan/mayan/apps/ocr/views.py;0
-FILE_NAME_17=123;Python;0;16;0;1;0;/home/rosarior/development/mayan/mayan/apps/ocr/api.py;0
-FILE_NAME_18=7270;Python;0;16;0;1;0;/home/rosarior/development/mayan/mayan/apps/permissions/views.py;0
-FILE_NAME_19=3613;HTML;0;16;0;1;0;/home/rosarior/development/mayan/mayan/apps/web_theme/templates/web_theme_base.html;0
-FILE_NAME_20=1800;HTML;0;16;0;1;0;/home/rosarior/development/mayan/mayan/apps/main/templates/base.html;0
-FILE_NAME_21=1588;HTML;0;16;0;1;0;/home/rosarior/development/mayan/mayan/apps/documents/templates/document_upload.html;0
diff --git a/requirements/development.txt b/requirements/development.txt
index 67436315af..427ff2cf00 100644
--- a/requirements/development.txt
+++ b/requirements/development.txt
@@ -1,24 +1,4 @@
-Django==1.3.1
Werkzeug==0.6.2
-django-extensions==0.6
-django-pagination==1.0.7
+django-extensions==0.7.1
django-rosetta==0.6.2
-wsgiref==0.1.2
-celery==2.2.2
-django-celery==2.2.2
-django-sentry==1.6.0
-django-taggit==0.9.3
--e git://github.com/django-mptt/django-mptt.git@0af02a95877041b2fd6d458bd95413dc1666c321#egg=django-mptt
--e git://github.com/ahupp/python-magic.git@a75cf0a4a7790eb106155c947af9612f15693b6e#egg=python-magic
-slate==0.3
-ghostscript==0.4.1
-pdfminer==20110227
-APScheduler==2.0.2
-Pillow==1.7.4
-cssmin==0.1.4
-django-compressor==1.1.1
--e git://github.com/rosarior/django-sendfile.git#egg=django-sendfile
-djangorestframework==0.2.3
-South==0.7.3
-python-gnupg==0.2.8
-python-hkp==0.1.3
+transifex-client==0.6.1
diff --git a/requirements/production.txt b/requirements/production.txt
index c6c3feac05..41ab10ed77 100644
--- a/requirements/production.txt
+++ b/requirements/production.txt
@@ -1,9 +1,6 @@
Django==1.3.1
django-pagination==1.0.7
wsgiref==0.1.2
-celery==2.2.2
-django-celery==2.2.2
-django-sentry==1.6.0
django-taggit==0.9.3
-e git://github.com/django-mptt/django-mptt.git@0af02a95877041b2fd6d458bd95413dc1666c321#egg=django-mptt
-e git://github.com/ahupp/python-magic.git@a75cf0a4a7790eb106155c947af9612f15693b6e#egg=python-magic
@@ -19,4 +16,4 @@ djangorestframework==0.2.3
South==0.7.3
python-gnupg==0.2.8
python-hkp==0.1.3
-kombu==1.4.2
+requests==0.10.1
diff --git a/runserver_plus.sh b/runserver_plus.sh
index 0dda6d19db..5fbf555024 100755
--- a/runserver_plus.sh
+++ b/runserver_plus.sh
@@ -1,6 +1,6 @@
#!/bin/sh
if [ -n "$1" ]; then
- ./manage.py runserver_plus $1 --adminmedia ./static/grappelli/
+ ./manage.py runserver_plus $1 --adminmedia ./static/admin/
else
- ./manage.py runserver_plus --adminmedia ./static/grappelli/
+ ./manage.py runserver_plus --adminmedia ./static/admin/
fi
diff --git a/settings.py b/settings.py
index bd59969f15..a0da8da709 100644
--- a/settings.py
+++ b/settings.py
@@ -18,7 +18,6 @@ DEVELOPMENT = False
TEMPLATE_DEBUG = False
ADMINS = ()
-SENTRY_ADMINS = ('root@localhost',)
MANAGERS = ADMINS
DATABASES = {
@@ -53,6 +52,8 @@ LANGUAGES = (
('es', ugettext('Spanish')),
('pt', ugettext('Portuguese')),
('ru', ugettext('Russian')),
+ ('it', ugettext('Italian')),
+ ('pl', ugettext('Polish')),
)
SITE_ID = 1
@@ -117,6 +118,7 @@ TEMPLATE_DIRS = (
)
INSTALLED_APPS = (
+#Django
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
@@ -126,56 +128,62 @@ INSTALLED_APPS = (
'django.contrib.admindocs',
'django.contrib.comments',
'django.contrib.staticfiles',
+# 3rd party
+# South
+ 'south',
+# Others
+ 'filetransfers',
+ 'taggit',
+ 'mptt',
+ 'compressor',
+ 'djangorestframework',
+# Base generic
+ 'permissions',
'project_setup',
'project_tools',
'smart_settings',
'navigation',
'lock_manager',
'web_theme',
+# pagination needs to go after web_theme so that the pagination template
+# if found
+ 'pagination',
'common',
'django_gpg',
- 'pagination',
'dynamic_search',
- 'filetransfers',
+ 'acls',
'converter',
- 'permissions',
- 'djcelery',
- 'indexer',
- 'paging',
- 'sentry',
- 'sentry.client',
- 'sentry.client.celery',
- 'storage',
- 'folders',
- 'taggit',
- 'tags',
- 'document_comments',
'user_management',
- 'metadata',
- 'documents',
- 'linking',
- 'mptt',
- 'document_indexing',
- 'ocr',
- 'sources',
'mimetype',
'scheduler',
'job_processor',
+ 'feedback',
+# Mayan EDMS
+ 'storage',
+ 'folders',
+ 'tags',
+ 'document_comments',
+ 'metadata',
+ 'documents',
+ 'linking',
+ 'document_indexing',
+ 'document_acls',
+ 'ocr',
+ 'sources',
'history',
'main',
- 'compressor',
- 'djangorestframework',
'rest_api',
- 'south',
+ 'document_signatures',
+
+# Has to be last so the other apps can register it's signals
+ 'signaler',
)
TEMPLATE_CONTEXT_PROCESSORS = (
'django.contrib.auth.context_processors.auth',
'django.core.context_processors.i18n',
- #'django.core.context_processors.media',
'django.core.context_processors.static',
'django.core.context_processors.request',
-# 'django.contrib.messages.context_processors.messages',
)
STATICFILES_FINDERS = (
@@ -188,106 +196,7 @@ COMPRESS_PARSER = 'compressor.parser.HtmlParser'
COMPRESS_CSS_FILTERS = ['compressor.filters.css_default.CssAbsoluteFilter', 'compressor.filters.cssmin.CSSMinFilter']
COMPRESS_ENABLED=False
-
-#===== User configuration options ===============
-#--------- Pagination ------------------
-#PAGINATION_DEFAULT_PAGINATION = 10
-#--------- Web theme app ---------------
-#WEB_THEME_THEME = 'default'
-#-------------- Main -----------------
-#MAIN_SIDE_BAR_SEARCH = False
-#------------ Common --------------
-# Printing
-# from common.literals import PAGE_SIZE_LETTER, PAGE_ORIENTATION_PORTRAIT
-#COMMON_DEFAULT_PAPER_SIZE = PAGE_SIZE_LETTER
-#COMMON_DEFAULT_PAGE_ORIENTATION = PAGE_ORIENTATION_PORTRAIT
-#------------ Storage --------------
-#DOCUMENTS_STORAGE_BACKEND = FileBasedStorage
-# GridFS settings
-#STORAGE_GRIDFS_HOST = 'localhost' # or list ['host a', 'host b']
-#STORAGE_GRIDFS_PORT = 27017
-#STORAGE_GRIDFS_DATABASE_NAME = u'document_storage'
-# Filebased
-#STORAGE_FILESTORAGE_LOCATION = u'document_storage'
-#---------- Metadata -----------------
-# METADATA_AVAILABLE_FUNCTIONS = {}
-# METADATA_AVAILABLE_MODELS = {}
-#---------- Indexing -----------------
-#DOCUMENT_INDEXING_AVAILABLE_INDEXING_FUNCTIONS = {}
-# Flesystem serving
-#DOCUMENT_INDEXING_FILESYSTEM_FILESERVING_ENABLE = True
-#DOCUMENT_INDEXING_FILESYSTEM_FILESERVING_PATH = u'/tmp/mayan/documents'
-#DOCUMENT_INDEXING_FILESYSTEM_SLUGIFY_PATHS = False
-#---------- Documents ------------------
-# Upload
-#DOCUMENTS_USE_STAGING_DIRECTORY = False
-#DOCUMENTS_STAGING_DIRECTORY = u'/tmp/mayan/staging'
-#DOCUMENTS_DELETE_STAGING_FILE_AFTER_UPLOAD = False
-#DOCUMENTS_STAGING_FILES_PREVIEW_SIZE = '640x480'
-#DOCUMENTS_ENABLE_SINGLE_DOCUMENT_UPLOAD = True
-#DOCUMENTS_UNCOMPRESS_COMPRESSED_LOCAL_FILES = True
-#DOCUMENTS_UNCOMPRESS_COMPRESSED_STAGING_FILES = True
-
-# Saving
-#DOCUMENTS_CHECKSUM_FUNCTION = lambda x: hashlib.sha256(x).hexdigest())
-#DOCUMENTS_UUID_FUNCTION = lambda:unicode(uuid.uuid4())
-#DOCUMENTS_DEFAULT_TRANSFORMATIONS = []
-
-# Usage
-#DOCUMENTS_PREVIEW_SIZE = '640x480'
-#DOCUMENTS_PRINT_SIZE = '640x480'
-#DOCUMENTS_THUMBNAIL_SIZE = '50x50'
-#DOCUMENTS_DISPLAY_SIZE = '1200'
-#DOCUMENTS_MULTIPAGE_PREVIEW_SIZE = '160x120'
-#DOCUMENTS_AVAILABLE_TRANSFORMATIONS = {}
-#example: DOCUMENTS_DEFAULT_TRANSFORMATIONS = [{'name':'rotate', 'arguments':"{'degrees':270}"}]
-#DOCUMENTS_RECENT_COUNT = 40
-#DOCUMENTS_ZOOM_PERCENT_STEP = 50
-#DOCUMENTS_ZOOM_MAX_LEVEL = 200
-#DOCUMENTS_ZOOM_MIN_LEVEL = 50
-#DOCUMENTS_ROTATION_STEP = 90
-
-#------------- Groups --------------------
-#GROUPING_SHOW_EMPTY_GROUPS = True
-#------------ Converter --------------
-#CONVERTER_DEFAULT_OPTIONS = u''
-#CONVERTER_LOW_QUALITY_OPTIONS = u''
-#CONVERTER_HIGH_QUALITY_OPTIONS = u'-density 400'
-#CONVERTER_OCR_OPTIONS = u'-colorspace Gray -depth 8 -resample 200x200'
-#CONVERTER_IM_CONVERT_PATH = u'/usr/bin/convert'
-#CONVERTER_IM_IDENTIFY_PATH = u'/usr/bin/identify'
-#CONVERTER_UNPAPER_PATH = u'/usr/bin/unpaper'
-#CONVERTER_GRAPHICS_BACKEND = u'converter.backends.imagemagick'
-#CONVERTER_GM_PATH = u'/usr/bin/gm'
-#CONVERTER_GM_SETTINGS = u''
-#------------ OCR --------------
-#OCR_TESSERACT_PATH = u'/usr/bin/tesseract'
-#OCR_NODE_CONCURRENT_EXECUTION = 1
-#OCR_TESSERACT_LANGUAGE = u'eng'
-#OCR_REPLICATION_DELAY = 10
-#OCR_AUTOMATIC_OCR = False
-#OCR_PDFTOTEXT_PATH = u'/usr/bin/pdftotext'
-#OCR_QUEUE_PROCESSING_INTERVAL = 10 # In seconds
-#OCR_CACHE_URI = None # Can be a single host (u'memcached://127.0.0.1:11211/'), or multiple separated by a semicolon
-#------------ Permissions --------------
-#ROLES_DEFAULT_ROLES = []
-#------------ Searching --------------
-#SEARCH_LIMIT = 100
-#------------ django-sendfile --------------
-# Change to xsendfile for apache if x-sendfile is enabled
SENDFILE_BACKEND = 'sendfile.backends.simple'
-#----------- django-celery --------------
-import djcelery
-djcelery.setup_loader()
-BROKER_HOST = "localhost"
-BROKER_PORT = 5672
-BROKER_USER = "guest"
-BROKER_PASSWORD = "guest"
-BROKER_VHOST = "/"
-CELERYBEAT_SCHEDULER = 'djcelery.schedulers.DatabaseScheduler'
-#======== End of user configuration options =======
-#--------- Celery ------------------
-CELERY_DISABLE_RATE_LIMITS = True
#--------- Web theme ---------------
WEB_THEME_ENABLE_SCROLL_JS = False
#--------- Django -------------------
@@ -334,22 +243,19 @@ if DEVELOPMENT:
import rosetta
INSTALLED_APPS += ('rosetta',)
except ImportError:
- #print 'rosetta is not installed'
pass
try:
import django_extensions
INSTALLED_APPS += ('django_extensions',)
except ImportError:
- #print 'django_extensions is not installed'
pass
try:
import debug_toolbar
#INSTALLED_APPS +=('debug_toolbar',)
except ImportError:
- #print 'debug_toolbar is not installed'
- pass
+ pass
TEMPLATE_CONTEXT_PROCESSORS += ('django.core.context_processors.debug',)
diff --git a/urls.py b/urls.py
index a4ccd38cef..a6ae677f51 100644
--- a/urls.py
+++ b/urls.py
@@ -15,7 +15,6 @@ urlpatterns = patterns('',
(r'^tags/', include('tags.urls')),
(r'^admin/doc/', include('django.contrib.admindocs.urls')),
(r'^admin/', include(admin.site.urls)),
- (r'^sentry/', include('sentry.urls')),
(r'^comments/', include('document_comments.urls')),
(r'^user_management/', include('user_management.urls')),
(r'^settings/', include('smart_settings.urls')),
@@ -27,8 +26,12 @@ urlpatterns = patterns('',
(r'^sources/', include('sources.urls')),
(r'^project_setup/', include('project_setup.urls')),
(r'^project_tools/', include('project_tools.urls')),
+ (r'^acls/', include('acls.urls')),
+ (r'^document_acls/', include('document_acls.urls')),
(r'^api/', include('rest_api.urls')),
- (r'^signatures/', include('django_gpg.urls')),
+ (r'^gpg/', include('django_gpg.urls')),
+ (r'^documents/signatures/', include('document_signatures.urls')),
+ (r'^feedback/', include('feedback.urls')),
)
diff --git a/wsgi/dispatch.wsgi b/wsgi/dispatch.wsgi
index fc2615a09a..68cd5368ac 100644
--- a/wsgi/dispatch.wsgi
+++ b/wsgi/dispatch.wsgi
@@ -4,7 +4,9 @@ import site
sys.stdout = sys.stderr
-ve_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'lib/python2.6/site-packages'))
+#TODO fix properly
+ve_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'lib/python2.7/site-packages')) # Change python 2.6 to the python version you are using
+
# Add the virtual Python environment site-packages directory to the path
site.addsitedir(ve_path)
@@ -16,7 +18,7 @@ sys.path.insert(0, ve_path)
# Avoid ``[Errno 13] Permission denied: '/var/www/.python-eggs'`` messages
os.environ['PYTHON_EGG_CACHE'] = '/tmp'
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
-os.environ['CELERY_LOADER'] = 'django'
from django.core.handlers.wsgi import WSGIHandler
+
application = WSGIHandler()